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 a51b4b20bcb..1e3dc1d374b 100644 --- a/cinder/tests/unit/volume/drivers/ibm/test_storwize_svc.py +++ b/cinder/tests/unit/volume/drivers/ibm/test_storwize_svc.py @@ -10342,25 +10342,34 @@ class StorwizeSVCReplicationTestCase(test.TestCase): rel_info = self.driver._helpers.get_relationship_info(volume['name']) self.assertIsNone(rel_info) - def test_storwize_create_snapshot_volume_with_mirror_replica(self): + @ddt.data(({'mirror_type': 'mm_type'}), + ({'mirror_type': 'gm_type'}), + ({'mirror_type': 'gmcv_default_type'}), + ({'mirror_type': 'gmcv_with_cps900_type'})) + def test_storwize_create_snapshot_volume_with_mirror_replica(self, + vol_spec): # Set replication target self.driver.configuration.set_override('replication_device', [self.rep_target]) self.driver.do_setup(self.ctxt) + rep_type = getattr(self, vol_spec['mirror_type']) # Create metro mirror replication volume. - vol1, model_update = self._create_test_volume(self.mm_type) + vol1, model_update = self._create_test_volume(rep_type) self.assertEqual(fields.ReplicationStatus.ENABLED, model_update['replication_status']) snap = testutils.create_snapshot(self.ctxt, vol1.id) self.driver.create_snapshot(snap) - - vol2 = self._generate_vol_info(self.mm_type) + self._assert_vol_exists(snap['name'], True) + vol2 = self._generate_vol_info(rep_type) model_update = self.driver.create_volume_from_snapshot(vol2, snap) self.assertEqual(fields.ReplicationStatus.ENABLED, model_update['replication_status']) - self._validate_replic_vol_creation(vol2) + if "gmcv" in vol_spec['mirror_type']: + self._validate_replic_vol_creation(vol2, isGMCV=True) + else: + self._validate_replic_vol_creation(vol2) if self.USESIM: self.sim.error_injection('lsfcmap', 'speed_up') @@ -10368,28 +10377,6 @@ class StorwizeSVCReplicationTestCase(test.TestCase): self.driver.delete_snapshot(snap) self.driver.delete_volume(vol1) - # Create gmcv replication volume. - vol1, model_update = self._create_test_volume(self.gmcv_default_type) - self.assertEqual(fields.ReplicationStatus.ENABLED, - model_update['replication_status']) - self._validate_replic_vol_creation(vol1, True) - snap = testutils.create_snapshot(self.ctxt, vol1.id) - self.assertRaises(exception.VolumeDriverException, - self.driver.create_snapshot, - snap) - self.driver.delete_volume(vol1) - - # gmcv with specified cycle_period_seconds - vol1, model_update = self._create_test_volume( - self.gmcv_with_cps900_type) - self.assertEqual(fields.ReplicationStatus.ENABLED, - model_update['replication_status']) - self._validate_replic_vol_creation(vol1, True) - snap = testutils.create_snapshot(self.ctxt, vol1.id) - self.assertRaises(exception.VolumeDriverException, - self.driver.create_snapshot, snap) - self.driver.delete_volume(vol1) - def test_storwize_create_cloned_volume_with_mirror_replica(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 fc19f1afd5d..f482f1f78eb 100644 --- a/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py +++ b/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py @@ -3634,16 +3634,6 @@ class StorwizeSVCCommonDriver(san.SanDriver, LOG.error(msg) raise exception.VolumeDriverException(message=msg) - rep_type = self._get_volume_replicated_type( - ctxt, None, source_vol['volume_type_id']) - if rep_type == storwize_const.GMCV: - # GMCV volume will have problem to failback - # when it has flash copy relationship besides change volumes - msg = _('create_snapshot: Create snapshot to ' - 'gmcv replication volume is not allowed.') - LOG.error(msg) - raise exception.VolumeDriverException(message=msg) - pool = volume_utils.extract_host(source_vol['host'], 'pool') opts = self._get_vdisk_params(source_vol['volume_type_id']) @@ -6285,47 +6275,71 @@ class StorwizeSVCCommonDriver(san.SanDriver, "relationship of %(vol)s does not exist in " "backend.", {'vol': volume.id}) model_update['status'] = fields.GroupStatus.ERROR - elif (rccg['copy_type'] != 'empty_group' and - (rccg['copy_type'] != rcrel['copy_type'] or - rccg['state'] != rcrel['state'] or - rccg['primary'] != rcrel['primary'] or - rccg['cycling_mode'] != rcrel['cycling_mode'] or - (rccg['cycle_period_seconds'] != - rcrel['cycle_period_seconds']))): - LOG.error("Failed to update rccg %(rccg)s: remote copy " - "type of %(vol)s is %(vol_rc_type)s, the rccg " - "type is %(rccg_type)s. rcrel state is " - "%(rcrel_state)s, rccg state is %(rccg_state)s. " - "rcrel primary is %(rcrel_primary)s, rccg " - "primary is %(rccg_primary)s. " - "rcrel cycling mode is %(rcrel_cmode)s, rccg " - "cycling mode is %(rccg_cmode)s. rcrel cycling " - "period is %(rcrel_period)s, rccg cycling " - "period is %(rccg_period)s. ", - {'rccg': rccg_name, - 'vol': volume.id, - 'vol_rc_type': rcrel['copy_type'], - 'rccg_type': rccg['copy_type'], - 'rcrel_state': rcrel['state'], - 'rccg_state': rccg['state'], - 'rcrel_primary': rcrel['primary'], - 'rccg_primary': rccg['primary'], - 'rcrel_cmode': rcrel['cycling_mode'], - 'rccg_cmode': rccg['cycling_mode'], - 'rcrel_period': rcrel['cycle_period_seconds'], - 'rccg_period': rccg['cycle_period_seconds']}) - model_update['status'] = fields.GroupStatus.ERROR else: - self._helpers.chrcrelationship(rcrel['name'], rccg_name) - if rccg['copy_type'] == 'empty_group': - rccg = self._helpers.get_rccg(rccg_name) - added_vols.append({'id': volume.id, - 'group_id': group.id}) + if rccg and rccg.get('cycling_mode', None) == 'multi': + self._helpers.stop_relationship(vol_name) + rcrel = self._helpers.get_relationship_info(vol_name) + if (rccg['state'] != 'empty' and + rccg['state'] != 'consistent_stopped' or + rccg['state'] != 'inconsistent_stopped'): + self._helpers.stop_rccg(rccg_name) + # To handle existing group updation, refresh rccg + # state to avoid unnecessary stop_rccg calls. + rccg = self._helpers.get_rccg(rccg_name) + + if (rccg['copy_type'] != 'empty_group' and + any(k for k in ('copy_type', 'state', 'primary', + 'cycling_mode', 'cycle_period_seconds') + if rccg[k] != rcrel[k])): + LOG.error("Failed to update rccg %(rccg)s: remote " + "copy type of %(vol)s is %(vol_rc_type)s, " + "the rccg type is %(rccg_type)s. rcrel " + "state %(rcrel_state)s, rccg state is " + "%(rccg_state)s rcrel primary is " + "%(rcrel_primary)s, rccg primary is " + "%(rccg_primary)s. rcrel cycling mode is " + "%(rcrel_cmode)s, rccg cycling mode is " + "%(rccg_cmode)s. rcrel cycling period is " + "%(rcrel_period)s, rccg cycling " + "period is %(rccg_period)s. ", + {'rccg': rccg_name, + 'vol': volume.id, + 'vol_rc_type': rcrel['copy_type'], + 'rccg_type': rccg['copy_type'], + 'rcrel_state': rcrel['state'], + 'rccg_state': rccg['state'], + 'rcrel_primary': rcrel['primary'], + 'rccg_primary': rccg['primary'], + 'rcrel_cmode': rcrel['cycling_mode'], + 'rccg_cmode': rccg['cycling_mode'], + 'rcrel_period': + rcrel['cycle_period_seconds'], + 'rccg_period': + rccg['cycle_period_seconds']}) + # This rcrel updation failed ,it has to be started + # explicitly. + self._helpers.start_relationship(vol_name) + model_update['status'] = fields.GroupStatus.ERROR + else: + self._helpers.chrcrelationship(rcrel['name'], + rccg_name) + if rccg['copy_type'] == 'empty_group': + rccg = self._helpers.get_rccg(rccg_name) + added_vols.append({'id': volume.id, + 'group_id': group.id}) except exception.VolumeBackendAPIException as err: model_update['status'] = fields.GroupStatus.ERROR LOG.error("Failed to add the remote copy of volume %(vol)s to " "group. Exception: %(exception)s.", {'vol': volume.name, 'exception': err}) + self._helpers.start_relationship(vol_name) + + if (rccg and len(add_volumes) > 0 and + rccg.get('cycling_mode', None) == 'multi'): + if rccg.get('primary', None) == 'aux': + self._helpers.start_rccg(rccg_name, primary='aux') + elif rccg.get('primary', None) == 'master': + self._helpers.start_rccg(rccg_name, primary='master') # Remove remote copy relationship from rccg removed_vols = [] diff --git a/releasenotes/notes/bug-1922013-ibm-svf-fix_addvol_gmcv_grp-caa0bc2035747d99.yaml b/releasenotes/notes/bug-1922013-ibm-svf-fix_addvol_gmcv_grp-caa0bc2035747d99.yaml new file mode 100644 index 00000000000..390d70d5d7c --- /dev/null +++ b/releasenotes/notes/bug-1922013-ibm-svf-fix_addvol_gmcv_grp-caa0bc2035747d99.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + IBM Spectrum Virtualize Family driver `Bug #1922013 + `_: Fixed issues in + adding volumes to GMCV group.