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 31e9c3d4053..43a4d6e440c 100644 --- a/cinder/tests/unit/volume/drivers/ibm/test_storwize_svc.py +++ b/cinder/tests/unit/volume/drivers/ibm/test_storwize_svc.py @@ -9569,6 +9569,134 @@ class StorwizeSVCReplicationTestCase(test.TestCase): get_relationship_info.assert_called_once_with(fake_name) delete_relationship.assert_called_once_with(fake_name) + @mock.patch.object(storwize_svc_common.StorwizeHelpers, + 'delete_vdisk') + @mock.patch.object(storwize_svc_common.StorwizeHelpers, + 'delete_relationship') + @mock.patch.object(storwize_svc_common.StorwizeHelpers, + 'get_relationship_info') + def test_retain_target_volume(self, get_relationship_info, + delete_relationship, + delete_vdisk): + # Set replication target. + + self.driver.configuration.set_override('replication_device', + [self.rep_target]) + self.driver.do_setup(self.ctxt) + fake_name = 'volume-%s' % fake.VOLUME_ID + target_volume_fake_name = ( + storwize_const.REPLICA_AUX_VOL_PREFIX + fake_name) + target_change_fake_name = ( + storwize_const.REPLICA_CHG_VOL_PREFIX + target_volume_fake_name) + get_relationship_info.return_value = {'aux_vdisk_name': + fake_name} + self.driver._helpers.delete_rc_volume(fake_name, + target_vol=True, + retain_aux_volume=True) + get_relationship_info.assert_called_once_with(target_volume_fake_name) + delete_relationship.assert_called_once_with(target_volume_fake_name) + + calls = [mock.call(target_change_fake_name, force_delete=False, + force_unmap=True)] + delete_vdisk.assert_has_calls(calls, any_order=True) + self.assertEqual(1, delete_vdisk.call_count) + + @mock.patch.object(storwize_svc_common.StorwizeHelpers, + 'delete_vdisk') + @mock.patch.object(storwize_svc_common.StorwizeHelpers, + 'delete_relationship') + @mock.patch.object(storwize_svc_common.StorwizeHelpers, + 'get_relationship_info') + def test_retain_target_volume_invalid_parameters_1( + self, get_relationship_info, + delete_relationship, + delete_vdisk): + # Set replication target. + + self.driver.configuration.set_override('replication_device', + [self.rep_target]) + self.driver.do_setup(self.ctxt) + fake_name = 'volume-%s' % fake.VOLUME_ID + master_change_fake_name = ( + storwize_const.REPLICA_CHG_VOL_PREFIX + fake_name) + get_relationship_info.return_value = {'aux_vdisk_name': + fake_name} + self.driver._helpers.delete_rc_volume(fake_name, + target_vol=False, + retain_aux_volume=True) + get_relationship_info.assert_called_once_with(fake_name) + delete_relationship.assert_called_once_with(fake_name) + calls = [mock.call(master_change_fake_name, force_delete=False, + force_unmap=True), + mock.call(fake_name, force_delete=False, force_unmap=True)] + delete_vdisk.assert_has_calls(calls, any_order=True) + self.assertEqual(2, delete_vdisk.call_count) + + @mock.patch.object(storwize_svc_common.StorwizeHelpers, + 'delete_vdisk') + @mock.patch.object(storwize_svc_common.StorwizeHelpers, + 'delete_relationship') + @mock.patch.object(storwize_svc_common.StorwizeHelpers, + 'get_relationship_info') + def test_retain_target_volume_invalid_parameters_2( + self, get_relationship_info, + delete_relationship, + delete_vdisk): + # Set replication target. + + self.driver.configuration.set_override('replication_device', + [self.rep_target]) + self.driver.do_setup(self.ctxt) + fake_name = 'volume-%s' % fake.VOLUME_ID + target_volume_fake_name = ( + storwize_const.REPLICA_AUX_VOL_PREFIX + fake_name) + target_change_fake_name = ( + storwize_const.REPLICA_CHG_VOL_PREFIX + target_volume_fake_name) + get_relationship_info.return_value = {'aux_vdisk_name': + fake_name} + self.driver._helpers.delete_rc_volume(fake_name, + target_vol=True, + retain_aux_volume=False) + get_relationship_info.assert_called_once_with(target_volume_fake_name) + delete_relationship.assert_called_once_with(target_volume_fake_name) + calls = [mock.call(target_change_fake_name, force_delete=False, + force_unmap=True), + mock.call(target_volume_fake_name, force_delete=False, + force_unmap=True)] + delete_vdisk.assert_has_calls(calls, any_order=True) + self.assertEqual(2, delete_vdisk.call_count) + + @mock.patch.object(storwize_svc_common.StorwizeHelpers, + 'delete_vdisk') + @mock.patch.object(storwize_svc_common.StorwizeHelpers, + 'delete_relationship') + @mock.patch.object(storwize_svc_common.StorwizeHelpers, + 'get_relationship_info') + def test_retain_target_volume_invalid_parameters_3( + self, get_relationship_info, + delete_relationship, + delete_vdisk): + # Set replication target. + + self.driver.configuration.set_override('replication_device', + [self.rep_target]) + self.driver.do_setup(self.ctxt) + fake_name = 'volume-%s' % fake.VOLUME_ID + master_change_fake_name = ( + storwize_const.REPLICA_CHG_VOL_PREFIX + fake_name) + get_relationship_info.return_value = {'aux_vdisk_name': + fake_name} + self.driver._helpers.delete_rc_volume(fake_name, + target_vol=False, + retain_aux_volume=False) + get_relationship_info.assert_called_once_with(fake_name) + delete_relationship.assert_called_once_with(fake_name) + calls = [mock.call(master_change_fake_name, force_delete=False, + force_unmap=True), + mock.call(fake_name, force_delete=False, force_unmap=True)] + delete_vdisk.assert_has_calls(calls, any_order=True) + self.assertEqual(2, delete_vdisk.call_count) + def test_storwize_failover_host_backend_error(self): self.driver.configuration.set_override('replication_device', [self.rep_target]) 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 26c3e9eaaa3..2192cbac359 100644 --- a/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py +++ b/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py @@ -147,6 +147,13 @@ storwize_svc_opts = [ 'performs a complete cycle at most once each period. ' 'The default is 300 seconds, and the valid seconds ' 'are 60-86400.'), + cfg.BoolOpt('storwize_svc_retain_aux_volume', + default=False, + help='Enable or disable retaining of aux volume on secondary ' + 'storage during delete of the volume on primary storage ' + 'or moving the primary volume from mirror to non-mirror ' + 'with replication enabled. This option is valid for ' + 'SVC.'), ] CONF = cfg.CONF @@ -2196,7 +2203,7 @@ class StorwizeHelpers(object): return relationship[0] if len(relationship) > 0 else None def delete_rc_volume(self, volume_name, target_vol=False, - force_unmap=True): + force_unmap=True, retain_aux_volume=False): vol_name = volume_name if target_vol: vol_name = storwize_const.REPLICA_AUX_VOL_PREFIX + volume_name @@ -2210,9 +2217,15 @@ class StorwizeHelpers(object): storwize_const.REPLICA_CHG_VOL_PREFIX + vol_name, force_unmap=force_unmap, force_delete=False) - self.delete_vdisk(vol_name, - force_unmap=force_unmap, - force_delete=False) + # We want to retain the aux volume after retyping + # from mirror to non mirror storage template or + # on delete of the primary volume based on user's + # choice of config value for storwize_svc_retain_aux_volume. + # Default value is False. + if (retain_aux_volume is False and target_vol) or not target_vol: + self.delete_vdisk(vol_name, + force_unmap=force_unmap, + force_delete=False) except Exception as e: msg = (_('Unable to delete the volume for ' 'volume %(vol)s. Exception: %(err)s.'), @@ -3132,7 +3145,11 @@ class StorwizeSVCCommonDriver(san.SanDriver, if rep_type: if self._aux_backend_helpers: self._aux_backend_helpers.delete_rc_volume( - volume['name'], target_vol=True, force_unmap=force_unmap) + volume['name'], + target_vol=True, + force_unmap=force_unmap, + retain_aux_volume=self.configuration.safe_get( + 'storwize_svc_retain_aux_volume')) if not self._active_backend_id: self._master_backend_helpers.delete_rc_volume( volume['name'], force_unmap=force_unmap) @@ -4890,9 +4907,12 @@ class StorwizeSVCCommonDriver(san.SanDriver, force_unmap = True if old_rep_type and not new_rep_type: - self._aux_backend_helpers.delete_rc_volume(volume['name'], - target_vol=True, - force_unmap=force_unmap) + self._aux_backend_helpers.delete_rc_volume( + volume['name'], + target_vol=True, + force_unmap=force_unmap, + retain_aux_volume=self.configuration.safe_get( + 'storwize_svc_retain_aux_volume')) if storwize_const.GMCV == old_rep_type: self._helpers.delete_vdisk( storwize_const.REPLICA_CHG_VOL_PREFIX + volume['name'], diff --git a/releasenotes/notes/storwize-retain-aux-volme-f90fa6fde657d64f.yaml b/releasenotes/notes/storwize-retain-aux-volme-f90fa6fde657d64f.yaml new file mode 100644 index 00000000000..b4c959a6b2c --- /dev/null +++ b/releasenotes/notes/storwize-retain-aux-volme-f90fa6fde657d64f.yaml @@ -0,0 +1,8 @@ +--- +features: + - | + Added the option ``storwize_svc_retain_aux_volume`` to IBM Storwize Driver + which takes ``True`` or ``False``. This option is to enable or disable + retaining of auxiliary volume on secondary storage during delete of the + volume on primary storage or moving the primary volume from mirror to + non-mirror with replication enabled. The default value is ``False``.