diff --git a/cinder/tests/unit/volume/drivers/dell_emc/test_vmax.py b/cinder/tests/unit/volume/drivers/dell_emc/test_vmax.py index 8415b53a0..4e6f3bbee 100644 --- a/cinder/tests/unit/volume/drivers/dell_emc/test_vmax.py +++ b/cinder/tests/unit/volume/drivers/dell_emc/test_vmax.py @@ -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 = ( @@ -4480,6 +4484,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', @@ -4498,7 +4506,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) @@ -5601,15 +5609,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) @@ -5656,12 +5665,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'])) @@ -6666,7 +6676,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()) @@ -6675,8 +6685,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) @@ -6696,6 +6707,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') @@ -6722,23 +6737,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'])) @@ -8325,7 +8342,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( @@ -8336,8 +8353,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'])) @@ -8347,7 +8365,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, @@ -8367,8 +8385,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'])) @@ -8536,30 +8555,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 @@ -9033,57 +9028,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 diff --git a/cinder/volume/drivers/dell_emc/vmax/common.py b/cinder/volume/drivers/dell_emc/vmax/common.py index ae3306274..9b761f5a5 100644 --- a/cinder/volume/drivers/dell_emc/vmax/common.py +++ b/cinder/volume/drivers/dell_emc/vmax/common.py @@ -2009,8 +2009,8 @@ 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 @@ -2018,50 +2018,23 @@ class VMAXCommon(object): :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(_LW( - "Unable to get target endpoints for hardwareId " - "%(instance)s."), - {'instance': hardwareIdInstance}) - continue - except Exception: - LOG.warning(_LW( - "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.", diff --git a/cinder/volume/drivers/dell_emc/vmax/fc.py b/cinder/volume/drivers/dell_emc/vmax/fc.py index 1abadf546..921b8cc2d 100644 --- a/cinder/volume/drivers/dell_emc/vmax/fc.py +++ b/cinder/volume/drivers/dell_emc/vmax/fc.py @@ -77,7 +77,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" @@ -358,8 +357,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 diff --git a/cinder/volume/drivers/dell_emc/vmax/masking.py b/cinder/volume/drivers/dell_emc/vmax/masking.py index e9a76f190..38c3788ea 100644 --- a/cinder/volume/drivers/dell_emc/vmax/masking.py +++ b/cinder/volume/drivers/dell_emc/vmax/masking.py @@ -2504,6 +2504,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(_LI( + "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, diff --git a/cinder/volume/drivers/dell_emc/vmax/utils.py b/cinder/volume/drivers/dell_emc/vmax/utils.py index 70f058aa0..40c05d3fd 100644 --- a/cinder/volume/drivers/dell_emc/vmax/utils.py +++ b/cinder/volume/drivers/dell_emc/vmax/utils.py @@ -2639,46 +2639,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