diff --git a/cinder/tests/unit/test_hpe3par.py b/cinder/tests/unit/test_hpe3par.py index 0d8a5d3221c..6a05e5c218c 100644 --- a/cinder/tests/unit/test_hpe3par.py +++ b/cinder/tests/unit/test_hpe3par.py @@ -121,11 +121,13 @@ class HPE3PARBaseDriver(object): VOLUME_ID_SNAP = '761fc5e5-5191-4ec7-aeba-33e36de44156' FAKE_DESC = 'test description name' FAKE_FC_PORTS = [{'portPos': {'node': 7, 'slot': 1, 'cardPort': 1}, + 'type': 1, 'portWWN': '0987654321234', 'protocol': 1, 'mode': 2, 'linkState': 4}, {'portPos': {'node': 6, 'slot': 1, 'cardPort': 1}, + 'type': 1, 'portWWN': '123456789000987', 'protocol': 1, 'mode': 2, @@ -334,6 +336,7 @@ class HPE3PARBaseDriver(object): 'PORT_STATE_READY': 4, 'PORT_PROTO_ISCSI': 2, 'PORT_PROTO_FC': 1, + 'PORT_TYPE_HOST': 1, 'TASK_DONE': TASK_DONE, 'TASK_ACTIVE': TASK_ACTIVE, 'HOST_EDIT_ADD': 1, @@ -4487,16 +4490,16 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase): 'firmwareVersion': None, 'hostSpeed': 0, 'model': None, - 'portPos': {'cardPort': 1, 'node': 1, - 'slot': 2}, + 'portPos': {'cardPort': 1, 'node': 7, + 'slot': 1}, 'vendor': None, 'wwn': self.wwn[0]}, {'driverVersion': None, 'firmwareVersion': None, 'hostSpeed': 0, 'model': None, - 'portPos': {'cardPort': 1, 'node': 0, - 'slot': 2}, + 'portPos': {'cardPort': 1, 'node': 6, + 'slot': 1}, 'vendor': None, 'wwn': self.wwn[1]}]}] mock_client.queryHost.return_value = { @@ -4509,6 +4512,13 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase): hpeexceptions.HTTPNotFound('fake'), [{'active': True, 'volumeName': self.VOLUME_3PAR_NAME, + 'portPos': {'node': 7, 'slot': 1, 'cardPort': 1}, + 'remoteName': self.wwn[1], + 'lun': 90, 'type': 0}], + [{'active': True, + 'volumeName': self.VOLUME_3PAR_NAME, + 'portPos': {'node': 6, 'slot': 1, 'cardPort': 1}, + 'remoteName': self.wwn[0], 'lun': 90, 'type': 0}]] location = ("%(volume_name)s,%(lun_id)s,%(host)s,%(nsp)s" % @@ -4517,6 +4527,16 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase): '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', '123456789000987'], + 'target_discovered': True, + 'initiator_target_map': + {'123456789012345': ['123456789000987'], + '123456789054321': ['0987654321234']}}} with mock.patch.object(hpecommon.HPE3PARCommon, '_create_client') as mock_create_client: @@ -4534,11 +4554,20 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase): 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), + lun=None, + portPos={'node': 7, 'slot': 1, 'cardPort': 1}), + mock.call.getHostVLUNs(self.FAKE_HOST), + mock.call.createVLUN( + self.VOLUME_3PAR_NAME, + auto=False, + hostname=self.FAKE_HOST, + lun=90, + portPos={'node': 6, 'slot': 1, 'cardPort': 1}), mock.call.getHostVLUNs(self.FAKE_HOST)] mock_client.assert_has_calls( @@ -4546,7 +4575,7 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase): expected + self.standard_logout) - self.assertDictMatch(self.properties, result) + self.assertDictMatch(expected_properties, result) @mock.patch('cinder.zonemanager.utils.create_lookup_service') def test_initialize_connection_with_lookup_single_nsp(self, mock_lookup): @@ -4587,7 +4616,7 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase): [{'active': True, 'volumeName': self.VOLUME_3PAR_NAME, 'lun': 90, 'type': 0, - 'portPos': {'cardPort': 1, 'node': 7, 'slot': 1}, }]] + 'portPos': {'cardPort': 1, 'node': 7, 'slot': 1}}]] location = ("%(volume_name)s,%(lun_id)s,%(host)s,%(nsp)s" % {'volume_name': self.VOLUME_3PAR_NAME, @@ -4655,16 +4684,16 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase): 'firmwareVersion': None, 'hostSpeed': 0, 'model': None, - 'portPos': {'cardPort': 1, 'node': 1, - 'slot': 2}, + 'portPos': {'cardPort': 1, 'node': 7, + 'slot': 1}, 'vendor': None, 'wwn': self.wwn[0]}, {'driverVersion': None, 'firmwareVersion': None, 'hostSpeed': 0, 'model': None, - 'portPos': {'cardPort': 1, 'node': 0, - 'slot': 2}, + 'portPos': {'cardPort': 1, 'node': 6, + 'slot': 1}, 'vendor': None, 'wwn': self.wwn[1]}]}] mock_client.queryHost.return_value = { @@ -4677,6 +4706,13 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase): hpeexceptions.HTTPNotFound('fake'), [{'active': True, 'volumeName': self.VOLUME_3PAR_NAME, + 'lun': 90, 'type': 0, + 'remoteName': self.wwn[1], + 'portPos': {'cardPort': 1, 'node': 7, 'slot': 1}}], + [{'active': True, + 'volumeName': self.VOLUME_3PAR_NAME, + 'portPos': {'node': 6, 'slot': 1, 'cardPort': 1}, + 'remoteName': self.wwn[0], 'lun': 90, 'type': 0}]] location = ("%(volume_name)s,%(lun_id)s,%(host)s,%(nsp)s" % @@ -4685,6 +4721,16 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase): 'host': self.FAKE_HOST, 'nsp': 'something'}) mock_client.createVLUN.return_value = location + expected_properties = { + 'driver_volume_type': 'fibre_channel', + 'data': { + 'encrypted': True, + 'target_lun': 90, + 'target_wwn': ['0987654321234', '123456789000987'], + 'target_discovered': True, + 'initiator_target_map': + {'123456789012345': ['123456789000987'], + '123456789054321': ['0987654321234']}}} with mock.patch.object(hpecommon.HPE3PARCommon, '_create_client') as mock_create_client: @@ -4702,11 +4748,20 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase): 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), + lun=None, + portPos={'node': 7, 'slot': 1, 'cardPort': 1}), + mock.call.getHostVLUNs(self.FAKE_HOST), + mock.call.createVLUN( + self.VOLUME_3PAR_NAME, + auto=False, + hostname=self.FAKE_HOST, + lun=90, + portPos={'node': 6, 'slot': 1, 'cardPort': 1}), mock.call.getHostVLUNs(self.FAKE_HOST)] mock_client.assert_has_calls( @@ -4714,8 +4769,6 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase): expected + self.standard_logout) - expected_properties = self.properties - expected_properties['data']['encrypted'] = True self.assertDictMatch(expected_properties, result) def test_terminate_connection(self): diff --git a/cinder/volume/drivers/hpe/hpe_3par_fc.py b/cinder/volume/drivers/hpe/hpe_3par_fc.py index 853b70355e5..dd3eb589355 100644 --- a/cinder/volume/drivers/hpe/hpe_3par_fc.py +++ b/cinder/volume/drivers/hpe/hpe_3par_fc.py @@ -101,10 +101,12 @@ class HPE3PARFCDriver(driver.TransferVD, 3.0.5 - Optimize array ID retrieval 3.0.6 - Update replication to version 2.1 3.0.7 - Remove metadata that tracks the instance ID. bug #1572665 + 3.0.8 - NSP feature, creating FC Vlun as match set instead of + host sees. bug #1577993 """ - VERSION = "3.0.7" + VERSION = "3.0.8" def __init__(self, *args, **kwargs): super(HPE3PARFCDriver, self).__init__(*args, **kwargs) @@ -265,26 +267,69 @@ class HPE3PARFCDriver(driver.TransferVD, try: # we have to make sure we have a host host = self._create_host(common, volume, connector) - target_wwns, init_targ_map, numPaths = \ self._build_initiator_target_map(common, connector) - # check if a VLUN already exists for this host existing_vlun = common.find_existing_vlun(volume, host) vlun = None if existing_vlun is None: # now that we have a host, create the VLUN - if self.lookup_service is not None and numPaths == 1: - nsp = None - active_fc_port_list = common.get_active_fc_target_ports() - for port in active_fc_port_list: - if port['portWWN'].lower() == target_wwns[0].lower(): - nsp = port['nsp'] - break - vlun = common.create_vlun(volume, host, nsp) + nsp = None + lun_id = None + active_fc_port_list = common.get_active_fc_target_ports() + + if self.lookup_service: + if not init_targ_map: + msg = _("Setup is incomplete. Device mapping " + "not found from FC network. " + "Cannot perform VLUN creation.") + LOG.error(msg) + raise exception.FCSanLookupServiceException(msg) + + for target_wwn in target_wwns: + for port in active_fc_port_list: + if port['portWWN'].lower() == target_wwn.lower(): + nsp = port['nsp'] + vlun = common.create_vlun(volume, + host, + nsp, + lun_id=lun_id) + if lun_id is None: + lun_id = vlun['lun'] + break else: - vlun = common.create_vlun(volume, host) + init_targ_map.clear() + del target_wwns[:] + host_connected_nsp = [] + for fcpath in host['FCPaths']: + if 'portPos' in fcpath: + host_connected_nsp.append( + common.build_nsp(fcpath['portPos'])) + for port in active_fc_port_list: + if ( + port['type'] == common.client.PORT_TYPE_HOST and + port['nsp'] in host_connected_nsp + ): + nsp = port['nsp'] + vlun = common.create_vlun(volume, + host, + nsp, + lun_id=lun_id) + target_wwns.append(port['portWWN']) + if vlun['remoteName'] in init_targ_map: + init_targ_map[vlun['remoteName']].append( + port['portWWN']) + else: + init_targ_map[vlun['remoteName']] = [ + port['portWWN']] + if lun_id is None: + lun_id = vlun['lun'] + if lun_id is None: + # New vlun creation failed + msg = _('No new vlun(s) were created') + LOG.error(msg) + raise exception.VolumeDriverException(msg) else: vlun = existing_vlun @@ -296,7 +341,6 @@ class HPE3PARFCDriver(driver.TransferVD, encryption_key_id = volume.get('encryption_key_id', None) info['data']['encrypted'] = encryption_key_id is not None - return info finally: self._logout(common) diff --git a/releasenotes/notes/3par-create-fc-vlun-match-set-type-babcf2cbce1ce317.yaml b/releasenotes/notes/3par-create-fc-vlun-match-set-type-babcf2cbce1ce317.yaml new file mode 100644 index 00000000000..b9f3ece88ab --- /dev/null +++ b/releasenotes/notes/3par-create-fc-vlun-match-set-type-babcf2cbce1ce317.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - 3PAR driver creates FC VLUN of match-set type instead of host sees. + With match-set, the host will see the virtual volume on specified + NSP (Node-Slot-Port). This change in vlun type fixes bug 1577993. \ No newline at end of file