PowerMax driver - performance improvements
1. Changing a payload parameter to in modifying storage group so that a new volume does not have to be created on every operation. This is especially relevent as when we delete a volume we do not wait for the tracks to deallocate. This volume (once deallocation is eventually complete) can be reused. 2. Optimization on driver initialization to call method to determine whether array is a powermax only once. Change-Id: Iea8f445052be4882fb6450d939774eeb7124384e
This commit is contained in:
parent
3e55f98aac
commit
8d972bec8a
|
@ -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'}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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, __ = (
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"},
|
||||
|
|
Loading…
Reference in New Issue