From 1d8fe040c767072d581db6cfd4cee6827dae8973 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Ferr=C3=A3o?= <2031761+viniciusferrao@users.noreply.github.com> Date: Thu, 20 Aug 2026 22:58:25 -0300 Subject: [PATCH 1/3] fix(getinstdisk): prefer direct attached disks over RAID volumes The driver sort put the ahci and ata_piix controllers in the same choice group as the PMC MaxRAID and megaraid_sas RAID controllers. On a server with both, the sort could select a RAID data volume as the OS install disk. Move the RAID controllers to the second choice group. The direct attached controllers hold the likely boot volume, and a server with only RAID volumes still selects them from the second group. The SAS host adapters move to the third group and every other driver to a new fourth group, so the relative order of the remaining drivers does not change. The RHEL 10 installer includes its own copy of the script, so both carry the change. Recovered from the lenovobuild branch. --- xCAT-server/share/xcat/install/scripts/getinstdisk | 12 ++++++++---- .../share/xcat/install/scripts/getinstdisk.rhels10 | 12 ++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/xCAT-server/share/xcat/install/scripts/getinstdisk b/xCAT-server/share/xcat/install/scripts/getinstdisk index 846e33734..20020a45a 100644 --- a/xCAT-server/share/xcat/install/scripts/getinstdisk +++ b/xCAT-server/share/xcat/install/scripts/getinstdisk @@ -201,22 +201,26 @@ if [ -z "$install_disk" ]; then # Sort disks by DRIVER type case "$disk_driver" in - "ata_piix"*|"PMC MaxRAID"|"ahci"|"megaraid_sas") + "ata_piix"*|"ahci") echo "$disk $disk_data" >> "$tmpfile""$file_pre""firstchoicedisks" echo "[get_install_disk] Add disk: $disk $disk_data into $file_pre firstchoicedisks" ;; - "mptsas"|"mpt2sas"|"mpt3sas") + "PMC MaxRAID"|"megaraid_sas") echo "$disk $disk_data" >> "$tmpfile""$file_pre""secondchoicedisks" echo "[get_install_disk] Add disk: $disk $disk_data into $file_pre secondchoicedisks" ;; - *) + "mptsas"|"mpt2sas"|"mpt3sas") echo "$disk $disk_data" >> "$tmpfile""$file_pre""thirdchoicedisks" echo "[get_install_disk] Add disk: $disk $disk_data into $file_pre thirdchoicedisks" ;; + *) + echo "$disk $disk_data" >> "$tmpfile""$file_pre""fourthchoicedisks" + echo "[get_install_disk] Add disk: $disk $disk_data into $file_pre fourthchoicedisks" + ;; esac done - for seq in first second third; do + for seq in first second third fourth; do if [ -s $tmpfile$file_pre${seq}choicedisks ]; then install_file="$tmpfile$file_pre${seq}choicedisks" break diff --git a/xCAT-server/share/xcat/install/scripts/getinstdisk.rhels10 b/xCAT-server/share/xcat/install/scripts/getinstdisk.rhels10 index 57f05620a..0a058bbce 100644 --- a/xCAT-server/share/xcat/install/scripts/getinstdisk.rhels10 +++ b/xCAT-server/share/xcat/install/scripts/getinstdisk.rhels10 @@ -201,22 +201,26 @@ if [ -z "$install_disk" ]; then # Sort disks by DRIVER type case "$disk_driver" in - "ata_piix"*|"PMC MaxRAID"|"ahci"|"megaraid_sas") + "ata_piix"*|"ahci") echo "$disk $disk_data" >> "$tmpfile""$file_pre""firstchoicedisks" echo "[get_install_disk] Add disk: $disk $disk_data into $file_pre firstchoicedisks" ;; - "mptsas"|"mpt2sas"|"mpt3sas") + "PMC MaxRAID"|"megaraid_sas") echo "$disk $disk_data" >> "$tmpfile""$file_pre""secondchoicedisks" echo "[get_install_disk] Add disk: $disk $disk_data into $file_pre secondchoicedisks" ;; - *) + "mptsas"|"mpt2sas"|"mpt3sas") echo "$disk $disk_data" >> "$tmpfile""$file_pre""thirdchoicedisks" echo "[get_install_disk] Add disk: $disk $disk_data into $file_pre thirdchoicedisks" ;; + *) + echo "$disk $disk_data" >> "$tmpfile""$file_pre""fourthchoicedisks" + echo "[get_install_disk] Add disk: $disk $disk_data into $file_pre fourthchoicedisks" + ;; esac done - for seq in first second third; do + for seq in first second third fourth; do if [ -s $tmpfile$file_pre${seq}choicedisks ]; then install_file="$tmpfile$file_pre${seq}choicedisks" break From 321595fb623e935aa8aeadf9337e8dd652848c22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Ferr=C3=A3o?= <2031761+viniciusferrao@users.noreply.github.com> Date: Thu, 20 Aug 2026 22:59:11 -0300 Subject: [PATCH 2/3] test(getinstdisk): cover the install disk selection order Run the real scripts in a sandbox. A stub udevadm serves the device properties from fixture files, and the partition list and the output paths move into the sandbox. Every case runs against the common script and against the copy the RHEL 10 installer includes. Cover the direct attached disk against a RAID volume, a RAID only server, the host adapter against a direct attached disk and against an unknown driver, an NVMe device from the last group, and the default fallback. Against the previous scripts the RAID cases fail, so they discriminate. --- xCAT-test/unit/getinstdisk_selection.t | 134 +++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 xCAT-test/unit/getinstdisk_selection.t diff --git a/xCAT-test/unit/getinstdisk_selection.t b/xCAT-test/unit/getinstdisk_selection.t new file mode 100644 index 000000000..fe3ea3bd4 --- /dev/null +++ b/xCAT-test/unit/getinstdisk_selection.t @@ -0,0 +1,134 @@ +#!/usr/bin/env perl +use strict; +use warnings; + +use FindBin; +use File::Spec; +use File::Temp qw(tempdir); +use Test::More; + +my $repo_root = File::Spec->catdir( $FindBin::Bin, '..', '..' ); +my $script_dir = File::Spec->catdir( $repo_root, 'xCAT-server', 'share', 'xcat', 'install', 'scripts' ); + +# The RHEL 10 installer includes its own copy of the script, so both carry the +# same selection order and both are exercised here. +my @scripts = map { File::Spec->catfile( $script_dir, $_ ) } qw(getinstdisk getinstdisk.rhels10); +plan skip_all => 'getinstdisk not found' if grep { !-r $_ } @scripts; +our $script; + +sub slurp { + open( my $fh, '<', $_[0] ) or die "Unable to read $_[0]: $!"; + my $c = do { local $/; <$fh> }; + close($fh); + return $c; +} + +# The script reads /proc/partitions and writes under /tmp, so each scenario +# runs a copy with those paths moved into its own sandbox, and a stub udevadm +# serves the device properties from fixture files. +sub run_scenario { + my (%disk) = @_; + my $sandbox = tempdir( CLEANUP => 1 ); + my $fixdir = "$sandbox/fix"; + my $bindir = "$sandbox/bin"; + mkdir $fixdir; + mkdir $bindir; + + my $body = slurp($script); + $body =~ s{/proc/partitions}{$sandbox/partitions}g; + $body =~ s{/tmp/xcat\.install_disk}{$sandbox/xcat.install_disk}g; + $body =~ s{/tmp/xcat\.getinstalldisk}{$sandbox/xcat.getinstalldisk}g; + $body =~ s{/dev/md/Volume0}{$sandbox/md/Volume0}g; + $body =~ s{"/dev/xvda"}{"$sandbox/xvda"}g; + open( my $sh, '>', "$sandbox/getinstdisk" ) or die $!; + print $sh $body; + close($sh); + + open( my $parts, '>', "$sandbox/partitions" ) or die $!; + print $parts "major minor #blocks name\n\n"; + my $minor = 0; + for my $name ( sort keys %disk ) { + printf $parts " 8 %5d 524288000 %s\n", $minor++, $name; + } + close($parts); + + for my $name ( sort keys %disk ) { + my %attr = %{ $disk{$name} }; + open( my $props, '>', "$fixdir/$name.props" ) or die $!; + print $props "ID_WWN=$attr{wwn}\n" if $attr{wwn}; + print $props "DEVTYPE=disk\n"; + close($props); + open( my $attrs, '>', "$fixdir/$name.attrs" ) or die $!; + print $attrs qq{ ATTRS{size}=="1024000000"\n}; + print $attrs qq{ DRIVERS=="$attr{driver}"\n} if $attr{driver}; + my @models = $attr{models} ? @{ $attr{models} } : ( $attr{model} ? $attr{model} : () ); + print $attrs qq{ ATTRS{model}=="$_"\n} for @models; + close($attrs); + } + + open( my $udev, '>', "$bindir/udevadm" ) or die $!; + print $udev <<'UDEV'; +#!/bin/sh +for a in "$@"; do + case "$a" in + --name=*) name=${a#--name=} ;; + esac +done +name=${name#/dev/} +case "$*" in +*--query=property*) cat "$FIXDIR/$name.props" 2>/dev/null ;; +*--attribute-walk*) cat "$FIXDIR/$name.attrs" 2>/dev/null ;; +esac +exit 0 +UDEV + close($udev); + chmod 0755, "$bindir/udevadm"; + + local $ENV{FIXDIR} = $fixdir; + local $ENV{PATH} = "$bindir:$ENV{PATH}"; + local $ENV{MASTER_IP} = ''; + system("sh $sandbox/getinstdisk >$sandbox/log 2>&1"); + my $chosen = -r "$sandbox/xcat.install_disk" ? slurp("$sandbox/xcat.install_disk") : ''; + chomp $chosen; + return $chosen; +} + +# Every scenario asserts against both copies of the script. +sub selects { + my ( $expected, $name, %disk ) = @_; + for my $candidate (@scripts) { + local $script = $candidate; + my $variant = ( File::Spec->splitpath($candidate) )[2]; + is( run_scenario(%disk), $expected, "$name ($variant)" ); + } + return; +} + +# A direct attached disk wins over a RAID volume when both are present. The +# RAID volume sorts first by name, so the choice comes from the driver group. +selects( '/dev/sdb', 'the direct attached disk wins over the RAID volume', + sda => { driver => 'megaraid_sas' }, + sdb => { driver => 'ahci' } ); + +# A server with only RAID volumes still selects one. +selects( '/dev/sda', 'a RAID volume is selected when nothing better exists', + sda => { driver => 'megaraid_sas' } ); + +# A SAS host adapter loses to a direct attached disk, and still wins over a +# driver with no group of its own. +selects( '/dev/sdb', 'the direct attached disk wins over the host adapter', + sda => { driver => 'mpt3sas' }, + sdb => { driver => 'ahci' } ); + +selects( '/dev/sda', 'the host adapter wins over an unknown driver', + sda => { driver => 'mpt3sas' }, + sdb => { driver => 'virtio_blk' } ); + +# A driverless NVMe device still gets selected from the last group. +selects( '/dev/nvme0n1', 'an NVMe device is selected from the last group', + nvme0n1 => {} ); + +# No usable disk falls back to the documented default. +selects( '/dev/sda', 'no disks fall back to the default' ); + +done_testing(); From 549034d758067e3aeebb1373ca124229f865148d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Ferr=C3=A3o?= <2031761+viniciusferrao@users.noreply.github.com> Date: Fri, 21 Aug 2026 01:13:14 -0300 Subject: [PATCH 3/3] test(getinstdisk): follow the SAS host adapters to the third group The install disk autotest reads the log of a node whose disks sit behind a SAS host adapter, and that driver group moved from the second choice to the third. Read the third group instead. --- xCAT-test/autotest/testcase/get_install_disk/fresh_install_disk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xCAT-test/autotest/testcase/get_install_disk/fresh_install_disk b/xCAT-test/autotest/testcase/get_install_disk/fresh_install_disk index 7d1103be9..c75af50c8 100644 --- a/xCAT-test/autotest/testcase/get_install_disk/fresh_install_disk +++ b/xCAT-test/autotest/testcase/get_install_disk/fresh_install_disk @@ -56,7 +56,7 @@ check:output=~0x500a0751036d9e61 check:output=~0x500a0751036d9e83 check:output=~0x500a0751036d9e7a check:output=~0x500a0751036d9c24 -cmd:cat /tmp/__GETNODEATTR($$CN,os)__-__GETNODEATTR($$CN,arch)__fr_$$NO | grep "into wwn secondchoicedisks" +cmd:cat /tmp/__GETNODEATTR($$CN,os)__-__GETNODEATTR($$CN,arch)__fr_$$NO | grep "into wwn thirdchoicedisks" check:output=~sda 0x500a0751036d9e61 check:output=~sdb 0x500a0751036d9c24 check:output=~sdc 0x500a0751036d9e7a