X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/c4fa80c6ed2445e1e384455944eb6c4108906cad..0eb72b526bf8bbb011551ecf019f604e17a534f1:/services/nodemanager/tests/test_computenode_driver_gce.py diff --git a/services/nodemanager/tests/test_computenode_driver_gce.py b/services/nodemanager/tests/test_computenode_driver_gce.py index f995a8de17..cfc4add63b 100644 --- a/services/nodemanager/tests/test_computenode_driver_gce.py +++ b/services/nodemanager/tests/test_computenode_driver_gce.py @@ -1,4 +1,7 @@ #!/usr/bin/env python +# Copyright (C) The Arvados Authors. All rights reserved. +# +# SPDX-License-Identifier: AGPL-3.0 from __future__ import absolute_import, print_function @@ -14,6 +17,20 @@ from . import testutil class GCEComputeNodeDriverTestCase(testutil.DriverTestMixin, unittest.TestCase): TEST_CLASS = gce.ComputeNodeDriver + def setUp(self): + super(GCEComputeNodeDriverTestCase, self).setUp() + self.driver_mock().list_images.return_value = [ + testutil.cloud_object_mock('testimage', selfLink='image-link')] + self.driver_mock().ex_list_disktypes.return_value = [ + testutil.cloud_object_mock(name, selfLink=name + '-link') + for name in ['pd-standard', 'pd-ssd', 'local-ssd']] + self.driver_mock.reset_mock() + + def new_driver(self, auth_kwargs={}, list_kwargs={}, create_kwargs={}): + create_kwargs.setdefault('image', 'testimage') + return super(GCEComputeNodeDriverTestCase, self).new_driver( + auth_kwargs, list_kwargs, create_kwargs) + def test_driver_instantiation(self): kwargs = {'user_id': 'foo'} driver = self.new_driver(auth_kwargs=kwargs) @@ -24,24 +41,25 @@ class GCEComputeNodeDriverTestCase(testutil.DriverTestMixin, unittest.TestCase): image_mocks = [testutil.cloud_object_mock(c) for c in 'abc'] list_method = self.driver_mock().list_images list_method.return_value = image_mocks - driver = self.new_driver(create_kwargs={'image': 'B'}) + driver = self.new_driver(create_kwargs={'image': 'b'}) self.assertEqual(1, list_method.call_count) - def test_list_sizes_requires_location_match(self): - locations = [testutil.cloud_object_mock(name) - for name in ['there', 'here', 'other']] - self.driver_mock().list_locations.return_value = locations - driver = self.new_driver(create_kwargs={'location': 'HERE'}) - driver.list_sizes() - self.assertIs(locations[1], - self.driver_mock().list_sizes.call_args[0][0]) - def test_create_includes_ping_secret(self): arv_node = testutil.arvados_node_mock(info={'ping_secret': 'ssshh'}) driver = self.new_driver() driver.create_node(testutil.MockSize(1), arv_node) metadata = self.driver_mock().create_node.call_args[1]['ex_metadata'] - self.assertIn('ping_secret=ssshh', metadata.get('user-data')) + self.assertIn('ping_secret=ssshh', metadata.get('arv-ping-url')) + + def test_create_raises_but_actually_succeeded(self): + arv_node = testutil.arvados_node_mock(1, hostname=None) + driver = self.new_driver() + nodelist = [testutil.cloud_node_mock(1)] + nodelist[0].name = 'compute-000000000000001-zzzzz' + self.driver_mock().list_nodes.return_value = nodelist + self.driver_mock().create_node.side_effect = IOError + n = driver.create_node(testutil.MockSize(1), arv_node) + self.assertEqual('compute-000000000000001-zzzzz', n.name) def test_create_sets_default_hostname(self): driver = self.new_driver() @@ -59,6 +77,26 @@ class GCEComputeNodeDriverTestCase(testutil.DriverTestMixin, unittest.TestCase): self.assertEqual(['testA', 'testB'], self.driver_mock().create_node.call_args[1]['ex_tags']) + def test_create_with_two_disks_attached(self): + driver = self.new_driver(create_kwargs={'image': 'testimage'}) + driver.create_node(testutil.MockSize(1), testutil.arvados_node_mock()) + create_disks = self.driver_mock().create_node.call_args[1].get( + 'ex_disks_gce_struct', []) + self.assertEqual(2, len(create_disks)) + self.assertTrue(create_disks[0].get('autoDelete')) + self.assertTrue(create_disks[0].get('boot')) + self.assertEqual('PERSISTENT', create_disks[0].get('type')) + init_params = create_disks[0].get('initializeParams', {}) + self.assertEqual('pd-standard-link', init_params.get('diskType')) + self.assertEqual('image-link', init_params.get('sourceImage')) + # Our node images expect the SSD to be named `tmp` to find and mount it. + self.assertEqual('tmp', create_disks[1].get('deviceName')) + self.assertTrue(create_disks[1].get('autoDelete')) + self.assertFalse(create_disks[1].get('boot', 'unset')) + self.assertEqual('SCRATCH', create_disks[1].get('type')) + init_params = create_disks[1].get('initializeParams', {}) + self.assertEqual('local-ssd-link', init_params.get('diskType')) + def test_list_nodes_requires_tags_match(self): # A node matches if our list tags are a subset of the node's tags. # Test behavior with no tags, no match, partial matches, different @@ -88,16 +126,15 @@ class GCEComputeNodeDriverTestCase(testutil.DriverTestMixin, unittest.TestCase): cloud_node = testutil.cloud_node_mock( 2, metadata=start_metadata.copy(), zone=testutil.cloud_object_mock('testzone')) + self.driver_mock().ex_get_node.return_value = cloud_node driver = self.new_driver() driver.sync_node(cloud_node, arv_node) - args, kwargs = self.driver_mock().connection.async_request.call_args - self.assertEqual('/zones/TESTZONE/instances/2/setMetadata', args[0]) - for key in ['kind', 'fingerprint']: - self.assertEqual(start_metadata[key], kwargs['data'][key]) + args, kwargs = self.driver_mock().ex_set_node_metadata.call_args + self.assertEqual(cloud_node, args[0]) plain_metadata['hostname'] = 'compute1.zzzzz.arvadosapi.com' self.assertEqual( plain_metadata, - {item['key']: item['value'] for item in kwargs['data']['items']}) + {item['key']: item['value'] for item in args[1]}) def test_sync_node_updates_hostname_tag(self): self.check_sync_node_updates_hostname_tag( @@ -110,9 +147,7 @@ class GCEComputeNodeDriverTestCase(testutil.DriverTestMixin, unittest.TestCase): arv_node = testutil.arvados_node_mock(8) cloud_node = testutil.cloud_node_mock( 9, metadata={}, zone=testutil.cloud_object_mock('failzone')) - mock_response = self.driver_mock().connection.async_request() - mock_response.success.return_value = False - mock_response.error = 'sync error test' + mock_response = self.driver_mock().ex_set_node_metadata.side_effect = (Exception('sync error test'),) driver = self.new_driver() with self.assertRaises(Exception) as err_check: driver.sync_node(cloud_node, arv_node) @@ -136,6 +171,19 @@ class GCEComputeNodeDriverTestCase(testutil.DriverTestMixin, unittest.TestCase): metadata = self.driver_mock().create_node.call_args[1]['ex_metadata'] self.assertLessEqual(start_time, metadata.get('booted_at')) + def test_known_node_fqdn(self): + name = 'fqdntest.zzzzz.arvadosapi.com' + node = testutil.cloud_node_mock(metadata=self.build_gce_metadata( + {'hostname': name})) + self.assertEqual(name, gce.ComputeNodeDriver.node_fqdn(node)) + + def test_unknown_node_fqdn(self): + # Return an empty string. This lets fqdn be safely compared + # against an expected value, and ComputeNodeMonitorActor + # should try to update it. + node = testutil.cloud_node_mock(metadata=self.build_gce_metadata({})) + self.assertEqual('', gce.ComputeNodeDriver.node_fqdn(node)) + def test_deliver_ssh_key_in_metadata(self): test_ssh_key = 'ssh-rsa-foo' arv_node = testutil.arvados_node_mock(1) @@ -156,3 +204,38 @@ class GCEComputeNodeDriverTestCase(testutil.DriverTestMixin, unittest.TestCase): self.assertEqual( service_accounts, self.driver_mock().create_node.call_args[1]['ex_service_accounts']) + + def test_fix_string_size(self): + # As of 0.18, the libcloud GCE driver sets node.size to the size's name. + # It's supposed to be the actual size object. Make sure our driver + # patches that up in listings. + size = testutil.MockSize(2) + node = testutil.cloud_node_mock(size=size) + node.size = size.name + self.driver_mock().list_sizes.return_value = [size] + self.driver_mock().list_nodes.return_value = [node] + driver = self.new_driver() + nodelist = driver.list_nodes() + self.assertEqual(1, len(nodelist)) + self.assertIs(node, nodelist[0]) + self.assertIs(size, nodelist[0].size) + + def test_skip_fix_when_size_not_string(self): + # Ensure we don't monkeypatch node sizes unless we need to. + size = testutil.MockSize(3) + node = testutil.cloud_node_mock(size=size) + self.driver_mock().list_nodes.return_value = [node] + driver = self.new_driver() + nodelist = driver.list_nodes() + self.assertEqual(1, len(nodelist)) + self.assertIs(node, nodelist[0]) + self.assertIs(size, nodelist[0].size) + + def test_node_found_after_timeout_has_fixed_size(self): + size = testutil.MockSize(4) + cloud_node = testutil.cloud_node_mock(size=size.id) + self.check_node_found_after_timeout_has_fixed_size(size, cloud_node) + + def test_list_empty_nodes(self): + self.driver_mock().list_nodes.return_value = [] + self.assertEqual([], self.new_driver().list_nodes())