From 8116de89ea8cc410150b3b9006aaa8d7b0a365fd Mon Sep 17 00:00:00 2001 From: Simon Dodsley Date: Thu, 4 Jun 2020 09:04:30 -0400 Subject: [PATCH] Add revert to snapshot support for Pure Storage drivers Add support for reverting to snapshot in the Pure Storage iSCSI and FC drivers Change-Id: I73b25777611cad2afd09a57755cf445318cf9797 Implements: blueprint purestorage-revert-snapshot --- cinder/tests/unit/volume/drivers/test_pure.py | 50 ++++++++++++++++++- cinder/volume/drivers/pure.py | 31 +++++++++--- ...rage-revert-snapshot-b7e0ec4f958418c4.yaml | 3 ++ 3 files changed, 75 insertions(+), 9 deletions(-) create mode 100644 releasenotes/notes/pure-storage-revert-snapshot-b7e0ec4f958418c4.yaml diff --git a/cinder/tests/unit/volume/drivers/test_pure.py b/cinder/tests/unit/volume/drivers/test_pure.py index 14a710c11c4..08ff0b6e6fd 100644 --- a/cinder/tests/unit/volume/drivers/test_pure.py +++ b/cinder/tests/unit/volume/drivers/test_pure.py @@ -532,8 +532,7 @@ class PureDriverTestCase(test.TestCase): self.purestorage_module.VERSION = '1.4.0' self.purestorage_module.PureHTTPError = FakePureStorageHTTPError - @staticmethod - def fake_get_array(*args, **kwargs): + def fake_get_array(self, *args, **kwargs): if 'action' in kwargs and kwargs['action'] == 'monitor': return PERF_INFO_RAW @@ -627,6 +626,22 @@ class PureBaseSharedDriverTestCase(PureDriverTestCase): group_name = "consisgroup-%s-cinder" % group.id return group, group_name + def new_fake_group_snap(self, group=None): + if group: + group_name = "consisgroup-%s-cinder" % group.id + else: + group, group_name = self.new_fake_group() + group_snap = fake_group_snapshot.fake_group_snapshot_obj( + mock.MagicMock()) + + group_snap_name = "%s.cgsnapshot-%s-cinder" % (group_name, + group_snap.id) + + group_snap.group = group + group_snap.group_id = group.id + + return group_snap, group_snap_name + @ddt.ddt class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase): @@ -915,6 +930,37 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase): self.assertEqual(49, len(result)) self.assertIsNotNone(pure.GENERATED_NAME.match(result)) + def test_revert_to_snapshot(self): + vol, vol_name = self.new_fake_vol(set_provider_id=True) + snap, snap_name = self.new_fake_snap(vol) + + context = mock.MagicMock() + self.driver.revert_to_snapshot(context, vol, snap) + + self.array.copy_volume.assert_called_with(snap_name, vol_name, + overwrite=True) + self.assert_error_propagates([self.array.copy_volume], + self.driver.revert_to_snapshot, + context, vol, snap) + + def test_revert_to_snapshot_group(self): + vol, vol_name = self.new_fake_vol(set_provider_id=True) + group, group_name = self.new_fake_group() + group_snap, group_snap_name = self.new_fake_group_snap(group) + snap, snap_name = self.new_fake_snap(vol, group_snap) + + copy_vol_name = "%s.%s" % (group_snap_name, vol_name) + + context = mock.MagicMock() + self.driver.revert_to_snapshot(context, vol, snap) + + self.array.copy_volume.assert_called_with(copy_vol_name, vol_name, + overwrite=True) + + self.assert_error_propagates([self.array.copy_volume], + self.driver.revert_to_snapshot, + context, vol, snap) + @mock.patch(BASE_DRIVER_OBJ + "._add_to_group_if_needed") @mock.patch(BASE_DRIVER_OBJ + "._get_replication_type_from_vol_type") def test_create_volume(self, mock_get_repl_type, mock_add_to_group): diff --git a/cinder/volume/drivers/pure.py b/cinder/volume/drivers/pure.py index 141be5f2992..37f0c934d0c 100644 --- a/cinder/volume/drivers/pure.py +++ b/cinder/volume/drivers/pure.py @@ -403,6 +403,28 @@ class PureBaseVolumeDriver(san.SanDriver): }) return vol_updates, None + @pure_driver_debug_trace + def revert_to_snapshot(self, context, volume, snapshot): + """Is 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 + """ + vol_name = self._generate_purity_vol_name(volume) + if snapshot['group_snapshot'] or snapshot['cgsnapshot']: + snap_name = self._get_pgroup_snap_name_from_snapshot(snapshot) + else: + snap_name = self._get_snap_name(snapshot) + + LOG.debug("Reverting from snapshot %(snap)s to volume " + "%(vol)s", {'vol': vol_name, 'snap': snap_name}) + + current_array = self._get_current_array() + + current_array.copy_volume(snap_name, vol_name, overwrite=True) + @pure_driver_debug_trace def create_volume(self, volume): """Creates a volume.""" @@ -422,11 +444,6 @@ class PureBaseVolumeDriver(san.SanDriver): else: snap_name = self._get_snap_name(snapshot) - if not snap_name: - msg = _('Unable to determine snapshot name in Purity for snapshot ' - '%(id)s.') % {'id': snapshot['id']} - raise PureDriverException(reason=msg) - current_array = self._get_current_array() current_array.copy_volume(snap_name, vol_name) @@ -2344,7 +2361,7 @@ class PureISCSIDriver(PureBaseVolumeDriver, san.SanISCSIDriver): the underlying storage connectivity with the FlashArray. """ - VERSION = "10.0.iscsi" + VERSION = "11.0.iscsi" def __init__(self, *args, **kwargs): execute = kwargs.pop("execute", utils.execute) @@ -2591,7 +2608,7 @@ class PureFCDriver(PureBaseVolumeDriver, driver.FibreChannelDriver): supports the Cinder Fibre Channel Zone Manager. """ - VERSION = "10.0.fc" + VERSION = "11.0.fc" def __init__(self, *args, **kwargs): execute = kwargs.pop("execute", utils.execute) diff --git a/releasenotes/notes/pure-storage-revert-snapshot-b7e0ec4f958418c4.yaml b/releasenotes/notes/pure-storage-revert-snapshot-b7e0ec4f958418c4.yaml new file mode 100644 index 00000000000..8ae46ec49bd --- /dev/null +++ b/releasenotes/notes/pure-storage-revert-snapshot-b7e0ec4f958418c4.yaml @@ -0,0 +1,3 @@ +--- +features: + - Add reverting to snapshot support in Pure Storage Cinder driver.