8799: shutdown_eligible() returns "node is draining" when in drain state. Add commen...
[arvados.git] / services / nodemanager / tests / test_computenode_driver_gce.py
index 17114b6d452eb88dead2c1759d85ae292a16d6d5..e8b2fa36c582876359fa6e667f80e9a7cb1f3013 100644 (file)
@@ -14,6 +14,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,7 +38,7 @@ 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_create_includes_ping_secret(self):
@@ -34,6 +48,16 @@ class GCEComputeNodeDriverTestCase(testutil.DriverTestMixin, unittest.TestCase):
         metadata = self.driver_mock().create_node.call_args[1]['ex_metadata']
         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()
         driver.create_node(testutil.MockSize(1),
@@ -50,6 +74,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
@@ -82,7 +126,7 @@ class GCEComputeNodeDriverTestCase(testutil.DriverTestMixin, unittest.TestCase):
         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])
+        self.assertEqual('/zones/testzone/instances/2/setMetadata', args[0])
         for key in ['kind', 'fingerprint']:
             self.assertEqual(start_metadata[key], kwargs['data'][key])
         plain_metadata['hostname'] = 'compute1.zzzzz.arvadosapi.com'
@@ -127,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)
@@ -147,3 +204,33 @@ 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_list_empty_nodes(self):
+        self.driver_mock().list_nodes.return_value = []
+        self.assertEqual([], self.new_driver().list_nodes())