Skip to content

Commit 483adb0

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 01ddebb commit 483adb0

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
@@ -425,6 +426,42 @@ def _host_disks(host: Host, hosts_cli_disks: list[DiskDevName] | None) -> Iterab
425426
ret = {host: list(_host_disks(host, cli_disks.get(host.hostname_or_ip)))
426427
for host in pools_hosts_by_name_or_ip.values()
427428
}
429+
# Cross-host deduplication: a LUN in use on any host (same WWN) is unavailable on all hosts.
430+
# This matters for shared FC/iSCSI LUNs visible on multiple hosts simultaneously.
431+
used_wwns = {
432+
disk.wwn
433+
for host_disks in ret.values()
434+
for disk in host_disks
435+
if disk.wwn and not disk.available
436+
}
437+
if used_wwns:
438+
logging.debug("cross-host used WWNs: %s", used_wwns)
439+
ret = {
440+
host: [
441+
dataclasses.replace(disk, available=False) if (disk.wwn and disk.wwn in used_wwns) else disk
442+
for disk in host_disks
443+
]
444+
for host, host_disks in ret.items()
445+
}
446+
# LUNs reserved for lvmohba/lvmoiscsi: sort them to the end so they are
447+
# only picked if no other disk is available.
448+
reserved_wwns: set[str] = set()
449+
try:
450+
import data
451+
for key in ('LVMOHBA_DEVICE_CONFIG', 'LVMOISCSI_DEVICE_CONFIG'):
452+
cfg = getattr(data, key, None)
453+
if isinstance(cfg, dict):
454+
scsiid = cfg.get('SCSIid', '').lower().lstrip('0x')
455+
if scsiid:
456+
reserved_wwns.add(scsiid)
457+
except ImportError:
458+
pass
459+
if reserved_wwns:
460+
logging.debug("reserved WWNs (lvmohba/lvmoiscsi): %s", reserved_wwns)
461+
ret = {
462+
host: sorted(host_disks, key=lambda d: d.wwn in reserved_wwns)
463+
for host, host_disks in ret.items()
464+
}
428465
logging.debug("disks collected: %s", {host.hostname_or_ip: value for host, value in ret.items()})
429466
return ret
430467

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

@@ -677,7 +678,7 @@ def rescan_block_devices_info(self) -> None:
677678
"""
678679
# Majors: 8=SCSI/SATA, 65-71,128-135=SCSI extended, 259=NVMe/blkext
679680
LOCAL_MAJORS = '8,65,66,67,68,69,70,71,128,129,130,131,132,133,134,135,259'
680-
LSBLK_FIELDS = 'NAME,KNAME,PKNAME,SIZE,LOG-SEC,TYPE'
681+
LSBLK_FIELDS = 'NAME,KNAME,PKNAME,SIZE,LOG-SEC,TYPE,WWN'
681682

682683
devices: list[Host.BlockDeviceInfo] = []
683684

@@ -698,13 +699,16 @@ def rescan_block_devices_info(self) -> None:
698699
disk_name = r['name']
699700
dev = f'/dev/{disk_name}'
700701
available = self._disk_is_available_local(disk_name)
702+
raw_wwn = r.get('wwn', '').strip()
703+
wwn = raw_wwn[2:] if raw_wwn.startswith('0x') else raw_wwn
701704
devices.append(Host.BlockDeviceInfo(
702705
name=disk_name,
703706
path=dev,
704707
size=int(r['size']),
705708
log_sec=int(r['log-sec']),
706709
type='disk',
707710
available=available,
711+
wwn=wwn,
708712
))
709713

710714
# --- mdadm arrays ---
@@ -748,16 +752,19 @@ def rescan_block_devices_info(self) -> None:
748752
if not r or r.get('type') != 'mpath':
749753
continue
750754
dm_name = r['name'] # e.g. "dm-3"
751-
dm_alias = r.get('dm-name', '').strip() # e.g. "mpathb"
755+
dm_alias = r.get('dm-name', '').strip() # e.g. "mpathb" or "3600507681381022548000000000001ec"
752756
path = f'/dev/mapper/{dm_alias}' if dm_alias else f'/dev/{dm_name}'
753757
mountpoint = self.ssh(f'lsblk --noheadings -o MOUNTPOINT /dev/{dm_name} 2>/dev/null || true').strip()
758+
# DM alias is the LUN WWN when multipath names the device after it (all-hex, ≥16 chars)
759+
wwn = dm_alias if re.fullmatch(r'[0-9a-f]{16,}', dm_alias) else ''
754760
devices.append(Host.BlockDeviceInfo(
755761
name=dm_name,
756762
path=path,
757763
size=int(r['size']),
758764
log_sec=int(r.get('log-sec', '0') or '0'),
759765
type='mpath',
760766
available=len(mountpoint) == 0,
767+
wwn=wwn,
761768
))
762769

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

0 commit comments

Comments
 (0)