PowerMax driver - changing from 9.0 to 9.1 REST endpoints

Changing unisphere for powermax REST endpoint from 9.0 to 9.1.

Change-Id: Ie072e1c4cd2db204664896dc4dc0c131a9341d57
This commit is contained in:
Simon O'Donovan 2019-04-18 16:05:56 +01:00 committed by Helen Walsh
parent a0eacd123f
commit bcc12d383a
8 changed files with 68 additions and 58 deletions

View File

@ -67,7 +67,7 @@ class PowerMaxData(object):
device_id4 = '00004' device_id4 = '00004'
rdf_group_name = '23_24_007' rdf_group_name = '23_24_007'
rdf_group_no = '70' rdf_group_no = '70'
u4v_version = '90' u4v_version = '91'
storagegroup_name_source = 'Grp_source_sg' storagegroup_name_source = 'Grp_source_sg'
storagegroup_name_target = 'Grp_target_sg' storagegroup_name_target = 'Grp_target_sg'
group_snapshot_name = 'Grp_snapshot' group_snapshot_name = 'Grp_snapshot'
@ -438,12 +438,12 @@ class PowerMaxData(object):
portgroup = [{'portGroupId': port_group_name_f, portgroup = [{'portGroupId': port_group_name_f,
'symmetrixPortKey': [ 'symmetrixPortKey': [
{'directorId': 'FA-1D', {'directorId': 'FA-1D',
'portId': 'FA-1D:4'}], 'portId': '4'}],
'maskingview': [masking_view_name_f]}, 'maskingview': [masking_view_name_f]},
{'portGroupId': port_group_name_i, {'portGroupId': port_group_name_i,
'symmetrixPortKey': [ 'symmetrixPortKey': [
{'directorId': 'SE-4E', {'directorId': 'SE-4E',
'portId': 'SE-4E:0'}], 'portId': '0'}],
'maskingview': [masking_view_name_i]}] 'maskingview': [masking_view_name_i]}]
port_list = [ port_list = [
@ -663,7 +663,7 @@ class PowerMaxData(object):
# replication # replication
volume_snap_vx = {'snapshotLnks': [], volume_snap_vx = {'snapshotLnks': [],
'snapshotSrc': [ 'snapshotSrcs': [
{'generation': 0, {'generation': 0,
'linkedDevices': [ 'linkedDevices': [
{'targetDevice': device_id2, {'targetDevice': device_id2,
@ -748,7 +748,7 @@ class PowerMaxData(object):
{'symmetrixId': array_herc, {'symmetrixId': array_herc,
'model': 'PowerMax 2000', 'model': 'PowerMax 2000',
'ucode': '5978.1091.1092'}] 'ucode': '5978.1091.1092'}]
version_details = {'version': 'V9.0.0.1'} version_details = {'version': 'V9.1.0.1'}
headroom = {'headroom': [{'headroomCapacity': 20348.29}]} headroom = {'headroom': [{'headroomCapacity': 20348.29}]}
@ -995,7 +995,7 @@ class PowerMaxData(object):
data_dict = {volume_id: volume_info_dict} data_dict = {volume_id: volume_info_dict}
platform = 'Linux-4.4.0-104-generic-x86_64-with-Ubuntu-16.04-xenial' platform = 'Linux-4.4.0-104-generic-x86_64-with-Ubuntu-16.04-xenial'
unisphere_version = u'V9.0.0.1' unisphere_version = u'V9.1.0.1'
openstack_release = '12.0.0.0b3.dev401' openstack_release = '12.0.0.0b3.dev401'
openstack_version = '12.0.0' openstack_version = '12.0.0'
python_version = '2.7.12' python_version = '2.7.12'

View File

@ -229,7 +229,7 @@ class FakeRequestsSession(object):
if job['jobId'] in url: if job['jobId'] in url:
return_object = job return_object = job
break break
elif 'version' in url: elif 'info' in url:
return_object = self.data.version_details return_object = self.data.version_details
else: else:
for symm in self.data.symmetrix: for symm in self.data.symmetrix:

View File

@ -1072,8 +1072,10 @@ class PowerMaxCommonTest(test.TestCase):
def test_get_ip_and_iqn(self): def test_get_ip_and_iqn(self):
ref_ip_iqn = [{'iqn': self.data.initiator, ref_ip_iqn = [{'iqn': self.data.initiator,
'ip': self.data.ip}] 'ip': self.data.ip}]
director = self.data.portgroup[1]['symmetrixPortKey'][0]['directorId']
port = self.data.portgroup[1]['symmetrixPortKey'][0]['portId'] port = self.data.portgroup[1]['symmetrixPortKey'][0]['portId']
ip_iqn_list = self.common._get_ip_and_iqn(self.data.array, port) dirport = "%s:%s" % (director, port)
ip_iqn_list = self.common._get_ip_and_iqn(self.data.array, dirport)
self.assertEqual(ref_ip_iqn, ip_iqn_list) self.assertEqual(ref_ip_iqn, ip_iqn_list)
def test_find_ip_and_iqns(self): def test_find_ip_and_iqns(self):

View File

@ -228,7 +228,7 @@ class PowerMaxRestTest(test.TestCase):
def test_get_uni_version(self): def test_get_uni_version(self):
version, major_version = self.rest.get_uni_version() version, major_version = self.rest.get_uni_version()
self.assertEqual('90', major_version) self.assertEqual('91', major_version)
with mock.patch.object(self.rest, '_get_request', return_value=None): with mock.patch.object(self.rest, '_get_request', return_value=None):
version, major_version = self.rest.get_uni_version() version, major_version = self.rest.get_uni_version()
self.assertIsNone(major_version) self.assertIsNone(major_version)
@ -317,12 +317,12 @@ class PowerMaxRestTest(test.TestCase):
'storageGroupId': self.data.storagegroup_name_f, 'storageGroupId': self.data.storagegroup_name_f,
'emulation': 'FBA', 'emulation': 'FBA',
'sloBasedStorageGroupParam': [ 'sloBasedStorageGroupParam': [
{'num_of_vols': 0, {'sloId': self.data.slo,
'sloId': self.data.slo,
'workloadSelection': 'NONE', 'workloadSelection': 'NONE',
'volumeAttribute': { 'volumeAttributes': [{
'volume_size': '0', 'volume_size': '0',
'capacityUnit': 'GB'}}]} 'capacityUnit': 'GB',
'num_of_vols': 0}]}]}
mock_sg.assert_called_once_with(self.data.array, payload) mock_sg.assert_called_once_with(self.data.array, payload)
def test_create_storage_group_failed(self): def test_create_storage_group_failed(self):
@ -350,12 +350,12 @@ class PowerMaxRestTest(test.TestCase):
'storageGroupId': self.data.default_sg_compr_disabled, 'storageGroupId': self.data.default_sg_compr_disabled,
'emulation': 'FBA', 'emulation': 'FBA',
'sloBasedStorageGroupParam': [ 'sloBasedStorageGroupParam': [
{'num_of_vols': 0, {'sloId': self.data.slo,
'sloId': self.data.slo,
'workloadSelection': self.data.workload, 'workloadSelection': self.data.workload,
'volumeAttribute': { 'volumeAttributes': [{
'volume_size': '0', 'volume_size': '0',
'capacityUnit': 'GB'}, 'capacityUnit': 'GB',
'num_of_vols': 0}],
'noCompression': 'true'}]} 'noCompression': 'true'}]}
mock_sg.assert_called_once_with(self.data.array, payload) mock_sg.assert_called_once_with(self.data.array, payload)
@ -475,8 +475,9 @@ class PowerMaxRestTest(test.TestCase):
def test_add_child_sg_to_parent_sg(self): def test_add_child_sg_to_parent_sg(self):
payload = {'editStorageGroupActionParam': { payload = {'editStorageGroupActionParam': {
'addExistingStorageGroupParam': { 'expandStorageGroupParam': {
'storageGroupId': [self.data.storagegroup_name_f]}}} 'addExistingStorageGroupParam': {
'storageGroupId': [self.data.storagegroup_name_f]}}}}
with mock.patch.object( with mock.patch.object(
self.rest, 'modify_storage_group', self.rest, 'modify_storage_group',
return_value=(202, self.data.job_list[0])) as mck_mod_sg: return_value=(202, self.data.job_list[0])) as mck_mod_sg:
@ -484,7 +485,7 @@ class PowerMaxRestTest(test.TestCase):
self.data.array, self.data.storagegroup_name_f, self.data.array, self.data.storagegroup_name_f,
self.data.parent_sg_f, self.data.extra_specs) self.data.parent_sg_f, self.data.extra_specs)
mck_mod_sg.assert_called_once_with( mck_mod_sg.assert_called_once_with(
self.data.array, self.data.parent_sg_f, payload, version='83') self.data.array, self.data.parent_sg_f, payload)
def test_remove_child_sg_from_parent_sg(self): def test_remove_child_sg_from_parent_sg(self):
payload = {'editStorageGroupActionParam': { payload = {'editStorageGroupActionParam': {
@ -1001,7 +1002,7 @@ class PowerMaxRestTest(test.TestCase):
def test_create_volume_snap(self): def test_create_volume_snap(self):
snap_name = self.data.volume_snap_vx[ snap_name = self.data.volume_snap_vx[
'snapshotSrc'][0]['snapshotName'] 'snapshotSrcs'][0]['snapshotName']
device_id = self.data.device_id device_id = self.data.device_id
extra_specs = self.data.extra_specs extra_specs = self.data.extra_specs
payload = {'deviceNameListSource': [{'name': device_id}], payload = {'deviceNameListSource': [{'name': device_id}],
@ -1034,8 +1035,8 @@ class PowerMaxRestTest(test.TestCase):
array = self.data.array array = self.data.array
source_id = self.data.device_id source_id = self.data.device_id
target_id = self.data.volume_snap_vx[ target_id = self.data.volume_snap_vx[
'snapshotSrc'][0]['linkedDevices'][0]['targetDevice'] 'snapshotSrcs'][0]['linkedDevices'][0]['targetDevice']
snap_name = self.data.volume_snap_vx['snapshotSrc'][0]['snapshotName'] snap_name = self.data.volume_snap_vx['snapshotSrcs'][0]['snapshotName']
extra_specs = self.data.extra_specs extra_specs = self.data.extra_specs
payload = {'deviceNameListSource': [{'name': source_id}], payload = {'deviceNameListSource': [{'name': source_id}],
'deviceNameListTarget': [ 'deviceNameListTarget': [
@ -1043,8 +1044,7 @@ class PowerMaxRestTest(test.TestCase):
'copy': 'true', 'action': "", 'copy': 'true', 'action': "",
'star': 'false', 'force': 'false', 'star': 'false', 'force': 'false',
'exact': 'false', 'remote': 'false', 'exact': 'false', 'remote': 'false',
'symforce': 'false', 'nocopy': 'false', 'symforce': 'false', 'generation': 0}
'generation': 0}
payload_restore = {'deviceNameListSource': [{'name': source_id}], payload_restore = {'deviceNameListSource': [{'name': source_id}],
'deviceNameListTarget': [{'name': source_id}], 'deviceNameListTarget': [{'name': source_id}],
'action': 'Restore', 'action': 'Restore',
@ -1094,7 +1094,7 @@ class PowerMaxRestTest(test.TestCase):
def test_delete_volume_snap(self): def test_delete_volume_snap(self):
array = self.data.array array = self.data.array
snap_name = self.data.volume_snap_vx['snapshotSrc'][0]['snapshotName'] snap_name = self.data.volume_snap_vx['snapshotSrcs'][0]['snapshotName']
source_device_id = self.data.device_id source_device_id = self.data.device_id
payload = {'deviceNameListSource': [{'name': source_device_id}], payload = {'deviceNameListSource': [{'name': source_device_id}],
'generation': 0} 'generation': 0}
@ -1108,7 +1108,7 @@ class PowerMaxRestTest(test.TestCase):
def test_delete_volume_snap_restore(self): def test_delete_volume_snap_restore(self):
array = self.data.array array = self.data.array
snap_name = self.data.volume_snap_vx['snapshotSrc'][0]['snapshotName'] snap_name = self.data.volume_snap_vx['snapshotSrcs'][0]['snapshotName']
source_device_id = self.data.device_id source_device_id = self.data.device_id
payload = {'deviceNameListSource': [{'name': source_device_id}], payload = {'deviceNameListSource': [{'name': source_device_id}],
'restore': True, 'generation': 0} 'restore': True, 'generation': 0}
@ -1128,22 +1128,22 @@ class PowerMaxRestTest(test.TestCase):
def test_get_volume_snap(self): def test_get_volume_snap(self):
array = self.data.array array = self.data.array
snap_name = self.data.volume_snap_vx['snapshotSrc'][0]['snapshotName'] snap_name = self.data.volume_snap_vx['snapshotSrcs'][0]['snapshotName']
device_id = self.data.device_id device_id = self.data.device_id
ref_snap = self.data.volume_snap_vx['snapshotSrc'][0] ref_snap = self.data.volume_snap_vx['snapshotSrcs'][0]
snap = self.rest.get_volume_snap(array, device_id, snap_name) snap = self.rest.get_volume_snap(array, device_id, snap_name)
self.assertEqual(ref_snap, snap) self.assertEqual(ref_snap, snap)
def test_get_volume_snap_none(self): def test_get_volume_snap_none(self):
array = self.data.array array = self.data.array
snap_name = self.data.volume_snap_vx['snapshotSrc'][0]['snapshotName'] snap_name = self.data.volume_snap_vx['snapshotSrcs'][0]['snapshotName']
device_id = self.data.device_id device_id = self.data.device_id
with mock.patch.object(self.rest, 'get_volume_snap_info', with mock.patch.object(self.rest, 'get_volume_snap_info',
return_value=None): return_value=None):
snap = self.rest.get_volume_snap(array, device_id, snap_name) snap = self.rest.get_volume_snap(array, device_id, snap_name)
self.assertIsNone(snap) self.assertIsNone(snap)
with mock.patch.object(self.rest, 'get_volume_snap_info', with mock.patch.object(self.rest, 'get_volume_snap_info',
return_value={'snapshotSrc': []}): return_value={'snapshotSrcs': []}):
snap = self.rest.get_volume_snap(array, device_id, snap_name) snap = self.rest.get_volume_snap(array, device_id, snap_name)
self.assertIsNone(snap) self.assertIsNone(snap)
@ -1167,10 +1167,10 @@ class PowerMaxRestTest(test.TestCase):
source_id = self.data.device_id source_id = self.data.device_id
generation = 0 generation = 0
target_id = self.data.volume_snap_vx[ target_id = self.data.volume_snap_vx[
'snapshotSrc'][0]['linkedDevices'][0]['targetDevice'] 'snapshotSrcs'][0]['linkedDevices'][0]['targetDevice']
snap_name = self.data.volume_snap_vx['snapshotSrc'][0]['snapshotName'] snap_name = self.data.volume_snap_vx['snapshotSrcs'][0]['snapshotName']
ref_sync = self.data.volume_snap_vx[ ref_sync = self.data.volume_snap_vx[
'snapshotSrc'][0]['linkedDevices'][0] 'snapshotSrcs'][0]['linkedDevices'][0]
sync = self.rest.get_sync_session( sync = self.rest.get_sync_session(
array, source_id, snap_name, target_id, generation) array, source_id, snap_name, target_id, generation)
self.assertEqual(ref_sync, sync) self.assertEqual(ref_sync, sync)

View File

@ -108,9 +108,10 @@ class PowerMaxFCDriver(san.SanDriver, driver.FibreChannelDriver):
- Fix for PowerMax OS replication settings (bug #1812685) - Fix for PowerMax OS replication settings (bug #1812685)
- Support for storage-assisted in-use retype - Support for storage-assisted in-use retype
(bp/powermax-storage-assisted-inuse-retype) (bp/powermax-storage-assisted-inuse-retype)
4.1.0 - Changing from 90 to 91 rest endpoints
""" """
VERSION = "4.0.0" VERSION = "4.1.0"
# ThirdPartySystems wiki # ThirdPartySystems wiki
CI_WIKI_NAME = "EMC_VMAX_CI" CI_WIKI_NAME = "EMC_VMAX_CI"

View File

@ -113,9 +113,10 @@ class PowerMaxISCSIDriver(san.SanISCSIDriver):
- Fix for PowerMax OS replication settings (bug #1812685) - Fix for PowerMax OS replication settings (bug #1812685)
- Support for storage-assisted in-use retype - Support for storage-assisted in-use retype
(bp/powermax-storage-assisted-inuse-retype) (bp/powermax-storage-assisted-inuse-retype)
4.1.0 - Changing from 90 to 91 rest endpoints
""" """
VERSION = "4.0.0" VERSION = "4.1.0"
# ThirdPartySystems wiki # ThirdPartySystems wiki
CI_WIKI_NAME = "EMC_VMAX_CI" CI_WIKI_NAME = "EMC_VMAX_CI"

View File

@ -38,7 +38,7 @@ LOG = logging.getLogger(__name__)
SLOPROVISIONING = 'sloprovisioning' SLOPROVISIONING = 'sloprovisioning'
REPLICATION = 'replication' REPLICATION = 'replication'
SYSTEM = 'system' SYSTEM = 'system'
U4V_VERSION = '90' U4V_VERSION = '91'
UCODE_5978 = '5978' UCODE_5978 = '5978'
retry_exc_tuple = (exception.VolumeBackendAPIException,) retry_exc_tuple = (exception.VolumeBackendAPIException,)
# HTTP constants # HTTP constants
@ -584,8 +584,8 @@ class PowerMaxRest(object):
:returns: version dict :returns: version dict
""" """
version_url = "/%s/system/version" % U4V_VERSION version_url = "/%s/system/info" % U4V_VERSION
version_dict = self._get_request(version_url, 'version') version_dict = self._get_request(version_url, 'info')
if not version_dict: if not version_dict:
LOG.error("Unisphere version info not found.") LOG.error("Unisphere version info not found.")
return version_dict return version_dict
@ -678,7 +678,8 @@ class PowerMaxRest(object):
:returns: bool :returns: bool
""" """
is_compression_capable = False is_compression_capable = False
target_uri = "/84/sloprovisioning/symmetrix?compressionCapable=true" target_uri = ("/%s/sloprovisioning/symmetrix?compressionCapable=true"
% U4V_VERSION)
status_code, message = self.request(target_uri, GET) status_code, message = self.request(target_uri, GET)
self.check_status_code_success( self.check_status_code_success(
"Check if compression enabled", status_code, message) "Check if compression enabled", status_code, message)
@ -750,10 +751,11 @@ class PowerMaxRest(object):
:param extra_specs: the extra specifications :param extra_specs: the extra specifications
""" """
payload = {"editStorageGroupActionParam": { payload = {"editStorageGroupActionParam": {
"addExistingStorageGroupParam": { "expandStorageGroupParam": {
"storageGroupId": [child_sg]}}} "addExistingStorageGroupParam": {
sc, job = self.modify_storage_group(array, parent_sg, payload, "storageGroupId": [child_sg]}}}}
version="83")
sc, job = self.modify_storage_group(array, parent_sg, payload)
self.wait_for_job('Add child sg to parent sg', sc, job, extra_specs) self.wait_for_job('Add child sg to parent sg', sc, job, extra_specs)
def remove_child_sg_from_parent_sg( def remove_child_sg_from_parent_sg(
@ -806,12 +808,12 @@ class PowerMaxRest(object):
if slo: if slo:
if self.is_next_gen_array(array): if self.is_next_gen_array(array):
workload = 'NONE' workload = 'NONE'
slo_param = {"num_of_vols": 0, slo_param = {"sloId": slo,
"sloId": slo,
"workloadSelection": workload, "workloadSelection": workload,
"volumeAttribute": { "volumeAttributes": [{
"volume_size": "0", "volume_size": "0",
"capacityUnit": "GB"}} "capacityUnit": "GB",
"num_of_vols": 0}]}
if do_disable_compression: if do_disable_compression:
slo_param.update({"noCompression": "true"}) slo_param.update({"noCompression": "true"})
elif self.is_compression_capable(array): elif self.is_compression_capable(array):
@ -854,7 +856,7 @@ class PowerMaxRest(object):
{"executionOption": "ASYNCHRONOUS", {"executionOption": "ASYNCHRONOUS",
"editStorageGroupActionParam": { "editStorageGroupActionParam": {
"expandStorageGroupParam": { "expandStorageGroupParam": {
"addVolumeParam": { "addVolumeParam": [{
"num_of_vols": 1, "num_of_vols": 1,
"emulation": "FBA", "emulation": "FBA",
"create_new_volumes": "False", "create_new_volumes": "False",
@ -863,7 +865,7 @@ class PowerMaxRest(object):
"volumeIdentifierChoice": "identifier_name"}, "volumeIdentifierChoice": "identifier_name"},
"volumeAttribute": { "volumeAttribute": {
"volume_size": volume_size, "volume_size": volume_size,
"capacityUnit": "GB"}}}}}) "capacityUnit": "GB"}}]}}})
status_code, job = self.modify_storage_group( status_code, job = self.modify_storage_group(
array, storagegroup_name, payload) array, storagegroup_name, payload)
@ -1413,7 +1415,7 @@ class PowerMaxRest(object):
if portgroup_info: if portgroup_info:
port_key = portgroup_info["symmetrixPortKey"] port_key = portgroup_info["symmetrixPortKey"]
for key in port_key: for key in port_key:
port = key['portId'] port = "%s:%s" % (key['directorId'], key['portId'])
portlist.append(port) portlist.append(port)
return portlist return portlist
@ -1804,8 +1806,7 @@ class PowerMaxRest(object):
"copy": 'true', "action": action, "copy": 'true', "action": action,
"star": 'false', "force": 'false', "star": 'false', "force": 'false',
"exact": 'false', "remote": 'false', "exact": 'false', "remote": 'false',
"symforce": 'false', "nocopy": 'false', "symforce": 'false', "generation": generation}
"generation": generation}
elif action == "Rename": elif action == "Rename":
operation = 'Rename snapVx snapshot' operation = 'Rename snapVx snapshot'
@ -1868,9 +1869,9 @@ class PowerMaxRest(object):
snapshot = None snapshot = None
snap_info = self.get_volume_snap_info(array, device_id) snap_info = self.get_volume_snap_info(array, device_id)
if snap_info: if snap_info:
if (snap_info.get('snapshotSrc') and if (snap_info.get('snapshotSrcs') and
bool(snap_info['snapshotSrc'])): bool(snap_info['snapshotSrcs'])):
for snap in snap_info['snapshotSrc']: for snap in snap_info['snapshotSrcs']:
if snap['snapshotName'] == snap_name: if snap['snapshotName'] == snap_name:
if snap['generation'] == generation: if snap['generation'] == generation:
snapshot = snap snapshot = snap
@ -1887,8 +1888,8 @@ class PowerMaxRest(object):
snapshot_list = [] snapshot_list = []
snap_info = self.get_volume_snap_info(array, source_device_id) snap_info = self.get_volume_snap_info(array, source_device_id)
if snap_info: if snap_info:
if bool(snap_info['snapshotSrc']): if bool(snap_info['snapshotSrcs']):
snapshot_list = snap_info['snapshotSrc'] snapshot_list = snap_info['snapshotSrcs']
return snapshot_list return snapshot_list
def is_vol_in_rep_session(self, array, device_id): def is_vol_in_rep_session(self, array, device_id):

View File

@ -0,0 +1,5 @@
---
other:
- |
PowerMax driver - the minimum version of Unisphere for PowerMax required
for Train is 9.1, so all the latest 91 REST endpoints will be used.