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.