Browse Source

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
(cherry picked from commit 70899a9aa3)
(cherry picked from commit 1ee6acb509)
changes/67/668567/1
Gorka Eguileor 2 years ago
committed by Keigo Noha
parent
commit
66d9d2a908
  1. 42
      os_brick/initiator/linuxfc.py
  2. 27
      os_brick/tests/initiator/test_linuxfc.py
  3. 10
      releasenotes/notes/fc-always-check-single-wwnn-1595689da0eb673b.yaml

42
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 = []
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)
# 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))
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:

27
os_brick/tests/initiator/test_linuxfc.py

@ -260,6 +260,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]]]

10
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.
Loading…
Cancel
Save