diff --git a/cinder/tests/unit/volume/drivers/hpe/test_hpe3par.py b/cinder/tests/unit/volume/drivers/hpe/test_hpe3par.py index ffe4b7f077b..2ee5b0204a0 100644 --- a/cinder/tests/unit/volume/drivers/hpe/test_hpe3par.py +++ b/cinder/tests/unit/volume/drivers/hpe/test_hpe3par.py @@ -5578,7 +5578,7 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver): mock_create_client.return_value = mock_client result = self.driver.initialize_connection( self.volume, - self.connector) + self.connector_multipath_enabled) expected = [ mock.call.getVolume(self.VOLUME_3PAR_NAME), @@ -5612,6 +5612,84 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver): self.assertDictEqual(expected_properties, result) + def test_initialize_connection_single_path(self): + # setup_mock_client drive with default configuration + # and return the mock HTTP 3PAR client + mock_client = self.setup_driver() + mock_client.getVolume.return_value = {'userCPG': HPE3PAR_CPG} + mock_client.getCPG.return_value = {} + mock_client.getHost.side_effect = [ + hpeexceptions.HTTPNotFound('fake'), + {'name': self.FAKE_HOST, + 'FCPaths': [{'driverVersion': None, + 'firmwareVersion': None, + 'hostSpeed': 0, + 'model': None, + 'portPos': {'cardPort': 1, 'node': 7, + 'slot': 1}, + 'vendor': None, + 'wwn': self.wwn[0]}]}] + mock_client.queryHost.return_value = { + 'members': [{ + 'name': self.FAKE_HOST + }] + } + + mock_client.getHostVLUNs.side_effect = [ + hpeexceptions.HTTPNotFound('fake'), + [{'active': True, + 'volumeName': self.VOLUME_3PAR_NAME, + 'portPos': {'node': 7, 'slot': 1, 'cardPort': 1}, + 'remoteName': self.wwn[0], + 'lun': 90, 'type': 0}]] + + location = ("%(volume_name)s,%(lun_id)s,%(host)s,%(nsp)s" % + {'volume_name': self.VOLUME_3PAR_NAME, + 'lun_id': 90, + 'host': self.FAKE_HOST, + 'nsp': 'something'}) + mock_client.createVLUN.return_value = location + expected_properties = { + 'driver_volume_type': 'fibre_channel', + 'data': { + 'encrypted': False, + 'target_lun': 90, + 'target_wwn': ['0987654321234'], + 'target_discovered': True, + 'initiator_target_map': + {'123456789012345': ['0987654321234']}}} + + with mock.patch.object(hpecommon.HPE3PARCommon, + '_create_client') as mock_create_client: + mock_create_client.return_value = mock_client + result = self.driver.initialize_connection( + self.volume, + self.connector.copy()) + + expected = [ + mock.call.getVolume(self.VOLUME_3PAR_NAME), + mock.call.getCPG(HPE3PAR_CPG), + mock.call.getHost(self.FAKE_HOST), + mock.call.queryHost(wwns=['123456789012345']), + mock.call.getHost(self.FAKE_HOST), + mock.call.getPorts(), + mock.call.getHostVLUNs(self.FAKE_HOST), + mock.call.getPorts(), + mock.call.createVLUN( + self.VOLUME_3PAR_NAME, + auto=True, + hostname=self.FAKE_HOST, + lun=None, + portPos={'node': 7, 'slot': 1, 'cardPort': 1}), + mock.call.getHostVLUNs(self.FAKE_HOST)] + + mock_client.assert_has_calls( + self.standard_login + + expected + + self.standard_logout) + + self.assertDictEqual(expected_properties, result) + @mock.patch('cinder.zonemanager.utils.create_lookup_service') def test_initialize_connection_with_lookup_single_nsp(self, mock_lookup): # setup_mock_client drive with default configuration @@ -5772,7 +5850,7 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver): mock_create_client.return_value = mock_client result = self.driver.initialize_connection( self.volume_encrypted, - self.connector) + self.connector_multipath_enabled) expected = [ mock.call.getVolume(self.VOLUME_3PAR_NAME), @@ -6419,7 +6497,7 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver): host = self.driver._create_host( common, self.volume, - self.connector) + self.connector_multipath_enabled) expected = [ mock.call.getVolume('osv-0DM4qZEVSKON-DXN-NwVpw'), mock.call.getCPG(HPE3PAR_CPG), @@ -6466,7 +6544,7 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver): host = self.driver._create_host( common, self.volume, - self.connector) + self.connector_multipath_enabled) expected = [ mock.call.getVolume('osv-0DM4qZEVSKON-DXN-NwVpw'), mock.call.getCPG(HPE3PAR_CPG), @@ -6508,7 +6586,7 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver): host = self.driver._create_host( common, self.volume, - self.connector) + self.connector_multipath_enabled) expected = [ mock.call.getVolume('osv-0DM4qZEVSKON-DXN-NwVpw'), @@ -6548,7 +6626,7 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver): host = self.driver._create_host( common, self.volume, - self.connector) + self.connector_multipath_enabled) expected = [ mock.call.getVolume('osv-0DM4qZEVSKON-DXN-NwVpw'), mock.call.getCPG(HPE3PAR_CPG), @@ -6587,7 +6665,7 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver): host = self.driver._create_host( common, self.volume, - self.connector) + self.connector_multipath_enabled) # On Python 3, hash is randomized, and so set() is used to get # the expected order fcwwns = list(set(('123456789054321', '123456789012345'))) @@ -6630,7 +6708,7 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver): host = self.driver._create_host( common, self.volume, - self.connector) + self.connector_multipath_enabled) expected = [ mock.call.getVolume('osv-0DM4qZEVSKON-DXN-NwVpw'), @@ -6673,7 +6751,7 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver): host = self.driver._create_host( common, self.volume, - self.connector) + self.connector_multipath_enabled) expected = [ mock.call.getVolume('osv-0DM4qZEVSKON-DXN-NwVpw'), diff --git a/cinder/volume/drivers/hpe/hpe_3par_fc.py b/cinder/volume/drivers/hpe/hpe_3par_fc.py index cca70401c1a..3d3aa5a91c3 100644 --- a/cinder/volume/drivers/hpe/hpe_3par_fc.py +++ b/cinder/volume/drivers/hpe/hpe_3par_fc.py @@ -108,10 +108,11 @@ class HPE3PARFCDriver(hpebasedriver.HPE3PARDriverBase): 3.0.12 - Adds consistency group capability in generic volume groups. 4.0.0 - Adds base class. 4.0.1 - Added check to remove FC zones. bug #1730720 + 4.0.2 - Create one vlun in single path configuration. bug #1727176 """ - VERSION = "4.0.1" + VERSION = "4.0.2" # The name of the CI wiki page. CI_WIKI_NAME = "HPE_Storage_CI" @@ -168,6 +169,10 @@ class HPE3PARFCDriver(hpebasedriver.HPE3PARDriverBase): host = self._create_host(common, volume, connector) target_wwns, init_targ_map, numPaths = \ self._build_initiator_target_map(common, connector) + if not connector.get('multipath'): + target_wwns = target_wwns[:1] + initiator = connector.get('wwpns')[0] + init_targ_map[initiator] = init_targ_map[initiator][:1] # check if a VLUN already exists for this host existing_vlun = common.find_existing_vlun(volume, host) @@ -387,6 +392,8 @@ class HPE3PARFCDriver(hpebasedriver.HPE3PARDriverBase): hostname = common._safe_hostname(connector['host']) cpg = common.get_cpg(volume, allowSnap=True) domain = common.get_domain(cpg) + if not connector.get('multipath'): + connector['wwpns'] = connector['wwpns'][:1] try: host = common._get_3par_host(hostname) # Check whether host with wwn of initiator present on 3par