From d317c54edb2bfcfef523e5ccbc0119c78539824e Mon Sep 17 00:00:00 2001 From: Vivek Soni Date: Thu, 21 Sep 2017 01:57:29 -0700 Subject: [PATCH] 3PAR: Cinder volume revert to snapshot support This commit implements reverting volume to a snapshot when backend_storage is 3PAR Change-Id: Ib89e68df8b93724e6042fa535139bd86fd232d92 --- .../unit/volume/drivers/hpe/test_hpe3par.py | 64 +++++++++++++++++++ cinder/volume/drivers/hpe/hpe_3par_common.py | 46 ++++++++++++- cinder/volume/drivers/hpe/hpe_3par_fc.py | 9 +++ cinder/volume/drivers/hpe/hpe_3par_iscsi.py | 9 +++ ...t-volume-to-snapshot-6aa0dffb010265e5.yaml | 3 + 5 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 releasenotes/notes/revert-volume-to-snapshot-6aa0dffb010265e5.yaml diff --git a/cinder/tests/unit/volume/drivers/hpe/test_hpe3par.py b/cinder/tests/unit/volume/drivers/hpe/test_hpe3par.py index 88b66147640..d7c47cee870 100644 --- a/cinder/tests/unit/volume/drivers/hpe/test_hpe3par.py +++ b/cinder/tests/unit/volume/drivers/hpe/test_hpe3par.py @@ -3034,6 +3034,70 @@ class HPE3PARBaseDriver(object): expected + self.standard_logout) + def test_revert_to_snapshot(self): + # setup_mock_client drive with default configuration + # and return the mock HTTP 3PAR client + volume = {'name': self.VOLUME_NAME, + 'id': self.VOLUME_ID_SNAP, + 'display_name': 'Foo Volume', + 'size': 2, + 'host': self.FAKE_CINDER_HOST, + 'volume_type': None, + 'volume_type_id': None} + + mock_client = self.setup_driver() + mock_client.isOnlinePhysicalCopy.return_value = False + with mock.patch.object(hpecommon.HPE3PARCommon, + '_create_client') as mock_create_client: + mock_create_client.return_value = mock_client + self.driver.revert_to_snapshot(self.ctxt, volume, self.snapshot) + + expected = [ + mock.call.isOnlinePhysicalCopy('osv-dh-F5VGRTseuujPjbeRBVg'), + mock.call.promoteVirtualCopy('oss-L4I73ONuTci9Fd4ceij-MQ', + optional={}) + ] + + mock_client.assert_has_calls( + self.standard_login + + expected + + self.standard_logout) + + @mock.patch.object(volume_types, 'get_volume_type') + def test_revert_to_snapshot_replicated_volume(self, _mock_volume_types): + + _mock_volume_types.return_value = { + 'name': 'replicated', + 'extra_specs': { + 'replication_enabled': ' True', + 'volume_type': self.volume_type_replicated}} + + mock_client = self.setup_driver() + mock_client.isOnlinePhysicalCopy.return_value = True + mock_client.getStorageSystemInfo.return_value = mock.ANY + + with mock.patch.object(hpecommon.HPE3PARCommon, + '_create_client') as mock_create_client: + mock_create_client.return_value = mock_client + self.driver.revert_to_snapshot( + self.ctxt, + self.volume_replicated, + self.snapshot) + expected = [ + mock.call.stopRemoteCopy('rcg-0DM4qZEVSKON-DXN-N'), + mock.call.isOnlinePhysicalCopy('osv-0DM4qZEVSKON-DXN-NwVpw'), + mock.call.promoteVirtualCopy( + 'oss-L4I73ONuTci9Fd4ceij-MQ', + optional={'online': True, 'allowRemoteCopyParent': True}), + mock.call.startRemoteCopy('rcg-0DM4qZEVSKON-DXN-N') + ] + mock_client.assert_has_calls( + self.get_id_login + + self.standard_logout + + self.standard_login + + expected + + self.standard_logout) + def test_delete_snapshot(self): # setup_mock_client drive with default configuration # and return the mock HTTP 3PAR client diff --git a/cinder/volume/drivers/hpe/hpe_3par_common.py b/cinder/volume/drivers/hpe/hpe_3par_common.py index 989c8b0ab2b..fef38d88ec8 100644 --- a/cinder/volume/drivers/hpe/hpe_3par_common.py +++ b/cinder/volume/drivers/hpe/hpe_3par_common.py @@ -264,11 +264,12 @@ class HPE3PARCommon(object): 3.0.37 - Fixed image cache enabled capability. bug #1686985 3.0.38 - Fixed delete operation of replicated volume which is part of QOS. bug #1717875 + 3.0.39 - Add support for revert to snapshot. """ - VERSION = "3.0.38" + VERSION = "3.0.39" stats = {} @@ -3068,6 +3069,49 @@ class HPE3PARCommon(object): msg = _("Volume has a temporary snapshot.") raise exception.VolumeIsBusy(message=msg) + def revert_to_snapshot(self, volume, snapshot): + """Revert volume to snapshot. + + :param volume: A dictionary describing the volume to revert + :param snapshot: A dictionary describing the latest snapshot + """ + volume_name = self._get_3par_vol_name(volume['id']) + snapshot_name = self._get_3par_snap_name(snapshot['id']) + rcg_name = self._get_3par_rcg_name(volume['id']) + + optional = {} + replication_flag = self._volume_of_replicated_type(volume) + if replication_flag: + LOG.debug("Found replicated volume: %(volume)s.", + {'volume': volume_name}) + optional['allowRemoteCopyParent'] = True + try: + self.client.stopRemoteCopy(rcg_name) + except Exception as ex: + msg = (_("There was an error stoping remote copy: %s.") % + six.text_type(ex)) + LOG.error(msg) + raise exception.VolumeBackendAPIException(data=msg) + + if self.client.isOnlinePhysicalCopy(volume_name): + LOG.debug("Found an online copy for %(volume)s.", + {'volume': volume_name}) + optional['online'] = True + + self.client.promoteVirtualCopy(snapshot_name, optional=optional) + + if replication_flag: + try: + self.client.startRemoteCopy(rcg_name) + except Exception as ex: + msg = (_("There was an error starting remote copy: %s.") % + six.text_type(ex)) + LOG.error(msg) + raise exception.VolumeBackendAPIException(data=msg) + + LOG.info("Volume %(volume)s succesfully reverted to %(snap)s.", + {'volume': volume_name, 'snap': snapshot_name}) + def find_existing_vlun(self, volume, host): """Finds an existing VLUN for a volume on a host. diff --git a/cinder/volume/drivers/hpe/hpe_3par_fc.py b/cinder/volume/drivers/hpe/hpe_3par_fc.py index f9fdbde658b..34f7d960600 100644 --- a/cinder/volume/drivers/hpe/hpe_3par_fc.py +++ b/cinder/volume/drivers/hpe/hpe_3par_fc.py @@ -675,6 +675,15 @@ class HPE3PARFCDriver(driver.ManageableVD, finally: self._logout(common) + @utils.trace + def revert_to_snapshot(self, context, volume, snapshot): + """Revert volume to snapshot.""" + common = self._login() + try: + common.revert_to_snapshot(volume, snapshot) + finally: + self._logout(common) + @utils.trace def migrate_volume(self, context, volume, host): if volume['status'] == 'in-use': diff --git a/cinder/volume/drivers/hpe/hpe_3par_iscsi.py b/cinder/volume/drivers/hpe/hpe_3par_iscsi.py index 6912597273b..6ee609c4640 100644 --- a/cinder/volume/drivers/hpe/hpe_3par_iscsi.py +++ b/cinder/volume/drivers/hpe/hpe_3par_iscsi.py @@ -946,6 +946,15 @@ class HPE3PARISCSIDriver(driver.ManageableVD, finally: self._logout(common) + @utils.trace + def revert_to_snapshot(self, context, volume, snapshot): + """Revert volume to snapshot.""" + common = self._login() + try: + common.revert_to_snapshot(volume, snapshot) + finally: + self._logout(common) + @utils.trace def migrate_volume(self, context, volume, host): if volume['status'] == 'in-use': diff --git a/releasenotes/notes/revert-volume-to-snapshot-6aa0dffb010265e5.yaml b/releasenotes/notes/revert-volume-to-snapshot-6aa0dffb010265e5.yaml new file mode 100644 index 00000000000..3eb4c6bfac4 --- /dev/null +++ b/releasenotes/notes/revert-volume-to-snapshot-6aa0dffb010265e5.yaml @@ -0,0 +1,3 @@ +--- +features: + - Added revert volume to snapshot in 3par driver.