diff --git a/xCAT-genesis-builder/dracut_105/el/module-setup.sh b/xCAT-genesis-builder/dracut_105/el/module-setup.sh index d410d50f8..32f0aadda 100755 --- a/xCAT-genesis-builder/dracut_105/el/module-setup.sh +++ b/xCAT-genesis-builder/dracut_105/el/module-setup.sh @@ -47,6 +47,9 @@ install() { dracut_install mount.nfs sshd vi reboot lspci parted tmux mkfs mkfs.ext4 mkfs.xfs xfs_db #dracut_install libvirtd /usr/share/libvirt/cpu_map.xml /usr/bin/qemu-img /usr/libexec/qemu-kvm dracut_install mkswap df ifenslave ssh-keygen scp clear + # getdestiny makes its request file with mktemp. Without it the node reports no + # destiny, so xcatd never moves nodelist.status past powering-on. + dracut_install mktemp dracut_install lldpad # RHEL 10 packages no ISC dhcp-client. Install whichever client the build root carries; diff --git a/xCAT-genesis-builder/dracut_105/ubuntu/module-setup.sh b/xCAT-genesis-builder/dracut_105/ubuntu/module-setup.sh index f2668dd39..6d89aa046 100755 --- a/xCAT-genesis-builder/dracut_105/ubuntu/module-setup.sh +++ b/xCAT-genesis-builder/dracut_105/ubuntu/module-setup.sh @@ -52,6 +52,9 @@ install() { dracut_install mount.nfs sshd vi reboot lspci parted screen mkfs mkfs.ext4 mkfs.btrfs #dracut_install libvirtd /usr/share/libvirt/cpu_map.xml /usr/bin/qemu-img /usr/libexec/qemu-kvm dracut_install mkswap df ifenslave ssh-keygen scp clear + # getdestiny makes its request file with mktemp. Without it the node reports no + # destiny, so xcatd never moves nodelist.status past powering-on. + dracut_install mktemp dracut_install dhclient lldpad # OpenSSH 9.8 moved the per-connection work into sshd-session, which sshd execs by diff --git a/xCAT-genesis-builder/verify-genesis-payload b/xCAT-genesis-builder/verify-genesis-payload index 3a9e0094f..7addc544f 100755 --- a/xCAT-genesis-builder/verify-genesis-payload +++ b/xCAT-genesis-builder/verify-genesis-payload @@ -37,6 +37,7 @@ for path in "$@"; do done require usr/sbin/sshd "Genesis is reached over ssh" +require usr/bin/mktemp "getdestiny makes its request file with it" # OpenSSH 9.8 split the per-connection work into sshd-session, which sshd execs by absolute # path. EL9 carries OpenSSH 9.9, so an image with sshd alone refuses every connection. diff --git a/xCAT-test/autotest/testcase/genesis/genesistest.pl b/xCAT-test/autotest/testcase/genesis/genesistest.pl index f78392161..6b520d744 100755 --- a/xCAT-test/autotest/testcase/genesis/genesistest.pl +++ b/xCAT-test/autotest/testcase/genesis/genesistest.pl @@ -83,29 +83,7 @@ if (!(-e $nodestanza)) { ####nodesetshell test for genesis #################################### if ($genesis_nodesetshell_test) { - send_msg(2, "[$$]:Running nodeset NODE shell test..............."); - `nodeset $noderange shell`; - if ($?) { - send_msg(0, "[$$]:nodeset $noderange shell failed..............."); - exit 1; - } - `rpower $noderange boot`; - if ($?) { - send_msg(0, "[$$]:rpower $noderange failed..............."); - exit 1; - } - else { - send_msg(2, "Installing with \"nodeset $noderange shell\" for shell test"); - sleep 120; # wait 2 min for install to finish - wait_for_boot(); - } - #run nodeshell test - send_msg(2, "prepare for nodeshell script."); - if ( &testxdsh(3)) { - send_msg(0, "[$$]:Could not verify test results using xdsh..............."); - exit 1; - } - send_msg(2, "[$$]:Running nodesetshell test success..............."); + exit 1 if &run_nodeset_shell_test(); } #################################### ####runcmd test for genesis @@ -142,6 +120,36 @@ if ($clear_env) { send_msg(2, "[$$]:Clear genesis test enviroment success..............."); } ################################## +#run_nodeset_shell_test +################################# +sub run_nodeset_shell_test { + send_msg(2, "[$$]:Running nodeset NODE shell test..............."); + `nodeset $noderange shell`; + if ($?) { + send_msg(0, "[$$]:nodeset $noderange shell failed..............."); + return 1; + } + `rpower $noderange boot`; + if ($?) { + send_msg(0, "[$$]:rpower $noderange failed..............."); + return 1; + } + send_msg(2, "Installing with \"nodeset $noderange shell\" for shell test"); + sleep 120; # wait 2 min for install to finish + if (&wait_for_node_status("shell")) { + send_msg(0, "[$$]:$noderange did not report the shell destiny..............."); + return 1; + } + #run nodeshell test + send_msg(2, "prepare for nodeshell script."); + if (&testxdsh(3)) { + send_msg(0, "[$$]:Could not verify test results using xdsh..............."); + return 1; + } + send_msg(2, "[$$]:Running nodesetshell test success..............."); + return 0; +} +################################## #report_genesis_files ################################# sub report_genesis_files { @@ -223,7 +231,7 @@ sub rungenesiscmd { else { send_msg(2, "Installing with \"$rinstall_cmd\" for runcmd test"); sleep 120; # wait 2 min for install to finish - wait_for_boot(); + $value = -1 if &wait_for_node_status("configuring"); } return $value; } @@ -266,7 +274,7 @@ sub rungenesisimg { } else { send_msg(2, "Installing with \"$rinstall_cmd\" for runimage test\n"); sleep 120; # wait 2 min for install to finish - wait_for_boot(); + $value = -1 if &wait_for_node_status("booting"); } return $value; } @@ -375,8 +383,9 @@ sub clearenv { `cat $nodestanza | chdef -z`; unlink("$nodestanza"); } + # "rinstall boot" boots the node from its disk, which carries no operating system, + # so the node reports no destiny and nodelist.status stays at powering-on. Only wait. sleep 120; # wait 2 min for reboot to finish - wait_for_boot(); return 0; } #################################### @@ -448,9 +457,10 @@ sub send_msg { } ######################################### -### Wait for node to be in "booted" state +### Wait for the node to report the status its destiny implies ########################################## -sub wait_for_boot { +sub wait_for_node_status { + my ($expected) = @_; my $iterations = 30; # Max wait 30x10 = 5 min my $sleep_interval = 10; my $boot_status; @@ -458,11 +468,11 @@ sub wait_for_boot { foreach my $i (1..$iterations) { $boot_status = `lsdef $noderange -i status -c | cut -d'=' -f2`; chop($boot_status); - if ($boot_status eq "booted") { + if ($boot_status eq $expected) { return 0; } sleep $sleep_interval; } - print "After $iterations iterations node status: $boot_status \n"; + print "After $iterations iterations node status: $boot_status, expected $expected \n"; return 1; } diff --git a/xCAT-test/autotest/testcase/genesis/test.sh b/xCAT-test/autotest/testcase/genesis/test.sh index 07694ed83..542d065d2 100755 --- a/xCAT-test/autotest/testcase/genesis/test.sh +++ b/xCAT-test/autotest/testcase/genesis/test.sh @@ -23,11 +23,41 @@ TESTNODE_ARCH="$(uname -m)" # against a scratch tree. TFTPDIR="${TFTPDIR:-/tftpboot}" +# grub2.pm names the boot loader grub2., with every ppc64 flavour written as "ppc". +TESTNODE_LOADER_ARCH="$TESTNODE_ARCH" +[[ $TESTNODE_LOADER_ARCH =~ ^ppc64 ]] && TESTNODE_LOADER_ARCH="ppc" +STAGED_BOOT_LOADER="" + MASTER_PRIVATE_IP="192.168.1.1" MASTER_PRIVATE_NETMASK="255.255.0.0" MASTER_PRIVATE_NETWORK="192_168_0_0-255_255_0_0" +# xCAT builds no grub2 network boot loader for x86_64 or aarch64. The administrator installs +# grub2. by hand -- docs/source/guides/install-guides/yum/grub2.rst. grub2.pm stops the +# configuration when the file is absent, and this case reads the configuration only. +function stage_boot_loader() { + local loader="$TFTPDIR/boot/grub2/grub2.$TESTNODE_LOADER_ARCH"; + if [[ -e $loader ]];then + return 0; + fi + mkdir -p "$TFTPDIR/boot/grub2" || return 1; + : > "$loader" || return 1; + STAGED_BOOT_LOADER="$loader"; + echo "Staged an empty boot loader at $loader for the check"; + return 0; +} + +function unstage_boot_loader() { + if [[ -z $STAGED_BOOT_LOADER ]];then + return 0; + fi + # grub2.pm links grub2- to the loader. Remove the link with the file it points at. + rm -f "$STAGED_BOOT_LOADER" "$TFTPDIR/boot/grub2/grub2-${TESTNODE}"; + STAGED_BOOT_LOADER=""; + return 0; +} + function check_destiny() { cmd="chdef ${TESTNODE} arch=${TESTNODE_ARCH} cons=ipmi groups=all ip=${TESTNODE_IP} mac=4e:ee:ee:ee:ee:0e netboot=$NETBOOT tftpserver=$MASTER_PRIVATE_IP xcatmaster=$MASTER_PRIVATE_IP"; runcmd $cmd; @@ -58,8 +88,15 @@ function check_destiny() { grep ${TESTNODE} /etc/hosts cmd="nodeset ${TESTNODE} shell"; runcmd $cmd; + # grub2.pm writes the boot configuration and only then stops on a missing boot loader, + # so the file the check reads below exists even when nodeset failed. + nodeset_rc=$?; cmd="ip addr del $MASTER_PRIVATE_IP/$MASTER_PRIVATE_NETMASK dev $NET2"; runcmd $cmd; + if [[ $nodeset_rc -ne 0 ]];then + echo "'nodeset ${TESTNODE} shell' FAILED"; + return 1; + fi echo "Check if 'nodeset ${TESTNODE} shell' is added to ${SHELLFOLDER}/${TESTNODE}" echo "===============================================" cat "${SHELLFOLDER}/${TESTNODE}" @@ -97,9 +134,12 @@ while [ "$#" -ge "0" ]; do SHELLFOLDER="$TFTPDIR/xcat/xnba/nodes" else SHELLFOLDER="$TFTPDIR/boot/grub2"; + stage_boot_loader || exit 1; fi check_destiny ; - if [[ $? -eq 1 ]];then + rc=$?; + unstage_boot_loader; + if [[ $rc -eq 1 ]];then exit 1 else exit 0