Skip to content

Commit ede9108

Browse files
committed
Avoid using lvmohba/lvmoiscsi LUNs for other SR tests
Add a WWN field to BlockDeviceInfo (populated from lsblk for local disks, and from the DM alias for mpath devices). In the disks fixture, use WWNs to: - Mark a LUN unavailable on all hosts if it is already in use on any host (cross-host deduplication for shared FC/iSCSI LUNs). - Sort LUNs listed in LVMOHBA_DEVICE_CONFIG or LVMOISCSI_DEVICE_CONFIG to the end of each host's disk list, so they are only selected by other tests when no other disk is available. Signed-off-by: Gaëtan Lehmann <gaetan.lehmann@vates.tech>
1 parent 0cda409 commit ede9108

2 files changed

Lines changed: 46 additions & 2 deletions

File tree

conftest.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import pytest
44

5+
import dataclasses
56
import itertools
67
import logging
78
import os
@@ -414,6 +415,42 @@ def _host_disks(host: Host, hosts_cli_disks: list[DiskDevName] | None) -> Iterab
414415
ret = {host: list(_host_disks(host, cli_disks.get(host.hostname_or_ip)))
415416
for host in pools_hosts_by_name_or_ip.values()
416417
}
418+
# Cross-host deduplication: a LUN in use on any host (same WWN) is unavailable on all hosts.
419+
# This matters for shared FC/iSCSI LUNs visible on multiple hosts simultaneously.
420+
used_wwns = {
421+
disk.wwn
422+
for host_disks in ret.values()
423+
for disk in host_disks
424+
if disk.wwn and not disk.available
425+
}
426+
if used_wwns:
427+
logging.debug("cross-host used WWNs: %s", used_wwns)
428+
ret = {
429+
host: [
430+
dataclasses.replace(disk, available=False) if (disk.wwn and disk.wwn in used_wwns) else disk
431+
for disk in host_disks
432+
]
433+
for host, host_disks in ret.items()
434+
}
435+
# LUNs reserved for lvmohba/lvmoiscsi: sort them to the end so they are
436+
# only picked if no other disk is available.
437+
reserved_wwns: set[str] = set()
438+
try:
439+
import data
440+
for key in ('LVMOHBA_DEVICE_CONFIG', 'LVMOISCSI_DEVICE_CONFIG'):
441+
cfg = getattr(data, key, None)
442+
if isinstance(cfg, dict):
443+
scsiid = cfg.get('SCSIid', '').lower().lstrip('0x')
444+
if scsiid:
445+
reserved_wwns.add(scsiid)
446+
except ImportError:
447+
pass
448+
if reserved_wwns:
449+
logging.debug("reserved WWNs (lvmohba/lvmoiscsi): %s", reserved_wwns)
450+
ret = {
451+
host: sorted(host_disks, key=lambda d: d.wwn in reserved_wwns)
452+
for host, host_disks in ret.items()
453+
}
417454
logging.debug("disks collected: %s", {host.hostname_or_ip: value for host, value in ret.items()})
418455
return ret
419456

lib/host.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ class BlockDeviceInfo:
6363
log_sec: int # logical sector size; 0 for md/mpath
6464
type: str # "disk", "md", "mpath"
6565
available: bool # not mounted, not member of md/lvm/mpath/zfs
66+
wwn: str = '' # LUN WWN (hex, no 0x prefix); same LUN has same WWN across hosts
6667

6768
block_devices_info: list[BlockDeviceInfo]
6869

@@ -651,7 +652,7 @@ def rescan_block_devices_info(self) -> None:
651652
"""
652653
# Majors: 8=SCSI/SATA, 65-71,128-135=SCSI extended, 259=NVMe/blkext
653654
LOCAL_MAJORS = '8,65,66,67,68,69,70,71,128,129,130,131,132,133,134,135,259'
654-
LSBLK_FIELDS = 'NAME,KNAME,PKNAME,SIZE,LOG-SEC,TYPE'
655+
LSBLK_FIELDS = 'NAME,KNAME,PKNAME,SIZE,LOG-SEC,TYPE,WWN'
655656

656657
devices: list[Host.BlockDeviceInfo] = []
657658

@@ -672,13 +673,16 @@ def rescan_block_devices_info(self) -> None:
672673
disk_name = r['name']
673674
dev = f'/dev/{disk_name}'
674675
available = self._disk_is_available_local(disk_name)
676+
raw_wwn = r.get('wwn', '').strip()
677+
wwn = raw_wwn[2:] if raw_wwn.startswith('0x') else raw_wwn
675678
devices.append(Host.BlockDeviceInfo(
676679
name=disk_name,
677680
path=dev,
678681
size=int(r['size']),
679682
log_sec=int(r['log-sec']),
680683
type='disk',
681684
available=available,
685+
wwn=wwn,
682686
))
683687

684688
# --- mdadm arrays ---
@@ -722,16 +726,19 @@ def rescan_block_devices_info(self) -> None:
722726
if not r or r.get('type') != 'mpath':
723727
continue
724728
dm_name = r['name'] # e.g. "dm-3"
725-
dm_alias = r.get('dm-name', '').strip() # e.g. "mpathb"
729+
dm_alias = r.get('dm-name', '').strip() # e.g. "mpathb" or "3600507681381022548000000000001ec"
726730
path = f'/dev/mapper/{dm_alias}' if dm_alias else f'/dev/{dm_name}'
727731
mountpoint = self.ssh(f'lsblk --noheadings -o MOUNTPOINT /dev/{dm_name} 2>/dev/null || true').strip()
732+
# DM alias is the LUN WWN when multipath names the device after it (all-hex, ≥16 chars)
733+
wwn = dm_alias if re.fullmatch(r'[0-9a-f]{16,}', dm_alias) else ''
728734
devices.append(Host.BlockDeviceInfo(
729735
name=dm_name,
730736
path=path,
731737
size=int(r['size']),
732738
log_sec=int(r.get('log-sec', '0') or '0'),
733739
type='mpath',
734740
available=len(mountpoint) == 0,
741+
wwn=wwn,
735742
))
736743

737744
self.block_devices_info = sorted(devices, key=lambda d: d.name)

0 commit comments

Comments
 (0)