From a6f4caabd32999c7f776c3814a36ca96146545e5 Mon Sep 17 00:00:00 2001 From: Naoki Saito Date: Wed, 7 Aug 2019 17:33:08 +0900 Subject: [PATCH] NEC Driver: Support revert to snapshot Adding support to revert a volume to a snapshot in NEC driver. This patch implements revert_to_snapshot(). This patch also deletes unused classes(class UnpairWaitForBackup, class UnpairWaitForDDRBackup). Change-Id: I1bf5bd3856009e92921cbbd7f91734e070d5e86f --- .../unit/volume/drivers/nec/test_volume.py | 60 +++++++++++++++++ cinder/volume/drivers/nec/cli.py | 67 +++++++++++++------ cinder/volume/drivers/nec/volume.py | 2 + cinder/volume/drivers/nec/volume_helper.py | 52 ++++++++++++++ .../drivers/nec-storage-m-series-driver.rst | 2 + doc/source/reference/support-matrix.ini | 2 +- ...t-revert-to-sanpshot-58cddebfbf06d222.yaml | 5 ++ 7 files changed, 168 insertions(+), 22 deletions(-) create mode 100644 releasenotes/notes/nec-storage-assist-revert-to-sanpshot-58cddebfbf06d222.yaml diff --git a/cinder/tests/unit/volume/drivers/nec/test_volume.py b/cinder/tests/unit/volume/drivers/nec/test_volume.py index aff3043e936..2d8108b5dad 100644 --- a/cinder/tests/unit/volume/drivers/nec/test_volume.py +++ b/cinder/tests/unit/volume/drivers/nec/test_volume.py @@ -16,6 +16,7 @@ import ddt import mock +import time from cinder import context from cinder import exception @@ -1439,3 +1440,62 @@ class ManageUnmanage_Snap_test(volume_helper.MStorageDSVDriver, test.TestCase): newsnap, snaps[0]['reference']) self.assertEqual(6, size_in_gb) + + +class RevertToSnapshotTestCase(volume_helper.MStorageDSVDriver, test.TestCase): + + def setUp(self): + super(RevertToSnapshotTestCase, self).setUp() + self._set_config(conf.Configuration(None), 'dummy', 'dummy') + self.do_setup(None) + self.mock_object(self._cli, 'view_all', return_value=xml_out) + + def test_revert_to_snapshot(self): + vol = DummyVolume("1febb976-86d0-42ed-9bc0-4aa3e158f27d") + snap = DummySnapshot("63410c76-2f12-4473-873d-74a63dfcd3e2") + self.mock_object(time, 'sleep') + self.mock_object(self._cli, '_execute', + return_value=('success', 0, 0)) + self.mock_object(self._cli, 'query_BV_SV_status', + return_value='snap/active') + self.revert_to_snapshot(None, vol, snap) + self._cli._execute.assert_called_once_with( + 'iSMsc_restore -bv yEUHrXa5AHMjOZZLb93eP -bvflg ld ' + '-sv 31HxzqBiAFTUxxOlcVn3EA -svflg ld -derivsv keep -nowait') + + vol.id = constants.VOLUME_ID + with self.assertRaisesRegex(exception.NotFound, + 'Logical Disk `LX:vD03hJCiHvGpvP4iSevKk` ' + 'has unbound already.'): + self.revert_to_snapshot(None, vol, snap) + vol.id = '1febb976-86d0-42ed-9bc0-4aa3e158f27d' + snap.id = constants.SNAPSHOT_ID + with self.assertRaisesRegex(exception.NotFound, + 'Logical Disk `LX:18FkaTGqa43xSFL8aX4A2N` ' + 'has unbound already.'): + self.revert_to_snapshot(None, vol, snap) + snap.id = '63410c76-2f12-4473-873d-74a63dfcd3e2' + self.mock_object(self._cli, 'query_BV_SV_status', + return_value='rst/exec') + with self.assertRaisesRegex(exception.VolumeBackendAPIException, + 'The snapshot does not exist or is ' + 'not in snap/active status. ' + 'bvname=LX:yEUHrXa5AHMjOZZLb93eP, ' + 'svname=LX:31HxzqBiAFTUxxOlcVn3EA, ' + 'status=rst/exec'): + self.revert_to_snapshot(None, vol, snap) + + return_status = ['snap/active', 'rst/exec', 'snap/active'] + self.mock_object(self._cli, 'query_BV_SV_status', + side_effect=return_status) + self.revert_to_snapshot(None, vol, snap) + + return_status = ['snap/active', 'rst/exec', 'snap/fault'] + self.mock_object(self._cli, 'query_BV_SV_status', + side_effect=return_status) + with self.assertRaisesRegex(exception.VolumeBackendAPIException, + 'Failed to restore from snapshot. ' + 'bvname=LX:yEUHrXa5AHMjOZZLb93eP, ' + 'svname=LX:31HxzqBiAFTUxxOlcVn3EA, ' + 'status=snap/fault'): + self.revert_to_snapshot(None, vol, snap) diff --git a/cinder/volume/drivers/nec/cli.py b/cinder/volume/drivers/nec/cli.py index 6aa612314ad..4bd7e202149 100644 --- a/cinder/volume/drivers/nec/cli.py +++ b/cinder/volume/drivers/nec/cli.py @@ -584,6 +584,46 @@ class MStorageISMCLI(object): cmd = 'iSMcfg generationdel -bvname %s -count 1' % bvname self._execute(cmd) + def snapshot_restore(self, bvname, svname): + """Snapshot restore.""" + query_status = self.query_BV_SV_status(bvname[3:], svname[3:]) + if query_status == 'snap/active': + cmd = ('iSMsc_restore -bv %(bv)s -bvflg ld -sv %(sv)s ' + '-svflg ld -derivsv keep -nowait' + % {'bv': bvname[3:], 'sv': svname[3:]}) + self._execute(cmd) + + retry_count = 0 + while True: + query_status = self.query_BV_SV_status(bvname[3:], svname[3:]) + if query_status == 'rst/exec': + # Restoration is in progress. + sleep_time = get_sleep_time_for_clone(retry_count) + LOG.debug('Sleep %d seconds Start', sleep_time) + time.sleep(sleep_time) + retry_count += 1 + elif query_status == 'snap/active': + # Restoration was successful. + break + else: + # Restoration failed. + msg = (_('Failed to restore from snapshot. ' + 'bvname=%(bvname)s, svname=%(svname)s, ' + 'status=%(status)s') % + {'bvname': bvname, 'svname': svname, + 'status': query_status}) + LOG.error(msg) + raise exception.VolumeBackendAPIException(data=msg) + else: + msg = (_('The snapshot does not exist or is ' + 'not in snap/active status. ' + 'bvname=%(bvname)s, svname=%(svname)s, ' + 'status=%(status)s') % + {'bvname': bvname, 'svname': svname, + 'status': query_status}) + LOG.error(msg) + raise exception.VolumeBackendAPIException(data=msg) + def query_BV_SV_status(self, bvname, svname): cmd = ('iSMsc_query -bv %(bv)s -bvflg ld -sv %(sv)s -svflg ld ' '-summary | ' @@ -593,7 +633,12 @@ class MStorageISMCLI(object): % {'bv': bvname, 'sv': svname, 'line': svname}) out, err, status = self._execute(cmd) - query_status = out[34:48].strip() + delimiter = ') ' + start = out.find(delimiter) + if start == -1: + return None + start += len(delimiter) + query_status = out[start:].split(' ')[0] LOG.debug('snap/state:%s.', query_status) return query_status @@ -729,16 +774,6 @@ class UnpairWait(object): pass -class UnpairWaitForBackup(UnpairWait): - def __init__(self, volume_properties, cli): - super(UnpairWaitForBackup, self).__init__(volume_properties, cli) - - def _execute(self): - LOG.debug('UnpairWaitForBackup start.') - - self._wait(True) - - class UnpairWaitForRestore(UnpairWait): def __init__(self, volume_properties, cli): super(UnpairWaitForRestore, self).__init__(volume_properties, cli) @@ -815,16 +850,6 @@ class UnpairWaitForMigrate(UnpairWait): self._volume_properties['rvname']) -class UnpairWaitForDDRBackup(UnpairWaitForBackup): - def __init__(self, volume_properties, cli): - super(UnpairWaitForDDRBackup, self).__init__(volume_properties, cli) - - def _execute(self): - LOG.debug('UnpairWaitForDDRBackup start.') - - self._wait(False) - - class UnpairWaitForDDRRestore(UnpairWaitForRestore): def __init__(self, volume_properties, cli): super(UnpairWaitForDDRRestore, self).__init__(volume_properties, cli) diff --git a/cinder/volume/drivers/nec/volume.py b/cinder/volume/drivers/nec/volume.py index 5f9b5f1f5c6..5309b7d190d 100644 --- a/cinder/volume/drivers/nec/volume.py +++ b/cinder/volume/drivers/nec/volume.py @@ -50,6 +50,7 @@ class MStorageISCSIDriver(volume_helper.MStorageDSVDriver, 1.11.1 - Add support pytyon 3. Add support for multi-attach. Add support of more than 4 iSCSI portals for a node. + Add support to revert a volume to a snapshot. """ VERSION = '1.11.1' @@ -114,6 +115,7 @@ class MStorageFCDriver(volume_helper.MStorageDSVDriver, 1.11.1 - Add support pytyon 3. Add support for multi-attach. Add support of more than 4 iSCSI portals for a node. + Add support to revert a volume to a snapshot. """ VERSION = '1.11.1' diff --git a/cinder/volume/drivers/nec/volume_helper.py b/cinder/volume/drivers/nec/volume_helper.py index 2f5dedb70d9..fa78f5d42be 100644 --- a/cinder/volume/drivers/nec/volume_helper.py +++ b/cinder/volume/drivers/nec/volume_helper.py @@ -1825,3 +1825,55 @@ class MStorageDSVDriver(MStorageDriver): 'snap_id': snapshot.id, 'snapvol_id': snapshot.volume_id, 'specs': specs}) + + def revert_to_snapshot(self, context, volume, snapshot): + """called to perform revert volume from snapshot. + + :param context: Our working context. + :param volume: the volume to be reverted. + :param snapshot: the snapshot data revert to volume. + :return None + """ + msgparm = ('Volume ID = %(vol_id)s, ' + 'Snapshot ID = %(snap_id)s, ' + 'Snapshot Volume ID = %(snapvol_id)s' + % {'vol_id': volume.id, + 'snap_id': snapshot.id, + 'snapvol_id': snapshot.volume_id}) + try: + self._revert_to_snapshot(context, volume, snapshot) + LOG.info('Reverted to Snapshot (%s)', msgparm) + except exception.CinderException as e: + with excutils.save_and_reraise_exception(): + LOG.warning('Failed to revert to Snapshot ' + '(%(msgparm)s) (%(exception)s)', + {'msgparm': msgparm, 'exception': e}) + + def _revert_to_snapshot(self, context, volume, snapshot): + LOG.debug('_revert_to_snapshot (Volume ID = %(vol_id)s, ' + 'Snapshot ID = %(snap_id)s) Start.', + {'vol_id': volume.id, 'snap_id': snapshot.id}) + xml = self._cli.view_all(self._properties['ismview_path']) + pools, lds, ldsets, used_ldns, hostports, max_ld_count = ( + self.configs(xml)) + # get BV name. + bvname = ( + self.get_ldname(volume.id, + self._properties['ld_name_format'])) + if bvname not in lds: + msg = _('Logical Disk `%s` has unbound already.') % bvname + LOG.error(msg) + raise exception.NotFound(msg) + + # get SV name. + svname = ( + self.get_ldname(snapshot.id, + self._properties['ld_backupname_format'])) + if svname not in lds: + msg = _('Logical Disk `%s` has unbound already.') % svname + LOG.error(msg) + raise exception.NotFound(msg) + + self._cli.snapshot_restore(bvname, svname) + + LOG.debug('_revert_to_snapshot(Volume ID = %s) End.', volume.id) diff --git a/doc/source/configuration/block-storage/drivers/nec-storage-m-series-driver.rst b/doc/source/configuration/block-storage/drivers/nec-storage-m-series-driver.rst index 3504a675ddd..375bd59f9ac 100644 --- a/doc/source/configuration/block-storage/drivers/nec-storage-m-series-driver.rst +++ b/doc/source/configuration/block-storage/drivers/nec-storage-m-series-driver.rst @@ -53,6 +53,8 @@ Supported operations - Manage and unmanage a volume. - Manage and unmanage a snapshot. - Attach a volume to multiple instances at once (multi-attach). +- Revert a volume to a snapshot. + Preparation ~~~~~~~~~~~ diff --git a/doc/source/reference/support-matrix.ini b/doc/source/reference/support-matrix.ini index 415f7440896..df06c930178 100644 --- a/doc/source/reference/support-matrix.ini +++ b/doc/source/reference/support-matrix.ini @@ -852,7 +852,7 @@ driver.lenovo=missing driver.linbit_linstor=missing driver.lvm=complete driver.macrosan=missing -driver.nec=missing +driver.nec=complete driver.netapp_ontap=missing driver.netapp_solidfire=complete driver.nexenta=missing diff --git a/releasenotes/notes/nec-storage-assist-revert-to-sanpshot-58cddebfbf06d222.yaml b/releasenotes/notes/nec-storage-assist-revert-to-sanpshot-58cddebfbf06d222.yaml new file mode 100644 index 00000000000..1e6f60dde44 --- /dev/null +++ b/releasenotes/notes/nec-storage-assist-revert-to-sanpshot-58cddebfbf06d222.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + NEC Driver: Added support to revert a volume to a snapshot. +