Leverage the iSCSI mpath to get the WWN

Now that we search the multipath device even if we haven't been able to
find the WWN in the sysfs we can leverage the multipath daemon
information on sysfs to get the WWN.

Pass the mpath to "get_sysfs_wwn" method where we check the sysfs to get
the WWN.

Conflicts:
	os_brick/tests/initiator/connectors/test_iscsi.py
	os_brick/tests/initiator/test_linuxscsi.py
The tests required a few fixes to account for the differences between
the branches and the changes introduced by the backports this one
builds upon.

Change-Id: Id1905bc174b8f2f3a345664d8a0a05284ca69927
(cherry picked from commit 0cdd9bbbe2)
(cherry picked from commit 31c01b543c)
This commit is contained in:
Gorka Eguileor 2020-06-01 19:07:47 +02:00 committed by Luigi Toscano
parent 57ac89910e
commit 609f0bcf83
4 changed files with 46 additions and 3 deletions

View File

@ -737,7 +737,7 @@ class ISCSIConnector(base.BaseLinuxConnector, base_iscsi.BaseISCSIConnector):
data['failed_logins'])):
# We have devices but we don't know the wwn yet
if not wwn and found:
wwn = self._linuxscsi.get_sysfs_wwn(found)
wwn = self._linuxscsi.get_sysfs_wwn(found, mpath)
if not mpath and found:
mpath = self._linuxscsi.find_sysfs_multipath_dm(found)
# We have the wwn but not a multipath
@ -778,6 +778,8 @@ class ISCSIConnector(base.BaseLinuxConnector, base_iscsi.BaseISCSIConnector):
if not mpath:
LOG.warning('No dm was created, connection to volume is probably '
'bad and will perform poorly.')
elif not wwn:
wwn = self._linuxscsi.get_sysfs_wwn(found, mpath)
return self._get_connect_result(connection_properties, wwn, found,
mpath)

View File

@ -119,8 +119,20 @@ class LinuxSCSI(executor.Executor):
return dev_info
def get_sysfs_wwn(self, device_names):
def get_sysfs_wwn(self, device_names, mpath=None):
"""Return the wwid from sysfs in any of devices in udev format."""
# If we have a multipath DM we know that it has found the WWN
if mpath:
# We have the WWN in /uuid even with friendly names, unline /name
try:
with open('/sys/block/%s/dm/uuid' % mpath) as f:
# Contents are matph-WWN, so get the part we want
wwid = f.read().strip()[6:]
if wwid: # Check should not be needed, but just in case
return wwid
except Exception as exc:
LOG.warning('Failed to read the DM uuid: %s', exc)
wwid = self.get_sysfs_wwid(device_names)
glob_str = '/dev/disk/by-id/scsi-'
wwn_paths = glob.glob(glob_str + '*')

View File

@ -1206,6 +1206,8 @@ Setting up iSCSI targets: unused
result = list(get_wwn_mock.call_args[0][0])
result.sort()
self.assertEqual(['sda', 'sdb', 'sdc', 'sdd'], result)
# Check we pass the mpath
self.assertIsNone(get_wwn_mock.call_args[0][1])
add_wwid_mock.assert_called_once_with('wwn')
self.assertNotEqual(0, add_path_mock.call_count)
self.assertGreaterEqual(find_dm_mock.call_count, 2)
@ -1238,10 +1240,13 @@ Setting up iSCSI targets: unused
'path': '/dev/dm-0'}
self.assertEqual(expected, res)
self.assertGreaterEqual(get_wwn_mock.call_count, 2)
self.assertGreaterEqual(get_wwn_mock.call_count, 3)
result = list(get_wwn_mock.call_args[0][0])
result.sort()
self.assertEqual(['sda', 'sdb', 'sdc', 'sdd'], result)
# Initially mpath we pass is None, but on last call is the mpath
mpath_values = [c[1][1] for c in get_wwn_mock._mock_mock_calls]
self.assertEqual([None, None, 'dm-0'], mpath_values[0:3])
add_wwid_mock.assert_not_called()
add_path_mock.assert_not_called()
self.assertGreaterEqual(find_dm_mock.call_count, 2)

View File

@ -848,6 +848,16 @@ loop0 0"""
mock_exec.assert_called_once_with(
'multipathd', 'show', 'status', run_as_root=True, root_helper=None)
@mock.patch('six.moves.builtins.open')
def test_get_sysfs_wwn_mpath(self, open_mock):
wwn = '3600d0230000000000e13955cc3757800'
cm_open = open_mock.return_value.__enter__.return_value
cm_open.read.return_value = 'mpath-' + wwn
res = self.linuxscsi.get_sysfs_wwn(mock.sentinel.device_names, 'dm-1')
open_mock.assert_called_once_with('/sys/block/dm-1/dm/uuid')
self.assertEqual(wwn, res)
@mock.patch('glob.glob')
@mock.patch.object(linuxscsi.LinuxSCSI, 'get_sysfs_wwid')
def test_get_sysfs_wwn_single_designator(self, get_wwid_mock, glob_mock):
@ -859,6 +869,20 @@ loop0 0"""
glob_mock.assert_called_once_with('/dev/disk/by-id/scsi-*')
get_wwid_mock.assert_called_once_with(mock.sentinel.device_names)
@mock.patch('six.moves.builtins.open', side_effect=Exception)
@mock.patch('glob.glob')
@mock.patch.object(linuxscsi.LinuxSCSI, 'get_sysfs_wwid')
def test_get_sysfs_wwn_mpath_exc(self, get_wwid_mock, glob_mock,
open_mock):
glob_mock.return_value = ['/dev/disk/by-id/scsi-wwid1',
'/dev/disk/by-id/scsi-wwid2']
get_wwid_mock.return_value = 'wwid1'
res = self.linuxscsi.get_sysfs_wwn(mock.sentinel.device_names, 'dm-1')
open_mock.assert_called_once_with('/sys/block/dm-1/dm/uuid')
self.assertEqual('wwid1', res)
glob_mock.assert_called_once_with('/dev/disk/by-id/scsi-*')
get_wwid_mock.assert_called_once_with(mock.sentinel.device_names)
@mock.patch('os.listdir', return_value=['sda', 'sdd'])
@mock.patch('os.path.realpath', side_effect=('/other/path',
'/dev/dm-5',