From dd963cf11056aaa8d2b8048789876f43dd6bb03a Mon Sep 17 00:00:00 2001 From: Jeff Peeler Date: Mon, 28 Jan 2013 15:24:54 -0500 Subject: [PATCH] Add cinder support to resource volume Fixes bug #1073164 Change-Id: I190067e5ea9334e336e6f105222905b1d48408fd Signed-off-by: Jeff Peeler --- heat/engine/clients.py | 38 +++++++++++++++++++++++++++++++++ heat/engine/resource.py | 3 +++ heat/engine/resources/volume.py | 31 +++++++++++++++------------ heat/tests/test_volume.py | 16 ++++++++------ 4 files changed, 67 insertions(+), 21 deletions(-) diff --git a/heat/engine/clients.py b/heat/engine/clients.py index 7a42b788..b32992b0 100644 --- a/heat/engine/clients.py +++ b/heat/engine/clients.py @@ -32,6 +32,11 @@ try: except ImportError: quantumclient = None logger.info('quantumclient not available') +try: + from cinderclient.v1 import client as cinderclient +except ImportError: + cinderclient = None + logger.info('cinderclient not available') cloud_opts = [ @@ -53,6 +58,7 @@ class OpenStackClients(object): self._keystone = None self._swift = None self._quantum = None + self._cinder = None def keystone(self): if self._keystone: @@ -173,6 +179,38 @@ class OpenStackClients(object): return self._quantum + def cinder(self): + if cinderclient is None: + return self.nova('volume') + if self._cinder: + return self._cinder + + con = self.context + args = { + 'project_id': con.tenant, + 'auth_url': con.auth_url, + 'service_type': 'volume', + } + + if con.password is not None: + args['username'] = con.username + args['api_key'] = con.password + elif con.auth_token is not None: + args['username'] = con.service_user + args['api_key'] = con.service_password + args['project_id'] = con.service_tenant + args['proxy_token'] = con.auth_token + args['proxy_token_id'] = con.tenant_id + else: + logger.error("Cinder connection failed, " + "no password or auth_token!") + return None + logger.debug('cinder args %s', args) + + self._cinder = cinderclient.Client(**args) + + return self._cinder + if cfg.CONF.cloud_backend: cloud_backend_module = importutils.import_module(cfg.CONF.cloud_backend) diff --git a/heat/engine/resource.py b/heat/engine/resource.py index e6a5ee60..98b6ea74 100644 --- a/heat/engine/resource.py +++ b/heat/engine/resource.py @@ -268,6 +268,9 @@ class Resource(object): def quantum(self): return self.stack.clients.quantum() + def cinder(self): + return self.stack.clients.cinder() + def create(self): ''' Create the resource. Subclasses should provide a handle_create() method diff --git a/heat/engine/resources/volume.py b/heat/engine/resources/volume.py index 9af2236f..4d5b2f92 100644 --- a/heat/engine/resources/volume.py +++ b/heat/engine/resources/volume.py @@ -34,7 +34,7 @@ class Volume(resource.Resource): super(Volume, self).__init__(name, json_snippet, stack) def handle_create(self): - vol = self.nova('volume').volumes.create( + vol = self.cinder().volumes.create( self.properties['Size'], display_name=self.physical_resource_name(), display_description=self.physical_resource_name()) @@ -52,12 +52,13 @@ class Volume(resource.Resource): def handle_delete(self): if self.resource_id is not None: - vol = self.nova('volume').volumes.get(self.resource_id) + vol = self.cinder().volumes.get(self.resource_id) + if vol.status == 'in-use': logger.warn('cant delete volume when in-use') raise exception.Error("Volume in use") - self.nova('volume').volumes.delete(self.resource_id) + self.cinder().volumes.delete(self.resource_id) class VolumeAttachment(resource.Resource): @@ -77,12 +78,13 @@ class VolumeAttachment(resource.Resource): volume_id = self.properties['VolumeId'] logger.warn('Attaching InstanceId %s VolumeId %s Device %s' % (server_id, volume_id, self.properties['Device'])) - volapi = self.nova().volumes - va = volapi.create_server_volume(server_id=server_id, - volume_id=volume_id, - device=self.properties['Device']) + va = self.nova().volumes.create_server_volume( + server_id=server_id, + volume_id=volume_id, + device=self.properties['Device']) + + vol = self.cinder().volumes.get(va.id) - vol = self.nova('volume').volumes.get(va.id) while vol.status == 'available' or vol.status == 'attaching': eventlet.sleep(1) vol.get() @@ -100,12 +102,11 @@ class VolumeAttachment(resource.Resource): logger.info('VolumeAttachment un-attaching %s %s' % (server_id, volume_id)) - volapi = self.nova().volumes try: - volapi.delete_server_volume(server_id, - volume_id) + vol = self.cinder().volumes.get(volume_id) - vol = self.nova('volume').volumes.get(volume_id) + self.nova().volumes.delete_server_volume(server_id, + volume_id) logger.info('un-attaching %s, status %s' % (volume_id, vol.status)) while vol.status == 'in-use': @@ -113,11 +114,13 @@ class VolumeAttachment(resource.Resource): (volume_id, vol.status)) eventlet.sleep(1) try: - volapi.delete_server_volume(server_id, - volume_id) + self.nova().volumes.delete_server_volume( + server_id, + volume_id) except Exception: pass vol.get() + logger.info('volume status of %s now %s' % (volume_id, vol.status)) except clients.novaclient.exceptions.NotFound as e: logger.warning('Deleting VolumeAttachment %s %s - not found' % (server_id, volume_id)) diff --git a/heat/tests/test_volume.py b/heat/tests/test_volume.py index b831f6b3..6f967862 100644 --- a/heat/tests/test_volume.py +++ b/heat/tests/test_volume.py @@ -34,7 +34,8 @@ class VolumeTest(unittest.TestCase): def setUp(self): self.m = mox.Mox() self.fc = fakes.FakeClient() - self.m.StubOutWithMock(vol.Volume, 'nova') + self.m.StubOutWithMock(vol.Volume, 'cinder') + self.m.StubOutWithMock(vol.VolumeAttachment, 'cinder') self.m.StubOutWithMock(vol.VolumeAttachment, 'nova') self.m.StubOutWithMock(self.fc.volumes, 'create') self.m.StubOutWithMock(self.fc.volumes, 'get') @@ -90,7 +91,7 @@ class VolumeTest(unittest.TestCase): stack_name = 'test_volume_stack' # create script - vol.Volume.nova('volume').MultipleTimes().AndReturn(self.fc) + vol.Volume.cinder().MultipleTimes().AndReturn(self.fc) self.fc.volumes.create( u'1', display_description='%s.DataVolume' % stack_name, display_name='%s.DataVolume' % stack_name).AndReturn(fv) @@ -124,7 +125,7 @@ class VolumeTest(unittest.TestCase): stack_name = 'test_volume_create_error_stack' # create script - vol.Volume.nova('volume').AndReturn(self.fc) + vol.Volume.cinder().AndReturn(self.fc) self.fc.volumes.create( u'1', display_description='%s.DataVolume' % stack_name, display_name='%s.DataVolume' % stack_name).AndReturn(fv) @@ -149,14 +150,15 @@ class VolumeTest(unittest.TestCase): stack_name = 'test_volume_attach_error_stack' # volume create - vol.Volume.nova('volume').MultipleTimes().AndReturn(self.fc) + vol.Volume.cinder().MultipleTimes().AndReturn(self.fc) self.fc.volumes.create( u'1', display_description='%s.DataVolume' % stack_name, display_name='%s.DataVolume' % stack_name).AndReturn(fv) # create script vol.VolumeAttachment.nova().MultipleTimes().AndReturn(self.fc) - vol.VolumeAttachment.nova('volume').MultipleTimes().AndReturn(self.fc) + vol.VolumeAttachment.cinder().MultipleTimes().AndReturn(self.fc) + eventlet.sleep(1).MultipleTimes().AndReturn(None) self.fc.volumes.create_server_volume( device=u'/dev/vdc', @@ -185,14 +187,14 @@ class VolumeTest(unittest.TestCase): stack_name = 'test_volume_attach_stack' # volume create - vol.Volume.nova('volume').MultipleTimes().AndReturn(self.fc) + vol.Volume.cinder().MultipleTimes().AndReturn(self.fc) self.fc.volumes.create( u'1', display_description='%s.DataVolume' % stack_name, display_name='%s.DataVolume' % stack_name).AndReturn(fv) # create script vol.VolumeAttachment.nova().MultipleTimes().AndReturn(self.fc) - vol.VolumeAttachment.nova('volume').MultipleTimes().AndReturn(self.fc) + vol.VolumeAttachment.cinder().MultipleTimes().AndReturn(self.fc) eventlet.sleep(1).MultipleTimes().AndReturn(None) self.fc.volumes.create_server_volume( device=u'/dev/vdc', -- 2.45.2