Merge "PowerMax driver - changing from 9.0 to 9.1 REST endpoints"

This commit is contained in:
Zuul 2019-06-26 18:43:28 +00:00 committed by Gerrit Code Review
commit 9b92e2ec6b
8 changed files with 68 additions and 58 deletions

View File

@ -67,7 +67,7 @@ class PowerMaxData(object):
device_id4 = '00004'
rdf_group_name = '23_24_007'
rdf_group_no = '70'
u4v_version = '90'
u4v_version = '91'
storagegroup_name_source = 'Grp_source_sg'
storagegroup_name_target = 'Grp_target_sg'
group_snapshot_name = 'Grp_snapshot'
@ -438,12 +438,12 @@ class PowerMaxData(object):
portgroup = [{'portGroupId': port_group_name_f,
'symmetrixPortKey': [
{'directorId': 'FA-1D',
'portId': 'FA-1D:4'}],
'portId': '4'}],
'maskingview': [masking_view_name_f]},
{'portGroupId': port_group_name_i,
'symmetrixPortKey': [
{'directorId': 'SE-4E',
'portId': 'SE-4E:0'}],
'portId': '0'}],
'maskingview': [masking_view_name_i]}]
port_list = [
@ -663,7 +663,7 @@ class PowerMaxData(object):
# replication
volume_snap_vx = {'snapshotLnks': [],
'snapshotSrc': [
'snapshotSrcs': [
{'generation': 0,
'linkedDevices': [
{'targetDevice': device_id2,
@ -748,7 +748,7 @@ class PowerMaxData(object):
{'symmetrixId': array_herc,
'model': 'PowerMax 2000',
'ucode': '5978.1091.1092'}]
version_details = {'version': 'V9.0.0.1'}
version_details = {'version': 'V9.1.0.1'}
headroom = {'headroom': [{'headroomCapacity': 20348.29}]}
@ -995,7 +995,7 @@ class PowerMaxData(object):
data_dict = {volume_id: volume_info_dict}
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_version = '12.0.0'
python_version = '2.7.12'

View File

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

View File

@ -1072,8 +1072,10 @@ class PowerMaxCommonTest(test.TestCase):
def test_get_ip_and_iqn(self):
ref_ip_iqn = [{'iqn': self.data.initiator,
'ip': self.data.ip}]
director = self.data.portgroup[1]['symmetrixPortKey'][0]['directorId']
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)
def test_find_ip_and_iqns(self):

View File

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

View File

@ -113,9 +113,10 @@ class PowerMaxISCSIDriver(san.SanISCSIDriver):
- Fix for PowerMax OS replication settings (bug #1812685)
- Support for storage-assisted in-use 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
CI_WIKI_NAME = "EMC_VMAX_CI"

View File

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