3 from __future__ import absolute_import, print_function
9 import libcloud.compute.base as cloud_base
10 import libcloud.compute.providers as cloud_provider
11 import libcloud.compute.types as cloud_types
12 from libcloud.compute.drivers import gce
14 from . import BaseComputeNodeDriver
15 from .. import arvados_node_fqdn
17 class ComputeNodeDriver(BaseComputeNodeDriver):
18 """Compute node driver wrapper for GCE
20 This translates cloud driver requests to GCE's specific parameters.
22 DEFAULT_DRIVER = cloud_provider.get_driver(cloud_types.Provider.GCE)
25 service_accounts = None
27 def __init__(self, auth_kwargs, list_kwargs, create_kwargs,
28 driver_class=DEFAULT_DRIVER):
29 super(ComputeNodeDriver, self).__init__(
30 auth_kwargs, list_kwargs, create_kwargs,
33 for key in self.create_kwargs.keys():
34 init_method = getattr(self, '_init_' + key, None)
35 if init_method is not None:
36 new_pair = init_method(self.create_kwargs.pop(key))
37 if new_pair is not None:
38 self.create_kwargs[new_pair[0]] = new_pair[1]
40 def _init_image_id(self, image_id):
41 return 'image', image_id
43 def _init_ping_host(self, ping_host):
44 self.ping_host = ping_host
46 def _init_service_accounts(self, service_accounts_str):
47 self.service_accounts = json.loads(service_accounts_str)
49 def _init_network_id(self, subnet_id):
50 return 'ex_network', subnet_id
52 def _init_ssh_key(self, filename):
53 with open(filename) as ssh_file:
54 self.ssh_key = ssh_file.read().strip()
56 def arvados_create_kwargs(self, arvados_node):
57 result = {'ex_metadata': self.list_kwargs.copy() }
58 ping_secret = arvados_node['info'].get('ping_secret')
59 if ping_secret is not None:
60 ping_url = ('https://{}/arvados/v1/nodes/{}/ping?ping_secret={}'.
61 format(self.ping_host, arvados_node['uuid'],
63 result['ex_userdata'] = ping_url
64 if self.service_accounts is not None:
65 result['ex_service_accounts'] = self.service_accounts
67 # SSH keys are delivered to GCE nodes via ex_metadata: see
68 # http://stackoverflow.com/questions/26752617/creating-sshkeys-for-gce-instance-using-libcloud
69 if self.ssh_key is not None:
70 result['ex_metadata']['sshKeys'] = 'root:{}'.format(self.ssh_key)
73 # When an Arvados node is synced with a GCE node, the Arvados hostname
74 # is forwarded in a GCE tag 'hostname-foo'.
75 # TODO(twp): implement an ex_set_metadata method (at least until
76 # libcloud supports the API setMetadata method) so we can pass this
77 # sensibly in the node metadata.
78 def sync_node(self, cloud_node, arvados_node):
79 tags = ['hostname-{}'.format(arvados_node_fqdn(arvados_node))]
80 self.real.ex_set_node_tags(cloud_node, tags)
83 def node_start_time(cls, node):
84 time_str = node.extra['launch_time'].split('.', 2)[0] + 'UTC'
85 return time.mktime(time.strptime(
86 time_str,'%Y-%m-%dT%H:%M:%S%Z')) - time.timezone