From 70899a9aa3e4bdd3f1b1a7024807390cd55c4958 Mon Sep 17 00:00:00 2001 From: Gorka Eguileor Date: Thu, 9 May 2019 17:25:03 +0200 Subject: [PATCH] FC: Ignore some HBAs from map for single WWNN Current FC OS-Brick code only checks for single WWNN to exclude some HBAs from scanning when we don't receive an initiator_target_map from the backend. There are storage arrays,like XtremIO, that due to their architecture and design have all target ports automatically mapped to LUNs and are returning the initiator_target_map, but some of those ports may not be connected to our HBAs, so we end up with another case of bug #1765000. This patch makes sure that we always check if the target implements single WWNN, not only when we don't receive the initiator_target_map. With this we decrease the likelihood of ending with unexpected devices in our system, because now we will ignore unconnected HBAs (even if reported in the initiator_target_map) if we are working with single WWNN target. Related-Bug: #1765000 Closes-Bug: #1828440 Change-Id: I02c208142f5b342f894666831449243863eccbfe --- os_brick/initiator/linuxfc.py | 38 +++++++++---------- os_brick/tests/initiator/test_linuxfc.py | 27 +++++++++++++ ...ys-check-single-wwnn-1595689da0eb673b.yaml | 10 +++++ 3 files changed, 56 insertions(+), 19 deletions(-) create mode 100644 releasenotes/notes/fc-always-check-single-wwnn-1595689da0eb673b.yaml diff --git a/os_brick/initiator/linuxfc.py b/os_brick/initiator/linuxfc.py index 3d6c4c941..65ddfff7a 100644 --- a/os_brick/initiator/linuxfc.py +++ b/os_brick/initiator/linuxfc.py @@ -89,28 +89,28 @@ class LinuxFibreChannel(linuxscsi.LinuxSCSI): if ports: hbas = [hba for hba in hbas if hba['port_name'] in ports] LOG.debug('Using initiator target map to exclude HBAs') - process = [(hba, get_ctsl(hba, connection_properties)) - for hba in hbas] - # With no target map we'll check if target implements single WWNN for - # all ports, if it does we only use HBAs connected (info was found), - # otherwise we are forced to blindly scan all HBAs. - else: - with_info = [] - no_info = [] + # Check if target implements single WWNN for all ports, if it does we + # only use HBAs connected (info was found), otherwise we are forced to + # blindly scan all HBAs. We also do this when we have + # initiator_target_map, because some drivers return all HBAs but they + # implement single WWNN and we avoid adding unrelated LUNs this way + # (LP bug#1765000). + with_info = [] + no_info = [] - for hba in hbas: - ctls = get_ctsl(hba, connection_properties) - found_info = True - for hba_channel, target_id, target_lun in ctls: - if hba_channel == '-' or target_id == '-': - found_info = False - target_list = with_info if found_info else no_info - target_list.append((hba, ctls)) + for hba in hbas: + ctls = get_ctsl(hba, connection_properties) + found_info = True + for hba_channel, target_id, target_lun in ctls: + if hba_channel == '-' or target_id == '-': + found_info = False + target_list = with_info if found_info else no_info + target_list.append((hba, ctls)) - process = with_info or no_info - msg = "implements" if with_info else "doesn't implement" - LOG.debug('FC target %s single WWNN for all ports.', msg) + process = with_info or no_info + msg = "implements" if with_info else "doesn't implement" + LOG.debug('FC target %s single WWNN for all ports.', msg) for hba, ctls in process: for hba_channel, target_id, target_lun in ctls: diff --git a/os_brick/tests/initiator/test_linuxfc.py b/os_brick/tests/initiator/test_linuxfc.py index 70dcf3381..0814bdb11 100644 --- a/os_brick/tests/initiator/test_linuxfc.py +++ b/os_brick/tests/initiator/test_linuxfc.py @@ -295,6 +295,33 @@ class LinuxFCTestCase(base.TestCase): mock.call(hbas[1], con_props)] mock_get_chan.assert_has_calls(expected_calls) + def test_rescan_hosts_initiator_map_single_wwnn(self): + """Test FC rescan with initiator map and single WWNN.""" + get_chan_results = [[['2', '3', 1], ['4', '5', 1]], [['-', '-', 1]]] + + hbas, con_props = self.__get_rescan_info(zone_manager=True) + + with mock.patch.object(self.lfc, '_execute', + return_value=None) as execute_mock, \ + mock.patch.object(self.lfc, '_get_hba_channel_scsi_target', + side_effect=get_chan_results) as mock_get_chan: + + self.lfc.rescan_hosts(hbas, con_props) + expected_commands = [ + mock.call('tee', '-a', '/sys/class/scsi_host/host6/scan', + process_input='2 3 1', + root_helper=None, run_as_root=True), + mock.call('tee', '-a', '/sys/class/scsi_host/host6/scan', + process_input='4 5 1', + root_helper=None, run_as_root=True)] + + execute_mock.assert_has_calls(expected_commands) + self.assertEqual(len(expected_commands), execute_mock.call_count) + + expected_calls = [mock.call(hbas[0], con_props), + mock.call(hbas[1], con_props)] + mock_get_chan.assert_has_calls(expected_calls) + def test_rescan_hosts_wildcard(self): """Test when we don't have initiator map or target is single WWNN.""" get_chan_results = [[['-', '-', 1]], [['-', '-', 1]]] diff --git a/releasenotes/notes/fc-always-check-single-wwnn-1595689da0eb673b.yaml b/releasenotes/notes/fc-always-check-single-wwnn-1595689da0eb673b.yaml new file mode 100644 index 000000000..780889ebf --- /dev/null +++ b/releasenotes/notes/fc-always-check-single-wwnn-1595689da0eb673b.yaml @@ -0,0 +1,10 @@ +--- +fixes: + - | + Always check if we are dealing with a single WWNN Fibre Channel target, + even when we receive an initiator_target_map. + This allows us to exclude unconnected HBAs from our scan for storage arrays + that automatically connect all target ports (due to their architecture and + design) even if the Cinder driver returns the initiator_target_map, + provided the target has a single WWNN. + Excluding these HBAs prevents undesired volumes from being connected.