[ARVADOS] created: 5dfdd042f8931fa7f001256471c0b624f768504c

git at public.curoverse.com git at public.curoverse.com
Thu Mar 26 13:55:34 EDT 2015


        at  5dfdd042f8931fa7f001256471c0b624f768504c (commit)


commit 5dfdd042f8931fa7f001256471c0b624f768504c
Author: Brett Smith <brett at curoverse.com>
Date:   Thu Mar 26 13:31:01 2015 -0400

    5502: Node Manager attaches a local SSD to GCE compute nodes.
    
    This is the best option to provide temporary working space for compute
    work on GCE.

diff --git a/services/nodemanager/arvnodeman/computenode/driver/gce.py b/services/nodemanager/arvnodeman/computenode/driver/gce.py
index 6380d0e..36bfc96 100644
--- a/services/nodemanager/arvnodeman/computenode/driver/gce.py
+++ b/services/nodemanager/arvnodeman/computenode/driver/gce.py
@@ -34,11 +34,17 @@ class ComputeNodeDriver(BaseComputeNodeDriver):
         super(ComputeNodeDriver, self).__init__(
             auth_kwargs, list_kwargs, create_kwargs,
             driver_class)
+        self._disktype_links = {dt.name: self._object_link(dt)
+                                for dt in self.real.ex_list_disktypes()}
 
     @staticmethod
     def _name_key(cloud_object):
         return cloud_object.name
 
+    @staticmethod
+    def _object_link(cloud_object):
+        return cloud_object.extra.get('selfLink')
+
     def _init_image(self, image_name):
         return 'image', self.search_for(
             image_name, 'list_images', self._name_key)
@@ -59,14 +65,39 @@ class ComputeNodeDriver(BaseComputeNodeDriver):
 
     def arvados_create_kwargs(self, arvados_node):
         cluster_id, _, node_id = arvados_node['uuid'].split('-')
-        result = {'name': 'compute-{}-{}'.format(node_id, cluster_id),
+        name = 'compute-{}-{}'.format(node_id, cluster_id)
+        disks = [
+            {'autoDelete': True,
+             'boot': True,
+             'deviceName': name,
+             'initializeParams':
+                 {'diskName': name,
+                  'diskType': self._disktype_links['pd-standard'],
+                  'sourceImage': self._object_link(self.create_kwargs['image']),
+                  },
+             'type': 'PERSISTENT',
+             },
+            {'autoDelete': True,
+             'boot': False,
+             # Boot images rely on this device name to find the SSD.
+             # Any change must be coordinated in the image.
+             'deviceName': 'tmp',
+             'initializeParams':
+                 {'diskType': self._disktype_links['local-ssd'],
+                  },
+             'type': 'SCRATCH',
+             },
+            ]
+        result = {'name': name,
                   'ex_metadata': self.create_kwargs['ex_metadata'].copy(),
-                  'ex_tags': list(self.node_tags)}
-        result['ex_metadata']['arv-ping-url'] = self._make_ping_url(
-            arvados_node)
-        result['ex_metadata']['booted_at'] = time.strftime(ARVADOS_TIMEFMT,
-                                                           time.gmtime())
-        result['ex_metadata']['hostname'] = arvados_node_fqdn(arvados_node)
+                  'ex_tags': list(self.node_tags),
+                  'ex_disks_gce_struct': disks,
+                  }
+        result['ex_metadata'].update({
+                'arv-ping-url': self._make_ping_url(arvados_node),
+                'booted_at': time.strftime(ARVADOS_TIMEFMT, time.gmtime()),
+                'hostname': arvados_node_fqdn(arvados_node),
+                })
         return result
 
     def list_nodes(self):
diff --git a/services/nodemanager/tests/test_computenode_driver_gce.py b/services/nodemanager/tests/test_computenode_driver_gce.py
index dd0d5c6..b9d7ee9 100644
--- a/services/nodemanager/tests/test_computenode_driver_gce.py
+++ b/services/nodemanager/tests/test_computenode_driver_gce.py
@@ -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)
@@ -50,6 +64,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
diff --git a/services/nodemanager/tests/testutil.py b/services/nodemanager/tests/testutil.py
index 6c386e2..82d6479 100644
--- a/services/nodemanager/tests/testutil.py
+++ b/services/nodemanager/tests/testutil.py
@@ -34,13 +34,14 @@ def arvados_node_mock(node_num=99, job_uuid=None, age=-1, **kwargs):
     node.update(kwargs)
     return node
 
-def cloud_object_mock(name_id):
+def cloud_object_mock(name_id, **extra):
     # A very generic mock, useful for stubbing libcloud objects we
     # only search for and pass around, like locations, subnets, etc.
     cloud_object = mock.NonCallableMagicMock(['id', 'name'],
                                              name='cloud_object')
     cloud_object.name = str(name_id)
     cloud_object.id = 'id_' + cloud_object.name
+    cloud_object.extra = extra
     return cloud_object
 
 def cloud_node_mock(node_num=99, **extra):

commit b8261deb6e1035134d7ce8f004cc49deeed1bd27
Author: Brett Smith <brett at curoverse.com>
Date:   Thu Mar 26 12:29:38 2015 -0400

    5502: Adjust id and name of Node Manager cloud object mocks.
    
    Some GCE objects like disk types have predictable names, so it's
    helpful to be able to mock objects with the same name.  Use the
    name_id argument is the literal name, and generate an id from it.

diff --git a/services/nodemanager/tests/test_computenode_driver_ec2.py b/services/nodemanager/tests/test_computenode_driver_ec2.py
index 595f1f4..d28a2a6 100644
--- a/services/nodemanager/tests/test_computenode_driver_ec2.py
+++ b/services/nodemanager/tests/test_computenode_driver_ec2.py
@@ -34,7 +34,7 @@ class EC2ComputeNodeDriverTestCase(testutil.DriverTestMixin, unittest.TestCase):
         list_method = self.driver_mock().list_images
         list_method.return_value = [testutil.cloud_object_mock(c)
                                     for c in 'abc']
-        driver = self.new_driver(create_kwargs={'image_id': 'b'})
+        driver = self.new_driver(create_kwargs={'image_id': 'id_b'})
         self.assertEqual(1, list_method.call_count)
 
     def test_create_includes_ping_secret(self):
diff --git a/services/nodemanager/tests/test_computenode_driver_gce.py b/services/nodemanager/tests/test_computenode_driver_gce.py
index 465adc5..dd0d5c6 100644
--- a/services/nodemanager/tests/test_computenode_driver_gce.py
+++ b/services/nodemanager/tests/test_computenode_driver_gce.py
@@ -24,7 +24,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):
@@ -82,7 +82,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'
diff --git a/services/nodemanager/tests/testutil.py b/services/nodemanager/tests/testutil.py
index 650a232..6c386e2 100644
--- a/services/nodemanager/tests/testutil.py
+++ b/services/nodemanager/tests/testutil.py
@@ -39,8 +39,8 @@ def cloud_object_mock(name_id):
     # only search for and pass around, like locations, subnets, etc.
     cloud_object = mock.NonCallableMagicMock(['id', 'name'],
                                              name='cloud_object')
-    cloud_object.id = str(name_id)
-    cloud_object.name = cloud_object.id.upper()
+    cloud_object.name = str(name_id)
+    cloud_object.id = 'id_' + cloud_object.name
     return cloud_object
 
 def cloud_node_mock(node_num=99, **extra):

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list