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
This commit is contained in:
parent
8cb5fe3623
commit
70899a9aa3
@ -89,28 +89,28 @@ class LinuxFibreChannel(linuxscsi.LinuxSCSI):
|
|||||||
if ports:
|
if ports:
|
||||||
hbas = [hba for hba in hbas if hba['port_name'] in ports]
|
hbas = [hba for hba in hbas if hba['port_name'] in ports]
|
||||||
LOG.debug('Using initiator target map to exclude HBAs')
|
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
|
# Check if target implements single WWNN for all ports, if it does we
|
||||||
# all ports, if it does we only use HBAs connected (info was found),
|
# only use HBAs connected (info was found), otherwise we are forced to
|
||||||
# otherwise we are forced to blindly scan all HBAs.
|
# blindly scan all HBAs. We also do this when we have
|
||||||
else:
|
# initiator_target_map, because some drivers return all HBAs but they
|
||||||
with_info = []
|
# implement single WWNN and we avoid adding unrelated LUNs this way
|
||||||
no_info = []
|
# (LP bug#1765000).
|
||||||
|
with_info = []
|
||||||
|
no_info = []
|
||||||
|
|
||||||
for hba in hbas:
|
for hba in hbas:
|
||||||
ctls = get_ctsl(hba, connection_properties)
|
ctls = get_ctsl(hba, connection_properties)
|
||||||
found_info = True
|
found_info = True
|
||||||
for hba_channel, target_id, target_lun in ctls:
|
for hba_channel, target_id, target_lun in ctls:
|
||||||
if hba_channel == '-' or target_id == '-':
|
if hba_channel == '-' or target_id == '-':
|
||||||
found_info = False
|
found_info = False
|
||||||
target_list = with_info if found_info else no_info
|
target_list = with_info if found_info else no_info
|
||||||
target_list.append((hba, ctls))
|
target_list.append((hba, ctls))
|
||||||
|
|
||||||
process = with_info or no_info
|
process = with_info or no_info
|
||||||
msg = "implements" if with_info else "doesn't implement"
|
msg = "implements" if with_info else "doesn't implement"
|
||||||
LOG.debug('FC target %s single WWNN for all ports.', msg)
|
LOG.debug('FC target %s single WWNN for all ports.', msg)
|
||||||
|
|
||||||
for hba, ctls in process:
|
for hba, ctls in process:
|
||||||
for hba_channel, target_id, target_lun in ctls:
|
for hba_channel, target_id, target_lun in ctls:
|
||||||
|
@ -295,6 +295,33 @@ class LinuxFCTestCase(base.TestCase):
|
|||||||
mock.call(hbas[1], con_props)]
|
mock.call(hbas[1], con_props)]
|
||||||
mock_get_chan.assert_has_calls(expected_calls)
|
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):
|
def test_rescan_hosts_wildcard(self):
|
||||||
"""Test when we don't have initiator map or target is single WWNN."""
|
"""Test when we don't have initiator map or target is single WWNN."""
|
||||||
get_chan_results = [[['-', '-', 1]], [['-', '-', 1]]]
|
get_chan_results = [[['-', '-', 1]], [['-', '-', 1]]]
|
||||||
|
@ -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…
x
Reference in New Issue
Block a user