From 06523d30adc2e2765b3ca1f3e634e9b2d82f3e2f Mon Sep 17 00:00:00 2001 From: gksk Date: Thu, 8 Oct 2020 17:14:39 +0000 Subject: [PATCH] [SVF] RevertToSnapshot support for GM volumes The current IBM Spectrum Virtualize Family does not support Revert to Snapshot for Global Mirror volumes. Added necessary code changes to storwize cinder driver to support revert to snapshot for GM volumes. Change-Id: I71ab47d7e46afebdcd0ed062e26afdd9e598e3f1 --- .../volume/drivers/ibm/test_storwize_svc.py | 117 ++++++++++++++++-- .../ibm/storwize_svc/storwize_svc_common.py | 13 +- ...-globalmirror-volume-e70fdb9115020283.yaml | 4 + 3 files changed, 119 insertions(+), 15 deletions(-) create mode 100644 releasenotes/notes/svf-revert-to-snapshot-globalmirror-volume-e70fdb9115020283.yaml diff --git a/cinder/tests/unit/volume/drivers/ibm/test_storwize_svc.py b/cinder/tests/unit/volume/drivers/ibm/test_storwize_svc.py index 1b782cd30d7..755090b5e83 100644 --- a/cinder/tests/unit/volume/drivers/ibm/test_storwize_svc.py +++ b/cinder/tests/unit/volume/drivers/ibm/test_storwize_svc.py @@ -3496,7 +3496,6 @@ class StorwizeSVCISCSIDriverTestCase(test.TestCase): 'target_lun': 0, 'auth_method': 'CHAP', 'discovery_auth_method': 'CHAP'}}} - volume1['volume_type_id'] = types[protocol]['id'] volume2['volume_type_id'] = types[protocol]['id'] @@ -7320,34 +7319,63 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase): '_prepare_fc_map') @mock.patch.object(storwize_svc_common.StorwizeSSH, 'startfcmap') - def test_revert_to_snapshot(self, startfcmap, prepare_fc_map, mkfcmap): + @mock.patch.object(storwize_svc_common.StorwizeHelpers, + 'stop_relationship') + @mock.patch.object(storwize_svc_common.StorwizeHelpers, + 'start_relationship') + def test_revert_to_snapshot(self, start_relationship, + stop_relationship, startfcmap, + prepare_fc_map, mkfcmap): mkfcmap.side_effect = ['1'] vol1 = self._generate_vol_info() snap1 = self._generate_snap_info(vol1.id) vol1.size = '11' - self.assertRaises(exception.InvalidInput, self.driver.revert_to_snapshot, self.ctxt, vol1, snap1) - vol2 = self._generate_vol_info() snap2 = self._generate_snap_info(vol2.id) - with mock.patch.object(storwize_svc_common.StorwizeSVCCommonDriver, '_get_volume_replicated_type') as vol_rep_type: - vol_rep_type.side_effect = [True, False] - self.assertRaises(exception.InvalidInput, - self.driver.revert_to_snapshot, self.ctxt, - vol2, snap2) + vol_rep_type.side_effect = [False] self.driver.revert_to_snapshot(self.ctxt, vol2, snap2) - mkfcmap.assert_called_once_with( - snap2.name, vol2.name, True, - self.driver.configuration.storwize_svc_flashcopy_rate) + mkfcmap.assert_called_once_with(snap2.name, vol2.name, True, + self.driver.configuration. + storwize_svc_flashcopy_rate) prepare_fc_map.assert_called_once_with( '1', self.driver.configuration.storwize_svc_flashcopy_timeout, - True,) + True) startfcmap.assert_called_once_with('1', True) + @mock.patch.object(storwize_svc_common.StorwizeSSH, + 'mkfcmap') + @mock.patch.object(storwize_svc_common.StorwizeHelpers, + '_prepare_fc_map') + @mock.patch.object(storwize_svc_common.StorwizeSSH, + 'startfcmap') + @mock.patch.object(storwize_svc_common.StorwizeHelpers, + 'start_relationship') + def test_revert_to_snapshot_replication_type(self, start_relationship, + startfcmap, + prepare_fc_map, mkfcmap): + vol1 = self._generate_vol_info() + snap1 = self._generate_snap_info(vol1.id) + vol1.size = '11' + self.assertRaises(exception.InvalidInput, + self.driver.revert_to_snapshot, self.ctxt, + vol1, snap1) + vol2 = self._generate_vol_info() + snap2 = self._generate_snap_info(vol2.id) + with mock.patch.object(storwize_svc_common.StorwizeSVCCommonDriver, + '_get_volume_replicated_type') as vol_rep_type: + vol_rep_type.side_effect = [True] + self.assertRaises(exception.VolumeBackendAPIException, + self.driver.revert_to_snapshot, self.ctxt, + vol2, snap2) + mkfcmap.assert_not_called() + prepare_fc_map.assert_not_called() + startfcmap.assert_not_called() + def test_storwize_create_volume_with_group_id(self): """Tests creating volume with gorup_id.""" @@ -8721,6 +8749,34 @@ class StorwizeHelpersTestCase(test.TestCase): is_data_reduction_pool.assert_called() self.assertEqual(call_count, is_data_reduction_pool.call_count) + @ddt.data(({'RC_name': None, + 'name': 'volume-12d-5'}, True), + ({'RC_name': 'fake_rcrel', + 'name': 'rep_volume-12d-6'}, False)) + @mock.patch.object(storwize_svc_common.StorwizeSSH, + 'startrcrelationship') + @mock.patch.object(storwize_svc_common.StorwizeSSH, + 'stoprcrelationship') + @mock.patch.object(storwize_svc_common.StorwizeHelpers, + 'get_vdisk_attributes') + @ddt.unpack + def test_stop_and_start_rc_relationship(self, opts, access, + get_vdisk_attributes, + stoprcrelationship, + startrcrelationship): + get_vdisk_attributes.side_effect = [{'RC_name': opts['RC_name']}, + {'RC_name': opts['RC_name']}] + self.storwize_svc_common.stop_relationship(opts['name']) + self.storwize_svc_common.start_relationship(opts['name']) + get_vdisk_attributes.assert_called_with(opts['name']) + if not opts['RC_name']: + stoprcrelationship.assert_not_called() + startrcrelationship.assert_not_called() + else: + stoprcrelationship.assert_called_once_with(opts['RC_name'], + access=access) + startrcrelationship.assert_called_once_with(opts['RC_name'], None) + @ddt.ddt class StorwizeSSHTestCase(test.TestCase): @@ -9680,6 +9736,41 @@ class StorwizeSVCReplicationTestCase(test.TestCase): self.driver.delete_volume(volume) self._validate_replic_vol_deletion(volume, True) + @mock.patch.object(storwize_svc_common.StorwizeSSH, + 'mkfcmap') + @mock.patch.object(storwize_svc_common.StorwizeHelpers, + '_prepare_fc_map') + @mock.patch.object(storwize_svc_common.StorwizeSSH, + 'startfcmap') + @mock.patch.object(storwize_svc_common.StorwizeHelpers, + 'stop_relationship') + @mock.patch.object(storwize_svc_common.StorwizeHelpers, + 'start_relationship') + def test_revert_to_snapshot_mirror_vol(self, start_relationship, + stop_relationship, startfcmap, + prepare_fc_map, mkfcmap): + mkfcmap.side_effect = ['1'] + vol1 = self._generate_vol_info(self.gm_type, + replication_status='enabled') + snap1 = self._generate_snap_info(vol1.id) + with mock.patch.object(storwize_svc_common.StorwizeSVCCommonDriver, + '_get_volume_replicated_type') as vol_rep_type: + vol_rep_type.side_effect = [True, False] + self.driver.revert_to_snapshot(self.ctxt, vol1, snap1) + mkfcmap.assert_called_once_with( + snap1.name, vol1.name, True, + self.driver.configuration.storwize_svc_flashcopy_rate) + prepare_fc_map.assert_called_once_with( + '1', self.driver.configuration.storwize_svc_flashcopy_timeout, + True) + startfcmap.assert_called_once_with('1', True) + self.assertEqual(fields.ReplicationStatus.ENABLED, + vol1.replication_status) + stop_relationship.assert_called_once_with("volume-" + vol1.id, + access=False) + start_relationship.assert_called_once_with("volume-" + vol1.id, + primary=None) + def test_storwize_extend_volume_replication(self): # Set replication target. self.driver.configuration.set_override('replication_device', diff --git a/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py b/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py index 782348d77fd..8d3a41a8bba 100644 --- a/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py +++ b/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py @@ -5603,9 +5603,16 @@ class StorwizeSVCCommonDriver(san.SanDriver, 'size is not equal to the snapshot size.')) rep_type = self._get_volume_replicated_type(context, volume) + if rep_type: - raise exception.InvalidInput( - reason=_('Reverting replication volume is not supported.')) + try: + self._helpers.stop_relationship(volume.name, access=False) + except Exception as err: + msg = (_("Stop RC relationship has failed for %(vol)s" + "due to: %(err)s.") + % {"vol": volume.name, "err": err}) + LOG.error(msg) + raise exception.VolumeBackendAPIException(data=msg) try: self._helpers.pretreatment_before_revert(volume.name) except Exception as err: @@ -5620,6 +5627,8 @@ class StorwizeSVCCommonDriver(san.SanDriver, snapshot.name, volume.name, self.configuration.storwize_svc_flashcopy_timeout, opts['flashcopy_rate'], True, True) + if rep_type: + self._helpers.start_relationship(volume.name, primary=None) except Exception as err: msg = (_("Reverting volume %(vol)s to snapshot %(snap)s failed " "due to: %(err)s.") diff --git a/releasenotes/notes/svf-revert-to-snapshot-globalmirror-volume-e70fdb9115020283.yaml b/releasenotes/notes/svf-revert-to-snapshot-globalmirror-volume-e70fdb9115020283.yaml new file mode 100644 index 00000000000..f623663ce3b --- /dev/null +++ b/releasenotes/notes/svf-revert-to-snapshot-globalmirror-volume-e70fdb9115020283.yaml @@ -0,0 +1,4 @@ +--- +features: + - | + IBM Spectrum Virtualize Family: Added support for revert to snapshot for global-mirror volume.