Merge "[SVF]:Fix clone fcmap not being deleted in cleanup" into stable/ussuri

This commit is contained in:
Zuul 2021-03-05 17:54:37 +00:00 committed by Gerrit Code Review
commit 51aaa57988
3 changed files with 257 additions and 22 deletions

View File

@ -25,6 +25,7 @@ from unittest import mock
import ddt
from oslo_concurrency import processutils
from oslo_config import cfg
from oslo_service import loopingcall
from oslo_utils import importutils
from oslo_utils import units
import paramiko
@ -8308,7 +8309,168 @@ class StorwizeHelpersTestCase(test.TestCase):
'status': 'copying',
'target_vdisk_name': 'testvol'}
self.storwize_svc_common.pretreatment_before_revert(vol)
stopfcmap.assert_called_once_with('4', split=True)
stopfcmap.assert_called_once_with('4')
@ddt.data({'copy_rate': '50', 'progress': '3', 'status': 'copying'},
{'copy_rate': '50', 'progress': '100', 'status': 'copying'},
{'copy_rate': '0', 'progress': '0', 'status': 'copying'},
{'copy_rate': '50', 'progress': '0', 'status': 'copying'},
{'copy_rate': '0', 'progress': '0', 'status': 'idle_or_copied'})
@mock.patch.object(storwize_svc_common.StorwizeSSH, 'chfcmap')
@mock.patch.object(storwize_svc_common.StorwizeSSH, 'stopfcmap')
@mock.patch.object(storwize_svc_common.StorwizeSSH, 'rmfcmap')
@mock.patch.object(storwize_svc_common.StorwizeHelpers,
'_get_flashcopy_mapping_attributes')
@mock.patch.object(storwize_svc_common.StorwizeHelpers,
'_get_vdisk_fc_mappings')
def test_check_vdisk_fc_mappings(self,
fc_data,
get_vdisk_fc_mappings,
get_fc_mapping_attributes,
rmfcmap, stopfcmap, chfcmap):
vol = 'testvol'
get_vdisk_fc_mappings.return_value = ['4']
get_fc_mapping_attributes.return_value = {
'copy_rate': fc_data['copy_rate'],
'progress': fc_data['progress'],
'status': fc_data['status'],
'target_vdisk_name': 'tar-testvol',
'rc_controlled': 'no',
'source_vdisk_name': 'testvol'}
if(fc_data['copy_rate'] != '0' and fc_data['progress'] == '100'
and fc_data['status'] == 'copying'):
(self.assertRaises(loopingcall.LoopingCallDone,
self.storwize_svc_common._check_vdisk_fc_mappings, vol, True,
False))
stopfcmap.assert_called_with('4')
self.assertEqual(1, stopfcmap.call_count)
else:
self.storwize_svc_common._check_vdisk_fc_mappings(vol, True,
False)
stopfcmap.assert_not_called()
self.assertEqual(0, stopfcmap.call_count)
get_vdisk_fc_mappings.assert_called()
get_fc_mapping_attributes.assert_called_with('4')
rmfcmap.assert_not_called()
self.assertEqual(1, get_fc_mapping_attributes.call_count)
self.assertEqual(0, rmfcmap.call_count)
if(fc_data['copy_rate'] == '0' and fc_data['progress'] == '0'
and fc_data['status'] in ['copying', 'idle_or_copied']):
chfcmap.assert_called_with('4', copyrate='50', autodel='on')
self.assertEqual(1, chfcmap.call_count)
else:
chfcmap.assert_not_called()
self.assertEqual(0, chfcmap.call_count)
@mock.patch.object(storwize_svc_common.StorwizeSSH, 'chfcmap')
@mock.patch.object(storwize_svc_common.StorwizeSSH, 'stopfcmap')
@mock.patch.object(storwize_svc_common.StorwizeSSH, 'rmfcmap')
@mock.patch.object(storwize_svc_common.StorwizeHelpers,
'_get_flashcopy_mapping_attributes')
@mock.patch.object(storwize_svc_common.StorwizeHelpers,
'_get_vdisk_fc_mappings')
def test_check_vdisk_fc_mappings_tarisvol(self,
get_vdisk_fc_mappings,
get_fc_mapping_attributes,
rmfcmap, stopfcmap, chfcmap):
vol = 'tar-testvol'
get_vdisk_fc_mappings.return_value = ['4']
get_fc_mapping_attributes.return_value = {
'copy_rate': '0',
'progress': '0',
'status': 'idle_or_copied',
'target_vdisk_name': 'tar-testvol',
'rc_controlled': 'no',
'source_vdisk_name': 'testvol'}
self.assertRaises(loopingcall.LoopingCallDone,
self.storwize_svc_common._check_vdisk_fc_mappings,
vol, True, False)
get_vdisk_fc_mappings.assert_called()
get_fc_mapping_attributes.assert_called_with('4')
stopfcmap.assert_not_called()
rmfcmap.assert_called_with('4')
chfcmap.assert_not_called()
self.assertEqual(1, get_fc_mapping_attributes.call_count)
self.assertEqual(0, stopfcmap.call_count)
self.assertEqual(1, rmfcmap.call_count)
self.assertEqual(0, chfcmap.call_count)
@ddt.data(([{'cp_rate': '0', 'prgs': '0', 'status': 'idle_or_copied',
'trg_vdisk': 'testvol', 'src_vdisk': 'tar_testvol'},
{'cp_rate': '50', 'prgs': '100', 'status': 'copying',
'trg_vdisk': 'tar_testvol', 'src_vdisk': 'testvol'},
{'cp_rate': '50', 'prgs': '3', 'status': 'copying',
'trg_vdisk': 'tar_testvol', 'src_vdisk': 'testvol'}], 1),
([{'cp_rate': '50', 'prgs': '100', 'status': 'idle_or_copied',
'trg_vdisk': 'testvol', 'src_vdisk': 'tar_testvol'},
{'cp_rate': '50', 'prgs': '100', 'status': 'copying',
'trg_vdisk': 'tar_testvol', 'src_vdisk': 'testvol'},
{'cp_rate': '50', 'prgs': '100', 'status': 'copying',
'trg_vdisk': 'testvol', 'src_vdisk': 'tar_testvol'}], 1),
([{'cp_rate': '50', 'prgs': '100', 'status': 'idle_or_copied',
'trg_vdisk': 'testvol', 'src_vdisk': 'tar_testvol'},
{'cp_rate': '50', 'prgs': '100', 'status': 'copying',
'trg_vdisk': 'tar_testvol', 'src_vdisk': 'testvol'},
{'cp_rate': '50', 'prgs': '100', 'status': 'copying',
'trg_vdisk': 'tar_testvol_1', 'src_vdisk': 'testvol'}], 2),
([{'cp_rate': '0', 'prgs': '0', 'status': 'copying',
'trg_vdisk': 'testvol', 'src_vdisk': 'snap_testvol'},
{'cp_rate': '50', 'prgs': '0', 'status': 'copying',
'trg_vdisk': 'tar_testvol', 'src_vdisk': 'testvol'},
{'cp_rate': '50', 'prgs': '0', 'status': 'copying',
'trg_vdisk': 'tar_testvol_1', 'src_vdisk': 'testvol'}], 0))
@mock.patch.object(storwize_svc_common.StorwizeSSH, 'chfcmap')
@mock.patch.object(storwize_svc_common.StorwizeSSH, 'stopfcmap')
@mock.patch.object(storwize_svc_common.StorwizeSSH, 'rmfcmap')
@mock.patch.object(storwize_svc_common.StorwizeHelpers,
'_get_flashcopy_mapping_attributes')
@mock.patch.object(storwize_svc_common.StorwizeHelpers,
'_get_vdisk_fc_mappings')
@ddt.unpack
def test_check_vdisk_fc_mappings_mul_fcs(self,
fc_data, stopfc_count,
get_vdisk_fc_mappings,
get_fc_mapping_attributes,
rmfcmap, stopfcmap, chfcmap):
vol = 'testvol'
get_vdisk_fc_mappings.return_value = ['4', '5', '7']
get_fc_mapping_attributes.side_effect = [
{
'copy_rate': fc_data[0]['cp_rate'],
'progress': fc_data[0]['prgs'],
'status': fc_data[0]['status'],
'target_vdisk_name': fc_data[0]['trg_vdisk'],
'rc_controlled': 'no',
'source_vdisk_name': fc_data[0]['src_vdisk']},
{
'copy_rate': fc_data[1]['cp_rate'],
'progress': fc_data[1]['prgs'],
'status': fc_data[1]['status'],
'target_vdisk_name': fc_data[1]['trg_vdisk'],
'rc_controlled': 'no',
'source_vdisk_name': fc_data[1]['src_vdisk']},
{
'copy_rate': fc_data[2]['cp_rate'],
'progress': fc_data[2]['prgs'],
'status': fc_data[2]['status'],
'target_vdisk_name': fc_data[2]['trg_vdisk'],
'rc_controlled': 'no',
'source_vdisk_name': fc_data[2]['src_vdisk']}]
self.storwize_svc_common._check_vdisk_fc_mappings(vol, True, True)
get_vdisk_fc_mappings.assert_called()
get_fc_mapping_attributes.assert_called()
rmfcmap.assert_not_called()
chfcmap.assert_not_called()
self.assertEqual(3, get_fc_mapping_attributes.call_count)
self.assertEqual(stopfc_count, stopfcmap.call_count)
self.assertEqual(0, rmfcmap.call_count)
self.assertEqual(0, chfcmap.call_count)
def test_storwize_check_flashcopy_rate_invalid1(self):
with mock.patch.object(storwize_svc_common.StorwizeHelpers,

View File

@ -2045,10 +2045,10 @@ class StorwizeHelpers(object):
return None
return resp[0]
def _check_vdisk_fc_mappings(self, name,
allow_snaps=True, allow_fctgt=False):
@cinder_utils.trace
def _check_delete_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)
wait_for_copy = False
for map_id in mapping_ids:
@ -2061,10 +2061,23 @@ class StorwizeHelpers(object):
target = attrs['target_vdisk_name']
copy_rate = attrs['copy_rate']
status = attrs['status']
progress = attrs['progress']
LOG.debug('Loopcall: source: %s, target: %s, copy_rate: %s, '
'status: %s, progress: %s, mapid: %s', source, target,
copy_rate, status, progress, map_id)
if allow_fctgt and target == name and status == 'copying':
self.ssh.stopfcmap(map_id)
attrs = self._get_flashcopy_mapping_attributes(map_id)
try:
self.ssh.stopfcmap(map_id)
except exception.VolumeBackendAPIException as ex:
LOG.warning(ex)
wait_for_copy = True
try:
attrs = self._get_flashcopy_mapping_attributes(map_id)
except exception.VolumeBackendAPIException as ex:
LOG.warning(ex)
wait_for_copy = True
continue
if attrs:
status = attrs['status']
else:
@ -2086,28 +2099,80 @@ class StorwizeHelpers(object):
{'name': name, 'src': source, 'tgt': target})
LOG.error(msg)
raise exception.VolumeDriverException(message=msg)
if status in ['copying', 'prepared']:
self.ssh.stopfcmap(map_id)
# Need to wait for the fcmap to change to
# stopped state before remove fcmap
try:
if status in ['copying', 'prepared']:
self.ssh.stopfcmap(map_id)
# Need to wait for the fcmap to change to
# stopped state before remove fcmap
wait_for_copy = True
elif status in ['stopping', 'preparing']:
wait_for_copy = True
else:
self.ssh.rmfcmap(map_id)
except exception.VolumeBackendAPIException as ex:
LOG.warning(ex)
wait_for_copy = True
elif status in ['stopping', 'preparing']:
wait_for_copy = True
else:
self.ssh.rmfcmap(map_id)
# Case 4: Copy in progress - wait and will autodelete
else:
if status == 'prepared':
self.ssh.stopfcmap(map_id)
self.ssh.rmfcmap(map_id)
elif status in ['idle_or_copied', 'stopped']:
# Prepare failed or stopped
self.ssh.rmfcmap(map_id)
else:
try:
if status == 'prepared':
self.ssh.stopfcmap(map_id)
self.ssh.rmfcmap(map_id)
elif status in ['idle_or_copied', 'stopped']:
# Prepare failed or stopped
self.ssh.rmfcmap(map_id)
elif (status in ['copying', 'prepared'] and
progress == '100'):
self.ssh.stopfcmap(map_id)
else:
wait_for_copy = True
except exception.VolumeBackendAPIException as ex:
LOG.warning(ex)
wait_for_copy = True
if not wait_for_copy or not len(mapping_ids):
raise loopingcall.LoopingCallDone(retvalue=True)
@cinder_utils.trace
def _check_vdisk_fc_mappings(self, name, allow_snaps=True,
allow_fctgt=False):
"""FlashCopy mapping check helper."""
# if this is a remove disk we need to be down to one fc clone
mapping_ids = self._get_vdisk_fc_mappings(name)
if len(mapping_ids) > 1 and allow_fctgt:
LOG.debug('Loopcall: vdisk %s has '
'more than one fc map. Waiting.', name)
for map_id in mapping_ids:
attrs = self._get_flashcopy_mapping_attributes(map_id)
if not attrs:
continue
source = attrs['source_vdisk_name']
target = attrs['target_vdisk_name']
copy_rate = attrs['copy_rate']
status = attrs['status']
progress = attrs['progress']
LOG.debug('Loopcall: source: %s, target: %s, copy_rate: %s, '
'status: %s, progress: %s, mapid: %s',
source, target, copy_rate, status, progress, map_id)
if copy_rate != '0' and source == name:
try:
if status in ['copying'] and progress == '100':
self.ssh.stopfcmap(map_id)
elif status == 'idle_or_copied' and progress == '100':
# wait for auto-delete of fcmap.
continue
elif status in ['idle_or_copied', 'stopped']:
# Prepare failed or stopped
self.ssh.rmfcmap(map_id)
# handle VolumeBackendAPIException to let it go through
# next attempts in case of any cli exception.
except exception.VolumeBackendAPIException as ex:
LOG.warning(ex)
return
return self._check_delete_vdisk_fc_mappings(
name, allow_snaps=allow_snaps, allow_fctgt=allow_fctgt)
def ensure_vdisk_no_fc_mappings(self, name, allow_snaps=True,
allow_fctgt=False):
"""Ensure vdisk has no flashcopy mappings."""
@ -2547,7 +2612,7 @@ class StorwizeHelpers(object):
elif copy_rate != '0' and progress == '100':
LOG.debug('Split completed clone map_id=%(map_id)s fcmap',
{'map_id': map_id})
self.ssh.stopfcmap(map_id, split=True)
self.ssh.stopfcmap(map_id)
class CLIResponse(object):

View File

@ -0,0 +1,8 @@
---
fixes:
- |
IBM Spectrum Virtualize driver `Bug #1890254
<https://bugs.launchpad.net/cinder/+bug/1890254>`_:
Fix check_vdisk_fc_mappings is not deleting all flashcopy
mappings while deleting source volume, when multiple clones
and snapshots are created using common source volume.