Merge "VMAX driver - Pre-zoned port group fix"
This commit is contained in:
commit
f1dfad4618
@ -297,6 +297,10 @@ class VMAXCommonData(object):
|
||||
'SYMMETRIX+000195900551+OS-fakehost-gold-I-MV')
|
||||
lunmaskctrl_name = (
|
||||
'OS-fakehost-gold-I-MV')
|
||||
mv_instance_name = {
|
||||
'CreationClassName': 'Symm_LunMaskingView',
|
||||
'ElementName': 'OS-fakehost-SRP_1-Bronze-DSS-I-Mv',
|
||||
'SystemName': 'SYMMETRIX+000195900551'}
|
||||
|
||||
rdf_group = 'test_rdf'
|
||||
srdf_group_instance = (
|
||||
@ -4473,6 +4477,10 @@ class VMAXISCSIDriverFastTestCase(test.TestCase):
|
||||
self.data.test_volume,
|
||||
self.data.connector)
|
||||
|
||||
@mock.patch.object(
|
||||
common.VMAXCommon,
|
||||
'get_target_wwns_from_masking_view',
|
||||
return_value=[{'Name': '5000090000000000'}])
|
||||
@mock.patch.object(
|
||||
masking.VMAXMasking,
|
||||
'get_initiator_group_from_masking_view',
|
||||
@ -4491,7 +4499,7 @@ class VMAXISCSIDriverFastTestCase(test.TestCase):
|
||||
return_value={'volume_backend_name': 'ISCSIFAST'})
|
||||
def test_detach_fast_success(
|
||||
self, mock_volume_type, mock_storage_group,
|
||||
mock_ig, mock_igc):
|
||||
mock_ig, mock_igc, mock_tw):
|
||||
self.driver.terminate_connection(
|
||||
self.data.test_volume, self.data.connector)
|
||||
|
||||
@ -5661,15 +5669,16 @@ class VMAXFCDriverFastTestCase(test.TestCase):
|
||||
def test_map_fast_success(self, _mock_volume_type, mock_maskingview,
|
||||
mock_is_same_host):
|
||||
common = self.driver.common
|
||||
common.get_target_wwns = mock.Mock(
|
||||
common.get_target_wwns_list = mock.Mock(
|
||||
return_value=VMAXCommonData.target_wwns)
|
||||
self.driver.common._get_correct_port_group = mock.Mock(
|
||||
return_value=self.data.port_group)
|
||||
data = self.driver.initialize_connection(
|
||||
self.data.test_volume, self.data.connector)
|
||||
# Test the no lookup service, pre-zoned case.
|
||||
common.get_target_wwns.assert_called_once_with(
|
||||
VMAXCommonData.storage_system, VMAXCommonData.connector)
|
||||
common.get_target_wwns_list.assert_called_once_with(
|
||||
VMAXCommonData.storage_system, self.data.test_volume,
|
||||
VMAXCommonData.connector)
|
||||
for init, target in data['data']['initiator_target_map'].items():
|
||||
self.assertIn(init[::-1], target)
|
||||
|
||||
@ -5716,12 +5725,13 @@ class VMAXFCDriverFastTestCase(test.TestCase):
|
||||
def test_detach_fast_success(self, mock_volume_type, mock_maskingview,
|
||||
mock_ig, mock_igc, mock_mv, mock_check_ig):
|
||||
common = self.driver.common
|
||||
common.get_target_wwns = mock.Mock(
|
||||
common.get_target_wwns_list = mock.Mock(
|
||||
return_value=VMAXCommonData.target_wwns)
|
||||
data = self.driver.terminate_connection(self.data.test_volume,
|
||||
self.data.connector)
|
||||
common.get_target_wwns.assert_called_once_with(
|
||||
VMAXCommonData.storage_system, VMAXCommonData.connector)
|
||||
common.get_target_wwns_list.assert_called_once_with(
|
||||
VMAXCommonData.storage_system, self.data.test_volume,
|
||||
VMAXCommonData.connector)
|
||||
numTargetWwns = len(VMAXCommonData.target_wwns)
|
||||
self.assertEqual(numTargetWwns, len(data['data']))
|
||||
|
||||
@ -6725,7 +6735,7 @@ class EMCV3DriverTestCase(test.TestCase):
|
||||
self, _mock_volume_type, mock_maskingview, mock_is_same_host,
|
||||
mock_element_name):
|
||||
common = self.driver.common
|
||||
common.get_target_wwns = mock.Mock(
|
||||
common.get_target_wwns_list = mock.Mock(
|
||||
return_value=VMAXCommonData.target_wwns)
|
||||
self.driver.common._initial_setup = mock.Mock(
|
||||
return_value=self.default_extraspec())
|
||||
@ -6734,8 +6744,9 @@ class EMCV3DriverTestCase(test.TestCase):
|
||||
data = self.driver.initialize_connection(
|
||||
self.data.test_volume_v3, self.data.connector)
|
||||
# Test the no lookup service, pre-zoned case.
|
||||
common.get_target_wwns.assert_called_once_with(
|
||||
VMAXCommonData.storage_system, VMAXCommonData.connector)
|
||||
common.get_target_wwns_list.assert_called_once_with(
|
||||
VMAXCommonData.storage_system, self.data.test_volume_v3,
|
||||
VMAXCommonData.connector)
|
||||
for init, target in data['data']['initiator_target_map'].items():
|
||||
self.assertIn(init[::-1], target)
|
||||
|
||||
@ -6755,6 +6766,10 @@ class EMCV3DriverTestCase(test.TestCase):
|
||||
self.data.test_volume,
|
||||
self.data.connector)
|
||||
|
||||
@mock.patch.object(
|
||||
masking.VMAXMasking,
|
||||
'get_port_group_from_masking_view',
|
||||
return_value='myPortGroup')
|
||||
@mock.patch.object(
|
||||
masking.VMAXMasking,
|
||||
'remove_and_reset_members')
|
||||
@ -6781,23 +6796,25 @@ class EMCV3DriverTestCase(test.TestCase):
|
||||
@mock.patch.object(
|
||||
masking.VMAXMasking,
|
||||
'get_masking_view_from_storage_group',
|
||||
return_value=VMAXCommonData.lunmaskctrl_name)
|
||||
return_value=[VMAXCommonData.mv_instance_name])
|
||||
@mock.patch.object(
|
||||
volume_types,
|
||||
'get_volume_type_extra_specs',
|
||||
return_value={'volume_backend_name': 'V3_BE'})
|
||||
def test_detach_v3_success(self, mock_volume_type, mock_maskingview,
|
||||
mock_ig, mock_igc, mock_mv, mock_check_ig,
|
||||
mock_element_name, mock_remove):
|
||||
mock_element_name, mock_remove, mock_pg):
|
||||
common = self.driver.common
|
||||
with mock.patch.object(common, 'get_target_wwns',
|
||||
with mock.patch.object(common, 'get_target_wwns_list',
|
||||
return_value=VMAXCommonData.target_wwns):
|
||||
with mock.patch.object(common, '_initial_setup',
|
||||
return_value=self.default_extraspec()):
|
||||
data = self.driver.terminate_connection(
|
||||
self.data.test_volume_v3, self.data.connector)
|
||||
common.get_target_wwns.assert_called_once_with(
|
||||
VMAXCommonData.storage_system, VMAXCommonData.connector)
|
||||
common.get_target_wwns_list.assert_called_once_with(
|
||||
VMAXCommonData.storage_system,
|
||||
self.data.test_volume_v3,
|
||||
VMAXCommonData.connector)
|
||||
numTargetWwns = len(VMAXCommonData.target_wwns)
|
||||
self.assertEqual(numTargetWwns, len(data['data']))
|
||||
|
||||
@ -8333,7 +8350,7 @@ class VMAXFCTest(test.TestCase):
|
||||
return_value='testMV')
|
||||
common.get_masking_views_by_port_group = mock.Mock(
|
||||
return_value=[])
|
||||
common.get_target_wwns = mock.Mock(
|
||||
common.get_target_wwns_list = mock.Mock(
|
||||
return_value=VMAXCommonData.target_wwns)
|
||||
initiatorGroupInstanceName = (
|
||||
self.driver.common.masking._get_initiator_group_from_masking_view(
|
||||
@ -8344,8 +8361,9 @@ class VMAXFCTest(test.TestCase):
|
||||
return_value=initiatorGroupInstanceName):
|
||||
data = self.driver.terminate_connection(self.data.test_volume_v3,
|
||||
self.data.connector)
|
||||
common.get_target_wwns.assert_called_once_with(
|
||||
VMAXCommonData.storage_system, VMAXCommonData.connector)
|
||||
common.get_target_wwns_list.assert_called_once_with(
|
||||
VMAXCommonData.storage_system, self.data.test_volume_v3,
|
||||
VMAXCommonData.connector)
|
||||
numTargetWwns = len(VMAXCommonData.target_wwns)
|
||||
self.assertEqual(numTargetWwns, len(data['data']))
|
||||
|
||||
@ -8355,7 +8373,7 @@ class VMAXFCTest(test.TestCase):
|
||||
return_value=None)
|
||||
@mock.patch.object(
|
||||
common.VMAXCommon,
|
||||
'get_target_wwns',
|
||||
'get_target_wwns_list',
|
||||
return_value=VMAXCommonData.target_wwns)
|
||||
@mock.patch.object(
|
||||
common.VMAXCommon,
|
||||
@ -8375,8 +8393,9 @@ class VMAXFCTest(test.TestCase):
|
||||
common.conn = FakeEcomConnection()
|
||||
data = self.driver.terminate_connection(self.data.test_volume_v3,
|
||||
self.data.connector)
|
||||
common.get_target_wwns.assert_called_once_with(
|
||||
VMAXCommonData.storage_system, VMAXCommonData.connector)
|
||||
common.get_target_wwns_list.assert_called_once_with(
|
||||
VMAXCommonData.storage_system, self.data.test_volume_v3,
|
||||
VMAXCommonData.connector)
|
||||
numTargetWwns = len(VMAXCommonData.target_wwns)
|
||||
self.assertEqual(numTargetWwns, len(data['data']))
|
||||
|
||||
@ -8544,30 +8563,6 @@ class VMAXUtilsTest(test.TestCase):
|
||||
self.driver = driver
|
||||
self.driver.utils = utils.VMAXUtils(object)
|
||||
|
||||
def test_get_target_endpoints(self):
|
||||
conn = FakeEcomConnection()
|
||||
hardwareid = 123456789012345
|
||||
result = self.driver.utils.get_target_endpoints(conn, hardwareid)
|
||||
self.assertEqual(
|
||||
([{'Name': '5000090000000000'}]), result)
|
||||
|
||||
def test_get_protocol_controller(self):
|
||||
conn = FakeEcomConnection()
|
||||
hardwareid = 123456789012345
|
||||
result = self.driver.utils.get_protocol_controller(conn, hardwareid)
|
||||
self.assertEqual(
|
||||
({'CreationClassName': 'Symm_LunMaskingView',
|
||||
'ElementName': 'OS-fakehost-gold-I-MV'}), result)
|
||||
|
||||
def test_get_protocol_controller_exception(self):
|
||||
conn = FakeEcomConnection()
|
||||
conn.AssociatorNames = mock.Mock(return_value=[])
|
||||
hardwareid = 123456789012345
|
||||
self.assertRaises(
|
||||
exception.VolumeBackendAPIException,
|
||||
self.driver.utils.get_protocol_controller,
|
||||
conn, hardwareid)
|
||||
|
||||
def test_set_target_element_supplier_in_rsd(self):
|
||||
conn = FakeEcomConnection()
|
||||
extraSpecs = self.data.extra_specs
|
||||
@ -8832,57 +8827,30 @@ class VMAXCommonTest(test.TestCase):
|
||||
sourceInstance, cloneName, extraSpecs)
|
||||
self.assertIsNotNone(duplicateVolumeInstance)
|
||||
|
||||
def test_get_target_wwn(self):
|
||||
@mock.patch.object(
|
||||
common.VMAXCommon,
|
||||
'get_target_wwns_from_masking_view',
|
||||
return_value=["5000090000000000"])
|
||||
def test_get_target_wwn_list(self, mock_tw):
|
||||
common = self.driver.common
|
||||
common.conn = FakeEcomConnection()
|
||||
targetWwns = common.get_target_wwns(
|
||||
VMAXCommonData.storage_system, VMAXCommonData.connector)
|
||||
targetWwns = common.get_target_wwns_list(
|
||||
VMAXCommonData.storage_system,
|
||||
VMAXCommonData.test_volume_v3, VMAXCommonData.connector)
|
||||
self.assertListEqual(["5000090000000000"], targetWwns)
|
||||
|
||||
@mock.patch.object(
|
||||
utils.VMAXUtils,
|
||||
'get_target_endpoints',
|
||||
return_value=None)
|
||||
def test_get_target_wwn_all_invalid(self, mock_target_ep):
|
||||
common.VMAXCommon,
|
||||
'get_target_wwns_from_masking_view',
|
||||
return_value=[])
|
||||
def test_get_target_wwn_list_empty(self, mock_tw):
|
||||
common = self.driver.common
|
||||
common.conn = FakeEcomConnection()
|
||||
|
||||
self.assertRaises(
|
||||
exception.VolumeBackendAPIException,
|
||||
common.get_target_wwns, VMAXCommonData.storage_system,
|
||||
VMAXCommonData.connector)
|
||||
|
||||
def test_get_target_wwn_one_invalid(self):
|
||||
common = self.driver.common
|
||||
common.conn = FakeEcomConnection()
|
||||
targetEndpoints = [{'CreationClassName': 'EMC_FCSCSIProtocolEndpoint',
|
||||
'Name': '5000090000000000'}]
|
||||
hardwareInstanceNames = (
|
||||
[{'CreationClassName': 'EMC_StorageHardwareID'}] * 3)
|
||||
e = exception.VolumeBackendAPIException('Get target endpoint ex')
|
||||
with mock.patch.object(common, '_find_storage_hardwareids',
|
||||
return_value=hardwareInstanceNames):
|
||||
with mock.patch.object(common.utils, 'get_target_endpoints',
|
||||
side_effect=[e, None, targetEndpoints]):
|
||||
targetWwns = common.get_target_wwns(
|
||||
VMAXCommonData.storage_system,
|
||||
VMAXCommonData.connector)
|
||||
self.assertListEqual(["5000090000000000"], targetWwns)
|
||||
|
||||
def test_get_target_wwn_all_invalid_endpoints(self):
|
||||
common = self.driver.common
|
||||
common.conn = FakeEcomConnection()
|
||||
hardwareInstanceNames = (
|
||||
[{'CreationClassName': 'EMC_StorageHardwareID'}] * 3)
|
||||
e = exception.VolumeBackendAPIException('Get target endpoint ex')
|
||||
with mock.patch.object(common, '_find_storage_hardwareids',
|
||||
return_value=hardwareInstanceNames):
|
||||
with mock.patch.object(common.utils, 'get_target_endpoints',
|
||||
side_effect=[e, None, None]):
|
||||
self.assertRaises(
|
||||
exception.VolumeBackendAPIException,
|
||||
common.get_target_wwns, VMAXCommonData.storage_system,
|
||||
VMAXCommonData.connector)
|
||||
common.get_target_wwns_list, VMAXCommonData.storage_system,
|
||||
VMAXCommonData.test_volume_v3, VMAXCommonData.connector)
|
||||
|
||||
def test_cleanup_target(self):
|
||||
common = self.driver.common
|
||||
|
@ -2008,59 +2008,32 @@ class VMAXCommon(object):
|
||||
LOG.debug("Device info: %(data)s.", {'data': data})
|
||||
return data, isLiveMigration, source_data
|
||||
|
||||
def get_target_wwns(self, storageSystem, connector):
|
||||
"""Find target WWNs.
|
||||
def get_target_wwns_list(self, storage_system, volume, connector):
|
||||
"""Find target WWN list.
|
||||
|
||||
:param storageSystem: the storage system name
|
||||
:param connector: the connector dict
|
||||
:returns: list -- targetWwns, the target WWN list
|
||||
:raises VolumeBackendAPIException:
|
||||
:raises: VolumeBackendAPIException
|
||||
"""
|
||||
targetWwns = set()
|
||||
try:
|
||||
fc_targets = self.get_target_wwns_from_masking_view(
|
||||
storage_system, volume, connector)
|
||||
except Exception:
|
||||
exception_message = _("Unable to get fc targets.")
|
||||
raise exception.VolumeBackendAPIException(
|
||||
data=exception_message)
|
||||
|
||||
storageHardwareService = self.utils.find_storage_hardwareid_service(
|
||||
self.conn, storageSystem)
|
||||
|
||||
hardwareIdInstances = self._find_storage_hardwareids(
|
||||
connector, storageHardwareService)
|
||||
|
||||
LOG.debug(
|
||||
"EMCGetTargetEndpoints: Service: %(service)s, "
|
||||
"Storage HardwareIDs: %(hardwareIds)s.",
|
||||
{'service': storageHardwareService,
|
||||
'hardwareIds': hardwareIdInstances})
|
||||
|
||||
for hardwareIdInstance in hardwareIdInstances:
|
||||
LOG.debug("HardwareID instance is: %(hardwareIdInstance)s.",
|
||||
{'hardwareIdInstance': hardwareIdInstance})
|
||||
try:
|
||||
targetEndpoints = (
|
||||
self.utils.get_target_endpoints(
|
||||
self.conn, hardwareIdInstance))
|
||||
if not targetEndpoints:
|
||||
LOG.warning(
|
||||
"Unable to get target endpoints for hardwareId "
|
||||
"%(instance)s.",
|
||||
{'instance': hardwareIdInstance})
|
||||
continue
|
||||
except Exception:
|
||||
LOG.warning(
|
||||
"Unable to get target endpoints for hardwareId "
|
||||
"%(instance)s.",
|
||||
{'instance': hardwareIdInstance}, exc_info=True)
|
||||
continue
|
||||
|
||||
LOG.debug("There are %(len)lu endpoints.",
|
||||
{'len': len(targetEndpoints)})
|
||||
for targetendpoint in targetEndpoints:
|
||||
wwn = targetendpoint['Name']
|
||||
# Add target wwn to the list if it is not already there.
|
||||
targetWwns.add(wwn)
|
||||
break
|
||||
LOG.debug("There are %(len)lu endpoints.", {'len': len(fc_targets)})
|
||||
for fc_target in fc_targets:
|
||||
wwn = fc_target
|
||||
# Add target wwn to the list if it is not already there.
|
||||
targetWwns.add(wwn)
|
||||
|
||||
if not targetWwns:
|
||||
exception_message = (_(
|
||||
"Unable to get target endpoints for any hardwareIds."))
|
||||
"Unable to get target endpoints."))
|
||||
raise exception.VolumeBackendAPIException(data=exception_message)
|
||||
|
||||
LOG.debug("Target WWNs: %(targetWwns)s.",
|
||||
|
@ -76,7 +76,6 @@ class VMAXFCDriver(driver.FibreChannelDriver):
|
||||
- Support for compression on All Flash
|
||||
- Volume replication 2.1 (bp add-vmax-replication)
|
||||
- rename and restructure driver (bp vmax-rename-dell-emc)
|
||||
|
||||
"""
|
||||
|
||||
VERSION = "2.5.0"
|
||||
@ -357,8 +356,8 @@ class VMAXFCDriver(driver.FibreChannelDriver):
|
||||
for initiator in map_d['initiator_port_wwn_list']:
|
||||
init_targ_map[initiator] = map_d['target_port_wwn_list']
|
||||
else: # No lookup service, pre-zoned case.
|
||||
target_wwns = self.common.get_target_wwns(storage_system,
|
||||
connector)
|
||||
target_wwns = self.common.get_target_wwns_list(
|
||||
storage_system, volume, connector)
|
||||
for initiator in initiator_wwns:
|
||||
init_targ_map[initiator] = target_wwns
|
||||
|
||||
|
@ -2497,6 +2497,15 @@ class VMAXMasking(object):
|
||||
conn, sgInstanceName)
|
||||
# Get initiator group from masking view.
|
||||
for mvInstanceName in mvInstanceNames:
|
||||
host = self.utils.get_host_short_name(connector['host'])
|
||||
mvInstance = conn.GetInstance(mvInstanceName)
|
||||
if host not in mvInstance['ElementName']:
|
||||
LOG.info(
|
||||
"Check 1: Connector host %(connHost)s "
|
||||
"does not match mv host %(mvHost)s. Skipping...",
|
||||
{'connHost': host,
|
||||
'mvHost': mvInstance['ElementName']})
|
||||
continue
|
||||
LOG.debug("Found masking view associated with SG "
|
||||
"%(storageGroup)s: %(maskingview)s",
|
||||
{'maskingview': mvInstanceName,
|
||||
|
@ -2348,46 +2348,6 @@ class VMAXUtils(object):
|
||||
foundIpAddress = cimProperties.value
|
||||
return foundIpAddress
|
||||
|
||||
def get_target_endpoints(self, conn, hardwareId):
|
||||
"""Given the hardwareId get the target endpoints.
|
||||
|
||||
:param conn: the connection to the ecom server
|
||||
:param hardwareId: the hardware Id
|
||||
:returns: targetEndpoints
|
||||
:raises: VolumeBackendAPIException
|
||||
"""
|
||||
protocolControllerInstanceName = self.get_protocol_controller(
|
||||
conn, hardwareId)
|
||||
|
||||
targetEndpoints = conn.AssociatorNames(
|
||||
protocolControllerInstanceName,
|
||||
ResultClass='EMC_FCSCSIProtocolEndpoint')
|
||||
|
||||
return targetEndpoints
|
||||
|
||||
def get_protocol_controller(self, conn, hardwareinstancename):
|
||||
"""Get the front end protocol endpoints of a hardware instance
|
||||
|
||||
:param conn: the ecom connection
|
||||
:param hardwareinstancename: the hardware instance name
|
||||
:returns: protocolControllerInstanceName
|
||||
:raises: VolumeBackendAPIException
|
||||
"""
|
||||
protocolControllerInstanceName = None
|
||||
protocol_controllers = conn.AssociatorNames(
|
||||
hardwareinstancename,
|
||||
ResultClass='EMC_FrontEndSCSIProtocolController')
|
||||
if len(protocol_controllers) > 0:
|
||||
protocolControllerInstanceName = protocol_controllers[0]
|
||||
if protocolControllerInstanceName is None:
|
||||
exceptionMessage = (_(
|
||||
"Unable to get target endpoints for hardwareId "
|
||||
"%(hardwareIdInstance)s.")
|
||||
% {'hardwareIdInstance': hardwareinstancename})
|
||||
LOG.error(exceptionMessage)
|
||||
raise exception.VolumeBackendAPIException(data=exceptionMessage)
|
||||
return protocolControllerInstanceName
|
||||
|
||||
def get_replication_setting_data(self, conn, repServiceInstanceName,
|
||||
replication_type, extraSpecs):
|
||||
"""Get the replication setting data
|
||||
|
Loading…
x
Reference in New Issue
Block a user