diff --git a/cinder/tests/unit/test_storwize_svc.py b/cinder/tests/unit/test_storwize_svc.py index 94a0c30bf51..bd4762e4080 100644 --- a/cinder/tests/unit/test_storwize_svc.py +++ b/cinder/tests/unit/test_storwize_svc.py @@ -3409,6 +3409,50 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase): self.driver.delete_volume(vol1) self._assert_vol_exists(vol1['name'], False) + def test_storwize_svc_delete_vol_with_fcmap(self): + vol1 = self._create_volume() + # create two snapshots + snap1 = self._generate_vol_info(vol1['name'], vol1['id']) + snap2 = self._generate_vol_info(vol1['name'], vol1['id']) + self.driver.create_snapshot(snap1) + self.driver.create_snapshot(snap2) + vol2 = self._generate_vol_info(None, None) + vol3 = self._generate_vol_info(None, None) + + # Create vol from the second snapshot + if self.USESIM: + self.sim.error_injection('lsfcmap', 'speed_up') + self.driver.create_volume_from_snapshot(vol2, snap2) + if self.USESIM: + # validate copyrate was set on the flash copy + for i, fcmap in self.sim._fcmappings_list.items(): + if fcmap['target'] == vol2['name']: + self.assertEqual('copying', fcmap['status']) + self._assert_vol_exists(vol2['name'], True) + + if self.USESIM: + self.sim.error_injection('lsfcmap', 'speed_up') + self.driver.create_cloned_volume(vol3, vol2) + + if self.USESIM: + # validate copyrate was set on the flash copy + for i, fcmap in self.sim._fcmappings_list.items(): + if fcmap['target'] == vol3['name']: + self.assertEqual('copying', fcmap['status']) + self._assert_vol_exists(vol3['name'], True) + + # Delete in the 'opposite' order to make sure it works + self.driver.delete_volume(vol3) + self._assert_vol_exists(vol3['name'], False) + self.driver.delete_volume(vol2) + self._assert_vol_exists(vol2['name'], False) + self.driver.delete_snapshot(snap2) + self._assert_vol_exists(snap2['name'], False) + self.driver.delete_snapshot(snap1) + self._assert_vol_exists(snap1['name'], False) + self.driver.delete_volume(vol1) + self._assert_vol_exists(vol1['name'], False) + def test_storwize_svc_volumes(self): # Create a first volume volume = self._generate_vol_info(None, None) 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 b411ce9d27a..d2791cd351e 100644 --- a/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py +++ b/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py @@ -1419,7 +1419,8 @@ class StorwizeHelpers(object): return None return resp[0] - def _check_vdisk_fc_mappings(self, name, allow_snaps=True): + def _check_vdisk_fc_mappings(self, name, + allow_snaps=True, allow_fctgt=False): """FlashCopy mapping check helper.""" LOG.debug('Loopcall: _check_vdisk_fc_mappings(), vdisk %s.', name) mapping_ids = self._get_vdisk_fc_mappings(name) @@ -1433,6 +1434,12 @@ class StorwizeHelpers(object): copy_rate = attrs['copy_rate'] status = attrs['status'] + if allow_fctgt and target == name and status == 'copying': + self.ssh.stopfcmap(map_id) + attrs = self._get_flashcopy_mapping_attributes(map_id) + if attrs: + status = attrs['status'] + if copy_rate == '0': if source == name: # Vdisk with snapshots. Return False if snapshot @@ -1463,18 +1470,20 @@ class StorwizeHelpers(object): if status == 'prepared': self.ssh.stopfcmap(map_id) self.ssh.rmfcmap(map_id) - elif status == 'idle_or_copied': - # Prepare failed + elif status in ['idle_or_copied', 'stopped']: + # Prepare failed or stopped self.ssh.rmfcmap(map_id) else: wait_for_copy = True if not wait_for_copy or not len(mapping_ids): raise loopingcall.LoopingCallDone(retvalue=True) - def ensure_vdisk_no_fc_mappings(self, name, allow_snaps=True): + def ensure_vdisk_no_fc_mappings(self, name, allow_snaps=True, + allow_fctgt=False): """Ensure vdisk has no flashcopy mappings.""" timer = loopingcall.FixedIntervalLoopingCall( - self._check_vdisk_fc_mappings, name, allow_snaps) + self._check_vdisk_fc_mappings, name, + allow_snaps, allow_fctgt) # Create a timer greenthread. The default volume service heart # beat is every 10 seconds. The flashcopy usually takes hours # before it finishes. Don't set the sleep interval shorter @@ -1558,7 +1567,8 @@ class StorwizeHelpers(object): if not self.is_vdisk_defined(vdisk): LOG.info(_LI('Tried to delete non-existent vdisk %s.'), vdisk) return - self.ensure_vdisk_no_fc_mappings(vdisk) + self.ensure_vdisk_no_fc_mappings(vdisk, allow_snaps=True, + allow_fctgt=True) self.ssh.rmvdisk(vdisk, force=force) LOG.debug('Leave: delete_vdisk: vdisk %s.', vdisk) diff --git a/releasenotes/notes/del_volume_with_fc-f024b9f2d6eaca0f.yaml b/releasenotes/notes/del_volume_with_fc-f024b9f2d6eaca0f.yaml new file mode 100644 index 00000000000..0d4766d1911 --- /dev/null +++ b/releasenotes/notes/del_volume_with_fc-f024b9f2d6eaca0f.yaml @@ -0,0 +1,4 @@ +--- +fixes: + - Fixed StorWize/SVC error causing volume deletion to get + stuck in the 'deleting' state when using FlashCopy.