Verify WWN of connected iSCSI devices if passed

If a WWN has been provided in connection_properties, verify that the
found devices have that expected WWN. Fail the attachment if not. This
prevents cases where a device already exists on the host from an old
attachment that wasn't fully cleaned up, and the new attachment got
the same LUN. Using this old device could lead to data corruption.

Change-Id: I45a2221c0518213dc8132831c0bde9db4734da2b
Closes-Bug: 1813609
This commit is contained in:
Avishay Traeger 2019-01-29 10:10:50 +02:00
parent 322554c386
commit 14be08d0b5
5 changed files with 39 additions and 0 deletions

View File

@ -153,6 +153,11 @@ class InvalidIOHandleObject(BrickException):
'type %(actual_type)s.')
class VolumeDeviceValidationFailed(BrickException):
message = _("Volume device validation failed for device %(device)s "
"(expected %(expected)s, found %(found)s.")
class VolumeEncryptionNotSupported(Invalid):
message = _("Volume encryption is not supported for %(volume_type)s "
"volume %(volume_id)s.")

View File

@ -538,6 +538,9 @@ class ISCSIConnector(base.BaseLinuxConnector, base_iscsi.BaseISCSIConnector):
return symlink
def _get_connect_result(self, con_props, wwn, devices_names, mpath=None):
if 'wwn' in con_props:
self._linuxscsi.verify_sysfs_wwns(devices_names, con_props['wwn'])
device = '/dev/' + (mpath or devices_names[0])
# NOTE(geguileo): This is only necessary because of the current

View File

@ -154,6 +154,16 @@ class LinuxSCSI(executor.Executor):
return udev_wwid
return ''
def verify_sysfs_wwns(self, device_names, expected_wwn):
"""Verify that all specified devices have the expected WWN."""
for device_name in device_names:
found_wwn = self.get_sysfs_wwn([device_name])
if found_wwn != expected_wwn:
raise exception.VolumeDeviceValidationFailed(
device=device_name, expected=expected_wwn,
found=found_wwn)
def get_scsi_wwn(self, path):
"""Read the WWN from page 0x83 value for a SCSI device."""

View File

@ -920,6 +920,18 @@ loop0 0"""
open_mock.assert_has_calls([mock.call('/sys/block/sda/device/wwid'),
mock.call('/sys/block/sdb/device/wwid')])
@mock.patch.object(linuxscsi.LinuxSCSI, 'get_sysfs_wwn')
def test_verify_sysfs_wwns_valid(self, get_wwn):
get_wwn.side_effect = ['123', '123', '123', '123']
self.linuxscsi.verify_sysfs_wwns(['sda', 'sdb', 'sdc', 'sdd'], '123')
@mock.patch.object(linuxscsi.LinuxSCSI, 'get_sysfs_wwn')
def test_verify_sysfs_wwns_invalid(self, get_wwn):
get_wwn.side_effect = ['123', '456', '123', '123']
self.assertRaises(exception.VolumeDeviceValidationFailed,
self.linuxscsi.verify_sysfs_wwns,
['sda', 'sdb', 'sdc', 'sdd'], '123')
@mock.patch.object(linuxscsi.priv_rootwrap, 'unlink_root')
@mock.patch('glob.glob')
@mock.patch('os.path.realpath', side_effect=['/dev/sda', '/dev/sdb',

View File

@ -0,0 +1,9 @@
---
fixes:
- |
Adds verification that found iSCSI devices have the expected WWN
(must be provided in connection_properties). The attachment fails if
the WWNs do not match. This prevents cases where a device already
exists on the host from an old attachment that wasn't fully cleaned
up, and the new attachment got the same LUN. Using this old device
could lead to data corruption.