Merge "[SVF]:Fix clone fcmap not being deleted in cleanup" into stable/ussuri
This commit is contained in:
commit
51aaa57988
|
@ -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,
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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.
|
Loading…
Reference in New Issue