Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/boto/mashups/server.py @ 2:6af9afd405e9 draft
"planemo upload commit 0a63dd5f4d38a1f6944587f52a8cd79874177fc1"
author | shellac |
---|---|
date | Thu, 14 May 2020 14:56:58 -0400 |
parents | 26e78fe6e8c4 |
children |
comparison
equal
deleted
inserted
replaced
1:75ca89e9b81c | 2:6af9afd405e9 |
---|---|
1 # Copyright (c) 2006,2007 Mitch Garnaat http://garnaat.org/ | |
2 # | |
3 # Permission is hereby granted, free of charge, to any person obtaining a | |
4 # copy of this software and associated documentation files (the | |
5 # "Software"), to deal in the Software without restriction, including | |
6 # without limitation the rights to use, copy, modify, merge, publish, dis- | |
7 # tribute, sublicense, and/or sell copies of the Software, and to permit | |
8 # persons to whom the Software is furnished to do so, subject to the fol- | |
9 # lowing conditions: | |
10 # | |
11 # The above copyright notice and this permission notice shall be included | |
12 # in all copies or substantial portions of the Software. | |
13 # | |
14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
15 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- | |
16 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | |
17 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
18 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
19 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | |
20 # IN THE SOFTWARE. | |
21 """ | |
22 High-level abstraction of an EC2 server | |
23 """ | |
24 | |
25 import boto | |
26 import boto.utils | |
27 from boto.compat import StringIO | |
28 from boto.mashups.iobject import IObject | |
29 from boto.pyami.config import Config, BotoConfigPath | |
30 from boto.mashups.interactive import interactive_shell | |
31 from boto.sdb.db.model import Model | |
32 from boto.sdb.db.property import StringProperty | |
33 import os | |
34 | |
35 | |
36 class ServerSet(list): | |
37 | |
38 def __getattr__(self, name): | |
39 results = [] | |
40 is_callable = False | |
41 for server in self: | |
42 try: | |
43 val = getattr(server, name) | |
44 if callable(val): | |
45 is_callable = True | |
46 results.append(val) | |
47 except: | |
48 results.append(None) | |
49 if is_callable: | |
50 self.map_list = results | |
51 return self.map | |
52 return results | |
53 | |
54 def map(self, *args): | |
55 results = [] | |
56 for fn in self.map_list: | |
57 results.append(fn(*args)) | |
58 return results | |
59 | |
60 class Server(Model): | |
61 | |
62 @property | |
63 def ec2(self): | |
64 if self._ec2 is None: | |
65 self._ec2 = boto.connect_ec2() | |
66 return self._ec2 | |
67 | |
68 @classmethod | |
69 def Inventory(cls): | |
70 """ | |
71 Returns a list of Server instances, one for each Server object | |
72 persisted in the db | |
73 """ | |
74 l = ServerSet() | |
75 rs = cls.find() | |
76 for server in rs: | |
77 l.append(server) | |
78 return l | |
79 | |
80 @classmethod | |
81 def Register(cls, name, instance_id, description=''): | |
82 s = cls() | |
83 s.name = name | |
84 s.instance_id = instance_id | |
85 s.description = description | |
86 s.save() | |
87 return s | |
88 | |
89 def __init__(self, id=None, **kw): | |
90 super(Server, self).__init__(id, **kw) | |
91 self._reservation = None | |
92 self._instance = None | |
93 self._ssh_client = None | |
94 self._pkey = None | |
95 self._config = None | |
96 self._ec2 = None | |
97 | |
98 name = StringProperty(unique=True, verbose_name="Name") | |
99 instance_id = StringProperty(verbose_name="Instance ID") | |
100 config_uri = StringProperty() | |
101 ami_id = StringProperty(verbose_name="AMI ID") | |
102 zone = StringProperty(verbose_name="Availability Zone") | |
103 security_group = StringProperty(verbose_name="Security Group", default="default") | |
104 key_name = StringProperty(verbose_name="Key Name") | |
105 elastic_ip = StringProperty(verbose_name="Elastic IP") | |
106 instance_type = StringProperty(verbose_name="Instance Type") | |
107 description = StringProperty(verbose_name="Description") | |
108 log = StringProperty() | |
109 | |
110 def setReadOnly(self, value): | |
111 raise AttributeError | |
112 | |
113 def getInstance(self): | |
114 if not self._instance: | |
115 if self.instance_id: | |
116 try: | |
117 rs = self.ec2.get_all_reservations([self.instance_id]) | |
118 except: | |
119 return None | |
120 if len(rs) > 0: | |
121 self._reservation = rs[0] | |
122 self._instance = self._reservation.instances[0] | |
123 return self._instance | |
124 | |
125 instance = property(getInstance, setReadOnly, None, 'The Instance for the server') | |
126 | |
127 def getAMI(self): | |
128 if self.instance: | |
129 return self.instance.image_id | |
130 | |
131 ami = property(getAMI, setReadOnly, None, 'The AMI for the server') | |
132 | |
133 def getStatus(self): | |
134 if self.instance: | |
135 self.instance.update() | |
136 return self.instance.state | |
137 | |
138 status = property(getStatus, setReadOnly, None, | |
139 'The status of the server') | |
140 | |
141 def getHostname(self): | |
142 if self.instance: | |
143 return self.instance.public_dns_name | |
144 | |
145 hostname = property(getHostname, setReadOnly, None, | |
146 'The public DNS name of the server') | |
147 | |
148 def getPrivateHostname(self): | |
149 if self.instance: | |
150 return self.instance.private_dns_name | |
151 | |
152 private_hostname = property(getPrivateHostname, setReadOnly, None, | |
153 'The private DNS name of the server') | |
154 | |
155 def getLaunchTime(self): | |
156 if self.instance: | |
157 return self.instance.launch_time | |
158 | |
159 launch_time = property(getLaunchTime, setReadOnly, None, | |
160 'The time the Server was started') | |
161 | |
162 def getConsoleOutput(self): | |
163 if self.instance: | |
164 return self.instance.get_console_output() | |
165 | |
166 console_output = property(getConsoleOutput, setReadOnly, None, | |
167 'Retrieve the console output for server') | |
168 | |
169 def getGroups(self): | |
170 if self._reservation: | |
171 return self._reservation.groups | |
172 else: | |
173 return None | |
174 | |
175 groups = property(getGroups, setReadOnly, None, | |
176 'The Security Groups controlling access to this server') | |
177 | |
178 def getConfig(self): | |
179 if not self._config: | |
180 remote_file = BotoConfigPath | |
181 local_file = '%s.ini' % self.instance.id | |
182 self.get_file(remote_file, local_file) | |
183 self._config = Config(local_file) | |
184 return self._config | |
185 | |
186 def setConfig(self, config): | |
187 local_file = '%s.ini' % self.instance.id | |
188 fp = open(local_file) | |
189 config.write(fp) | |
190 fp.close() | |
191 self.put_file(local_file, BotoConfigPath) | |
192 self._config = config | |
193 | |
194 config = property(getConfig, setConfig, None, | |
195 'The instance data for this server') | |
196 | |
197 def set_config(self, config): | |
198 """ | |
199 Set SDB based config | |
200 """ | |
201 self._config = config | |
202 self._config.dump_to_sdb("botoConfigs", self.id) | |
203 | |
204 def load_config(self): | |
205 self._config = Config(do_load=False) | |
206 self._config.load_from_sdb("botoConfigs", self.id) | |
207 | |
208 def stop(self): | |
209 if self.instance: | |
210 self.instance.stop() | |
211 | |
212 def start(self): | |
213 self.stop() | |
214 ec2 = boto.connect_ec2() | |
215 ami = ec2.get_all_images(image_ids = [str(self.ami_id)])[0] | |
216 groups = ec2.get_all_security_groups(groupnames=[str(self.security_group)]) | |
217 if not self._config: | |
218 self.load_config() | |
219 if not self._config.has_section("Credentials"): | |
220 self._config.add_section("Credentials") | |
221 self._config.set("Credentials", "aws_access_key_id", ec2.aws_access_key_id) | |
222 self._config.set("Credentials", "aws_secret_access_key", ec2.aws_secret_access_key) | |
223 | |
224 if not self._config.has_section("Pyami"): | |
225 self._config.add_section("Pyami") | |
226 | |
227 if self._manager.domain: | |
228 self._config.set('Pyami', 'server_sdb_domain', self._manager.domain.name) | |
229 self._config.set("Pyami", 'server_sdb_name', self.name) | |
230 | |
231 cfg = StringIO() | |
232 self._config.write(cfg) | |
233 cfg = cfg.getvalue() | |
234 r = ami.run(min_count=1, | |
235 max_count=1, | |
236 key_name=self.key_name, | |
237 security_groups = groups, | |
238 instance_type = self.instance_type, | |
239 placement = self.zone, | |
240 user_data = cfg) | |
241 i = r.instances[0] | |
242 self.instance_id = i.id | |
243 self.put() | |
244 if self.elastic_ip: | |
245 ec2.associate_address(self.instance_id, self.elastic_ip) | |
246 | |
247 def reboot(self): | |
248 if self.instance: | |
249 self.instance.reboot() | |
250 | |
251 def get_ssh_client(self, key_file=None, host_key_file='~/.ssh/known_hosts', | |
252 uname='root'): | |
253 import paramiko | |
254 if not self.instance: | |
255 print('No instance yet!') | |
256 return | |
257 if not self._ssh_client: | |
258 if not key_file: | |
259 iobject = IObject() | |
260 key_file = iobject.get_filename('Path to OpenSSH Key file') | |
261 self._pkey = paramiko.RSAKey.from_private_key_file(key_file) | |
262 self._ssh_client = paramiko.SSHClient() | |
263 self._ssh_client.load_system_host_keys() | |
264 self._ssh_client.load_host_keys(os.path.expanduser(host_key_file)) | |
265 self._ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) | |
266 self._ssh_client.connect(self.instance.public_dns_name, | |
267 username=uname, pkey=self._pkey) | |
268 return self._ssh_client | |
269 | |
270 def get_file(self, remotepath, localpath): | |
271 ssh_client = self.get_ssh_client() | |
272 sftp_client = ssh_client.open_sftp() | |
273 sftp_client.get(remotepath, localpath) | |
274 | |
275 def put_file(self, localpath, remotepath): | |
276 ssh_client = self.get_ssh_client() | |
277 sftp_client = ssh_client.open_sftp() | |
278 sftp_client.put(localpath, remotepath) | |
279 | |
280 def listdir(self, remotepath): | |
281 ssh_client = self.get_ssh_client() | |
282 sftp_client = ssh_client.open_sftp() | |
283 return sftp_client.listdir(remotepath) | |
284 | |
285 def shell(self, key_file=None): | |
286 ssh_client = self.get_ssh_client(key_file) | |
287 channel = ssh_client.invoke_shell() | |
288 interactive_shell(channel) | |
289 | |
290 def bundle_image(self, prefix, key_file, cert_file, size): | |
291 print('bundling image...') | |
292 print('\tcopying cert and pk over to /mnt directory on server') | |
293 ssh_client = self.get_ssh_client() | |
294 sftp_client = ssh_client.open_sftp() | |
295 path, name = os.path.split(key_file) | |
296 remote_key_file = '/mnt/%s' % name | |
297 self.put_file(key_file, remote_key_file) | |
298 path, name = os.path.split(cert_file) | |
299 remote_cert_file = '/mnt/%s' % name | |
300 self.put_file(cert_file, remote_cert_file) | |
301 print('\tdeleting %s' % BotoConfigPath) | |
302 # delete the metadata.ini file if it exists | |
303 try: | |
304 sftp_client.remove(BotoConfigPath) | |
305 except: | |
306 pass | |
307 command = 'sudo ec2-bundle-vol ' | |
308 command += '-c %s -k %s ' % (remote_cert_file, remote_key_file) | |
309 command += '-u %s ' % self._reservation.owner_id | |
310 command += '-p %s ' % prefix | |
311 command += '-s %d ' % size | |
312 command += '-d /mnt ' | |
313 if self.instance.instance_type == 'm1.small' or self.instance_type == 'c1.medium': | |
314 command += '-r i386' | |
315 else: | |
316 command += '-r x86_64' | |
317 print('\t%s' % command) | |
318 t = ssh_client.exec_command(command) | |
319 response = t[1].read() | |
320 print('\t%s' % response) | |
321 print('\t%s' % t[2].read()) | |
322 print('...complete!') | |
323 | |
324 def upload_bundle(self, bucket, prefix): | |
325 print('uploading bundle...') | |
326 command = 'ec2-upload-bundle ' | |
327 command += '-m /mnt/%s.manifest.xml ' % prefix | |
328 command += '-b %s ' % bucket | |
329 command += '-a %s ' % self.ec2.aws_access_key_id | |
330 command += '-s %s ' % self.ec2.aws_secret_access_key | |
331 print('\t%s' % command) | |
332 ssh_client = self.get_ssh_client() | |
333 t = ssh_client.exec_command(command) | |
334 response = t[1].read() | |
335 print('\t%s' % response) | |
336 print('\t%s' % t[2].read()) | |
337 print('...complete!') | |
338 | |
339 def create_image(self, bucket=None, prefix=None, key_file=None, cert_file=None, size=None): | |
340 iobject = IObject() | |
341 if not bucket: | |
342 bucket = iobject.get_string('Name of S3 bucket') | |
343 if not prefix: | |
344 prefix = iobject.get_string('Prefix for AMI file') | |
345 if not key_file: | |
346 key_file = iobject.get_filename('Path to RSA private key file') | |
347 if not cert_file: | |
348 cert_file = iobject.get_filename('Path to RSA public cert file') | |
349 if not size: | |
350 size = iobject.get_int('Size (in MB) of bundled image') | |
351 self.bundle_image(prefix, key_file, cert_file, size) | |
352 self.upload_bundle(bucket, prefix) | |
353 print('registering image...') | |
354 self.image_id = self.ec2.register_image('%s/%s.manifest.xml' % (bucket, prefix)) | |
355 return self.image_id | |
356 | |
357 def attach_volume(self, volume, device="/dev/sdp"): | |
358 """ | |
359 Attach an EBS volume to this server | |
360 | |
361 :param volume: EBS Volume to attach | |
362 :type volume: boto.ec2.volume.Volume | |
363 | |
364 :param device: Device to attach to (default to /dev/sdp) | |
365 :type device: string | |
366 """ | |
367 if hasattr(volume, "id"): | |
368 volume_id = volume.id | |
369 else: | |
370 volume_id = volume | |
371 return self.ec2.attach_volume(volume_id=volume_id, instance_id=self.instance_id, device=device) | |
372 | |
373 def detach_volume(self, volume): | |
374 """ | |
375 Detach an EBS volume from this server | |
376 | |
377 :param volume: EBS Volume to detach | |
378 :type volume: boto.ec2.volume.Volume | |
379 """ | |
380 if hasattr(volume, "id"): | |
381 volume_id = volume.id | |
382 else: | |
383 volume_id = volume | |
384 return self.ec2.detach_volume(volume_id=volume_id, instance_id=self.instance_id) | |
385 | |
386 def install_package(self, package_name): | |
387 print('installing %s...' % package_name) | |
388 command = 'yum -y install %s' % package_name | |
389 print('\t%s' % command) | |
390 ssh_client = self.get_ssh_client() | |
391 t = ssh_client.exec_command(command) | |
392 response = t[1].read() | |
393 print('\t%s' % response) | |
394 print('\t%s' % t[2].read()) | |
395 print('...complete!') |