Skip to content

Commit 20bf7c4

Browse files
MarkSymsCtxWescoeur
authored andcommitted
CA-411163: verify SCSI ids for SR PVs
If the iSCSI target exposes multiple LUNs which contain Volume Groups with the same ID as is required by an SR it is somewhat non-deterministic as to which actual PV will be used by the LVM subsystem when attaching the SR. To prevent unexpected failures, detect this condition and refuse to attach the SR. Signed-off-by: Mark Syms <mark.syms@cloud.com>
1 parent 2e919bc commit 20bf7c4

5 files changed

Lines changed: 53 additions & 0 deletions

File tree

drivers/LVHDoISCSISR.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,11 +478,21 @@ def attach(self, sr_uuid):
478478
scsiutil.rescan([self.iscsi.adapter[a]])
479479

480480
self._pathrefresh(LVHDoISCSISR)
481+
482+
# Check that we only have PVs for the volume group with the expected SCSI ID
483+
lvutil.checkPVScsiIds(self.vgname, self.SCSIid)
484+
481485
LVHDSR.LVHDSR.attach(self, sr_uuid)
482486
except Exception as inst:
483487
for i in self.iscsiSRs:
484488
i.detach(sr_uuid)
489+
490+
# If we already have a proper error just raise it
491+
if isinstance(inst, xs_errors.SROSError):
492+
raise
493+
485494
raise xs_errors.XenError("SRUnavailable", opterr=inst)
495+
486496
self._setMultipathableFlag(SCSIid=self.SCSIid)
487497

488498
def detach(self, sr_uuid):

drivers/XE_SR_ERRORCODES.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,12 @@
513513
<value>117</value>
514514
</code>
515515

516+
<code>
517+
<name>PVMultiIDs</name>
518+
<description>PVs found with multiple SCSI IDs</description>
519+
<value>119</value>
520+
</code>
521+
516522
<!-- Agent database query errors 150+ -->
517523
<code>
518524
<name>APISession</name>

drivers/lvutil.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import errno
2323
import time
2424

25+
import scsiutil
2526
from fairlock import Fairlock
2627
import util
2728
import xs_errors
@@ -589,6 +590,19 @@ def setActiveVG(path, active):
589590
text = cmd_lvm([CMD_VGCHANGE, "-a" + val, path])
590591

591592

593+
def checkPVScsiIds(vgname, SCSIid):
594+
# Get all the PVs for the specified vgName even if not active
595+
cmd = [CMD_PVS, '-a', '--select', f'vgname={vgname}', '--no-headings']
596+
text = cmd_lvm(cmd)
597+
pv_paths = [x.split()[0] for x in text.splitlines()]
598+
for pv_path in pv_paths:
599+
pv_scsi_id = scsiutil.getSCSIid(pv_path)
600+
if pv_scsi_id != SCSIid:
601+
raise xs_errors.XenError(
602+
'PVMultiIDs',
603+
opterr=f'Found PVs {",".join(pv_paths)} and unexpected '
604+
f'SCSI ID {pv_scsi_id}, expected {SCSIid}')
605+
592606
@lvmretry
593607
def create(name, size, vgname, tag=None, size_in_percentage=None):
594608
if size_in_percentage:

tests/test_LVHDoISCSISR.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,9 @@ def deepcopy(to_copy):
157157
lvlock_patcher = mock.patch('LVHDSR.lvutil.Fairlock')
158158
self.mock_lvlock = lvlock_patcher.start()
159159

160+
pv_check_patcher = mock.patch('LVHDoISCSISR.lvutil.checkPVScsiIds', autospec=True)
161+
self.mock_pv_check = pv_check_patcher.start()
162+
160163
self.addCleanup(mock.patch.stopall)
161164

162165
super().setUp()

tests/test_lvutil.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import testlib
77
import lvmlib
88
import util
9+
import xs_errors
910

1011
import lvutil
1112

@@ -393,3 +394,22 @@ def test_command_error(self, mock_smlog, mock_cmd_lvm):
393394
mock.call("PVs in VG vg1: []")
394395
])
395396
mock_smlog.assert_called_with("PVs in VG vg1: []")
397+
398+
@mock.patch('lvutil.scsiutil.getSCSIid', autospec=True)
399+
def test_check_PV_SCSI_IDs_failure(self, mock_get_scsi_id, mock_smlog, mock_cmd_lvm):
400+
mock_cmd_lvm.return_value = """ /dev/disk/by-id/scsi-360014057b7f26e2962843fa8a0645fbd VG_XenStorage-401d198b-60ab-1f21-1359-bd4f127b8f38 lvm2 d-- 0 0
401+
/dev/disk/by-id/scsi-36001405fdd436fa7f854cd685fc3b1fd VG_XenStorage-401d198b-60ab-1f21-1359-bd4f127b8f38 lvm2 a-- <49.99g 49.98g
402+
""" # noqa: E501
403+
mock_get_scsi_id.side_effect = ['36001405fdd436fa7f854cd685fc3b1fd',
404+
'360014057b7f26e2962843fa8a0645fbd']
405+
with self.assertRaises(xs_errors.SROSError) as srose:
406+
lvutil.checkPVScsiIds('VG_XenStorage-401d198b-60ab-1f21-1359-bd4f127b8f38',
407+
'36001405fdd436fa7f854cd685fc3b1fd')
408+
self.assertEqual(119, srose.exception.errno)
409+
410+
@mock.patch('lvutil.scsiutil.getSCSIid', autospec=True)
411+
def test_check_PV_SCSI_IDs_success(self, mock_get_scsi_id, mock_smlog, mock_cmd_lvm):
412+
mock_cmd_lvm.return_value = """ /dev/disk/by-id/scsi-360014057b7f26e2962843fa8a0645fbd VG_XenStorage-401d198b-60ab-1f21-1359-bd4f127b8f38 lvm2 d-- 0 0""" # noqa: E501
413+
mock_get_scsi_id.side_effect = ['36001405fdd436fa7f854cd685fc3b1fd']
414+
lvutil.checkPVScsiIds('VG_XenStorage-401d198b-60ab-1f21-1359-bd4f127b8f38',
415+
'36001405fdd436fa7f854cd685fc3b1fd')

0 commit comments

Comments
 (0)