3 from __future__ import absolute_import, print_function
7 import libcloud.compute.base as cloud_base
8 import libcloud.compute.providers as cloud_provider
9 import libcloud.compute.types as cloud_types
10 from libcloud.compute.drivers import ec2 as cloud_ec2
12 from . import BaseComputeNodeDriver, arvados_node_fqdn
14 ### Monkeypatch libcloud to support AWS' new SecurityGroup API.
15 # These classes can be removed when libcloud support specifying
16 # security groups with the SecurityGroupId parameter.
17 class ANMEC2Connection(cloud_ec2.EC2Connection):
18 def request(self, *args, **kwargs):
19 params = kwargs.get('params')
20 if (params is not None) and (params.get('Action') == 'RunInstances'):
21 for key in params.keys():
22 if key.startswith('SecurityGroup.'):
23 new_key = key.replace('Group.', 'GroupId.', 1)
24 params[new_key] = params.pop(key).id
25 kwargs['params'] = params
26 return super(ANMEC2Connection, self).request(*args, **kwargs)
29 class ANMEC2NodeDriver(cloud_ec2.EC2NodeDriver):
30 connectionCls = ANMEC2Connection
33 class ComputeNodeDriver(BaseComputeNodeDriver):
34 """Compute node driver wrapper for EC2.
36 This translates cloud driver requests to EC2's specific parameters.
38 DEFAULT_DRIVER = ANMEC2NodeDriver
42 def __init__(self, auth_kwargs, list_kwargs, create_kwargs,
43 driver_class=DEFAULT_DRIVER):
44 # We need full lists of keys up front because these loops modify
45 # dictionaries in-place.
46 for key in list_kwargs.keys():
47 list_kwargs[key.replace('_', ':')] = list_kwargs.pop(key)
48 self.tags = {key[4:]: value
49 for key, value in list_kwargs.iteritems()
50 if key.startswith('tag:')}
51 super(ComputeNodeDriver, self).__init__(
52 auth_kwargs, {'ex_filters': list_kwargs}, create_kwargs,
54 for key in self.create_kwargs.keys():
55 init_method = getattr(self, '_init_' + key, None)
56 if init_method is not None:
57 new_pair = init_method(self.create_kwargs.pop(key))
58 if new_pair is not None:
59 self.create_kwargs[new_pair[0]] = new_pair[1]
61 def _init_image_id(self, image_id):
62 return 'image', self.search_for(image_id, 'list_images')
64 def _init_ping_host(self, ping_host):
65 self.ping_host = ping_host
67 def _init_security_groups(self, group_names):
68 return 'ex_security_groups', [
69 self.search_for(gname.strip(), 'ex_get_security_groups')
70 for gname in group_names.split(',')]
72 def _init_subnet_id(self, subnet_id):
73 return 'ex_subnet', self.search_for(subnet_id, 'ex_list_subnets')
75 def _init_ssh_key(self, filename):
76 with open(filename) as ssh_file:
77 key = cloud_base.NodeAuthSSHKey(ssh_file.read())
80 def arvados_create_kwargs(self, arvados_node):
81 result = {'ex_metadata': self.tags.copy(),
82 'name': arvados_node_fqdn(arvados_node)}
83 ping_secret = arvados_node['info'].get('ping_secret')
84 if ping_secret is not None:
85 ping_url = ('https://{}/arvados/v1/nodes/{}/ping?ping_secret={}'.
86 format(self.ping_host, arvados_node['uuid'],
88 result['ex_userdata'] = ping_url
91 def sync_node(self, cloud_node, arvados_node):
92 metadata = self.arvados_create_kwargs(arvados_node)
93 tags = metadata['ex_metadata']
94 tags['Name'] = metadata['name']
95 self.real.ex_create_tags(cloud_node, tags)
98 def node_start_time(cls, node):
99 time_str = node.extra['launch_time'].split('.', 2)[0] + 'UTC'
100 return time.mktime(time.strptime(
101 time_str,'%Y-%m-%dT%H:%M:%S%Z')) - time.timezone