Merge "PowerMax Driver - Create vol suspend fix & DeviceID check" into stable/ussuri

This commit is contained in:
Zuul 2020-07-26 16:08:46 +00:00 committed by Gerrit Code Review
commit f43f156258
5 changed files with 336 additions and 106 deletions

View File

@ -1199,6 +1199,26 @@ class PowerMaxCommonTest(test.TestCase):
self.assertEqual(ref_response,
(volume_dict, rep_update, rep_info_dict))
@mock.patch.object(rest.PowerMaxRest, 'find_volume_device_id',
return_value=tpd.PowerMaxData.device_id2)
@mock.patch.object(
common.PowerMaxCommon, '_create_non_replicated_volume',
return_value=deepcopy(tpd.PowerMaxData.provider_location))
@mock.patch.object(rest.PowerMaxRest, 'get_volume',
return_value=tpd.PowerMaxData.volume_details[0])
def test_create_volume_update_returning_device_id(
self, mck_get, mck_create, mck_find):
volume = self.data.test_volume
volume_name = '1'
volume_size = self.data.test_volume.size
extra_specs = self.data.extra_specs
ref_response = (self.data.provider_location2, dict(), dict())
volume_dict, rep_update, rep_info_dict = (
self.common._create_volume(
volume, volume_name, volume_size, extra_specs))
self.assertEqual(ref_response,
(volume_dict, rep_update, rep_info_dict))
def test_create_volume_success_next_gen(self):
volume = self.data.test_volume
volume_name = '1'
@ -1223,7 +1243,7 @@ class PowerMaxCommonTest(test.TestCase):
@mock.patch.object(provision.PowerMaxProvision, 'create_volume_from_sg',
side_effect=exception.VolumeBackendAPIException(''))
@mock.patch.object(common.PowerMaxCommon,
'_cleanup_volume_create_post_failure')
'_cleanup_non_rdf_volume_create_post_failure')
@mock.patch.object(rest.PowerMaxRest, 'delete_storage_group')
def test_create_volume_failed(self, mck_del, mck_cleanup, mck_create):
volume = self.data.test_volume
@ -1251,41 +1271,111 @@ class PowerMaxCommonTest(test.TestCase):
extra_specs)
mck_del.assert_called_once()
@mock.patch.object(common.PowerMaxCommon, '_delete_from_srp')
@mock.patch.object(common.PowerMaxCommon, 'cleanup_rdf_device_pair')
@mock.patch.object(
rest.PowerMaxRest, 'is_vol_in_rep_session', return_value=('', '', [
{utils.RDF_GROUP_NO: tpd.PowerMaxData.rdf_group_no_1}]))
def test_cleanup_volume_create_post_failure_rdf_enabled(
self, mck_in, mck_clean, mck_del):
@mock.patch.object(rest.PowerMaxRest, 'srdf_resume_replication')
@mock.patch.object(utils.PowerMaxUtils, 'get_default_storage_group_name',
return_value=tpd.PowerMaxData.storagegroup_name_f)
@mock.patch.object(common.PowerMaxCommon, 'prepare_replication_details',
return_value=('', tpd.PowerMaxData.rep_extra_specs,
'', '',))
def test_cleanup_rdf_volume_create_post_failure_sync(
self, mck_prep, mck_sg, mck_resume, mck_sess, mck_clean):
array = self.data.array
volume = self.data.test_volume
volume_name = self.data.test_volume.name
extra_specs = deepcopy(self.data.extra_specs_rep_enabled)
extra_specs[utils.REP_CONFIG] = self.data.rep_config_sync
extra_specs['rep_mode'] = utils.REP_SYNC
devices = [self.data.device_id]
self.common._cleanup_volume_create_post_failure(
self.common._cleanup_rdf_volume_create_post_failure(
volume, volume_name, extra_specs, devices)
mck_in.assert_called_once_with(array, self.data.device_id)
mck_prep.assert_called_once_with(extra_specs)
mck_sg.assert_called_once_with(
extra_specs['srp'], extra_specs['slo'], extra_specs['workload'],
False, True, extra_specs['rep_mode'])
mck_resume.assert_called_once_with(
array, self.data.storagegroup_name_f, self.data.rdf_group_no_1,
self.data.rep_extra_specs)
mck_sess.assert_called_once_with(array, self.data.device_id)
mck_clean.assert_called_once_with(
array, self.data.rdf_group_no_1, self.data.device_id, extra_specs)
@mock.patch.object(common.PowerMaxCommon, 'cleanup_rdf_device_pair')
@mock.patch.object(
rest.PowerMaxRest, 'is_vol_in_rep_session', return_value=('', '', [
{utils.RDF_GROUP_NO: tpd.PowerMaxData.rdf_group_no_1}]))
@mock.patch.object(rest.PowerMaxRest, 'srdf_resume_replication')
@mock.patch.object(utils.PowerMaxUtils, 'get_rdf_management_group_name',
return_value=tpd.PowerMaxData.storagegroup_name_f)
@mock.patch.object(common.PowerMaxCommon, 'prepare_replication_details',
return_value=('', tpd.PowerMaxData.rep_extra_specs,
'', '',))
def test_cleanup_rdf_volume_create_post_failure_non_sync(
self, mck_prep, mck_mgmt, mck_resume, mck_sess, mck_clean):
array = self.data.array
volume = self.data.test_volume
volume_name = self.data.test_volume.name
extra_specs = deepcopy(self.data.extra_specs_rep_enabled)
extra_specs[utils.REP_CONFIG] = self.data.rep_config_async
extra_specs['rep_mode'] = utils.REP_ASYNC
devices = [self.data.device_id]
self.common._cleanup_rdf_volume_create_post_failure(
volume, volume_name, extra_specs, devices)
mck_prep.assert_called_once_with(extra_specs)
mck_mgmt.assert_called_once_with(extra_specs[utils.REP_CONFIG])
mck_resume.assert_called_once_with(
array, self.data.storagegroup_name_f, self.data.rdf_group_no_1,
self.data.rep_extra_specs)
mck_sess.assert_called_once_with(array, self.data.device_id)
mck_clean.assert_called_once_with(
array, self.data.rdf_group_no_1, self.data.device_id, extra_specs)
mck_del.assert_called_once_with(
array, self.data.device_id, volume_name, extra_specs)
@mock.patch.object(common.PowerMaxCommon, '_delete_from_srp')
@mock.patch.object(masking.PowerMaxMasking, 'remove_and_reset_members')
@mock.patch.object(
rest.PowerMaxRest, 'is_vol_in_rep_session', return_value=('', '', ''))
def test_cleanup_volume_create_post_failure_rdf_disabled(
self, mck_in, mck_remove, mck_del):
@mock.patch.object(rest.PowerMaxRest, 'is_vol_in_rep_session',
return_value=('', '', False))
@mock.patch.object(rest.PowerMaxRest, 'srdf_resume_replication')
@mock.patch.object(utils.PowerMaxUtils, 'get_rdf_management_group_name',
return_value=tpd.PowerMaxData.storagegroup_name_f)
@mock.patch.object(common.PowerMaxCommon, 'prepare_replication_details',
return_value=('', tpd.PowerMaxData.rep_extra_specs,
'', '',))
def test_cleanup_rdf_volume_create_post_failure_pre_rdf_establish(
self, mck_prep, mck_mgmt, mck_resume, mck_sess, mck_rem, mck_del):
array = self.data.array
volume = self.data.test_volume
volume_name = self.data.test_volume.name
extra_specs = deepcopy(self.data.extra_specs_rep_enabled)
extra_specs[utils.REP_CONFIG] = self.data.rep_config_sync
extra_specs['rep_mode'] = utils.REP_ASYNC
devices = [self.data.device_id]
self.common._cleanup_rdf_volume_create_post_failure(
volume, volume_name, extra_specs, devices)
mck_prep.assert_called_once_with(extra_specs)
mck_mgmt.assert_called_once_with(extra_specs[utils.REP_CONFIG])
mck_resume.assert_called_once_with(
array, self.data.storagegroup_name_f, self.data.rdf_group_no_1,
self.data.rep_extra_specs)
mck_sess.assert_called_once_with(array, self.data.device_id)
mck_rem.assert_called_once_with(array, volume, self.data.device_id,
volume_name, extra_specs, False)
mck_del.assert_called_once_with(array, self.data.device_id,
volume_name, extra_specs)
@mock.patch.object(common.PowerMaxCommon, '_delete_from_srp')
@mock.patch.object(masking.PowerMaxMasking, 'remove_and_reset_members')
def test_cleanup_non_rdf_volume_create_post_failure(
self, mck_remove, mck_del):
array = self.data.array
volume = self.data.test_volume
volume_name = self.data.test_volume.name
extra_specs = self.data.extra_specs
devices = [self.data.device_id]
self.common._cleanup_volume_create_post_failure(
self.common._cleanup_non_rdf_volume_create_post_failure(
volume, volume_name, extra_specs, devices)
mck_in.assert_called_once_with(array, self.data.device_id)
mck_remove.assert_called_once_with(
array, volume, self.data.device_id, volume_name, extra_specs,
False)

View File

@ -1174,6 +1174,41 @@ class PowerMaxReplicationTest(test.TestCase):
mck_resume.assert_called_once_with(
array, rdf_mgmt_grp, rdf_group_no, rep_extra_specs)
@mock.patch.object(rest.PowerMaxRest, 'srdf_resume_replication')
@mock.patch.object(
rest.PowerMaxRest, 'srdf_remove_device_pair_from_storage_group',
side_effect=exception.CinderException)
@mock.patch.object(
rest.PowerMaxRest, 'get_storage_groups_from_volume',
return_value=[tpd.PowerMaxData.storagegroup_name_f])
@mock.patch.object(
rest.PowerMaxRest, 'get_rdf_pair_volume',
return_value=tpd.PowerMaxData.rdf_group_vol_details)
@mock.patch.object(
common.PowerMaxCommon, '_get_replication_extra_specs',
return_value=tpd.PowerMaxData.rep_extra_specs)
@mock.patch.object(
common.PowerMaxCommon, 'get_rdf_details',
return_value=(tpd.PowerMaxData.rdf_group_no_1,
tpd.PowerMaxData.remote_array))
def test_cleanup_rdf_device_pair_attempt_resume_on_exception(
self, mck_rdf, mck_rep, mck_pair, mck_sg, mck_rem, mck_resume):
array = self.data.array
rdf_group_no = self.data.rdf_group_no_1
device_id = self.data.device_id
extra_specs = deepcopy(self.data.rep_extra_specs)
extra_specs[utils.REP_MODE] = utils.REP_SYNC
extra_specs[utils.REP_CONFIG] = self.data.rep_config_sync
rep_extra_specs = self.common._get_replication_extra_specs(
extra_specs, extra_specs[utils.REP_CONFIG])
self.assertRaises(
exception.CinderException,
self.common.cleanup_rdf_device_pair, array, rdf_group_no,
device_id, extra_specs)
mck_resume.assert_called_once_with(
array, self.data.storagegroup_name_f, rdf_group_no,
rep_extra_specs, False)
@mock.patch.object(
rest.PowerMaxRest, 'get_num_vols_in_sg', return_value=1)
@mock.patch.object(

View File

@ -1996,12 +1996,11 @@ class PowerMaxCommon(object):
def _create_volume(self, volume, volume_name, volume_size, extra_specs):
"""Create a volume.
:param volume_name: the volume
:param volume: the volume
:param volume_name: the volume name
:param volume_size: the volume size
:param extra_specs: extra specifications
:returns: volume_dict, rep_update, rep_info_dict --dict
:raises: VolumeBackendAPIException:
"""
# Set Create Volume options
is_re, rep_mode, storagegroup_name = False, None, None
@ -2044,33 +2043,64 @@ class PowerMaxCommon(object):
extra_specs[utils.WORKLOAD], extra_specs,
do_disable_compression, is_re, rep_mode)
if not is_re:
volume_dict = self._create_non_replicated_volume(
array, volume, volume_name, storagegroup_name,
volume_size, extra_specs)
else:
volume_dict, rep_update, rep_info_dict = (
self._create_replication_enabled_volume(
array, volume, volume_name, volume_size, extra_specs,
storagegroup_name, rep_mode))
# Compare volume ID against identifier on array. Update if needed.
# This can occur in cases where multiple edits are occurring at once.
found_device_id = self.rest.find_volume_device_id(array, volume_name)
returning_device_id = volume_dict['device_id']
if found_device_id != returning_device_id:
volume_dict['device_id'] = found_device_id
return volume_dict, rep_update, rep_info_dict
@coordination.synchronized("emc-nonrdf-vol-{storagegroup_name}-{array}")
def _create_non_replicated_volume(
self, array, volume, volume_name, storagegroup_name, volume_size,
extra_specs):
"""Create a volume without replication enabled
:param array: the primary array -- string
:param volume: the volume -- dict
:param volume_name: the volume name -- string
:param storagegroup_name: the storage group name -- string
:param volume_size: the volume size -- string
:param extra_specs: extra specifications -- dict
:return: volume_dict -- dict
:raises: VolumeBackendAPIException:
"""
existing_devices = self.rest.get_volumes_in_storage_group(
array, storagegroup_name)
try:
if not is_re:
volume_dict = self.provision.create_volume_from_sg(
array, volume_name, storagegroup_name,
volume_size, extra_specs, rep_info=None)
else:
volume_dict, rep_update, rep_info_dict = (
self._create_replication_enabled_volume(
array, volume, volume_name, volume_size, extra_specs,
storagegroup_name, rep_mode))
except Exception:
if storagegroup_name:
volume_dict = self.provision.create_volume_from_sg(
array, volume_name, storagegroup_name,
volume_size, extra_specs, rep_info=None)
return volume_dict
except Exception as e:
try:
# Attempt cleanup of storage group post exception.
updated_devices = set(self.rest.get_volumes_in_storage_group(
array, storagegroup_name))
devices_to_delete = [device for device in updated_devices
if device not in existing_devices]
if devices_to_delete:
self._cleanup_volume_create_post_failure(
self._cleanup_non_rdf_volume_create_post_failure(
volume, volume_name, extra_specs, devices_to_delete)
elif not existing_devices:
self.rest.delete_storage_group(array, storagegroup_name)
raise
return volume_dict, rep_update, rep_info_dict
finally:
# Pass actual exception that was raised now that cleanup
# attempt is finished. Mainly VolumeBackendAPIException raised
# from error status codes returned from the various REST jobs.
raise e
@coordination.synchronized('emc-rdf-vol-{storagegroup_name}-{array}')
def _create_replication_enabled_volume(
@ -2086,6 +2116,7 @@ class PowerMaxCommon(object):
:param storagegroup_name: the storage group name
:param rep_mode: the replication mode
:returns: volume_dict, rep_update, rep_info_dict --dict
:raises: VolumeBackendAPIException:
"""
def _is_first_vol_in_replicated_sg():
vol_dict = dict()
@ -2115,35 +2146,55 @@ class PowerMaxCommon(object):
return first_vol, rep_ex_specs, vol_dict
is_first_volume, rep_extra_specs, volume_info_dict = (
_is_first_vol_in_replicated_sg())
existing_devices = self.rest.get_volumes_in_storage_group(
array, storagegroup_name)
try:
is_first_volume, rep_extra_specs, volume_info_dict = (
_is_first_vol_in_replicated_sg())
if not is_first_volume:
self._validate_rdfg_status(array, extra_specs)
__, rep_extra_specs, rep_info_dict, __ = (
self.prepare_replication_details(extra_specs))
volume_info_dict = self.provision.create_volume_from_sg(
array, volume_name, storagegroup_name,
volume_size, extra_specs, rep_info_dict)
if not is_first_volume:
self._validate_rdfg_status(array, extra_specs)
__, rep_extra_specs, rep_info_dict, __ = (
self.prepare_replication_details(extra_specs))
volume_info_dict = self.provision.create_volume_from_sg(
array, volume_name, storagegroup_name,
volume_size, extra_specs, rep_info_dict)
rep_vol_dict = deepcopy(volume_info_dict)
rep_vol_dict.update({'device_uuid': volume_name,
'storage_group': storagegroup_name,
'size': volume_size})
rep_vol_dict = deepcopy(volume_info_dict)
rep_vol_dict.update({'device_uuid': volume_name,
'storage_group': storagegroup_name,
'size': volume_size})
remote_device_id = self.get_and_set_remote_device_uuid(
extra_specs, rep_extra_specs, rep_vol_dict)
rep_vol_dict.update({'remote_device_id': remote_device_id})
rep_update, rep_info_dict = self.gather_replication_updates(
extra_specs, rep_extra_specs, rep_vol_dict)
remote_device_id = self.get_and_set_remote_device_uuid(
extra_specs, rep_extra_specs, rep_vol_dict)
rep_vol_dict.update({'remote_device_id': remote_device_id})
rep_update, rep_info_dict = self.gather_replication_updates(
extra_specs, rep_extra_specs, rep_vol_dict)
if rep_mode in [utils.REP_ASYNC, utils.REP_METRO]:
self._add_volume_to_rdf_management_group(
array, volume_info_dict['device_id'], volume_name,
rep_extra_specs['array'], remote_device_id,
extra_specs)
if rep_mode in [utils.REP_ASYNC, utils.REP_METRO]:
self._add_volume_to_rdf_management_group(
array, volume_info_dict['device_id'], volume_name,
rep_extra_specs['array'], remote_device_id,
extra_specs)
return volume_info_dict, rep_update, rep_info_dict
return volume_info_dict, rep_update, rep_info_dict
except Exception as e:
try:
# Attempt cleanup of rdfg & storage group post exception
updated_devices = set(self.rest.get_volumes_in_storage_group(
array, storagegroup_name))
devices_to_delete = [device for device in updated_devices
if device not in existing_devices]
if devices_to_delete:
self._cleanup_rdf_volume_create_post_failure(
volume, volume_name, extra_specs, devices_to_delete)
elif not existing_devices:
self.rest.delete_storage_group(array, storagegroup_name)
finally:
# Pass actual exception that was raised now that cleanup
# attempt is finished. Mainly VolumeBackendAPIException raised
# from error status codes returned from the various REST jobs.
raise e
def _set_vmax_extra_specs(self, extra_specs, pool_record):
"""Set the PowerMax/VMAX extra specs.
@ -2386,49 +2437,66 @@ class PowerMaxCommon(object):
self.rest.srdf_suspend_replication(
array, rdf_mgmt_sg, rdf_group_no, rep_extra_specs)
try:
# 3. Check vol doesnt live in any SGs outside OpenStack managed SGs
if rdf_mgmt_sg and rdf_mgmt_sg in vol_sg_list:
vol_sg_list.remove(rdf_mgmt_sg)
if len(vol_sg_list) > 1:
exception_message = (_(
"There is more than one storage group associated with "
"device %(dev)s not including RDF management groups. "
"Please check device is not member of non-OpenStack "
"managed storage groups") % {'dev': device_id})
LOG.error(exception_message)
raise exception.VolumeBackendAPIException(exception_message)
else:
vol_src_sg = vol_sg_list[0]
# 3. Check vol does not live in any SGs outside OpenStack managed SGs
if rdf_mgmt_sg and rdf_mgmt_sg in vol_sg_list:
vol_sg_list.remove(rdf_mgmt_sg)
if len(vol_sg_list) > 1:
exception_message = (_(
"There is more than one storage group associated with device "
"%(dev)s not including RDF management groups. Please check "
"device is not member of non-OpenStack managed storage "
"groups") % {'dev': device_id})
LOG.error(exception_message)
raise exception.VolumeBackendAPIException(exception_message)
else:
vol_src_sg = vol_sg_list[0]
# 4. Remove device from SG and delete RDFG device pair
self.rest.srdf_remove_device_pair_from_storage_group(
array, vol_src_sg, rep_extra_specs['array'], device_id,
rep_extra_specs)
# 5. Remove the volume from any additional SGs
if rdf_mgmt_sg:
self.rest.remove_vol_from_sg(
array, rdf_mgmt_sg, device_id, extra_specs)
self.rest.remove_vol_from_sg(
remote_array, rdf_mgmt_sg, remote_device_id, rep_extra_specs)
# 6. Delete the r2 volume
self.rest.delete_volume(remote_array, remote_device_id)
# 7. Delete the SGs if there are no volumes remaining
self._cleanup_rdf_storage_groups_post_r2_delete(
array, remote_array, vol_src_sg, rdf_mgmt_sg, rdf_mgmt_cleanup)
# 8. Resume replication if RDFG still contains volumes
if resume_replication:
self.rest.srdf_resume_replication(
array, rdf_mgmt_sg, rep_extra_specs['rdf_group_no'],
# 4. Remove device from SG and delete RDFG device pair
self.rest.srdf_remove_device_pair_from_storage_group(
array, vol_src_sg, rep_extra_specs['array'], device_id,
rep_extra_specs)
LOG.info('Remote device %(dev)s deleted from RDF Group %(grp)s',
{'dev': remote_device_id,
'grp': rep_extra_specs['rdf_group_label']})
# 5. Remove the volume from any additional SGs
if rdf_mgmt_sg:
self.rest.remove_vol_from_sg(
array, rdf_mgmt_sg, device_id, extra_specs)
self.rest.remove_vol_from_sg(
remote_array, rdf_mgmt_sg, remote_device_id,
rep_extra_specs)
# 6. Delete the r2 volume
self.rest.delete_volume(remote_array, remote_device_id)
# 7. Delete the SGs if there are no volumes remaining
self._cleanup_rdf_storage_groups_post_r2_delete(
array, remote_array, vol_src_sg, rdf_mgmt_sg, rdf_mgmt_cleanup)
# 8. Resume replication if RDFG still contains volumes
if resume_replication:
self.rest.srdf_resume_replication(
array, rdf_mgmt_sg, rep_extra_specs['rdf_group_no'],
rep_extra_specs)
LOG.info('Remote device %(dev)s deleted from RDF Group %(grp)s',
{'dev': remote_device_id,
'grp': rep_extra_specs['rdf_group_label']})
except Exception as e:
# Attempt to resume SRDF groups after exception to avoid leaving
# them in a suspended state.
try:
if rdf_mgmt_sg:
self.rest.srdf_resume_replication(
array, rdf_mgmt_sg, rdf_group_no, rep_extra_specs,
False)
elif len(vol_sg_list) == 1:
self.rest.srdf_resume_replication(
array, vol_sg_list[0], rdf_group_no, rep_extra_specs,
False)
except Exception:
LOG.debug('Could not resume SRDF group after exception '
'during cleanup_rdf_device_pair.')
raise e
def _cleanup_rdf_storage_groups_post_r2_delete(
self, array, remote_array, sg_name, rdf_mgmt_sg, rdf_mgmt_cleanup):
@ -6092,9 +6160,9 @@ class PowerMaxCommon(object):
return replication_update, rep_info_dict
def _cleanup_volume_create_post_failure(
def _cleanup_non_rdf_volume_create_post_failure(
self, volume, volume_name, extra_specs, device_ids):
"""Delete lingering volumes that exist in an SG post exception.
"""Delete lingering volumes that exist in an non-RDF SG post exception.
:param volume: Cinder volume -- Volume
:param volume_name: Volume name -- str
@ -6103,17 +6171,52 @@ class PowerMaxCommon(object):
"""
array = extra_specs[utils.ARRAY]
for device_id in device_ids:
__, __, rdf_group = self.rest.is_vol_in_rep_session(
self.masking.remove_and_reset_members(
array, volume, device_id, volume_name, extra_specs, False)
self._delete_from_srp(
array, device_id, volume_name, extra_specs)
def _cleanup_rdf_volume_create_post_failure(
self, volume, volume_name, extra_specs, device_ids):
"""Delete lingering volumes that exist in an RDF SG post exception.
:param volume: Cinder volume -- Volume
:param volume_name: Volume name -- str
:param extra_specs: Volume extra specs -- dict
:param device_ids: Devices ids to be deleted -- list
"""
__, rep_extra_specs, __, __ = self.prepare_replication_details(
extra_specs)
array = extra_specs[utils.ARRAY]
srp = extra_specs['srp']
slo = extra_specs['slo']
workload = extra_specs['workload']
do_disable_compression = self.utils.is_compression_disabled(
extra_specs)
rep_mode = extra_specs['rep_mode']
rdf_group = rep_extra_specs['rdf_group_no']
rep_config = extra_specs[utils.REP_CONFIG]
if rep_mode is utils.REP_SYNC:
storagegroup_name = self.utils.get_default_storage_group_name(
srp, slo, workload, do_disable_compression, True, rep_mode)
else:
storagegroup_name = self.utils.get_rdf_management_group_name(
rep_config)
self.rest.srdf_resume_replication(
array, storagegroup_name, rdf_group, rep_extra_specs)
for device_id in device_ids:
__, __, vol_is_rdf = self.rest.is_vol_in_rep_session(
array, device_id)
if rdf_group:
rdf_group_no = rdf_group[0][utils.RDF_GROUP_NO]
self.cleanup_rdf_device_pair(array, rdf_group_no, device_id,
if vol_is_rdf:
self.cleanup_rdf_device_pair(array, rdf_group, device_id,
extra_specs)
else:
self.masking.remove_and_reset_members(
array, volume, device_id, volume_name, extra_specs, False)
self._delete_from_srp(
array, device_id, volume_name, extra_specs)
self._delete_from_srp(
array, device_id, volume_name, extra_specs)
def _validate_rdfg_status(self, array, extra_specs):
"""Validate RDF group states before and after various operations

View File

@ -126,9 +126,10 @@ class PowerMaxFCDriver(san.SanDriver, driver.FibreChannelDriver):
4.2.2 - U4P failover lock not released on exception (#1875640)
4.2.3 - Live migrate remove rep vol from sg (bug #1875432)
4.2.4 - Rep validation & retype suspension fix (bug #1875433)
4.2.5 - Create vol suspend fix & DeviceID check (bug #1877976)
"""
VERSION = "4.2.4"
VERSION = "4.2.5"
# ThirdPartySystems wiki
CI_WIKI_NAME = "EMC_VMAX_CI"

View File

@ -131,9 +131,10 @@ class PowerMaxISCSIDriver(san.SanISCSIDriver):
4.2.2 - U4P failover lock not released on exception (#1875640)
4.2.3 - Live migrate remove rep vol from sg (bug #1875432)
4.2.4 - Rep validation & retype suspension fix (bug #1875433)
4.2.5 - Create vol suspend fix & DeviceID check (bug #1877976)
"""
VERSION = "4.2.4"
VERSION = "4.2.5"
# ThirdPartySystems wiki
CI_WIKI_NAME = "EMC_VMAX_CI"