3 from __future__ import absolute_import, print_function
11 import arvnodeman.computenode.driver.gce as gce
12 from . import testutil
14 class GCEComputeNodeDriverTestCase(testutil.DriverTestMixin, unittest.TestCase):
15 TEST_CLASS = gce.ComputeNodeDriver
17 def test_driver_instantiation(self):
18 kwargs = {'user_id': 'foo'}
19 driver = self.new_driver(auth_kwargs=kwargs)
20 self.assertTrue(self.driver_mock.called)
21 self.assertEqual(kwargs, self.driver_mock.call_args[1])
23 def test_create_image_loaded_at_initialization_by_name(self):
24 image_mocks = [testutil.cloud_object_mock(c) for c in 'abc']
25 list_method = self.driver_mock().list_images
26 list_method.return_value = image_mocks
27 driver = self.new_driver(create_kwargs={'image': 'b'})
28 self.assertEqual(1, list_method.call_count)
30 def test_create_includes_ping_secret(self):
31 arv_node = testutil.arvados_node_mock(info={'ping_secret': 'ssshh'})
32 driver = self.new_driver()
33 driver.create_node(testutil.MockSize(1), arv_node)
34 metadata = self.driver_mock().create_node.call_args[1]['ex_metadata']
35 self.assertIn('ping_secret=ssshh', metadata.get('arv-ping-url'))
37 def test_create_sets_default_hostname(self):
38 driver = self.new_driver()
39 driver.create_node(testutil.MockSize(1),
40 testutil.arvados_node_mock(254, hostname=None))
41 create_kwargs = self.driver_mock().create_node.call_args[1]
42 self.assertEqual('compute-0000000000000fe-zzzzz',
43 create_kwargs.get('name'))
44 self.assertEqual('dynamic.compute.zzzzz.arvadosapi.com',
45 create_kwargs.get('ex_metadata', {}).get('hostname'))
47 def test_create_tags_from_list_tags(self):
48 driver = self.new_driver(list_kwargs={'tags': 'testA, testB'})
49 driver.create_node(testutil.MockSize(1), testutil.arvados_node_mock())
50 self.assertEqual(['testA', 'testB'],
51 self.driver_mock().create_node.call_args[1]['ex_tags'])
53 def test_list_nodes_requires_tags_match(self):
54 # A node matches if our list tags are a subset of the node's tags.
55 # Test behavior with no tags, no match, partial matches, different
56 # order, and strict supersets.
58 testutil.cloud_node_mock(node_num, tags=tag_set)
59 for node_num, tag_set in enumerate(
60 [[], ['bad'], ['good'], ['great'], ['great', 'ok'],
61 ['great', 'good'], ['good', 'fantastic', 'great']])]
62 cloud_mocks.append(testutil.cloud_node_mock())
63 self.driver_mock().list_nodes.return_value = cloud_mocks
64 driver = self.new_driver(list_kwargs={'tags': 'good, great'})
65 self.assertItemsEqual(['5', '6'], [n.id for n in driver.list_nodes()])
67 def build_gce_metadata(self, metadata_dict):
68 # Convert a plain metadata dictionary to the GCE data structure.
70 'kind': 'compute#metadata',
71 'fingerprint': 'testprint',
72 'items': [{'key': key, 'value': metadata_dict[key]}
73 for key in metadata_dict],
76 def check_sync_node_updates_hostname_tag(self, plain_metadata):
77 start_metadata = self.build_gce_metadata(plain_metadata)
78 arv_node = testutil.arvados_node_mock(1)
79 cloud_node = testutil.cloud_node_mock(
80 2, metadata=start_metadata.copy(),
81 zone=testutil.cloud_object_mock('testzone'))
82 driver = self.new_driver()
83 driver.sync_node(cloud_node, arv_node)
84 args, kwargs = self.driver_mock().connection.async_request.call_args
85 self.assertEqual('/zones/testzone/instances/2/setMetadata', args[0])
86 for key in ['kind', 'fingerprint']:
87 self.assertEqual(start_metadata[key], kwargs['data'][key])
88 plain_metadata['hostname'] = 'compute1.zzzzz.arvadosapi.com'
91 {item['key']: item['value'] for item in kwargs['data']['items']})
93 def test_sync_node_updates_hostname_tag(self):
94 self.check_sync_node_updates_hostname_tag(
95 {'testkey': 'testvalue', 'hostname': 'startvalue'})
97 def test_sync_node_adds_hostname_tag(self):
98 self.check_sync_node_updates_hostname_tag({'testkey': 'testval'})
100 def test_sync_node_raises_exception_on_failure(self):
101 arv_node = testutil.arvados_node_mock(8)
102 cloud_node = testutil.cloud_node_mock(
103 9, metadata={}, zone=testutil.cloud_object_mock('failzone'))
104 mock_response = self.driver_mock().connection.async_request()
105 mock_response.success.return_value = False
106 mock_response.error = 'sync error test'
107 driver = self.new_driver()
108 with self.assertRaises(Exception) as err_check:
109 driver.sync_node(cloud_node, arv_node)
110 self.assertIs(err_check.exception.__class__, Exception)
111 self.assertIn('sync error test', str(err_check.exception))
113 def test_node_create_time_zero_for_unknown_nodes(self):
114 node = testutil.cloud_node_mock()
115 self.assertEqual(0, gce.ComputeNodeDriver.node_start_time(node))
117 def test_node_create_time_for_known_node(self):
118 node = testutil.cloud_node_mock(metadata=self.build_gce_metadata(
119 {'booted_at': '1970-01-01T00:01:05Z'}))
120 self.assertEqual(65, gce.ComputeNodeDriver.node_start_time(node))
122 def test_node_create_time_recorded_when_node_boots(self):
123 start_time = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())
124 arv_node = testutil.arvados_node_mock()
125 driver = self.new_driver()
126 driver.create_node(testutil.MockSize(1), arv_node)
127 metadata = self.driver_mock().create_node.call_args[1]['ex_metadata']
128 self.assertLessEqual(start_time, metadata.get('booted_at'))
130 def test_known_node_fqdn(self):
131 name = 'fqdntest.zzzzz.arvadosapi.com'
132 node = testutil.cloud_node_mock(metadata=self.build_gce_metadata(
134 self.assertEqual(name, gce.ComputeNodeDriver.node_fqdn(node))
136 def test_unknown_node_fqdn(self):
137 # Return an empty string. This lets fqdn be safely compared
138 # against an expected value, and ComputeNodeMonitorActor
139 # should try to update it.
140 node = testutil.cloud_node_mock(metadata=self.build_gce_metadata({}))
141 self.assertEqual('', gce.ComputeNodeDriver.node_fqdn(node))
143 def test_deliver_ssh_key_in_metadata(self):
144 test_ssh_key = 'ssh-rsa-foo'
145 arv_node = testutil.arvados_node_mock(1)
146 with mock.patch('__builtin__.open',
147 mock.mock_open(read_data=test_ssh_key)) as mock_file:
148 driver = self.new_driver(create_kwargs={'ssh_key': 'ssh-key-file'})
149 mock_file.assert_called_once_with('ssh-key-file')
150 driver.create_node(testutil.MockSize(1), arv_node)
151 metadata = self.driver_mock().create_node.call_args[1]['ex_metadata']
152 self.assertEqual('root:ssh-rsa-foo', metadata.get('sshKeys'))
154 def test_create_driver_with_service_accounts(self):
155 service_accounts = {'email': 'foo@bar', 'scopes': ['storage-full']}
156 srv_acct_config = {'service_accounts': json.dumps(service_accounts)}
157 arv_node = testutil.arvados_node_mock(1)
158 driver = self.new_driver(create_kwargs=srv_acct_config)
159 driver.create_node(testutil.MockSize(1), arv_node)
162 self.driver_mock().create_node.call_args[1]['ex_service_accounts'])