]> review.fuel-infra Code Review - openstack-build/heat-build.git/commitdiff
Implement OS::Cinder::VolumeAttachment
authorThomas Herve <therve@gmail.com>
Tue, 21 May 2013 08:27:15 +0000 (10:27 +0200)
committerThomas Herve <therve@gmail.com>
Tue, 21 May 2013 08:27:15 +0000 (10:27 +0200)
This creates a new volume attachment resource with Cinder specific
naming.

Change-Id: Ie73b929925c58e47f3509d57dd385cbd4ea5a4c1

heat/engine/resources/volume.py
heat/tests/test_volume.py

index 5b2ca708af6bce646df658588d2319ec928f8178..ef09f8b331f6eb8d3d48da0a3b20a5f09caffd98 100644 (file)
@@ -102,7 +102,7 @@ class Volume(resource.Resource):
 
                 if vol.status == 'in-use':
                     logger.warn('cant delete volume when in-use')
-                    raise exception.Error("Volume in use")
+                    raise exception.Error('Volume in use')
 
                 self.cinder().volumes.delete(self.resource_id)
             except clients.cinderclient.exceptions.NotFound:
@@ -123,17 +123,18 @@ class VolumeAttachment(resource.Resource):
                                         'Required': True},
                          'VolumeId': {'Type': 'String',
                                       'Required': True},
-                         'Device': {'Type': "String",
+                         'Device': {'Type': 'String',
                                     'Required': True,
                                     'AllowedPattern': '/dev/vd[b-z]'}}
 
-    def __init__(self, name, json_snippet, stack):
-        super(VolumeAttachment, self).__init__(name, json_snippet, stack)
+    _instance_property = 'InstanceId'
+    _volume_property = 'VolumeId'
+    _device_property = 'Device'
 
     def handle_create(self):
-        server_id = self.properties['InstanceId']
-        volume_id = self.properties['VolumeId']
-        dev = self.properties['Device']
+        server_id = self.properties[self._instance_property]
+        volume_id = self.properties[self._volume_property]
+        dev = self.properties[self._device_property]
         inst = self.stack.clients.attach_volume_to_instance(server_id,
                                                             volume_id,
                                                             dev)
@@ -143,8 +144,8 @@ class VolumeAttachment(resource.Resource):
         return self.UPDATE_REPLACE
 
     def handle_delete(self):
-        server_id = self.properties['InstanceId']
-        volume_id = self.properties['VolumeId']
+        server_id = self.properties[self._instance_property]
+        volume_id = self.properties[self._volume_property]
         self.stack.clients.detach_volume_from_instance(server_id, volume_id)
 
 
@@ -200,9 +201,24 @@ class CinderVolume(Volume):
         return unicode(getattr(vol, key))
 
 
+class CinderVolumeAttachment(VolumeAttachment):
+
+    properties_schema = {'instance_uuid': {'Type': 'String',
+                                           'Required': True},
+                         'volume_id': {'Type': 'String',
+                                       'Required': True},
+                         'mountpoint': {'Type': 'String',
+                                        'Required': True}}
+
+    _instance_property = 'instance_uuid'
+    _volume_property = 'volume_id'
+    _device_property = 'mountpoint'
+
+
 def resource_mapping():
     return {
         'AWS::EC2::Volume': Volume,
         'AWS::EC2::VolumeAttachment': VolumeAttachment,
         'OS::Cinder::Volume': CinderVolume,
+        'OS::Cinder::VolumeAttachment': CinderVolumeAttachment,
     }
index 3d4266c03223c9bada9e67c771ee96bdc048b6f9..be5f98bbfe577bc6c976b2d73a82a7ff16f3246e 100644 (file)
@@ -225,7 +225,6 @@ class VolumeTest(HeatTestCase):
 
         # create script
         clients.OpenStackClients.nova().MultipleTimes().AndReturn(self.fc)
-        #clients.OpenStackClients.cinder().MultipleTimes().AndReturn(self.fc)
         eventlet.sleep(1).MultipleTimes().AndReturn(None)
         self.fc.volumes.create_server_volume(
             device=u'/dev/vdc',
@@ -505,6 +504,61 @@ class VolumeTest(HeatTestCase):
             'The Referenced Attribute (DataVolume unknown) is incorrect.',
             str(error))
 
+    def test_cinder_attachment(self):
+        fv = FakeVolume('creating', 'available')
+        fva = FakeVolume('attaching', 'in-use')
+        stack_name = 'test_volume_attach_stack'
+
+        # volume create
+        clients.OpenStackClients.cinder().MultipleTimes().AndReturn(
+            self.cinder_fc)
+        self.cinder_fc.volumes.create(
+            size=u'1', availability_zone='nova',
+            display_description='%s.DataVolume' % stack_name,
+            display_name='%s.DataVolume' % stack_name).AndReturn(fv)
+
+        # create script
+        clients.OpenStackClients.nova().MultipleTimes().AndReturn(self.fc)
+        eventlet.sleep(1).MultipleTimes().AndReturn(None)
+        self.fc.volumes.create_server_volume(
+            device=u'/dev/vdc',
+            server_id=u'WikiDatabase',
+            volume_id=u'vol-123').AndReturn(fva)
+
+        self.cinder_fc.volumes.get('vol-123').AndReturn(fva)
+
+        # delete script
+        fva = FakeVolume('in-use', 'available')
+        self.fc.volumes.delete_server_volume('WikiDatabase',
+                                             'vol-123').AndReturn(None)
+        self.cinder_fc.volumes.get('vol-123').AndReturn(fva)
+
+        self.m.ReplayAll()
+
+        t = template_format.parse(volume_template)
+        t['Resources']['DataVolume']['Properties']['AvailabilityZone'] = 'nova'
+        t['Resources']['MountPoint']['Properties'] = {
+            'instance_uuid': {'Ref': 'WikiDatabase'},
+            'volume_id': {'Ref': 'DataVolume'},
+            'mountpoint': '/dev/vdc'
+        }
+        stack = parse_stack(t, stack_name=stack_name)
+
+        scheduler.TaskRunner(stack['DataVolume'].create)()
+        self.assertEqual(fv.status, 'available')
+        resource = vol.CinderVolumeAttachment('MountPoint',
+                                              t['Resources']['MountPoint'],
+                                              stack)
+        self.assertEqual(resource.validate(), None)
+        scheduler.TaskRunner(resource.create)()
+        self.assertEqual(resource.state, vol.VolumeAttachment.CREATE_COMPLETE)
+
+        self.assertEqual(resource.handle_update({}), vol.Volume.UPDATE_REPLACE)
+
+        self.assertEqual(resource.delete(), None)
+
+        self.m.VerifyAll()
+
 
 class FakeVolume:
     status = 'attaching'