Merge "PowerMax Driver - Port status check"
This commit is contained in:
commit
afa04aa093
@ -1645,3 +1645,36 @@ class PowerMaxData(object):
|
||||
'SourceDeviceID': device_id,
|
||||
'SourceDeviceLabel': device_label,
|
||||
'SnapIdList': [snap_id]}
|
||||
|
||||
port_info = {
|
||||
"symmetrixPort": {
|
||||
"director_status": "Online",
|
||||
"maskingview": [
|
||||
"Test_MV",
|
||||
],
|
||||
"port_status": "ON",
|
||||
"symmetrixPortKey": {
|
||||
"directorId": "FA-1D",
|
||||
"portId": "4"
|
||||
},
|
||||
"portgroup": [
|
||||
"Test_PG"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
port_info_off = deepcopy(port_info)
|
||||
port_info_off.update({"symmetrixPort": {
|
||||
"director_status": "Offline",
|
||||
"port_status": "OFF"}})
|
||||
|
||||
port_info_no_status = deepcopy(port_info)
|
||||
port_info_no_status.update({"symmetrixPort": {
|
||||
"symmetrixPortKey": {
|
||||
"directorId": "FA-1D",
|
||||
"portId": "4"
|
||||
}
|
||||
}})
|
||||
|
||||
port_info_no_details = deepcopy(port_info)
|
||||
port_info_no_details.pop("symmetrixPort")
|
||||
|
@ -80,9 +80,11 @@ class PowerMaxMaskingTest(test.TestCase):
|
||||
self.driver.masking._sanity_port_group_check,
|
||||
None, self.data.array)
|
||||
|
||||
@mock.patch.object(
|
||||
masking.PowerMaxMasking, '_check_director_and_port_status')
|
||||
@mock.patch.object(rest.PowerMaxRest, 'get_portgroup',
|
||||
return_value=tpd.PowerMaxData.portgroup)
|
||||
def test_sanity_port_group_check(self, mock_pg):
|
||||
def test_sanity_port_group_check(self, mock_pg, mock_check):
|
||||
self.driver.masking._sanity_port_group_check(
|
||||
self.data.port_group_name_f, self.data.array)
|
||||
|
||||
@ -196,6 +198,8 @@ class PowerMaxMaskingTest(test.TestCase):
|
||||
self.data.storagegroup_name_i, self.data.storagegroup_name_f,
|
||||
self.data.extra_specs, True)
|
||||
|
||||
@mock.patch.object(
|
||||
masking.PowerMaxMasking, '_check_director_and_port_status')
|
||||
@mock.patch.object(rest.PowerMaxRest, 'get_masking_view',
|
||||
side_effect=[tpd.PowerMaxData.maskingview,
|
||||
tpd.PowerMaxData.maskingview, None])
|
||||
@ -206,7 +210,7 @@ class PowerMaxMaskingTest(test.TestCase):
|
||||
@mock.patch.object(masking.PowerMaxMasking, '_create_new_masking_view',
|
||||
return_value=None)
|
||||
def test_get_or_create_masking_view(self, mock_create_mv, mock_validate_mv,
|
||||
mock_get_mv):
|
||||
mock_get_mv, mock_check):
|
||||
for x in range(0, 3):
|
||||
self.driver.masking._get_or_create_masking_view(
|
||||
self.data.array, self.maskingviewdict,
|
||||
@ -358,11 +362,13 @@ class PowerMaxMaskingTest(test.TestCase):
|
||||
self.assertEqual(7, mock_get_sg.call_count)
|
||||
self.assertEqual(1, mock_move.call_count)
|
||||
|
||||
@mock.patch.object(
|
||||
masking.PowerMaxMasking, '_check_director_and_port_status')
|
||||
@mock.patch.object(
|
||||
rest.PowerMaxRest, 'get_portgroup',
|
||||
side_effect=([tpd.PowerMaxData.port_group_name_i, None]))
|
||||
def test_check_port_group(
|
||||
self, mock_get_pg):
|
||||
self, mock_get_pg, mock_check):
|
||||
for x in range(0, 2):
|
||||
_, msg = self.driver.masking._check_port_group(
|
||||
self.data.array, self.maskingviewdict['maskingview_name'])
|
||||
@ -1230,3 +1236,58 @@ class PowerMaxMaskingTest(test.TestCase):
|
||||
self.data.parent_sg_i)
|
||||
mock_create.assert_not_called
|
||||
mock_add.assert_not_called()
|
||||
|
||||
@mock.patch.object(rest.PowerMaxRest, 'get_port',
|
||||
return_value=tpd.PowerMaxData.port_info)
|
||||
@mock.patch.object(rest.PowerMaxRest, 'get_port_ids',
|
||||
return_value=['FA-1D:4'])
|
||||
def test_check_director_and_port_status(self, mock_port_ids, mock_port):
|
||||
self.mask._check_director_and_port_status(
|
||||
self.data.array, self.data.port_group_name_f)
|
||||
|
||||
@mock.patch.object(rest.PowerMaxRest, 'get_port',
|
||||
return_value=tpd.PowerMaxData.port_info_off)
|
||||
@mock.patch.object(rest.PowerMaxRest, 'get_port_ids',
|
||||
return_value=['FA-1D:4'])
|
||||
def test_check_director_and_port_status_invalid_status(
|
||||
self, mock_port_ids, mock_port):
|
||||
exception_message = (
|
||||
r"The director status is Offline and the port status is OFF for "
|
||||
r"dir:port FA-1D:4.")
|
||||
|
||||
with self.assertRaisesRegex(
|
||||
exception.VolumeBackendAPIException,
|
||||
exception_message):
|
||||
self.mask._check_director_and_port_status(
|
||||
self.data.array, self.data.port_group_name_f)
|
||||
|
||||
@mock.patch.object(rest.PowerMaxRest, 'get_port',
|
||||
return_value=tpd.PowerMaxData.port_info_no_status)
|
||||
@mock.patch.object(rest.PowerMaxRest, 'get_port_ids',
|
||||
return_value=['FA-1D:4'])
|
||||
def test_check_director_and_port_status_no_status(
|
||||
self, mock_port_ids, mock_port):
|
||||
exception_message = (
|
||||
r"Unable to get the director or port status for dir:port "
|
||||
r"FA-1D:4.")
|
||||
|
||||
with self.assertRaisesRegex(
|
||||
exception.VolumeBackendAPIException,
|
||||
exception_message):
|
||||
self.mask._check_director_and_port_status(
|
||||
self.data.array, self.data.port_group_name_f)
|
||||
|
||||
@mock.patch.object(rest.PowerMaxRest, 'get_port',
|
||||
return_value=tpd.PowerMaxData.port_info_no_details)
|
||||
@mock.patch.object(rest.PowerMaxRest, 'get_port_ids',
|
||||
return_value=['FA-1D:4'])
|
||||
def test_check_director_and_port_status_no_details(
|
||||
self, mock_port_ids, mock_port):
|
||||
exception_message = (
|
||||
r"Unable to get port information for dir:port FA-1D:4.")
|
||||
|
||||
with self.assertRaisesRegex(
|
||||
exception.VolumeBackendAPIException,
|
||||
exception_message):
|
||||
self.mask._check_director_and_port_status(
|
||||
self.data.array, self.data.port_group_name_f)
|
||||
|
@ -198,10 +198,12 @@ class PowerMaxReplicationTest(test.TestCase):
|
||||
self.iscsi_common.initialize_connection,
|
||||
self.data.test_volume, self.data.connector)
|
||||
|
||||
@mock.patch.object(
|
||||
masking.PowerMaxMasking, '_check_director_and_port_status')
|
||||
@mock.patch.object(
|
||||
masking.PowerMaxMasking, 'pre_multiattach',
|
||||
return_value=tpd.PowerMaxData.masking_view_dict_multiattach)
|
||||
def test_attach_metro_volume(self, mock_pre):
|
||||
def test_attach_metro_volume(self, mock_pre, mock_check):
|
||||
rep_extra_specs = deepcopy(tpd.PowerMaxData.rep_extra_specs)
|
||||
rep_extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
|
||||
hostlunid, remote_port_group = self.common._attach_metro_volume(
|
||||
|
@ -129,9 +129,10 @@ class PowerMaxFCDriver(san.SanDriver, driver.FibreChannelDriver):
|
||||
- Fix to enable legacy volumes to live migrate (#1867163)
|
||||
- Use of snap id instead of generation (bp powermax-snapset-ids)
|
||||
- Support for Failover Abilities (bp/powermax-failover-abilities)
|
||||
4.4.0 - Early check for status of port
|
||||
"""
|
||||
|
||||
VERSION = "4.3.0"
|
||||
VERSION = "4.4.0"
|
||||
|
||||
# ThirdPartySystems wiki
|
||||
CI_WIKI_NAME = "EMC_VMAX_CI"
|
||||
|
@ -135,9 +135,10 @@ class PowerMaxISCSIDriver(san.SanISCSIDriver):
|
||||
- Fix to enable legacy volumes to live migrate (#1867163)
|
||||
- Use of snap id instead of generation (bp powermax-snapset-ids)
|
||||
- Support for Failover Abilities (bp/powermax-failover-abilities)
|
||||
4.4.0 - Early check for status of port
|
||||
"""
|
||||
|
||||
VERSION = "4.3.0"
|
||||
VERSION = "4.4.0"
|
||||
|
||||
# ThirdPartySystems wiki
|
||||
CI_WIKI_NAME = "EMC_VMAX_CI"
|
||||
|
@ -215,6 +215,9 @@ class PowerMaxMasking(object):
|
||||
if not portgroup:
|
||||
exc_msg = ("Failed to get portgroup %(pg)s."
|
||||
% {'pg': port_group_name})
|
||||
else:
|
||||
self._check_director_and_port_status(
|
||||
serial_number, port_group_name)
|
||||
else:
|
||||
exc_msg = "Port group cannot be left empty."
|
||||
if exc_msg:
|
||||
@ -226,6 +229,48 @@ class PowerMaxMasking(object):
|
||||
raise exception.VolumeBackendAPIException(
|
||||
message=exception_message)
|
||||
|
||||
def _check_director_and_port_status(self, serial_number, port_group_name):
|
||||
"""Check the status of the director and port.
|
||||
|
||||
:param serial_number: the array serial number
|
||||
:param port_group_name: the port group name (can be None)
|
||||
"""
|
||||
exc_msg = None
|
||||
port_id_list = self.rest.get_port_ids(serial_number, port_group_name)
|
||||
if not port_id_list:
|
||||
exc_msg = ("Unable to get ports from portgroup %(pgn)s "
|
||||
% {'pgn': port_group_name})
|
||||
for port in port_id_list:
|
||||
port_info = self.rest.get_port(serial_number, port)
|
||||
if port_info:
|
||||
# Check that the director and port are online
|
||||
port_details = port_info.get("symmetrixPort")
|
||||
if port_details:
|
||||
director_status = port_details.get('director_status')
|
||||
port_status = port_details.get('port_status')
|
||||
if not director_status or not port_status:
|
||||
exc_msg = ("Unable to get the director or port status "
|
||||
"for dir:port %(port)s." % {'port': port})
|
||||
elif not (director_status.lower() == 'online' and (
|
||||
port_status.lower() == 'on')):
|
||||
exc_msg = ("The director status is %(ds)s and the "
|
||||
"port status is %(ps)s for dir:port "
|
||||
"%(port)s."
|
||||
% {'ds': director_status,
|
||||
'ps': port_status,
|
||||
'port': port})
|
||||
else:
|
||||
exc_msg = ("Unable to get port details for dir:port "
|
||||
"%(port)s." % {'port': port})
|
||||
else:
|
||||
exc_msg = ("Unable to get port information for dir:port "
|
||||
"%(port)s."
|
||||
% {'port': port})
|
||||
if exc_msg:
|
||||
LOG.error(exc_msg)
|
||||
raise exception.VolumeBackendAPIException(
|
||||
message=exc_msg)
|
||||
|
||||
def _create_new_masking_view(
|
||||
self, serial_number, masking_view_dict,
|
||||
maskingview_name, default_sg_name, extra_specs):
|
||||
@ -581,7 +626,10 @@ class PowerMaxMasking(object):
|
||||
"""
|
||||
msg = None
|
||||
portgroup = self.rest.get_portgroup(serial_number, portgroup_name)
|
||||
if portgroup is None:
|
||||
if portgroup:
|
||||
self._check_director_and_port_status(
|
||||
serial_number, portgroup_name)
|
||||
else:
|
||||
msg = ("Cannot get port group: %(portgroup)s from the array "
|
||||
"%(array)s. Portgroups must be pre-configured - please "
|
||||
"check the array."
|
||||
|
Loading…
Reference in New Issue
Block a user