From e211056d650b9be9f7501b1497416c8fc14312d5 Mon Sep 17 00:00:00 2001 From: Patrick East Date: Fri, 1 Jun 2018 18:23:09 -0700 Subject: [PATCH] FC fix for scanning only connected HBA's When provided an initiator target map and attempting a rescan in LinuxFibreChannel.rescan_hosts(...) if the system doesn't yet have /sys/class/fc_host/fc_transport/** directories then we can get into a position where the call to LinuxFibreChannel._get_hba_channel_scsi_target will return "None". Later on when we iterate through "process" and attempt to iterate on "cts" this will raise an exception. We used to fall back to a wildcard scan, and still do if no target map is provided. This fix will do just that, for cases where we don't have enough other information we just use wildcards. In testing it seems like this happens on first-time connections to a target after the ACLs have been setup on the arrays for the initiator. After that we can get the HBA channel and SCSI target with the grep call in _get_hba_channel_scsi_target Change-Id: Ifd79b055882bb513fccf21d584baaeb1d60e67f2 Closes-Bug: #1774283 (cherry picked from commit 50ef90251c474b69665fd49444db6ae06711f408) --- os_brick/initiator/linuxfc.py | 14 +++++++++----- os_brick/tests/initiator/test_linuxfc.py | 8 +++++--- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/os_brick/initiator/linuxfc.py b/os_brick/initiator/linuxfc.py index 89ae65275..a9db91b28 100644 --- a/os_brick/initiator/linuxfc.py +++ b/os_brick/initiator/linuxfc.py @@ -40,9 +40,10 @@ class LinuxFibreChannel(linuxscsi.LinuxSCSI): This method only works for Fibre Channel targets that implement a single WWNN for all ports, so caller should expect us to return either - None or an empty list. + explicit channel and targets or wild cards if we cannot determine them. - :returns: List or None + :returns: List of lists with [c, t] entries, the channel and target + may be '-' wildcards if unable to determine them. """ # We want the target's WWPNs, so we use the initiator_target_map if # present for this hba or default to target_wwns if not present. @@ -74,7 +75,7 @@ class LinuxFibreChannel(linuxscsi.LinuxSCSI): LOG.debug('Could not get HBA channel and SCSI target ID, path: ' '%(path)s*, reason: %(reason)s', {'path': path, 'reason': exc}) - return None + return [['-', '-']] def rescan_hosts(self, hbas, connection_properties): LOG.debug('Rescaning HBAs %(hbas)s with connection properties ' @@ -100,8 +101,11 @@ class LinuxFibreChannel(linuxscsi.LinuxSCSI): for hba in hbas: cts = get_cts(hba, connection_properties) - target_list = with_info if cts else no_info - cts = cts or [('-', '-')] + found_info = True + for hba_channel, target_id in cts: + if hba_channel == '-' or target_id == '-': + found_info = False + target_list = with_info if found_info else no_info target_list.append((hba, cts)) process = with_info or no_info diff --git a/os_brick/tests/initiator/test_linuxfc.py b/os_brick/tests/initiator/test_linuxfc.py index 38b93d85f..dbe6414cc 100644 --- a/os_brick/tests/initiator/test_linuxfc.py +++ b/os_brick/tests/initiator/test_linuxfc.py @@ -135,7 +135,7 @@ class LinuxFCTestCase(base.TestCase): 'grep -Gil "514f0c50023f6c00" ' '/sys/class/fc_transport/target6:*/port_name', shell=True) - self.assertIsNone(res) + self.assertEqual([['-', '-']], res) def test_rescan_hosts_initiator_map(self): """Test FC rescan with initiator map and not every HBA connected.""" @@ -177,7 +177,8 @@ class LinuxFCTestCase(base.TestCase): def test_rescan_hosts_single_wwnn(self): """Test FC rescan with no initiator map and single WWNN for ports.""" - get_chan_results = [[['2', '3'], ['4', '5']], [['6', '7']], None] + get_chan_results = [[['2', '3'], ['4', '5']], + [['6', '7']], [['-', '-']]] hbas, con_props = self.__get_rescan_info(zone_manager=True) # Remove the initiator map @@ -215,11 +216,12 @@ class LinuxFCTestCase(base.TestCase): def test_rescan_hosts_wildcard(self): """Test when we don't have initiator map or target is single WWNN.""" + get_chan_results = [[['-', '-']], [['-', '-']]] hbas, con_props = self.__get_rescan_info(zone_manager=True) # Remove the initiator map con_props.pop('initiator_target_map') with mock.patch.object(self.lfc, '_get_hba_channel_scsi_target', - side_effect=(None, [])), \ + side_effect=get_chan_results), \ mock.patch.object(self.lfc, '_execute', side_effect=None) as execute_mock: