From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [45.144.208.40]) by lore.proxmox.com (Postfix) with ESMTPS id 3DC211FF0ED for ; Fri, 31 Jul 2026 12:23:02 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id 6139121640; Fri, 31 Jul 2026 12:22:05 +0200 (CEST) From: Dietmar Maurer To: pve-devel@lists.proxmox.com Subject: [RFC pve-storage 02/27] diskmanage: add helper to list multipath devices Date: Fri, 31 Jul 2026 12:21:31 +0200 Message-ID: <20260731102156.3947857-3-dietmar@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260731102156.3947857-1-dietmar@proxmox.com> References: <20260731102156.3947857-1-dietmar@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 2 AWL -0.683 Adjusted score from AWL reputation of From: address DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment (newer systems) KAM_LAZY_DOMAIN_SECURITY 1 Sending domain does not have any anti-forgery methods KAM_LOTSOFHASH 0.25 Emails with lots of hash-like gibberish POISEN_SPAM_PILL 0.1 Meta: its spam POISEN_SPAM_PILL_1 0.1 random spam to be learned in bayes POISEN_SPAM_PILL_3 0.1 random spam to be learned in bayes RDNS_NONE 1.274 Delivered to internal network by a host with no rDNS SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_NONE 0.001 SPF: sender does not publish an SPF Record Message-ID-Hash: ILOAL5F27NRGNIO5MHVCEFEVVGSI6DFE X-Message-ID-Hash: ILOAL5F27NRGNIO5MHVCEFEVVGSI6DFE X-MailFrom: dietmar@zilli.proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Multipath mapped devices are deliberately not part of get_disks, whose callers (node disk list, local storage creation, ceph OSDs) manage local disks only. The storage wizard however needs to offer SAN LUNs, which on production FC/SAS setups are usually multipath devices. Aggregate vendor, model and transport from the member paths and reuse the usage detection of get_disks, so callers can tell whether a LUN is unused, already an LVM physical volume or otherwise occupied. Signed-off-by: Dietmar Maurer --- src/PVE/Diskmanage.pm | 79 ++++++++++++++++++- src/test/disk_tests/multipath/disklist | 9 +++ .../multipath/disklist_expected.json | 74 +++++++++++++++++ src/test/disk_tests/multipath/dm-0/dm/name | 1 + src/test/disk_tests/multipath/dm-0/dm/uuid | 1 + src/test/disk_tests/multipath/dm-0/size | 1 + src/test/disk_tests/multipath/dm-0_slaves | 4 + src/test/disk_tests/multipath/dm-1/dm/name | 1 + src/test/disk_tests/multipath/dm-1/dm/uuid | 1 + src/test/disk_tests/multipath/dm-1/size | 1 + src/test/disk_tests/multipath/dm-1_slaves | 4 + src/test/disk_tests/multipath/dm-2/dm/name | 1 + src/test/disk_tests/multipath/dm-2/dm/uuid | 1 + src/test/disk_tests/multipath/dm-2/size | 1 + src/test/disk_tests/multipath/dm-2_slaves | 1 + src/test/disk_tests/multipath/dm-3/dm/name | 1 + src/test/disk_tests/multipath/dm-3/dm/uuid | 1 + src/test/disk_tests/multipath/dm-3/size | 1 + src/test/disk_tests/multipath/dm-3_slaves | 1 + src/test/disk_tests/multipath/dm-4/dm/name | 1 + src/test/disk_tests/multipath/dm-4/dm/uuid | 1 + src/test/disk_tests/multipath/dm-4/size | 1 + src/test/disk_tests/multipath/dm-4_slaves | 1 + src/test/disk_tests/multipath/lsblk | 63 +++++++++++++++ src/test/disk_tests/multipath/lvs | 0 src/test/disk_tests/multipath/mounts | 1 + .../multipath/multipath_expected.json | 59 ++++++++++++++ src/test/disk_tests/multipath/partlist | 0 src/test/disk_tests/multipath/pvs | 1 + .../disk_tests/multipath/sda/device/model | 1 + .../disk_tests/multipath/sda/device/vendor | 1 + .../disk_tests/multipath/sda/holders/holder | 1 + .../disk_tests/multipath/sda/queue/rotational | 1 + src/test/disk_tests/multipath/sda/size | 1 + src/test/disk_tests/multipath/sda_udevadm | 18 +++++ .../disk_tests/multipath/sdb/device/model | 1 + .../disk_tests/multipath/sdb/device/vendor | 1 + .../disk_tests/multipath/sdb/holders/holder | 1 + .../disk_tests/multipath/sdb/queue/rotational | 1 + src/test/disk_tests/multipath/sdb/size | 1 + src/test/disk_tests/multipath/sdb_udevadm | 18 +++++ .../disk_tests/multipath/sdc/device/model | 1 + .../disk_tests/multipath/sdc/device/vendor | 1 + .../disk_tests/multipath/sdc/holders/holder | 1 + .../disk_tests/multipath/sdc/queue/rotational | 1 + src/test/disk_tests/multipath/sdc/size | 1 + src/test/disk_tests/multipath/sdc_udevadm | 18 +++++ .../disk_tests/multipath/sdd/device/model | 1 + .../disk_tests/multipath/sdd/device/vendor | 1 + .../disk_tests/multipath/sdd/holders/holder | 1 + .../disk_tests/multipath/sdd/queue/rotational | 1 + src/test/disk_tests/multipath/sdd/size | 1 + src/test/disk_tests/multipath/sdd_udevadm | 18 +++++ src/test/disk_tests/multipath/zpool | 1 + src/test/disklist_test.pm | 49 +++++++++++- 55 files changed, 452 insertions(+), 2 deletions(-) create mode 100644 src/test/disk_tests/multipath/disklist create mode 100644 src/test/disk_tests/multipath/disklist_expected.json create mode 100644 src/test/disk_tests/multipath/dm-0/dm/name create mode 100644 src/test/disk_tests/multipath/dm-0/dm/uuid create mode 100644 src/test/disk_tests/multipath/dm-0/size create mode 100644 src/test/disk_tests/multipath/dm-0_slaves create mode 100644 src/test/disk_tests/multipath/dm-1/dm/name create mode 100644 src/test/disk_tests/multipath/dm-1/dm/uuid create mode 100644 src/test/disk_tests/multipath/dm-1/size create mode 100644 src/test/disk_tests/multipath/dm-1_slaves create mode 100644 src/test/disk_tests/multipath/dm-2/dm/name create mode 100644 src/test/disk_tests/multipath/dm-2/dm/uuid create mode 100644 src/test/disk_tests/multipath/dm-2/size create mode 100644 src/test/disk_tests/multipath/dm-2_slaves create mode 100644 src/test/disk_tests/multipath/dm-3/dm/name create mode 100644 src/test/disk_tests/multipath/dm-3/dm/uuid create mode 100644 src/test/disk_tests/multipath/dm-3/size create mode 100644 src/test/disk_tests/multipath/dm-3_slaves create mode 100644 src/test/disk_tests/multipath/dm-4/dm/name create mode 100644 src/test/disk_tests/multipath/dm-4/dm/uuid create mode 100644 src/test/disk_tests/multipath/dm-4/size create mode 100644 src/test/disk_tests/multipath/dm-4_slaves create mode 100644 src/test/disk_tests/multipath/lsblk create mode 100644 src/test/disk_tests/multipath/lvs create mode 100644 src/test/disk_tests/multipath/mounts create mode 100644 src/test/disk_tests/multipath/multipath_expected.json create mode 100644 src/test/disk_tests/multipath/partlist create mode 100644 src/test/disk_tests/multipath/pvs create mode 100644 src/test/disk_tests/multipath/sda/device/model create mode 100644 src/test/disk_tests/multipath/sda/device/vendor create mode 100644 src/test/disk_tests/multipath/sda/holders/holder create mode 100644 src/test/disk_tests/multipath/sda/queue/rotational create mode 100644 src/test/disk_tests/multipath/sda/size create mode 100644 src/test/disk_tests/multipath/sda_udevadm create mode 100644 src/test/disk_tests/multipath/sdb/device/model create mode 100644 src/test/disk_tests/multipath/sdb/device/vendor create mode 100644 src/test/disk_tests/multipath/sdb/holders/holder create mode 100644 src/test/disk_tests/multipath/sdb/queue/rotational create mode 100644 src/test/disk_tests/multipath/sdb/size create mode 100644 src/test/disk_tests/multipath/sdb_udevadm create mode 100644 src/test/disk_tests/multipath/sdc/device/model create mode 100644 src/test/disk_tests/multipath/sdc/device/vendor create mode 100644 src/test/disk_tests/multipath/sdc/holders/holder create mode 100644 src/test/disk_tests/multipath/sdc/queue/rotational create mode 100644 src/test/disk_tests/multipath/sdc/size create mode 100644 src/test/disk_tests/multipath/sdc_udevadm create mode 100644 src/test/disk_tests/multipath/sdd/device/model create mode 100644 src/test/disk_tests/multipath/sdd/device/vendor create mode 100644 src/test/disk_tests/multipath/sdd/holders/holder create mode 100644 src/test/disk_tests/multipath/sdd/queue/rotational create mode 100644 src/test/disk_tests/multipath/sdd/size create mode 100644 src/test/disk_tests/multipath/sdd_udevadm create mode 100644 src/test/disk_tests/multipath/zpool diff --git a/src/PVE/Diskmanage.pm b/src/PVE/Diskmanage.pm index c04408e..ed5181f 100644 --- a/src/PVE/Diskmanage.pm +++ b/src/PVE/Diskmanage.pm @@ -174,7 +174,7 @@ sub get_smart_data { } sub get_lsblk_info { - my $cmd = [$LSBLK, '--json', '-o', 'path,parttype,fstype,tran']; + my $cmd = [$LSBLK, '--json', '-o', 'path,parttype,fstype,tran,pttype']; my $output = ""; eval { run_command($cmd, outfunc => sub { $output .= "$_[0]\n"; }); @@ -192,6 +192,7 @@ sub get_lsblk_info { parttype => $_->{parttype}, fstype => $_->{fstype}, tran => $_->{tran}, + pttype => $_->{pttype}, } } @{$list} }; @@ -771,6 +772,82 @@ sub get_disks { return $disklist; } +# Lists multipath mapped devices with information aggregated from their member paths, keyed by +# their kernel device name (dm-X). These are deliberately not returned by get_disks, as its +# callers manage local disks only. +sub get_multipath_disks { + my $mounted = mounted_blockdevs(); + my $lsblk_info = get_lsblk_info(); + my $zfshash = get_zfs_devices($lsblk_info); + my $lvmhash = get_lvm_devices($lsblk_info); + + my $disklist = {}; + + dir_glob_foreach( + '/sys/block', + 'dm-\d+', + sub { + my ($dev) = @_; + my $sysdir = "/sys/block/$dev"; + + my $uuid = file_read_firstline("$sysdir/dm/uuid") // return; + return if $uuid !~ m/^mpath-(\S+)$/; + my $wwid = $1; + + my $name = file_read_firstline("$sysdir/dm/name") // return; + my $devpath = "/dev/mapper/$name"; + my $resolved_devpath = abs_path($devpath); + my @devpaths = ($devpath); + push @devpaths, $resolved_devpath + if defined($resolved_devpath) && $resolved_devpath ne $devpath; + + my $size = get_sysdir_size($sysdir) or return; + + my $slaves = []; + dir_glob_foreach("$sysdir/slaves", '[^.].*', sub { push @$slaves, $_[0]; }); + @$slaves = sort @$slaves; + + my ($vendor, $model, $transport) = ('unknown', 'unknown', undef); + if (my $first = $slaves->[0]) { + if (my $sysdata = get_sysdir_info("/sys/block/$first")) { + $vendor = $sysdata->{vendor}; + $model = $sysdata->{model}; + } + $transport = $lsblk_info->{"/dev/$first"}->{tran}; + } + + my $used; + $used = 'LVM' if grep { $lvmhash->{$_} } @devpaths; + $used //= 'ZFS' if grep { $zfshash->{$_} } @devpaths; + my $info = {}; + for my $path (@devpaths) { + $info = $lsblk_info->{$path} // next; + last; + } + $used //= "$info->{fstype}" if defined($info->{fstype}); + $used //= 'mounted' if grep { $mounted->{$_} } @devpaths; + $used //= 'partitions' + if defined($info->{pttype}) && $info->{pttype} ne ''; + # partition mappings and other stacked devices show up as holders + $used //= 'Device Mapper' if !dir_is_empty("$sysdir/holders"); + + $disklist->{$dev} = { + devpath => $devpath, + size => $size, + vendor => $vendor, + model => $model, + wwn => $wwid, + paths => scalar($slaves->@*), + slaves => [map { "/dev/$_" } $slaves->@*], + }; + $disklist->{$dev}->{transport} = $transport if defined($transport); + $disklist->{$dev}->{used} = $used if $used; + }, + ); + + return $disklist; +} + sub get_partnum { my ($part_path) = @_; diff --git a/src/test/disk_tests/multipath/disklist b/src/test/disk_tests/multipath/disklist new file mode 100644 index 0000000..9293589 --- /dev/null +++ b/src/test/disk_tests/multipath/disklist @@ -0,0 +1,9 @@ +sda +sdb +sdc +sdd +dm-0 +dm-1 +dm-2 +dm-3 +dm-4 diff --git a/src/test/disk_tests/multipath/disklist_expected.json b/src/test/disk_tests/multipath/disklist_expected.json new file mode 100644 index 0000000..a8e74fa --- /dev/null +++ b/src/test/disk_tests/multipath/disklist_expected.json @@ -0,0 +1,74 @@ +{ + "sda": { + "devpath": "/dev/sda", + "size": 10737418240, + "vendor": "SANVEND", + "model": "SANMODEL", + "serial": "SSERa", + "wwn": "0x600140500000000a", + "gpt": 0, + "rpm": -1, + "type": "unknown", + "health": "UNKNOWN", + "wearout": "N/A", + "osdid": -1, + "osdid-list": null, + "by_id_link": "/dev/disk/by-id/scsi-36001405000000000000000000000000a", + "transport": "fc", + "used": "Device Mapper" + }, + "sdb": { + "devpath": "/dev/sdb", + "size": 10737418240, + "vendor": "SANVEND", + "model": "SANMODEL", + "serial": "SSERb", + "wwn": "0x600140500000000b", + "gpt": 0, + "rpm": -1, + "type": "unknown", + "health": "UNKNOWN", + "wearout": "N/A", + "osdid": -1, + "osdid-list": null, + "by_id_link": "/dev/disk/by-id/scsi-36001405000000000000000000000000b", + "transport": "fc", + "used": "Device Mapper" + }, + "sdc": { + "devpath": "/dev/sdc", + "size": 10737418240, + "vendor": "SANVEND", + "model": "SANMODEL", + "serial": "SSERc", + "wwn": "0x600140500000000c", + "gpt": 0, + "rpm": -1, + "type": "unknown", + "health": "UNKNOWN", + "wearout": "N/A", + "osdid": -1, + "osdid-list": null, + "by_id_link": "/dev/disk/by-id/scsi-36001405000000000000000000000000c", + "transport": "fc", + "used": "Device Mapper" + }, + "sdd": { + "devpath": "/dev/sdd", + "size": 10737418240, + "vendor": "SANVEND", + "model": "SANMODEL", + "serial": "SSERd", + "wwn": "0x600140500000000d", + "gpt": 0, + "rpm": -1, + "type": "unknown", + "health": "UNKNOWN", + "wearout": "N/A", + "osdid": -1, + "osdid-list": null, + "by_id_link": "/dev/disk/by-id/scsi-36001405000000000000000000000000d", + "transport": "fc", + "used": "Device Mapper" + } +} diff --git a/src/test/disk_tests/multipath/dm-0/dm/name b/src/test/disk_tests/multipath/dm-0/dm/name new file mode 100644 index 0000000..0ed057a --- /dev/null +++ b/src/test/disk_tests/multipath/dm-0/dm/name @@ -0,0 +1 @@ +mpatha \ No newline at end of file diff --git a/src/test/disk_tests/multipath/dm-0/dm/uuid b/src/test/disk_tests/multipath/dm-0/dm/uuid new file mode 100644 index 0000000..094955a --- /dev/null +++ b/src/test/disk_tests/multipath/dm-0/dm/uuid @@ -0,0 +1 @@ +mpath-3600140500000000000000000000000001 \ No newline at end of file diff --git a/src/test/disk_tests/multipath/dm-0/size b/src/test/disk_tests/multipath/dm-0/size new file mode 100644 index 0000000..8280959 --- /dev/null +++ b/src/test/disk_tests/multipath/dm-0/size @@ -0,0 +1 @@ +20971520 \ No newline at end of file diff --git a/src/test/disk_tests/multipath/dm-0_slaves b/src/test/disk_tests/multipath/dm-0_slaves new file mode 100644 index 0000000..1637315 --- /dev/null +++ b/src/test/disk_tests/multipath/dm-0_slaves @@ -0,0 +1,4 @@ +. +.. +sda +sdb diff --git a/src/test/disk_tests/multipath/dm-1/dm/name b/src/test/disk_tests/multipath/dm-1/dm/name new file mode 100644 index 0000000..f70ac3d --- /dev/null +++ b/src/test/disk_tests/multipath/dm-1/dm/name @@ -0,0 +1 @@ +mpathb \ No newline at end of file diff --git a/src/test/disk_tests/multipath/dm-1/dm/uuid b/src/test/disk_tests/multipath/dm-1/dm/uuid new file mode 100644 index 0000000..7e8567b --- /dev/null +++ b/src/test/disk_tests/multipath/dm-1/dm/uuid @@ -0,0 +1 @@ +mpath-3600140500000000000000000000000002 \ No newline at end of file diff --git a/src/test/disk_tests/multipath/dm-1/size b/src/test/disk_tests/multipath/dm-1/size new file mode 100644 index 0000000..8280959 --- /dev/null +++ b/src/test/disk_tests/multipath/dm-1/size @@ -0,0 +1 @@ +20971520 \ No newline at end of file diff --git a/src/test/disk_tests/multipath/dm-1_slaves b/src/test/disk_tests/multipath/dm-1_slaves new file mode 100644 index 0000000..cde08b3 --- /dev/null +++ b/src/test/disk_tests/multipath/dm-1_slaves @@ -0,0 +1,4 @@ +. +.. +sdc +sdd diff --git a/src/test/disk_tests/multipath/dm-2/dm/name b/src/test/disk_tests/multipath/dm-2/dm/name new file mode 100644 index 0000000..4770de4 --- /dev/null +++ b/src/test/disk_tests/multipath/dm-2/dm/name @@ -0,0 +1 @@ +mpathc diff --git a/src/test/disk_tests/multipath/dm-2/dm/uuid b/src/test/disk_tests/multipath/dm-2/dm/uuid new file mode 100644 index 0000000..2d607ea --- /dev/null +++ b/src/test/disk_tests/multipath/dm-2/dm/uuid @@ -0,0 +1 @@ +mpath-3600140500000000000000000000000003 diff --git a/src/test/disk_tests/multipath/dm-2/size b/src/test/disk_tests/multipath/dm-2/size new file mode 100644 index 0000000..14faeec --- /dev/null +++ b/src/test/disk_tests/multipath/dm-2/size @@ -0,0 +1 @@ +20971520 diff --git a/src/test/disk_tests/multipath/dm-2_slaves b/src/test/disk_tests/multipath/dm-2_slaves new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/test/disk_tests/multipath/dm-2_slaves @@ -0,0 +1 @@ + diff --git a/src/test/disk_tests/multipath/dm-3/dm/name b/src/test/disk_tests/multipath/dm-3/dm/name new file mode 100644 index 0000000..a98ef69 --- /dev/null +++ b/src/test/disk_tests/multipath/dm-3/dm/name @@ -0,0 +1 @@ +mpathd diff --git a/src/test/disk_tests/multipath/dm-3/dm/uuid b/src/test/disk_tests/multipath/dm-3/dm/uuid new file mode 100644 index 0000000..75f25b8 --- /dev/null +++ b/src/test/disk_tests/multipath/dm-3/dm/uuid @@ -0,0 +1 @@ +mpath-3600140500000000000000000000000004 diff --git a/src/test/disk_tests/multipath/dm-3/size b/src/test/disk_tests/multipath/dm-3/size new file mode 100644 index 0000000..14faeec --- /dev/null +++ b/src/test/disk_tests/multipath/dm-3/size @@ -0,0 +1 @@ +20971520 diff --git a/src/test/disk_tests/multipath/dm-3_slaves b/src/test/disk_tests/multipath/dm-3_slaves new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/test/disk_tests/multipath/dm-3_slaves @@ -0,0 +1 @@ + diff --git a/src/test/disk_tests/multipath/dm-4/dm/name b/src/test/disk_tests/multipath/dm-4/dm/name new file mode 100644 index 0000000..e084e8f --- /dev/null +++ b/src/test/disk_tests/multipath/dm-4/dm/name @@ -0,0 +1 @@ +mpathe diff --git a/src/test/disk_tests/multipath/dm-4/dm/uuid b/src/test/disk_tests/multipath/dm-4/dm/uuid new file mode 100644 index 0000000..0ca7875 --- /dev/null +++ b/src/test/disk_tests/multipath/dm-4/dm/uuid @@ -0,0 +1 @@ +mpath-3600140500000000000000000000000005 diff --git a/src/test/disk_tests/multipath/dm-4/size b/src/test/disk_tests/multipath/dm-4/size new file mode 100644 index 0000000..14faeec --- /dev/null +++ b/src/test/disk_tests/multipath/dm-4/size @@ -0,0 +1 @@ +20971520 diff --git a/src/test/disk_tests/multipath/dm-4_slaves b/src/test/disk_tests/multipath/dm-4_slaves new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/test/disk_tests/multipath/dm-4_slaves @@ -0,0 +1 @@ + diff --git a/src/test/disk_tests/multipath/lsblk b/src/test/disk_tests/multipath/lsblk new file mode 100644 index 0000000..91f7457 --- /dev/null +++ b/src/test/disk_tests/multipath/lsblk @@ -0,0 +1,63 @@ +{ + "blockdevices": [ + { + "path": "/dev/sda", + "parttype": null, + "fstype": null, + "tran": "fc" + }, + { + "path": "/dev/sdb", + "parttype": null, + "fstype": null, + "tran": "fc" + }, + { + "path": "/dev/sdc", + "parttype": null, + "fstype": null, + "tran": "fc" + }, + { + "path": "/dev/sdd", + "parttype": null, + "fstype": null, + "tran": "fc" + }, + { + "path": "/dev/mapper/mpatha", + "parttype": null, + "fstype": null, + "tran": null, + "pttype": null + }, + { + "path": "/dev/mapper/mpathb", + "parttype": null, + "fstype": null, + "tran": null, + "pttype": null + }, + { + "path": "/dev/mapper/mpathc", + "parttype": null, + "fstype": null, + "tran": null, + "pttype": "gpt" + }, + { + "path": "/dev/dm-3", + "parttype": null, + "fstype": null, + "tran": null, + "pttype": null + }, + { + "path": "/dev/dm-4", + "parttype": null, + "fstype": null, + "tran": null, + "pttype": null + } + ] +} diff --git a/src/test/disk_tests/multipath/lvs b/src/test/disk_tests/multipath/lvs new file mode 100644 index 0000000..e69de29 diff --git a/src/test/disk_tests/multipath/mounts b/src/test/disk_tests/multipath/mounts new file mode 100644 index 0000000..06ada27 --- /dev/null +++ b/src/test/disk_tests/multipath/mounts @@ -0,0 +1 @@ +/dev/mapper/mpathe /mnt diff --git a/src/test/disk_tests/multipath/multipath_expected.json b/src/test/disk_tests/multipath/multipath_expected.json new file mode 100644 index 0000000..62e6e1c --- /dev/null +++ b/src/test/disk_tests/multipath/multipath_expected.json @@ -0,0 +1,59 @@ +{ + "dm-0": { + "devpath": "/dev/mapper/mpatha", + "size": 10737418240, + "vendor": "SANVEND", + "model": "SANMODEL", + "wwn": "3600140500000000000000000000000001", + "paths": 2, + "slaves": [ + "/dev/sda", + "/dev/sdb" + ], + "transport": "fc" + }, + "dm-1": { + "devpath": "/dev/mapper/mpathb", + "size": 10737418240, + "vendor": "SANVEND", + "model": "SANMODEL", + "wwn": "3600140500000000000000000000000002", + "paths": 2, + "slaves": [ + "/dev/sdc", + "/dev/sdd" + ], + "transport": "fc", + "used": "LVM" + }, + "dm-2": { + "devpath": "/dev/mapper/mpathc", + "size": 10737418240, + "vendor": "unknown", + "model": "unknown", + "wwn": "3600140500000000000000000000000003", + "paths": 0, + "slaves": [], + "used": "partitions" + }, + "dm-3": { + "devpath": "/dev/mapper/mpathd", + "size": 10737418240, + "vendor": "unknown", + "model": "unknown", + "wwn": "3600140500000000000000000000000004", + "paths": 0, + "slaves": [], + "used": "ZFS" + }, + "dm-4": { + "devpath": "/dev/mapper/mpathe", + "size": 10737418240, + "vendor": "unknown", + "model": "unknown", + "wwn": "3600140500000000000000000000000005", + "paths": 0, + "slaves": [], + "used": "mounted" + } +} diff --git a/src/test/disk_tests/multipath/partlist b/src/test/disk_tests/multipath/partlist new file mode 100644 index 0000000..e69de29 diff --git a/src/test/disk_tests/multipath/pvs b/src/test/disk_tests/multipath/pvs new file mode 100644 index 0000000..9c2f9b9 --- /dev/null +++ b/src/test/disk_tests/multipath/pvs @@ -0,0 +1 @@ + /dev/dm-1 diff --git a/src/test/disk_tests/multipath/sda/device/model b/src/test/disk_tests/multipath/sda/device/model new file mode 100644 index 0000000..2f50f3f --- /dev/null +++ b/src/test/disk_tests/multipath/sda/device/model @@ -0,0 +1 @@ +SANMODEL \ No newline at end of file diff --git a/src/test/disk_tests/multipath/sda/device/vendor b/src/test/disk_tests/multipath/sda/device/vendor new file mode 100644 index 0000000..ead8944 --- /dev/null +++ b/src/test/disk_tests/multipath/sda/device/vendor @@ -0,0 +1 @@ +SANVEND \ No newline at end of file diff --git a/src/test/disk_tests/multipath/sda/holders/holder b/src/test/disk_tests/multipath/sda/holders/holder new file mode 100644 index 0000000..9255a92 --- /dev/null +++ b/src/test/disk_tests/multipath/sda/holders/holder @@ -0,0 +1 @@ +dm-holder \ No newline at end of file diff --git a/src/test/disk_tests/multipath/sda/queue/rotational b/src/test/disk_tests/multipath/sda/queue/rotational new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/src/test/disk_tests/multipath/sda/queue/rotational @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/test/disk_tests/multipath/sda/size b/src/test/disk_tests/multipath/sda/size new file mode 100644 index 0000000..8280959 --- /dev/null +++ b/src/test/disk_tests/multipath/sda/size @@ -0,0 +1 @@ +20971520 \ No newline at end of file diff --git a/src/test/disk_tests/multipath/sda_udevadm b/src/test/disk_tests/multipath/sda_udevadm new file mode 100644 index 0000000..7bd58b4 --- /dev/null +++ b/src/test/disk_tests/multipath/sda_udevadm @@ -0,0 +1,18 @@ +P: /devices/pci0000:00/0000:00:03.0/0000:02:00.0/host4/rport-4:0-0/target4:0:0/4:0:0:0/block/sda +N: sda +S: disk/by-id/scsi-36001405000000000000000000000000a +E: DEVLINKS=/dev/disk/by-id/scsi-36001405000000000000000000000000a +E: DEVNAME=/dev/sda +E: DEVPATH=/devices/pci0000:00/0000:00:03.0/0000:02:00.0/host4/rport-4:0-0/target4:0:0/4:0:0:0/block/sda +E: DEVTYPE=disk +E: ID_BUS=scsi +E: ID_MODEL=SANMODEL +E: ID_SCSI=1 +E: ID_SERIAL=SANSERIALa +E: ID_SERIAL_SHORT=SSERa +E: ID_TYPE=disk +E: ID_VENDOR=SANVEND +E: ID_WWN=0x600140500000000a +E: MAJOR=8 +E: MINOR=0 +E: SUBSYSTEM=block diff --git a/src/test/disk_tests/multipath/sdb/device/model b/src/test/disk_tests/multipath/sdb/device/model new file mode 100644 index 0000000..2f50f3f --- /dev/null +++ b/src/test/disk_tests/multipath/sdb/device/model @@ -0,0 +1 @@ +SANMODEL \ No newline at end of file diff --git a/src/test/disk_tests/multipath/sdb/device/vendor b/src/test/disk_tests/multipath/sdb/device/vendor new file mode 100644 index 0000000..ead8944 --- /dev/null +++ b/src/test/disk_tests/multipath/sdb/device/vendor @@ -0,0 +1 @@ +SANVEND \ No newline at end of file diff --git a/src/test/disk_tests/multipath/sdb/holders/holder b/src/test/disk_tests/multipath/sdb/holders/holder new file mode 100644 index 0000000..9255a92 --- /dev/null +++ b/src/test/disk_tests/multipath/sdb/holders/holder @@ -0,0 +1 @@ +dm-holder \ No newline at end of file diff --git a/src/test/disk_tests/multipath/sdb/queue/rotational b/src/test/disk_tests/multipath/sdb/queue/rotational new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/src/test/disk_tests/multipath/sdb/queue/rotational @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/test/disk_tests/multipath/sdb/size b/src/test/disk_tests/multipath/sdb/size new file mode 100644 index 0000000..8280959 --- /dev/null +++ b/src/test/disk_tests/multipath/sdb/size @@ -0,0 +1 @@ +20971520 \ No newline at end of file diff --git a/src/test/disk_tests/multipath/sdb_udevadm b/src/test/disk_tests/multipath/sdb_udevadm new file mode 100644 index 0000000..9a04c63 --- /dev/null +++ b/src/test/disk_tests/multipath/sdb_udevadm @@ -0,0 +1,18 @@ +P: /devices/pci0000:00/0000:00:03.0/0000:02:00.0/host4/rport-4:0-0/target4:0:0/4:0:0:0/block/sdb +N: sdb +S: disk/by-id/scsi-36001405000000000000000000000000b +E: DEVLINKS=/dev/disk/by-id/scsi-36001405000000000000000000000000b +E: DEVNAME=/dev/sdb +E: DEVPATH=/devices/pci0000:00/0000:00:03.0/0000:02:00.0/host4/rport-4:0-0/target4:0:0/4:0:0:0/block/sdb +E: DEVTYPE=disk +E: ID_BUS=scsi +E: ID_MODEL=SANMODEL +E: ID_SCSI=1 +E: ID_SERIAL=SANSERIALb +E: ID_SERIAL_SHORT=SSERb +E: ID_TYPE=disk +E: ID_VENDOR=SANVEND +E: ID_WWN=0x600140500000000b +E: MAJOR=8 +E: MINOR=0 +E: SUBSYSTEM=block diff --git a/src/test/disk_tests/multipath/sdc/device/model b/src/test/disk_tests/multipath/sdc/device/model new file mode 100644 index 0000000..2f50f3f --- /dev/null +++ b/src/test/disk_tests/multipath/sdc/device/model @@ -0,0 +1 @@ +SANMODEL \ No newline at end of file diff --git a/src/test/disk_tests/multipath/sdc/device/vendor b/src/test/disk_tests/multipath/sdc/device/vendor new file mode 100644 index 0000000..ead8944 --- /dev/null +++ b/src/test/disk_tests/multipath/sdc/device/vendor @@ -0,0 +1 @@ +SANVEND \ No newline at end of file diff --git a/src/test/disk_tests/multipath/sdc/holders/holder b/src/test/disk_tests/multipath/sdc/holders/holder new file mode 100644 index 0000000..9255a92 --- /dev/null +++ b/src/test/disk_tests/multipath/sdc/holders/holder @@ -0,0 +1 @@ +dm-holder \ No newline at end of file diff --git a/src/test/disk_tests/multipath/sdc/queue/rotational b/src/test/disk_tests/multipath/sdc/queue/rotational new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/src/test/disk_tests/multipath/sdc/queue/rotational @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/test/disk_tests/multipath/sdc/size b/src/test/disk_tests/multipath/sdc/size new file mode 100644 index 0000000..8280959 --- /dev/null +++ b/src/test/disk_tests/multipath/sdc/size @@ -0,0 +1 @@ +20971520 \ No newline at end of file diff --git a/src/test/disk_tests/multipath/sdc_udevadm b/src/test/disk_tests/multipath/sdc_udevadm new file mode 100644 index 0000000..acff253 --- /dev/null +++ b/src/test/disk_tests/multipath/sdc_udevadm @@ -0,0 +1,18 @@ +P: /devices/pci0000:00/0000:00:03.0/0000:02:00.0/host4/rport-4:0-0/target4:0:0/4:0:0:0/block/sdc +N: sdc +S: disk/by-id/scsi-36001405000000000000000000000000c +E: DEVLINKS=/dev/disk/by-id/scsi-36001405000000000000000000000000c +E: DEVNAME=/dev/sdc +E: DEVPATH=/devices/pci0000:00/0000:00:03.0/0000:02:00.0/host4/rport-4:0-0/target4:0:0/4:0:0:0/block/sdc +E: DEVTYPE=disk +E: ID_BUS=scsi +E: ID_MODEL=SANMODEL +E: ID_SCSI=1 +E: ID_SERIAL=SANSERIALc +E: ID_SERIAL_SHORT=SSERc +E: ID_TYPE=disk +E: ID_VENDOR=SANVEND +E: ID_WWN=0x600140500000000c +E: MAJOR=8 +E: MINOR=0 +E: SUBSYSTEM=block diff --git a/src/test/disk_tests/multipath/sdd/device/model b/src/test/disk_tests/multipath/sdd/device/model new file mode 100644 index 0000000..2f50f3f --- /dev/null +++ b/src/test/disk_tests/multipath/sdd/device/model @@ -0,0 +1 @@ +SANMODEL \ No newline at end of file diff --git a/src/test/disk_tests/multipath/sdd/device/vendor b/src/test/disk_tests/multipath/sdd/device/vendor new file mode 100644 index 0000000..ead8944 --- /dev/null +++ b/src/test/disk_tests/multipath/sdd/device/vendor @@ -0,0 +1 @@ +SANVEND \ No newline at end of file diff --git a/src/test/disk_tests/multipath/sdd/holders/holder b/src/test/disk_tests/multipath/sdd/holders/holder new file mode 100644 index 0000000..9255a92 --- /dev/null +++ b/src/test/disk_tests/multipath/sdd/holders/holder @@ -0,0 +1 @@ +dm-holder \ No newline at end of file diff --git a/src/test/disk_tests/multipath/sdd/queue/rotational b/src/test/disk_tests/multipath/sdd/queue/rotational new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/src/test/disk_tests/multipath/sdd/queue/rotational @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/test/disk_tests/multipath/sdd/size b/src/test/disk_tests/multipath/sdd/size new file mode 100644 index 0000000..8280959 --- /dev/null +++ b/src/test/disk_tests/multipath/sdd/size @@ -0,0 +1 @@ +20971520 \ No newline at end of file diff --git a/src/test/disk_tests/multipath/sdd_udevadm b/src/test/disk_tests/multipath/sdd_udevadm new file mode 100644 index 0000000..813c5f1 --- /dev/null +++ b/src/test/disk_tests/multipath/sdd_udevadm @@ -0,0 +1,18 @@ +P: /devices/pci0000:00/0000:00:03.0/0000:02:00.0/host4/rport-4:0-0/target4:0:0/4:0:0:0/block/sdd +N: sdd +S: disk/by-id/scsi-36001405000000000000000000000000d +E: DEVLINKS=/dev/disk/by-id/scsi-36001405000000000000000000000000d +E: DEVNAME=/dev/sdd +E: DEVPATH=/devices/pci0000:00/0000:00:03.0/0000:02:00.0/host4/rport-4:0-0/target4:0:0/4:0:0:0/block/sdd +E: DEVTYPE=disk +E: ID_BUS=scsi +E: ID_MODEL=SANMODEL +E: ID_SCSI=1 +E: ID_SERIAL=SANSERIALd +E: ID_SERIAL_SHORT=SSERd +E: ID_TYPE=disk +E: ID_VENDOR=SANVEND +E: ID_WWN=0x600140500000000d +E: MAJOR=8 +E: MINOR=0 +E: SUBSYSTEM=block diff --git a/src/test/disk_tests/multipath/zpool b/src/test/disk_tests/multipath/zpool new file mode 100644 index 0000000..e723f7e --- /dev/null +++ b/src/test/disk_tests/multipath/zpool @@ -0,0 +1 @@ + /dev/dm-3 - diff --git a/src/test/disklist_test.pm b/src/test/disklist_test.pm index a0dc01f..9e35430 100644 --- a/src/test/disklist_test.pm +++ b/src/test/disklist_test.pm @@ -18,6 +18,14 @@ my $testcount = 0; # testcount for TAP::Harness my $diskmanage_module; # mockmodule for PVE::Diskmanage my $print = 0; +my $multipath_aliases = { + '/dev/mapper/mpatha' => '/dev/dm-0', + '/dev/mapper/mpathb' => '/dev/dm-1', + '/dev/mapper/mpathc' => '/dev/dm-2', + '/dev/mapper/mpathd' => '/dev/dm-3', + '/dev/mapper/mpathe' => '/dev/dm-4', +}; + sub mocked_run_command { my ($cmd, %param) = @_; @@ -101,6 +109,16 @@ sub mocked_is_iscsi { return 0; } +sub mocked_file_read_firstline { + my ($path) = @_; + + my $originalsub = $diskmanage_module->original('file_read_firstline'); + + $path =~ s|^/sys/block|disk_tests/$testcasedir|; + + return &$originalsub($path); +} + sub mocked_dir_glob_foreach { my ($dir, $regex, $sub) = @_; @@ -109,6 +127,8 @@ sub mocked_dir_glob_foreach { # read lines in from file if ($dir =~ m{^/sys/block$}) { @$lines = split(/\n/, read_test_file('disklist')); + } elsif ($dir =~ m{^/sys/block/([^/]+)/slaves$}) { + @$lines = split(/\n/, read_test_file("${1}_slaves")); } elsif ($dir =~ m{^/sys/block/([^/]+)}) { @$lines = split(/\n/, read_test_file('partlist')); } @@ -213,6 +233,15 @@ sub test_disk_list { $testcount++; is_deeply($disks, $expected_disk_list, 'disk list should be the same'); + if (-f "disk_tests/$testcasedir/multipath_expected.json") { + my $multipath = PVE::Diskmanage::get_multipath_disks(); + my $expected_multipath = decode_json(read_test_file('multipath_expected.json')); + + print Dumper($multipath) if $print; + $testcount++; + is_deeply($multipath, $expected_multipath, 'multipath list should be the same'); + } + done_testing($testcount); }; } @@ -239,8 +268,15 @@ $diskmanage_module->mock('assert_blockdev' => sub { return 1; }); print("\tMocked assert_blockdev\n"); $diskmanage_module->mock( 'dir_is_empty' => sub { - # all partitions have a holder dir my $val = shift; + # let test cases provide the dir (e.g. holders) with content + my $mapped = $val; + $mapped =~ s|^/sys/block|disk_tests/$testcasedir|; + if (-d $mapped) { + my $originalsub = $diskmanage_module->original('dir_is_empty'); + return &$originalsub($mapped); + } + # all partitions have a holder dir if ($val =~ m|^/sys/block/.+/.+/|) { return 0; } @@ -248,6 +284,17 @@ $diskmanage_module->mock( }, ); print("\tMocked dir_is_empty\n"); +$diskmanage_module->mock('file_read_firstline' => \&mocked_file_read_firstline); +print("\tMocked file_read_firstline\n"); +$diskmanage_module->mock( + 'abs_path' => sub { + my ($path) = @_; + return $multipath_aliases->{$path} + if defined($multipath_aliases->{$path}); + return &{ $diskmanage_module->original('abs_path') }($path); + }, +); +print("\tMocked abs_path\n"); $diskmanage_module->mock('check_bin' => sub { return 1; }); print("\tMocked check_bin\n"); my $tools_module = Test::MockModule->new('PVE::ProcFSTools', no_auto => 1); -- 2.47.3