Merge "PowerMax driver - performance improvements"

This commit is contained in:
Zuul 2019-03-16 03:44:37 +00:00 committed by Gerrit Code Review
commit 023a022e20
9 changed files with 158 additions and 78 deletions

View File

@ -291,6 +291,8 @@ class PowerMaxData(object):
rep_extra_specs3['workload'] = workload
rep_extra_specs4 = deepcopy(rep_extra_specs3)
rep_extra_specs4['rdf_group_label'] = rdf_group_name
rep_extra_specs5 = deepcopy(rep_extra_specs2)
rep_extra_specs5['target_array_model'] = 'VMAX250F'
test_volume_type_1 = volume_type.VolumeType(
id='2b06255d-f5f0-4520-a953-b029196add6a', name='abc',
@ -744,7 +746,7 @@ class PowerMaxData(object):
'model': 'VMAX250F',
'ucode': '5977.1091.1092'},
{'symmetrixId': array_herc,
'model': 'VMAXHERC',
'model': 'PowerMax 2000',
'ucode': '5978.1091.1092'}]
version_details = {'version': 'V9.0.0.1'}

View File

@ -69,8 +69,8 @@ class PowerMaxCommonTest(test.TestCase):
None, 'config_group', None, None)
fc.PowerMaxFCDriver(configuration=configuration)
@mock.patch.object(rest.PowerMaxRest, 'is_next_gen_array',
return_value=True)
@mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
return_value=('PowerMax 2000', True))
@mock.patch.object(rest.PowerMaxRest, 'set_rest_credentials')
@mock.patch.object(common.PowerMaxCommon, '_get_slo_workload_combinations',
return_value=[])
@ -80,7 +80,7 @@ class PowerMaxCommonTest(test.TestCase):
def test_gather_info_next_gen(self, mock_parse, mock_combo, mock_rest,
mock_nextgen):
self.common._gather_info()
self.assertTrue(self.common.nextGen)
self.assertTrue(self.common.next_gen)
def test_get_slo_workload_combinations_powermax(self):
array_info = self.common.get_attributes_from_cinder_config()
@ -110,7 +110,8 @@ class PowerMaxCommonTest(test.TestCase):
return_value=tpd.PowerMaxData.powermax_slo_details['sloId'])
def test_get_slo_workload_combinations_next_gen(self, mck_slo, mck_wl,
mck_model):
self.common.nextGen = True
self.common.next_gen = True
self.common.array_model = 'PowerMax 2000'
finalarrayinfolist = self.common._get_slo_workload_combinations(
self.data.array_info_no_wl)
self.assertTrue(len(finalarrayinfolist) == 14)
@ -125,7 +126,7 @@ class PowerMaxCommonTest(test.TestCase):
return_value=tpd.PowerMaxData.powermax_slo_details['sloId'])
def test_get_slo_workload_combinations_next_gen_vmax(
self, mck_slo, mck_wl, mck_model):
self.common.nextGen = True
self.common.next_gen = True
finalarrayinfolist = self.common._get_slo_workload_combinations(
self.data.array_info_no_wl)
self.assertTrue(len(finalarrayinfolist) == 18)
@ -641,7 +642,7 @@ class PowerMaxCommonTest(test.TestCase):
extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
extra_specs[utils.WORKLOAD] = self.data.workload
ref_mv_dict = self.data.masking_view_dict
self.common.nextGen = False
self.common.next_gen = False
masking_view_dict = self.common._populate_masking_dict(
volume, connector, extra_specs)
self.assertEqual(ref_mv_dict, masking_view_dict)
@ -686,7 +687,7 @@ class PowerMaxCommonTest(test.TestCase):
connector = self.data.connector
extra_specs = deepcopy(self.data.extra_specs)
extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
self.common.nextGen = True
self.common.next_gen = True
masking_view_dict = self.common._populate_masking_dict(
volume, connector, extra_specs)
self.assertEqual('NONE', masking_view_dict[utils.WORKLOAD])
@ -822,11 +823,12 @@ class PowerMaxCommonTest(test.TestCase):
volume_name = '1'
volume_size = self.data.test_volume.size
extra_specs = self.data.extra_specs
self.common.nextGen = True
self.common.next_gen = True
with mock.patch.object(
self.utils, 'is_compression_disabled', return_value=True):
with mock.patch.object(
self.rest, 'is_next_gen_array', return_value=True):
self.rest, 'get_array_model_info',
return_value=('PowerMax 2000', True)):
with mock.patch.object(
self.masking,
'get_or_create_default_storage_group') as mock_get:
@ -947,7 +949,7 @@ class PowerMaxCommonTest(test.TestCase):
def test_set_vmax_extra_specs_next_gen(self):
srp_record = self.common.get_attributes_from_cinder_config()
self.common.nextGen = True
self.common.next_gen = True
extra_specs = self.common._set_vmax_extra_specs(
self.data.vol_type_extra_specs, srp_record)
ref_extra_specs = deepcopy(self.data.extra_specs_intervals_set)

