From 136428217df64684c9526537383356f8d1cf5db3 Mon Sep 17 00:00:00 2001 From: Thang Pham Date: Mon, 28 Sep 2015 19:08:03 -0700 Subject: [PATCH] Update extend_volume API to use versionedobjects The following patch updates extend_volume API to use volume versionedobjects. Changes were made to be backwards compatible with older RPC clients. It only includes changes to the core cinder code. Changes in the drivers are left to each driver maintainer to update. Note that this patch DOES NOT try to use object dot notation everywhere, since it would increase the size of the patch. Instead, it will be done in subsequent patches. Change-Id: I4192b35f8f3e2cd51b94db10b44727f23592ea86 Partial-Implements: blueprint cinder-objects --- cinder/tests/unit/test_volume_rpcapi.py | 18 +++++++++++-- cinder/volume/api.py | 14 +++++----- cinder/volume/manager.py | 34 ++++++++++++++----------- cinder/volume/rpcapi.py | 17 ++++++++++--- 4 files changed, 55 insertions(+), 28 deletions(-) diff --git a/cinder/tests/unit/test_volume_rpcapi.py b/cinder/tests/unit/test_volume_rpcapi.py index f5479aecd..ccb2f0265 100644 --- a/cinder/tests/unit/test_volume_rpcapi.py +++ b/cinder/tests/unit/test_volume_rpcapi.py @@ -370,13 +370,27 @@ class VolumeRpcAPITestCase(test.TestCase): '-8ffd-0800200c9a66', version='1.9') - def test_extend_volume(self): + @mock.patch('oslo_messaging.RPCClient.can_send_version', + return_value=True) + def test_extend_volume(self, can_send_version): self._test_volume_api('extend_volume', rpc_method='cast', - volume=self.fake_volume, + volume=self.fake_volume_obj, + new_size=1, + reservations=self.fake_reservations, + version='1.35') + can_send_version.assert_called_once_with('1.35') + + @mock.patch('oslo_messaging.RPCClient.can_send_version', + return_value=False) + def test_extend_volume_old(self, can_send_version): + self._test_volume_api('extend_volume', + rpc_method='cast', + volume=self.fake_volume_obj, new_size=1, reservations=self.fake_reservations, version='1.14') + can_send_version.assert_called_once_with('1.35') def test_migrate_volume(self): class FakeHost(object): diff --git a/cinder/volume/api.py b/cinder/volume/api.py index 634b449b1..57a87f702 100644 --- a/cinder/volume/api.py +++ b/cinder/volume/api.py @@ -1259,27 +1259,27 @@ class API(base.Base): @wrap_check_policy def extend(self, context, volume, new_size): - if volume['status'] != 'available': + if volume.status != 'available': msg = _('Volume %(vol_id)s status must be available ' 'to extend, but current status is: ' - '%(vol_status)s.') % {'vol_id': volume['id'], - 'vol_status': volume['status']} + '%(vol_status)s.') % {'vol_id': volume.id, + 'vol_status': volume.status} raise exception.InvalidVolume(reason=msg) - size_increase = (int(new_size)) - volume['size'] + size_increase = (int(new_size)) - volume.size if size_increase <= 0: msg = (_("New size for extend must be greater " "than current size. (current: %(size)s, " "extended: %(new_size)s).") % {'new_size': new_size, - 'size': volume['size']}) + 'size': volume.size}) raise exception.InvalidInput(reason=msg) try: reserve_opts = {'gigabytes': size_increase} QUOTAS.add_volume_type_opts(context, reserve_opts, - volume.get('volume_type_id')) + volume.volume_type_id) reservations = QUOTAS.reserve(context, - project_id=volume['project_id'], + project_id=volume.project_id, **reserve_opts) except exception.OverQuota as exc: usages = exc.kwargs['usages'] diff --git a/cinder/volume/manager.py b/cinder/volume/manager.py index c633d7140..2bd858c69 100644 --- a/cinder/volume/manager.py +++ b/cinder/volume/manager.py @@ -190,7 +190,7 @@ def locked_snapshot_operation(f): class VolumeManager(manager.SchedulerDependentManager): """Manages attachable block storage devices.""" - RPC_API_VERSION = '1.34' + RPC_API_VERSION = '1.35' target = messaging.Target(version=RPC_API_VERSION) @@ -1984,7 +1984,14 @@ class VolumeManager(manager.SchedulerDependentManager): context, snapshot, event_suffix, extra_usage_info=extra_usage_info, host=self.host) - def extend_volume(self, context, volume_id, new_size, reservations): + def extend_volume(self, context, volume_id, new_size, reservations, + volume=None): + # FIXME(thangp): Remove this in v2.0 of RPC API. + if volume is None: + # For older clients, mimic the old behavior and look up the volume + # by its volume_id. + volume = objects.Volume.get_by_id(context, volume_id) + try: # NOTE(flaper87): Verify the driver is enabled # before going forward. The exception will be caught @@ -1992,12 +1999,11 @@ class VolumeManager(manager.SchedulerDependentManager): utils.require_driver_initialized(self.driver) except exception.DriverNotInitialized: with excutils.save_and_reraise_exception(): - self.db.volume_update(context, volume_id, - {'status': 'error_extending'}) + volume.status = 'error_extending' + volume.save() - volume = self.db.volume_get(context, volume_id) - project_id = volume['project_id'] - size_increase = (int(new_size)) - volume['size'] + project_id = volume.project_id + size_increase = (int(new_size)) - volume.size self._notify_about_volume_usage(context, volume, "resize.start") try: self.driver.extend_volume(volume, new_size) @@ -2005,26 +2011,24 @@ class VolumeManager(manager.SchedulerDependentManager): LOG.exception(_LE("Extend volume failed."), resource=volume) try: - self.db.volume_update(context, volume['id'], + self.db.volume_update(context, volume.id, {'status': 'error_extending'}) raise exception.CinderException(_("Volume %s: Error trying " "to extend volume") % - volume_id) + volume.id) finally: QUOTAS.rollback(context, reservations, project_id=project_id) return QUOTAS.commit(context, reservations, project_id=project_id) - volume = self.db.volume_update(context, - volume['id'], - {'size': int(new_size), - 'status': 'available'}) - pool = vol_utils.extract_host(volume['host'], 'pool') + volume.update({'size': int(new_size), 'status': 'available'}) + volume.save() + pool = vol_utils.extract_host(volume.host, 'pool') if pool is None: # Legacy volume, put them into default pool pool = self.driver.configuration.safe_get( 'volume_backend_name') or vol_utils.extract_host( - volume['host'], 'pool', True) + volume.host, 'pool', True) try: self.stats['pools'][pool]['allocated_capacity_gb'] += size_increase diff --git a/cinder/volume/rpcapi.py b/cinder/volume/rpcapi.py index d3e4d71d4..c81e78341 100644 --- a/cinder/volume/rpcapi.py +++ b/cinder/volume/rpcapi.py @@ -82,6 +82,7 @@ class VolumeAPI(object): 1.32 - Adds support for sending objects over RPC in create_volume(). 1.33 - Adds support for sending objects over RPC in delete_volume(). 1.34 - Adds support for sending objects over RPC in retype(). + 1.35 - Adds support for sending objects over RPC in extend_volume(). """ BASE_RPC_API_VERSION = '1.0' @@ -231,10 +232,18 @@ class VolumeAPI(object): new_user=new_user, new_project=new_project) def extend_volume(self, ctxt, volume, new_size, reservations): - new_host = utils.extract_host(volume['host']) - cctxt = self.client.prepare(server=new_host, version='1.14') - cctxt.cast(ctxt, 'extend_volume', volume_id=volume['id'], - new_size=new_size, reservations=reservations) + new_host = utils.extract_host(volume.host) + + msg_args = {'volume_id': volume.id, 'new_size': new_size, + 'reservations': reservations} + if self.client.can_send_version('1.35'): + version = '1.35' + msg_args['volume'] = volume + else: + version = '1.14' + + cctxt = self.client.prepare(server=new_host, version=version) + cctxt.cast(ctxt, 'extend_volume', **msg_args) def migrate_volume(self, ctxt, volume, dest_host, force_host_copy): new_host = utils.extract_host(volume['host']) -- 2.45.2