Fix: FC partial target scan
When fetching the target value (T in HCTL) for the storage HBAs, we use the /sys/class/fc_transport path to find available targets. However, this path only contains targets that already have a LUN attached from, to the host. Scenario: If we have 2 controllers on the backend side with 4 target HBAs each (total 8). For the first LUN mapping from controller1, we will do a wildcard scan and find the 4 targets from controller1 which will get populated in the /fc_transport path. If we try mapping a LUN from controller2, we try to find targets in the fc_transport path but the path only contains targets from controller1 so we will not be able to discover the LUN from controller2 and fail with NoFibreChannelVolumeDeviceFound exception. Solution: In each rescan attempt, we will first search for targets in the fc_transport path: "/sys/class/fc_transport/target<host>*". If the target in not found then we will search in the fc_remote_ports path: "/sys/class/fc_remote_ports/rport-<host>*" If a [c,t,l] combination is found from either path, we add it to the list of ctls we later use it for scanning. This way, we don't alter the current "working" mechanism of scanning but also add an additional way of discovering targets and improving the scan to avoid failure scenarios in each rescan attempt. Closes-Bug: #2051237 Change-Id: Ia74b0fc24e0cf92453e65d15b4a76e565ed04d16
This commit is contained in:
parent
7ad6acdff5
commit
f2154eedf0
|
@ -33,7 +33,74 @@ class LinuxFibreChannel(linuxscsi.LinuxSCSI):
|
|||
# Only load the sysfs attributes we care about
|
||||
HBA_ATTRIBUTES = ('port_name', 'node_name', 'port_state')
|
||||
|
||||
def _get_hba_channel_scsi_target_lun(self, hba, conn_props):
|
||||
def _get_target_fc_transport_path(self, path, wwpn, lun):
|
||||
"""Scan target in the fc_transport path
|
||||
|
||||
Scan for target in the following path:
|
||||
* /sys/class/fc_transport/target<host>*
|
||||
|
||||
:returns: List with [c, t, l] if the target path exists else
|
||||
empty list
|
||||
"""
|
||||
cmd = 'grep -Gil "%(wwpns)s" %(path)s*/port_name' % {'wwpns': wwpn,
|
||||
'path': path}
|
||||
# We need to run command in shell to expand the * glob
|
||||
out, _err = self._execute(cmd, shell=True) # nosec: B604
|
||||
# The grep command will only return 1 path (if found)
|
||||
# associated with the target wwpn used for the search
|
||||
# in the current HBA host
|
||||
out_path = out.split('\n')[0]
|
||||
if out_path.startswith(path):
|
||||
return out_path.split('/')[4].split(':')[1:] + [lun]
|
||||
|
||||
return []
|
||||
|
||||
def _get_target_fc_remote_ports_path(self, path, wwpn, lun):
|
||||
"""Scan target in the fc_remote_ports path
|
||||
|
||||
Scan for target in the following path:
|
||||
* /sys/class/fc_remote_ports/rport-<host>*
|
||||
|
||||
If the path exist, we fetch the target value from the
|
||||
scsi_target_id file.
|
||||
Example: /sys/class/fc_remote_ports/rport-6:0-1/scsi_target_id
|
||||
|
||||
:returns: List with [c, t, l] if the target path exists else
|
||||
empty list
|
||||
"""
|
||||
cmd = 'grep -Gil "%(wwpns)s" %(path)s*/port_name' % {'wwpns': wwpn,
|
||||
'path': path}
|
||||
# We need to run command in shell to expand the * glob
|
||||
out, _err = self._execute(cmd, shell=True) # nosec: B604
|
||||
# The scsi_target_id file contains the target ID.
|
||||
# Example path:
|
||||
# /sys/class/fc_remote_ports/rport-2:0-0/scsi_target_id
|
||||
target_path = os.path.dirname(out) + '/scsi_target_id'
|
||||
# There could be a case where the out variable has empty string
|
||||
# and we end up with a path '/scsi_target_id' so check if it
|
||||
# starts with the correct path
|
||||
if target_path.startswith(path):
|
||||
try:
|
||||
scsi_target = '-1'
|
||||
with open(target_path) as scsi_target_file:
|
||||
lines = scsi_target_file.read()
|
||||
scsi_target = lines.split('\n')[0]
|
||||
except OSError:
|
||||
# We were not able to read from the scsi_target_id
|
||||
# file but we can still discover other targets so
|
||||
# continue
|
||||
pass
|
||||
# If the target value is -1, it is not a real target so
|
||||
# skip it
|
||||
if scsi_target != '-1':
|
||||
channel = target_path.split(':')[1].split('-')[0]
|
||||
return [channel, scsi_target, lun]
|
||||
|
||||
return []
|
||||
|
||||
def _get_hba_channel_scsi_target_lun(self,
|
||||
hba,
|
||||
conn_props):
|
||||
"""Get HBA channels, SCSI targets, LUNs to FC targets for given HBA.
|
||||
|
||||
Given an HBA and the connection properties we look for the HBA channels
|
||||
|
@ -48,6 +115,13 @@ class LinuxFibreChannel(linuxscsi.LinuxSCSI):
|
|||
based on the contents of the connection information data to know which
|
||||
target ports to look for.
|
||||
|
||||
We scan for targets in the following two paths:
|
||||
* /sys/class/fc_transport/target<host>*
|
||||
* /sys/class/fc_remote_ports/rport-<host>*
|
||||
|
||||
We search for targets in the fc_transport path first and if not
|
||||
found, we search in the fc_remote_ports path
|
||||
|
||||
:returns: 2-Tuple with the first entry being a list of [c, t, l]
|
||||
entries where the target port was found, and the second entry of the
|
||||
tuple being a set of luns for ports that were not found.
|
||||
|
@ -66,22 +140,27 @@ class LinuxFibreChannel(linuxscsi.LinuxSCSI):
|
|||
host_device = host_device[4:]
|
||||
|
||||
path = '/sys/class/fc_transport/target%s:' % host_device
|
||||
rpath = '/sys/class/fc_remote_ports/rport-%s:' % host_device
|
||||
|
||||
ctls = []
|
||||
luns_not_found = set()
|
||||
for wwpn, lun in targets:
|
||||
cmd = 'grep -Gil "%(wwpns)s" %(path)s*/port_name' % {'wwpns': wwpn,
|
||||
'path': path}
|
||||
try:
|
||||
# We need to run command in shell to expand the * glob
|
||||
out, _err = self._execute(cmd, shell=True) # nosec: B604
|
||||
ctls += [line.split('/')[4].split(':')[1:] + [lun]
|
||||
for line in out.split('\n') if line.startswith(path)]
|
||||
# Search for target in the fc_transport path first and if we
|
||||
# don't find ctl, search for target in the fc_remote_ports path
|
||||
ctl = (self._get_target_fc_transport_path(path, wwpn, lun) or
|
||||
self._get_target_fc_remote_ports_path(rpath, wwpn, lun))
|
||||
|
||||
if ctl:
|
||||
ctls.append(ctl)
|
||||
|
||||
except Exception as exc:
|
||||
LOG.debug('Could not get HBA channel and SCSI target ID, path:'
|
||||
' %(path)s*, reason: %(reason)s', {'path': path,
|
||||
'reason': exc})
|
||||
# If we didn't find any paths add it to the not found list
|
||||
luns_not_found.add(lun)
|
||||
|
||||
return ctls, luns_not_found
|
||||
|
||||
def rescan_hosts(self,
|
||||
|
|
|
@ -15,11 +15,13 @@
|
|||
import os.path
|
||||
from unittest import mock
|
||||
|
||||
import ddt
|
||||
|
||||
from os_brick.initiator import linuxfc
|
||||
from os_brick.tests import base
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class LinuxFCTestCase(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
@ -70,85 +72,124 @@ class LinuxFCTestCase(base.TestCase):
|
|||
del connection_properties['initiator_target_lun_map']
|
||||
return hbas, connection_properties
|
||||
|
||||
def test__get_hba_channel_scsi_target_lun_single_wwpn(self):
|
||||
execute_results = ('/sys/class/fc_transport/target6:0:1/port_name\n',
|
||||
'')
|
||||
@staticmethod
|
||||
def _get_expected_info(wwpns=["514f0c50023f6c00", "514f0c50023f6c01"],
|
||||
targets=1, remote_scan=False):
|
||||
|
||||
execute_results = []
|
||||
expected_cmds = []
|
||||
for i in range(0, targets):
|
||||
expected_cmds += [
|
||||
mock.call(f'grep -Gil "{wwpns[i]}" '
|
||||
'/sys/class/fc_transport/target6:*/port_name',
|
||||
shell=True)
|
||||
]
|
||||
if remote_scan:
|
||||
execute_results += [
|
||||
# We can only perform remote ports scan if the
|
||||
# fc_transport path returns empty output
|
||||
('', ''),
|
||||
# This is returned from the fc_remote_ports path
|
||||
(f'/sys/class/fc_remote_ports/rport-6:0-{i+1}'
|
||||
'/port_name\n', ''),
|
||||
]
|
||||
expected_cmds += [
|
||||
mock.call(f'grep -Gil "{wwpns[i]}" '
|
||||
'/sys/class/fc_remote_ports/rport-6:*/port_name',
|
||||
shell=True),
|
||||
]
|
||||
else:
|
||||
execute_results += [
|
||||
(f'/sys/class/fc_transport/target6:0:{i+1}/port_name\n',
|
||||
'')
|
||||
]
|
||||
|
||||
return execute_results, expected_cmds
|
||||
|
||||
@mock.patch('builtins.open')
|
||||
@ddt.data(True, False)
|
||||
def test__get_hba_channel_scsi_target_lun_single_wwpn(
|
||||
self, remote_scan, mock_open):
|
||||
execute_results, expected_cmds = self._get_expected_info(
|
||||
remote_scan=remote_scan)
|
||||
if remote_scan:
|
||||
mock_open = mock_open.return_value.__enter__.return_value
|
||||
mock_open.read.return_value = ('1\n')
|
||||
hbas, con_props = self.__get_rescan_info()
|
||||
con_props['target_wwn'] = con_props['target_wwn'][0]
|
||||
con_props['targets'] = con_props['targets'][0:1]
|
||||
with mock.patch.object(self.lfc, '_execute',
|
||||
return_value=execute_results) as execute_mock:
|
||||
side_effect=execute_results) as execute_mock:
|
||||
res = self.lfc._get_hba_channel_scsi_target_lun(hbas[0], con_props)
|
||||
execute_mock.assert_called_once_with(
|
||||
'grep -Gil "514f0c50023f6c00" '
|
||||
'/sys/class/fc_transport/target6:*/port_name',
|
||||
shell=True)
|
||||
execute_mock.assert_has_calls(expected_cmds)
|
||||
expected = ([['0', '1', 1]], set())
|
||||
self.assertEqual(expected, res)
|
||||
|
||||
def test__get_hba_channel_scsi_target_lun_with_initiator_target_map(self):
|
||||
execute_results = ('/sys/class/fc_transport/target6:0:1/port_name\n',
|
||||
'')
|
||||
@mock.patch('builtins.open')
|
||||
@ddt.data(True, False)
|
||||
def test__get_hba_channel_scsi_target_lun_with_initiator_target_map(
|
||||
self, remote_scan, mock_open):
|
||||
execute_results, expected_cmds = self._get_expected_info(
|
||||
wwpns=["514f0c50023f6c01"])
|
||||
if remote_scan:
|
||||
mock_open = mock_open.return_value.__enter__.return_value
|
||||
mock_open.read.return_value = ('1\n')
|
||||
hbas, con_props = self.__get_rescan_info(zone_manager=True)
|
||||
con_props['target_wwn'] = con_props['target_wwn'][0]
|
||||
con_props['targets'] = con_props['targets'][0:1]
|
||||
hbas[0]['port_name'] = '50014380186af83e'
|
||||
with mock.patch.object(self.lfc, '_execute',
|
||||
return_value=execute_results) as execute_mock:
|
||||
side_effect=execute_results) as execute_mock:
|
||||
res = self.lfc._get_hba_channel_scsi_target_lun(hbas[0], con_props)
|
||||
execute_mock.assert_called_once_with(
|
||||
'grep -Gil "514f0c50023f6c01" '
|
||||
'/sys/class/fc_transport/target6:*/port_name',
|
||||
shell=True)
|
||||
execute_mock.assert_has_calls(expected_cmds)
|
||||
expected = ([['0', '1', 1]], set())
|
||||
self.assertEqual(expected, res)
|
||||
|
||||
@mock.patch('builtins.open')
|
||||
@ddt.data(True, False)
|
||||
def test__get_hba_channel_scsi_target_lun_with_initiator_target_map_none(
|
||||
self):
|
||||
execute_results = ('/sys/class/fc_transport/target6:0:1/port_name\n',
|
||||
'')
|
||||
self, remote_scan, mock_open):
|
||||
execute_results, expected_cmds = self._get_expected_info()
|
||||
if remote_scan:
|
||||
mock_open = mock_open.return_value.__enter__.return_value
|
||||
mock_open.read.return_value = ('1\n')
|
||||
hbas, con_props = self.__get_rescan_info()
|
||||
con_props['target_wwn'] = con_props['target_wwn'][0]
|
||||
con_props['targets'] = con_props['targets'][0:1]
|
||||
con_props['initiator_target_map'] = None
|
||||
hbas[0]['port_name'] = '50014380186af83e'
|
||||
with mock.patch.object(self.lfc, '_execute',
|
||||
return_value=execute_results) as execute_mock:
|
||||
side_effect=execute_results) as execute_mock:
|
||||
res = self.lfc._get_hba_channel_scsi_target_lun(hbas[0], con_props)
|
||||
execute_mock.assert_called_once_with(
|
||||
'grep -Gil "514f0c50023f6c00" '
|
||||
'/sys/class/fc_transport/target6:*/port_name',
|
||||
shell=True)
|
||||
execute_mock.assert_has_calls(expected_cmds)
|
||||
expected = ([['0', '1', 1]], set())
|
||||
self.assertEqual(expected, res)
|
||||
|
||||
def test__get_hba_channel_scsi_target_lun_multiple_wwpn(self):
|
||||
execute_results = [
|
||||
['/sys/class/fc_transport/target6:0:1/port_name\n', ''],
|
||||
['/sys/class/fc_transport/target6:0:2/port_name\n', ''],
|
||||
]
|
||||
@mock.patch('builtins.open')
|
||||
@ddt.data(True, False)
|
||||
def test__get_hba_channel_scsi_target_lun_multiple_wwpn(
|
||||
self, remote_scan, mock_open):
|
||||
execute_results, expected_cmds = self._get_expected_info(targets=2)
|
||||
if remote_scan:
|
||||
mock_open = mock_open.return_value.__enter__.return_value
|
||||
mock_open.read.return_value = ('1\n')
|
||||
hbas, con_props = self.__get_rescan_info()
|
||||
with mock.patch.object(self.lfc, '_execute',
|
||||
side_effect=execute_results) as execute_mock:
|
||||
res = self.lfc._get_hba_channel_scsi_target_lun(hbas[0], con_props)
|
||||
expected_cmds = [
|
||||
mock.call('grep -Gil "514f0c50023f6c00" '
|
||||
'/sys/class/fc_transport/target6:*/port_name',
|
||||
shell=True),
|
||||
mock.call('grep -Gil "514f0c50023f6c01" '
|
||||
'/sys/class/fc_transport/target6:*/port_name',
|
||||
shell=True),
|
||||
]
|
||||
execute_mock.assert_has_calls(expected_cmds)
|
||||
|
||||
expected = ([['0', '1', 1], ['0', '2', 1]], set())
|
||||
self.assertEqual(expected, res)
|
||||
|
||||
def test__get_hba_channel_scsi_target_lun_multiple_wwpn_and_luns(self):
|
||||
execute_results = [
|
||||
['/sys/class/fc_transport/target6:0:1/port_name\n', ''],
|
||||
['/sys/class/fc_transport/target6:0:2/port_name\n', ''],
|
||||
]
|
||||
@mock.patch('builtins.open')
|
||||
@ddt.data(True, False)
|
||||
def test__get_hba_channel_scsi_target_lun_multiple_wwpn_and_luns(
|
||||
self, remote_scan, mock_open):
|
||||
execute_results, expected_cmds = self._get_expected_info(targets=2)
|
||||
if remote_scan:
|
||||
mock_open = mock_open.return_value.__enter__.return_value
|
||||
mock_open.read.return_value = ('1\n')
|
||||
hbas, con_props = self.__get_rescan_info()
|
||||
con_props['target_lun'] = [1, 7]
|
||||
con_props['targets'] = [
|
||||
|
@ -158,68 +199,51 @@ class LinuxFCTestCase(base.TestCase):
|
|||
with mock.patch.object(self.lfc, '_execute',
|
||||
side_effect=execute_results) as execute_mock:
|
||||
res = self.lfc._get_hba_channel_scsi_target_lun(hbas[0], con_props)
|
||||
expected_cmds = [
|
||||
mock.call('grep -Gil "514f0c50023f6c00" '
|
||||
'/sys/class/fc_transport/target6:*/port_name',
|
||||
shell=True),
|
||||
mock.call('grep -Gil "514f0c50023f6c01" '
|
||||
'/sys/class/fc_transport/target6:*/port_name',
|
||||
shell=True),
|
||||
]
|
||||
execute_mock.assert_has_calls(expected_cmds)
|
||||
|
||||
expected = ([['0', '1', 1], ['0', '2', 7]], set())
|
||||
self.assertEqual(expected, res)
|
||||
|
||||
def test__get_hba_channel_scsi_target_lun_zone_manager(self):
|
||||
execute_results = ('/sys/class/fc_transport/target6:0:1/port_name\n',
|
||||
'')
|
||||
@mock.patch('builtins.open')
|
||||
@ddt.data(True, False)
|
||||
def test__get_hba_channel_scsi_target_lun_zone_manager(
|
||||
self, remote_scan, mock_open):
|
||||
execute_results, expected_cmds = self._get_expected_info()
|
||||
if remote_scan:
|
||||
mock_open = mock_open.return_value.__enter__.return_value
|
||||
mock_open.read.return_value = ('1\n')
|
||||
hbas, con_props = self.__get_rescan_info(zone_manager=True)
|
||||
with mock.patch.object(self.lfc, '_execute',
|
||||
return_value=execute_results) as execute_mock:
|
||||
side_effect=execute_results) as execute_mock:
|
||||
res = self.lfc._get_hba_channel_scsi_target_lun(hbas[0], con_props)
|
||||
execute_mock.assert_called_once_with(
|
||||
'grep -Gil "514f0c50023f6c00" '
|
||||
'/sys/class/fc_transport/target6:*/port_name',
|
||||
shell=True)
|
||||
execute_mock.assert_has_calls(expected_cmds)
|
||||
expected = ([['0', '1', 1]], set())
|
||||
self.assertEqual(expected, res)
|
||||
|
||||
def test__get_hba_channel_scsi_target_lun_not_found(self):
|
||||
def test__get_hba_channel_scsi_target_lun_both_paths_not_found(self):
|
||||
_, expected_cmds = self._get_expected_info()
|
||||
hbas, con_props = self.__get_rescan_info(zone_manager=True)
|
||||
with mock.patch.object(self.lfc, '_execute',
|
||||
return_value=('', '')) as execute_mock:
|
||||
res = self.lfc._get_hba_channel_scsi_target_lun(hbas[0], con_props)
|
||||
execute_mock.assert_called_once_with(
|
||||
'grep -Gil "514f0c50023f6c00" '
|
||||
'/sys/class/fc_transport/target6:*/port_name',
|
||||
shell=True)
|
||||
execute_mock.assert_has_calls(expected_cmds)
|
||||
self.assertEqual(([], set()), res)
|
||||
|
||||
def test__get_hba_channel_scsi_target_lun_exception(self):
|
||||
_, expected_cmds = self._get_expected_info()
|
||||
hbas, con_props = self.__get_rescan_info(zone_manager=True)
|
||||
with mock.patch.object(self.lfc, '_execute',
|
||||
side_effect=Exception) as execute_mock:
|
||||
res = self.lfc._get_hba_channel_scsi_target_lun(hbas[0], con_props)
|
||||
execute_mock.assert_called_once_with(
|
||||
'grep -Gil "514f0c50023f6c00" '
|
||||
'/sys/class/fc_transport/target6:*/port_name',
|
||||
shell=True)
|
||||
execute_mock.assert_has_calls(expected_cmds)
|
||||
self.assertEqual(([], {1}), res)
|
||||
|
||||
def test__get_hba_channel_scsi_target_lun_some_exception(self):
|
||||
def test__get_hba_channel_scsi_target_lun_fc_transport_exception(self):
|
||||
execute_effects = [
|
||||
('/sys/class/fc_transport/target6:0:1/port_name\n', ''),
|
||||
Exception()
|
||||
]
|
||||
expected_cmds = [
|
||||
mock.call('grep -Gil "514f0c50023f6c00" '
|
||||
'/sys/class/fc_transport/target6:*/port_name',
|
||||
shell=True),
|
||||
mock.call('grep -Gil "514f0c50023f6c01" '
|
||||
'/sys/class/fc_transport/target6:*/port_name',
|
||||
shell=True),
|
||||
]
|
||||
_, expected_cmds = self._get_expected_info()
|
||||
hbas, con_props = self.__get_rescan_info()
|
||||
|
||||
with mock.patch.object(self.lfc, '_execute',
|
||||
|
@ -229,6 +253,86 @@ class LinuxFCTestCase(base.TestCase):
|
|||
expected = ([['0', '1', 1]], {1})
|
||||
self.assertEqual(expected, res)
|
||||
|
||||
@mock.patch('builtins.open')
|
||||
def test__get_hba_channel_scsi_target_lun_fc_remote_ports_exception(
|
||||
self, mock_open):
|
||||
execute_effects = [
|
||||
('', ''),
|
||||
('/sys/class/fc_remote_ports/rport-6:0-1/port_name\n', ''),
|
||||
('', ''),
|
||||
Exception()
|
||||
]
|
||||
mock_open = mock_open.return_value.__enter__.return_value
|
||||
mock_open.read.return_value = ('1\n')
|
||||
_, expected_cmds = self._get_expected_info()
|
||||
hbas, con_props = self.__get_rescan_info()
|
||||
|
||||
with mock.patch.object(self.lfc, '_execute',
|
||||
side_effect=execute_effects) as execute_mock:
|
||||
res = self.lfc._get_hba_channel_scsi_target_lun(hbas[0], con_props)
|
||||
execute_mock.assert_has_calls(expected_cmds)
|
||||
expected = ([['0', '1', 1]], {1})
|
||||
self.assertEqual(expected, res)
|
||||
|
||||
@mock.patch('builtins.open')
|
||||
def test__get_hba_channel_scsi_target_open_oserror(
|
||||
self, mock_open):
|
||||
execute_effects, expected_cmds = self._get_expected_info(
|
||||
targets=2, remote_scan=True)
|
||||
mock_open = mock_open.return_value.__enter__.return_value
|
||||
mock_open.read.side_effect = ['1\n', OSError()]
|
||||
hbas, con_props = self.__get_rescan_info()
|
||||
|
||||
with mock.patch.object(self.lfc, '_execute',
|
||||
side_effect=execute_effects) as execute_mock:
|
||||
res = self.lfc._get_hba_channel_scsi_target_lun(hbas[0], con_props)
|
||||
execute_mock.assert_has_calls(expected_cmds)
|
||||
expected = ([['0', '1', 1]], set())
|
||||
self.assertEqual(expected, res)
|
||||
|
||||
def test__get_target_fc_transport_path(self):
|
||||
path = '/sys/class/fc_transport/target6:'
|
||||
execute_results = ('/sys/class/fc_transport/target6:0:1/port_name\n',
|
||||
'')
|
||||
|
||||
_, con_props = self.__get_rescan_info()
|
||||
with mock.patch.object(self.lfc, '_execute',
|
||||
return_value=execute_results) as execute_mock:
|
||||
ctl = self.lfc._get_target_fc_transport_path(
|
||||
path, con_props['target_wwn'][0], 1)
|
||||
execute_mock.assert_called_once_with(
|
||||
'grep -Gil "514f0c50023f6c00" '
|
||||
'/sys/class/fc_transport/target6:*/port_name',
|
||||
shell=True)
|
||||
self.assertEqual(['0', '1', 1], ctl)
|
||||
|
||||
@mock.patch('builtins.open')
|
||||
def test__get_target_fc_remote_ports_path(self, mock_open):
|
||||
path = '/sys/class/fc_remote_ports/rport-6:'
|
||||
execute_results = [
|
||||
('/sys/class/fc_remote_ports/rport-6:0-1/port_name\n', ''),
|
||||
('1\n', ''),
|
||||
]
|
||||
scsi_target_path = (
|
||||
'/sys/class/fc_remote_ports/rport-6:0-1/scsi_target_id')
|
||||
mock_open.return_value.__enter__.return_value.read.return_value = (
|
||||
'1\n')
|
||||
hbas, con_props = self.__get_rescan_info()
|
||||
with mock.patch.object(self.lfc, '_execute',
|
||||
side_effect=execute_results) as execute_mock:
|
||||
ctl = self.lfc._get_target_fc_remote_ports_path(
|
||||
path, con_props['target_wwn'][0], 1)
|
||||
expected_cmds = [
|
||||
mock.call(
|
||||
'grep -Gil "514f0c50023f6c00" '
|
||||
'/sys/class/fc_remote_ports/rport-6:*/port_name',
|
||||
shell=True),
|
||||
]
|
||||
execute_mock.assert_has_calls(expected_cmds)
|
||||
mock_open.assert_called_once_with(scsi_target_path)
|
||||
|
||||
self.assertEqual(['0', '1', 1], ctl)
|
||||
|
||||
def test_rescan_hosts_initiator_map(self):
|
||||
"""Test FC rescan with initiator map and not every HBA connected."""
|
||||
get_chan_results = [([['2', '3', 1], ['4', '5', 1]], set()),
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
fixes:
|
||||
- |
|
||||
FC connector `bug #2051237
|
||||
<https://bugs.launchpad.net/os-brick/+bug/2051237>`_: Fix
|
||||
issue with fibre channel connector scanning partial targets.
|
||||
We search for target information in sysfs, first in fc_transport
|
||||
and then in fc_report_ports.
|
Loading…
Reference in New Issue