Skip to content

Commit 3845b8f

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 47d74f3 commit 3845b8f

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
@@ -3,6 +3,7 @@
33
import pytest
44

55
import argparse
6+
import dataclasses
67
import itertools
78
import logging
89
import os
@@ -435,6 +436,42 @@ def _host_disks(host: Host, hosts_cli_disks: list[DiskDevName] | None) -> Iterab
435436
ret = {host: list(_host_disks(host, cli_disks.get(host.hostname_or_ip)))
436437
for host in pools_hosts_by_name_or_ip.values()
437438
}
439+
# Cross-host deduplication: a LUN in use on any host (same WWN) is unavailable on all hosts.
440+
# This matters for shared FC/iSCSI LUNs visible on multiple hosts simultaneously.
441+
used_wwns = {
442+
disk.wwn
443+
for host_disks in ret.values()
444+
for disk in host_disks
445+
if disk.wwn and not disk.available
446+
}
447+
if used_wwns:
448+
logging.debug("cross-host used WWNs: %s", used_wwns)
449+
ret = {
450+
host: [
451+
dataclasses.replace(disk, available=False) if (disk.wwn and disk.wwn in used_wwns) else disk
452+
for disk in host_disks
453+
]
454+
for host, host_disks in ret.items()
455+
}
456+
# LUNs reserved for lvmohba/lvmoiscsi: sort them to the end so they are
457+
# only picked if no other disk is available.
458+
reserved_wwns: set[str] = set()
459+
try:
460+
import data
461+
for key in ('LVMOHBA_DEVICE_CONFIG', 'LVMOISCSI_DEVICE_CONFIG'):
462+
cfg = getattr(data, key, None)
463+
if isinstance(cfg, dict):
464+
scsiid = cfg.get('SCSIid', '').lower().lstrip('0x')
465+
if scsiid:
466+
reserved_wwns.add(scsiid)
467+
except ImportError:
468+
pass
469+
if reserved_wwns:
470+
logging.debug("reserved WWNs (lvmohba/lvmoiscsi): %s", reserved_wwns)
471+
ret = {
472+
host: sorted(host_disks, key=lambda d: d.wwn in reserved_wwns)
473+
for host, host_disks in ret.items()
474+
}
438475
logging.debug("disks collected: %s", {host.hostname_or_ip: value for host, value in ret.items()})
439476
return ret
440477

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 ---
@@ -742,16 +746,19 @@ def rescan_block_devices_info(self) -> None:
742746
if not r or r.get('type') != 'mpath':
743747
continue
744748
dm_name = r['name'] # e.g. "dm-3"
745-
dm_alias = r.get('dm-name', '').strip() # e.g. "mpathb"
749+
dm_alias = r.get('dm-name', '').strip() # e.g. "mpathb" or "3600507681381022548000000000001ec"
746750
path = f'/dev/mapper/{dm_alias}' if dm_alias else f'/dev/{dm_name}'
747751
mountpoint = self.ssh(f'lsblk --noheadings -o MOUNTPOINT /dev/{dm_name}').strip()
752+
# DM alias is the LUN WWN when multipath names the device after it (all-hex, ≥16 chars)
753+
wwn = dm_alias if re.fullmatch(r'[0-9a-f]{16,}', dm_alias) else ''
748754
devices.append(Host.BlockDeviceInfo(
749755
name=dm_name,
750756
path=path,
751757
size=int(r['size']),
752758
log_sec=int(r.get('log-sec', '0')),
753759
type='mpath',
754760
available=len(mountpoint) == 0,
761+
wwn=wwn,
755762
))
756763

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

0 commit comments

Comments
 (0)