View File

@ -247,7 +247,7 @@ class PowerMaxVolumeMetadataDebugTest(test.TestCase):
rest.PowerMaxRest, 'get_unisphere_version',
return_value={'version': tpd.PowerMaxData.unisphere_version})
@mock.patch.object(
rest.PowerMaxRest, 'get_array_serial',
rest.PowerMaxRest, 'get_array_detail',
return_value={'ucode': tpd.PowerMaxData.vmax_firmware_version,
'model': tpd.PowerMaxData.vmax_model})
def test_gather_version_info(

View File

@ -220,7 +220,7 @@ class PowerMaxReplicationTest(test.TestCase):
@mock.patch.object(common.PowerMaxCommon, '_remove_members')
@mock.patch.object(
common.PowerMaxCommon, '_get_replication_extra_specs',
return_value=tpd.PowerMaxData.rep_extra_specs)
return_value=tpd.PowerMaxData.rep_extra_specs2)
@mock.patch.object(
utils.PowerMaxUtils, 'is_volume_failed_over', return_value=True)
def test_unmap_lun_volume_failed_over(self, mock_fo, mock_es, mock_rm):
@ -260,7 +260,9 @@ class PowerMaxReplicationTest(test.TestCase):
@mock.patch.object(utils.PowerMaxUtils, 'is_metro_device',
return_value=True)
def test_initialize_connection_vol_metro(self, mock_md):
@mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
return_value=('VMAX250F', False))
def test_initialize_connection_vol_metro(self, mock_model, mock_md):
metro_connector = deepcopy(self.data.connector)
metro_connector['multipath'] = True
info_dict = self.common.initialize_connection(
@ -324,8 +326,10 @@ class PowerMaxReplicationTest(test.TestCase):
return_value=(False, False, None))
@mock.patch.object(common.PowerMaxCommon, 'extend_volume_is_replicated')
@mock.patch.object(common.PowerMaxCommon, '_sync_check')
def test_extend_volume_rep_enabled(self, mock_sync, mock_ex_re,
mock_is_re):
@mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
return_value=('VMAX250F', False))
def test_extend_volume_rep_enabled(self, mock_model, mock_sync,
mock_ex_re, mock_is_re):
extra_specs = deepcopy(self.extra_specs)
extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
volume_name = self.data.test_volume.name
@ -351,7 +355,9 @@ class PowerMaxReplicationTest(test.TestCase):
@mock.patch.object(common.PowerMaxCommon,
'_replicate_volume',
return_value=({}, {}))
def test_manage_existing_is_replicated(self, mock_rep):
@mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
return_value=('VMAX250F', False))
def test_manage_existing_is_replicated(self, mock_model, mock_rep):
extra_specs = deepcopy(self.extra_specs)
extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
external_ref = {u'source-name': u'00002'}
@ -368,7 +374,9 @@ class PowerMaxReplicationTest(test.TestCase):
extra_specs, delete_src=False)
@mock.patch.object(masking.PowerMaxMasking, 'remove_and_reset_members')
def test_setup_volume_replication(self, mock_rm):
@mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
return_value=('VMAX250F', False))
def test_setup_volume_replication(self, mock_model, mock_rm):
rep_status, rep_data, __ = self.common.setup_volume_replication(
self.data.array, self.data.test_volume, self.data.device_id,
self.extra_specs)
@ -378,7 +386,10 @@ class PowerMaxReplicationTest(test.TestCase):
@mock.patch.object(masking.PowerMaxMasking, 'remove_and_reset_members')
@mock.patch.object(common.PowerMaxCommon, '_create_volume')
def test_setup_volume_replication_target(self, mock_create, mock_rm):
@mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
return_value=('VMAX250F', False))
def test_setup_volume_replication_target(
self, mock_model, mock_create, mock_rm):
rep_status, rep_data, __ = self.common.setup_volume_replication(
self.data.array, self.data.test_volume, self.data.device_id,
self.extra_specs, self.data.device_id2)
@ -393,7 +404,7 @@ class PowerMaxReplicationTest(test.TestCase):
@mock.patch.object(rest.PowerMaxRest, 'get_size_of_device_on_array',
return_value=2)
@mock.patch.object(common.PowerMaxCommon, '_get_replication_extra_specs',
return_value=tpd.PowerMaxData.rep_extra_specs)
return_value=tpd.PowerMaxData.rep_extra_specs5)
@mock.patch.object(common.PowerMaxCommon, '_create_volume',
return_value=tpd.PowerMaxData.provider_location)
@mock.patch.object(common.PowerMaxCommon, '_sync_check')
@ -414,10 +425,13 @@ class PowerMaxReplicationTest(test.TestCase):
self.assertEqual('enabled', rep_status)
self.assertEqual(self.data.rdf_group_details, rep_data)
@mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
return_value=('VMAX250F', False))
@mock.patch.object(common.PowerMaxCommon, '_cleanup_remote_target')
def test_cleanup_lun_replication_success(self, mock_clean):
def test_cleanup_lun_replication_success(self, mock_clean, mock_model):
rep_extra_specs = deepcopy(self.data.rep_extra_specs)
rep_extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
rep_extra_specs['target_array_model'] = 'VMAX250F'
self.common.cleanup_lun_replication(
self.data.test_volume, '1', self.data.device_id,
self.extra_specs)
@ -436,8 +450,10 @@ class PowerMaxReplicationTest(test.TestCase):
self.data.device_id2, self.data.rdf_group_no, '1',
rep_extra_specs)
@mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
return_value=('VMAX250F', False))
@mock.patch.object(common.PowerMaxCommon, '_cleanup_remote_target')
def test_cleanup_lun_replication_no_target(self, mock_clean):
def test_cleanup_lun_replication_no_target(self, mock_clean, mock_model):
with mock.patch.object(self.common, 'get_remote_target_device',
return_value=(None, '', '', '', '')):
self.common.cleanup_lun_replication(
@ -591,12 +607,14 @@ class PowerMaxReplicationTest(test.TestCase):
self.data.device_id))
self.assertIsNone(target_device4)
@mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
return_value=('PowerMax 2000', True))
@mock.patch.object(common.PowerMaxCommon, 'setup_volume_replication')
@mock.patch.object(provision.PowerMaxProvision, 'extend_volume')
@mock.patch.object(provision.PowerMaxProvision, 'break_rdf_relationship')
@mock.patch.object(masking.PowerMaxMasking, 'remove_and_reset_members')
def test_extend_volume_is_replicated(self, mock_remove,
mock_break, mock_extend, mock_setup):
def test_extend_volume_is_replicated(self, mock_remove, mock_break,
mock_extend, mock_setup, mock_model):
self.common.extend_volume_is_replicated(
self.data.array, self.data.test_volume, self.data.device_id,
'vol1', '5', self.data.extra_specs_rep_enabled)
@ -626,10 +644,12 @@ class PowerMaxReplicationTest(test.TestCase):
self.data.device_id, 'vol1', '1',
self.data.extra_specs_rep_enabled)
@mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
return_value=('VMAX250F', False))
@mock.patch.object(common.PowerMaxCommon,
'add_volume_to_replication_group')
@mock.patch.object(masking.PowerMaxMasking, 'remove_and_reset_members')
def test_enable_rdf(self, mock_remove, mock_add):
def test_enable_rdf(self, mock_remove, mock_add, mock_model):
rep_config = self.utils.get_replication_config(
[self.replication_device])
self.common.enable_rdf(
@ -639,10 +659,12 @@ class PowerMaxReplicationTest(test.TestCase):
self.assertEqual(2, mock_remove.call_count)
self.assertEqual(2, mock_add.call_count)
@mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
return_value=('VMAX250F', False))
@mock.patch.object(masking.PowerMaxMasking,
'remove_vol_from_storage_group')
@mock.patch.object(common.PowerMaxCommon, '_cleanup_remote_target')
def test_enable_rdf_exception(self, mock_cleanup, mock_rm):
def test_enable_rdf_exception(self, mock_cleanup, mock_rm, mock_model):
rep_config = self.utils.get_replication_config(
[self.replication_device])
self.assertRaises(
@ -668,25 +690,31 @@ class PowerMaxReplicationTest(test.TestCase):
self.data.array, self.data.device_id, 'vol1',
self.extra_specs)
def test_get_replication_extra_specs(self):
@mock.patch.object(rest.PowerMaxRest,
'get_array_model_info',
return_value=('VMAX250F', False))
def test_get_replication_extra_specs(self, mock_model):
rep_config = self.utils.get_replication_config(
[self.replication_device])
# Path one - disable compression
extra_specs1 = deepcopy(self.extra_specs)
extra_specs1[utils.DISABLECOMPRESSION] = 'true'
ref_specs1 = deepcopy(self.data.rep_extra_specs2)
ref_specs1 = deepcopy(self.data.rep_extra_specs5)
rep_extra_specs1 = self.common._get_replication_extra_specs(
extra_specs1, rep_config)
self.assertEqual(ref_specs1, rep_extra_specs1)
# Path two - disable compression, not all flash
ref_specs2 = deepcopy(self.data.rep_extra_specs2)
ref_specs2 = deepcopy(self.data.rep_extra_specs5)
with mock.patch.object(self.rest, 'is_compression_capable',
return_value=False):
rep_extra_specs2 = self.common._get_replication_extra_specs(
extra_specs1, rep_config)
self.assertEqual(ref_specs2, rep_extra_specs2)
def test_get_replication_extra_specs_powermax(self):
@mock.patch.object(rest.PowerMaxRest,
'get_array_model_info',
return_value=('PowerMax 2000', True))
def test_get_replication_extra_specs_powermax(self, mock_model):
rep_config = self.utils.get_replication_config(
[self.replication_device])
rep_specs = deepcopy(self.data.rep_extra_specs2)
@ -695,6 +723,7 @@ class PowerMaxReplicationTest(test.TestCase):
# SLO not valid, both SLO and Workload set to NONE
rep_specs['slo'] = None
rep_specs['workload'] = None
rep_specs['target_array_model'] = 'PowerMax 2000'
with mock.patch.object(self.provision, 'verify_slo_workload',
return_value=(False, False)):
rep_extra_specs = self.common._get_replication_extra_specs(
@ -703,6 +732,7 @@ class PowerMaxReplicationTest(test.TestCase):
# SL valid, workload invalid, only workload set to NONE
rep_specs['slo'] = 'Diamond'
rep_specs['workload'] = None
rep_specs['target_array_model'] = 'PowerMax 2000'
with mock.patch.object(self.provision, 'verify_slo_workload',
return_value=(True, False)):
rep_extra_specs = self.common._get_replication_extra_specs(
@ -905,10 +935,13 @@ class PowerMaxReplicationTest(test.TestCase):
self.data.failed_resource, self.data.device_id, 'name',
self.data.remote_array, self.data.device_id2, extra_specs)
@mock.patch.object(rest.PowerMaxRest, 'get_array_model_info',
return_value=('VMAX250F', False))
@mock.patch.object(common.PowerMaxCommon,
'_add_volume_to_async_rdf_managed_grp')
@mock.patch.object(masking.PowerMaxMasking, 'remove_and_reset_members')
def test_setup_volume_replication_async(self, mock_rm, mock_add):
def test_setup_volume_replication_async(
self, mock_rm, mock_add, mock_model):
extra_specs = deepcopy(self.extra_specs)
extra_specs['rep_mode'] = utils.REP_ASYNC
rep_status, rep_data, __ = (

View File

@ -217,13 +217,13 @@ class PowerMaxRestTest(test.TestCase):
self.rest.modify_resource, array, category,
resource_type, resource_name)
def test_get_array_serial(self):
def test_get_array_detail(self):
ref_details = self.data.symmetrix[0]
array_details = self.rest.get_array_serial(self.data.array)
array_details = self.rest.get_array_detail(self.data.array)
self.assertEqual(ref_details, array_details)
def test_get_array_serial_failed(self):
array_details = self.rest.get_array_serial(self.data.failed_resource)
def test_get_array_detail_failed(self):
array_details = self.rest.get_array_detail(self.data.failed_resource)
self.assertIsNone(array_details)
def test_get_uni_version(self):
@ -241,32 +241,32 @@ class PowerMaxRestTest(test.TestCase):
def test_get_slo_list_powermax(self):
ref_settings = self.data.powermax_slo_details['sloId']
slo_settings = self.rest.get_slo_list(self.data.array)
slo_settings = self.rest.get_slo_list(
self.data.array, True, 'PowerMax 2000')
self.assertEqual(ref_settings, slo_settings)
def test_get_slo_list_vmax(self):
ref_settings = ['Diamond']
with mock.patch.object(self.rest, 'get_resource',
return_value=self.data.vmax_slo_details):
slo_settings = self.rest.get_slo_list(self.data.array)
slo_settings = self.rest.get_slo_list(
self.data.array, False, 'VMAX250F')
self.assertEqual(ref_settings, slo_settings)
def test_get_workload_settings(self):
ref_settings = self.data.workloadtype['workloadId']
wl_settings = self.rest.get_workload_settings(
self.data.array)
self.data.array, False)
self.assertEqual(ref_settings, wl_settings)
def test_get_workload_settings_next_gen(self):
with mock.patch.object(self.rest, 'is_next_gen_array',
return_value=True):
wl_settings = self.rest.get_workload_settings(
self.data.array_herc)
self.assertEqual(['None'], wl_settings)
wl_settings = self.rest.get_workload_settings(
self.data.array_herc, True)
self.assertEqual(['None'], wl_settings)
def test_get_workload_settings_failed(self):
wl_settings = self.rest.get_workload_settings(
self.data.failed_resource)
self.data.failed_resource, False)
self.assertEqual([], wl_settings)
def test_is_compression_capable_true(self):
@ -1479,6 +1479,16 @@ class PowerMaxRestTest(test.TestCase):
is_next_gen2 = self.rest.is_next_gen_array(self.data.array_herc)
self.assertTrue(is_next_gen2)
def test_get_array_model_info(self):
array_model_vmax, is_next_gen = self.rest.get_array_model_info(
self.data.array)
self.assertEqual('VMAX250F', array_model_vmax)
self.assertFalse(is_next_gen)
array_model_powermax, is_next_gen2 = self.rest.get_array_model_info(
self.data.array_herc)
self.assertTrue(is_next_gen2)
self.assertEqual('PowerMax 2000', array_model_powermax)
@mock.patch('oslo_service.loopingcall.FixedIntervalLoopingCall',
new=test_utils.ZeroIntervalLoopingCall)
@mock.patch.object(rest.PowerMaxRest, 'are_vols_rdf_paired',

View File

@ -184,7 +184,7 @@ class PowerMaxCommon(object):
self.failover = False
self._get_replication_info()
self._get_u4p_failover_info()
self.nextGen = False
self.next_gen = False
self._gather_info()
self.version_dict = {}
@ -199,7 +199,7 @@ class PowerMaxCommon(object):
"longer supported.")
self.rest.set_rest_credentials(array_info)
if array_info:
self.nextGen = self.rest.is_next_gen_array(
self.array_model, self.next_gen = self.rest.get_array_model_info(
array_info['SerialNumber'])
finalarrayinfolist = self._get_slo_workload_combinations(
array_info)
@ -351,10 +351,12 @@ class PowerMaxCommon(object):
if self.failover:
array = self.active_backend_id
slo_settings = self.rest.get_slo_list(array)
slo_settings = self.rest.get_slo_list(
array, self.next_gen, self.array_model)
slo_list = [x for x in slo_settings
if x.lower() not in ['none', 'optimized']]
workload_settings = self.rest.get_workload_settings(array)
workload_settings = self.rest.get_workload_settings(
array, self.next_gen)
workload_settings.append('None')
slo_workload_set = set(
['%(slo)s:%(workload)s' % {'slo': slo,
@ -362,7 +364,7 @@ class PowerMaxCommon(object):
for slo in slo_list for workload in workload_settings])
slo_workload_set.add('None:None')
if self.nextGen:
if self.next_gen:
LOG.warning("Workloads have been deprecated for arrays "
"running PowerMax OS uCode level 5978 or higher. "
"Any supplied workloads will be treated as None "
@ -375,7 +377,7 @@ class PowerMaxCommon(object):
slo_workload_set.add('Optimized:None')
# If array is 5978 or greater and a VMAX AFA add legacy SL/WL
# combinations
if any(self.rest.get_vmax_model(array) in x for x in
if any(self.array_model in x for x in
utils.VMAX_AFA_MODELS):
slo_workload_set.add('Diamond:OLTP')
slo_workload_set.add('Diamond:OLTP_REP')
@ -383,7 +385,7 @@ class PowerMaxCommon(object):
slo_workload_set.add('Diamond:DSS_REP')
slo_workload_set.add('Diamond:None')
if not any(self.rest.get_vmax_model(array) in x for x in
if not any(self.array_model in x for x in
utils.VMAX_AFA_MODELS):
slo_workload_set.add('Optimized:None')
@ -1450,7 +1452,7 @@ class PowerMaxCommon(object):
protocol = self.utils.get_short_protocol_type(self.protocol)
short_host_name = self.utils.get_host_short_name(connector['host'])
masking_view_dict[utils.SLO] = extra_specs[utils.SLO]
masking_view_dict[utils.WORKLOAD] = 'NONE' if self.nextGen else (
masking_view_dict[utils.WORKLOAD] = 'NONE' if self.next_gen else (
extra_specs[utils.WORKLOAD])
masking_view_dict[utils.ARRAY] = extra_specs[utils.ARRAY]
masking_view_dict[utils.SRP] = extra_specs[utils.SRP]
@ -1666,12 +1668,12 @@ class PowerMaxCommon(object):
:raises: VolumeBackendAPIException:
"""
array = extra_specs[utils.ARRAY]
next_gen = self.rest.is_next_gen_array(array)
array_model, next_gen = self.rest.get_array_model_info(array)
if next_gen:
extra_specs[utils.WORKLOAD] = 'NONE'
is_valid_slo, is_valid_workload = self.provision.verify_slo_workload(
array, extra_specs[utils.SLO],
extra_specs[utils.WORKLOAD], extra_specs[utils.SRP])
extra_specs[utils.WORKLOAD], next_gen, array_model)
if not is_valid_slo or not is_valid_workload:
exception_message = (_(
"Either SLO: %(slo)s or workload %(workload)s is invalid. "
@ -1769,14 +1771,14 @@ class PowerMaxCommon(object):
workload_from_extra_spec = pool_details[1]
# Check if legacy pool chosen
if (workload_from_extra_spec == pool_record['srpName'] or
self.nextGen):
self.next_gen):
workload_from_extra_spec = 'NONE'
elif pool_record.get('ServiceLevel'):
slo_from_extra_spec = pool_record['ServiceLevel']
workload_from_extra_spec = pool_record.get('Workload', 'None')
# If workload is None in cinder.conf, convert to string
if not workload_from_extra_spec or self.nextGen:
if not workload_from_extra_spec or self.next_gen:
workload_from_extra_spec = 'NONE'
LOG.info("Pool_name is not present in the extra_specs "
"- using slo/ workload from cinder.conf: %(slo)s/%(wl)s.",
@ -1784,7 +1786,8 @@ class PowerMaxCommon(object):
'wl': workload_from_extra_spec})
else:
slo_list = self.rest.get_slo_list(pool_record['SerialNumber'])
slo_list = self.rest.get_slo_list(
pool_record['SerialNumber'], self.next_gen, self.array_model)
if 'Optimized' in slo_list:
slo_from_extra_spec = 'Optimized'
elif 'Diamond' in slo_list:
@ -3428,7 +3431,8 @@ class PowerMaxCommon(object):
target_device_id=target_device_id,
replication_status=replication_status,
rep_mode=rep_extra_specs['rep_mode'],
rdf_group_label=self.rep_config['rdf_group_label'])
rdf_group_label=self.rep_config['rdf_group_label'],
target_array_model=rep_extra_specs['target_array_model'])
return replication_status, replication_driver_data, rep_info_dict
@ -4084,12 +4088,14 @@ class PowerMaxCommon(object):
# Check to see if SLO and Workload are configured on the target array.
if extra_specs[utils.SLO]:
rep_extra_specs['target_array_model'], next_gen = (
self.rest.get_array_model_info(rep_config['array']))
is_valid_slo, is_valid_workload = (
self.provision.verify_slo_workload(
rep_extra_specs[utils.ARRAY],
extra_specs[utils.SLO],
rep_extra_specs[utils.WORKLOAD],
rep_extra_specs[utils.SRP]))
rep_extra_specs[utils.WORKLOAD], next_gen,
rep_extra_specs['target_array_model']))
if not is_valid_slo:
LOG.warning("The target array does not support the "
"storage pool setting for SLO %(slo)s, "
@ -4102,7 +4108,6 @@ class PowerMaxCommon(object):
"%(workload)s, setting to NONE.",
{'workload': extra_specs[utils.WORKLOAD]})
rep_extra_specs[utils.WORKLOAD] = None
return rep_extra_specs
@staticmethod

View File

@ -131,7 +131,7 @@ class PowerMaxVolumeMetadata(object):
self.version_dict['unisphere_for_powermax_version'] = (
u4p_version_dict['version'])
self.version_dict['serial_number'] = serial_number
array_info_dict = self.rest.get_array_serial(serial_number)
array_info_dict = self.rest.get_array_detail(serial_number)
self.version_dict['storage_firmware_version'] = (
array_info_dict['ucode'])
self.version_dict['storage_model'] = array_info_dict['model']
@ -465,6 +465,7 @@ class PowerMaxVolumeMetadata(object):
None, None, None, None)
rep_mode, replication_status, rdf_group_label, use_bias = (
None, None, None, None)
target_array_model = None
if rep_info_dict:
rdf_group_no = rep_info_dict['rdf_group_no']
target_name = rep_info_dict['target_name']
@ -475,6 +476,7 @@ class PowerMaxVolumeMetadata(object):
rdf_group_label = rep_info_dict['rdf_group_label']
if utils.METROBIAS in extra_specs:
use_bias = extra_specs[utils.METROBIAS]
target_array_model = rep_info_dict['target_array_model']
default_sg = self.utils.derive_default_sg_from_extra_specs(
extra_specs, rep_mode)
@ -500,7 +502,8 @@ class PowerMaxVolumeMetadata(object):
'yes' if self.utils.is_compression_disabled(
extra_specs) else 'no'),
source_device_id=source_device_id,
temporary_snapvx=temporary_snapvx
temporary_snapvx=temporary_snapvx,
target_array_model=target_array_model
)
volume_metadata = self.update_volume_info_metadata(

View File

@ -452,13 +452,15 @@ class PowerMaxProvision(object):
return (total_capacity_gb, remaining_capacity_gb,
subscribed_capacity_gb, array_reserve_percent)
def verify_slo_workload(self, array, slo, workload, srp):
def verify_slo_workload(
self, array, slo, workload, is_next_gen=None, array_model=None):
"""Check if SLO and workload values are valid.
:param array: the array serial number
:param slo: Service Level Object e.g bronze
:param workload: workload e.g DSS
:param srp: the storage resource pool name
:param is_next_gen: can be None
:returns: boolean
"""
is_valid_slo, is_valid_workload = False, False
@ -472,8 +474,12 @@ class PowerMaxProvision(object):
if slo and slo.lower() == 'none':
slo = None
valid_slos = self.rest.get_slo_list(array)
valid_workloads = self.rest.get_workload_settings(array)
if is_next_gen or is_next_gen is None:
array_model, is_next_gen = self.rest.get_array_model_info(
array)
valid_slos = self.rest.get_slo_list(array, is_next_gen, array_model)
valid_workloads = self.rest.get_workload_settings(array, is_next_gen)
for valid_slo in valid_slos:
if slo == valid_slo:
is_valid_slo = True

View File

@ -539,7 +539,7 @@ class PowerMaxRest(object):
operation = 'delete %(res)s resource' % {'res': resource_type}
self.check_status_code_success(operation, status_code, message)
def get_array_serial(self, array):
def get_array_detail(self, array):
"""Get an array from its serial number.
:param array: the array serial number
@ -559,7 +559,7 @@ class PowerMaxRest(object):
:returns: bool
"""
is_next_gen = False
array_details = self.get_array_serial(array)
array_details = self.get_array_detail(array)
if array_details:
ucode_version = array_details['ucode'].split('.')[0]
if ucode_version >= UCODE_5978:
@ -603,17 +603,19 @@ class PowerMaxRest(object):
resource_name=srp, params=None)
return srp_details
def get_slo_list(self, array):
def get_slo_list(self, array, is_next_gen, array_model):
"""Retrieve the list of slo's from the array
:param array: the array serial number
:param is_next_gen: next generation flag
:param array_model
:returns: slo_list -- list of service level names
"""
slo_list = []
slo_dict = self.get_resource(array, SLOPROVISIONING, 'slo')
if slo_dict and slo_dict.get('sloId'):
if not self.is_next_gen_array(array) and (
any(self.get_vmax_model(array) in x for x in
if not is_next_gen and (
any(array_model in x for x in
utils.VMAX_AFA_MODELS)):
if 'Optimized' in slo_dict.get('sloId'):
slo_dict['sloId'].remove('Optimized')
@ -622,15 +624,16 @@ class PowerMaxRest(object):
slo_list.append(slo)
return slo_list
def get_workload_settings(self, array):
def get_workload_settings(self, array, is_next_gen):
"""Get valid workload options from array.
Workloads are no longer supported from HyperMaxOS 5978 onwards.
:param array: the array serial number
:param is_next_gen: is next generation flag
:returns: workload_setting -- list of workload names
"""
workload_setting = []
if self.is_next_gen_array(array):
if is_next_gen:
workload_setting.append('None')
else:
wl_details = self.get_resource(
@ -645,14 +648,29 @@ class PowerMaxRest(object):
:param array: the array serial number
:return: the PowerMax/VMAX model
"""
vmax_version = ''
system_uri = ("/%(version)s/system/symmetrix/%(array)s" % {
'version': U4V_VERSION, 'array': array})
system_info = self._get_request(system_uri, SYSTEM)
vmax_version = None
system_info = self.get_array_detail(array)
if system_info and system_info.get('model'):
vmax_version = system_info.get('model')
return vmax_version
def get_array_model_info(self, array):
"""Get the PowerMax/VMAX model.
:param array: the array serial number
:return: the PowerMax/VMAX model
"""
array_model = None
is_next_gen = False
system_info = self.get_array_detail(array)
if system_info and system_info.get('model'):
array_model = system_info.get('model')
if system_info:
ucode_version = system_info['ucode'].split('.')[0]
if ucode_version >= UCODE_5978:
is_next_gen = True
return array_model, is_next_gen
def is_compression_capable(self, array):
"""Check if array is compression capable.
@ -839,6 +857,7 @@ class PowerMaxRest(object):
"addVolumeParam": {
"num_of_vols": 1,
"emulation": "FBA",
"create_new_volumes": "False",
"volumeIdentifier": {
"identifier_name": volume_name,
"volumeIdentifierChoice": "identifier_name"},