2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-10-22 07:38:08 +00:00

test(xcat-core): the ipxe shim case reports a pass after leaving a node configured for installation

restore_state in ipxe_secureboot_shim.sh matched the saved nodeset state against
boot, offline, shell and standby. nodeset stat reports chain.currstate verbatim,
so runcmd=bmcsetup, osimage=<name>, runimage=<task> and the deprecated install,
netboot and statelite all fall past that list. The helper then restored nothing
and still printed IPXE_SHIM_OK, so the node kept the installation the case
configured and the next case on that node measured it.

The lookups hide the same failure one layer down. lsdef and nodeset run in a
pipeline, so the exit status comes from sed or head and is always zero, and an
attribute that is unset prints the same empty string as a lookup that failed.
The helper clears the provmethod and the netboot method it reads as unset, so a
failed lookup makes it delete a value the node really had.

The tests drive the helper through nine states and lookups. Against the unfixed
helper, all four refusal cases exit 0 and print IPXE_SHIM_OK after calling
nodeset osimage= on the node, and the provmethod case prints
"provmethod=unset" for a provmethod the stub holds set.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
This commit is contained in:
Daniel Hilst
2026-10-08 13:16:56 -03:00
parent 74954c9bc6
commit 87cd06e4e5
@@ -6,7 +6,10 @@
# the next case on that node measures the state this one left. So the helper has to report a
# failed restoration instead of its own result.
#
# lsdef, nodeset and chdef are stubbed, and every call is recorded in a log the tests read.
# lsdef, nodeset and chdef are stubbed, and every call is recorded in a log the tests read. A
# stub can also be told to fail: STUB_STAT_RC fails "nodeset stat", and STUB_LSDEF_FAIL_ATTR
# fails the lsdef of one attribute. Both failures print nothing on stdout, which is what an
# attribute that is unset prints too.
load 'helpers/shell_source'
@@ -29,6 +32,9 @@ setup()
# provmethod is what sends the helper through chdef on the way out.
export STUB_BEFORE=boot
export STUB_PROVMETHOD=
export STUB_PROFILE=compute
export STUB_STAT_RC=0
export STUB_LSDEF_FAIL_ATTR=
export STUB_NODESET_RESTORE_RC=0
export STUB_CHDEF_RC=0
export STUB_CHDEF_NETBOOT_RC=0
@@ -56,6 +62,12 @@ while [ $# -gt 0 ]; do
*) shift ;;
esac
done
# A failed lookup prints nothing and exits non-zero. An attribute that is unset prints nothing
# and exits zero, so only the exit status tells the two apart.
if [ -n "$STUB_LSDEF_FAIL_ATTR" ] && [ "$attr" = "$STUB_LSDEF_FAIL_ATTR" ]; then
echo "Error: could not read $attr" >&2
exit 1
fi
case "$type/$attr" in
site/tftpdir) echo " tftpdir=$STUB_TFTPDIR" ;;
site/installdir) echo " installdir=$STUB_INSTALLDIR" ;;
@@ -63,6 +75,7 @@ case "$type/$attr" in
node/arch) echo " arch=$STUB_ARCH" ;;
node/os) echo " os=$STUB_OS" ;;
node/provmethod) [ -n "$STUB_PROVMETHOD" ] && echo " provmethod=$STUB_PROVMETHOD" ;;
node/profile) [ -n "$STUB_PROFILE" ] && echo " profile=$STUB_PROFILE" ;;
osimage/) [ -n "$STUB_NO_OSIMAGE" ] && exit 1; exit 0 ;;
*) echo "unexpected lsdef $type $obj $attr" >&2; exit 1 ;;
esac
@@ -76,6 +89,7 @@ STUB
echo "nodeset $*" >>"$STUB_CALLS"
case "$2" in
stat)
[ "$STUB_STAT_RC" = 0 ] || { echo "Error: cannot reach the server" >&2; exit "$STUB_STAT_RC"; }
echo "$1: $STUB_BEFORE"
;;
osimage=*)
@@ -113,7 +127,7 @@ STUB
[ "$status" -eq 0 ]
[[ "$output" == *IPXE_SHIM_OK* ]]
grep -q "^nodeset $NODE boot$" "$CALLS"
grep -q "^chdef -t node -o $NODE provmethod=$" "$CALLS"
grep -q "^chdef -t node -o $NODE provmethod= profile=compute$" "$CALLS"
}
@test "a nodeset that cannot put the state back fails the case" {
@@ -131,7 +145,7 @@ STUB
[ "$status" -ne 0 ]
[[ "$output" != *IPXE_SHIM_OK* ]]
[[ "$output" == *IPXE_SHIM_FAIL* ]]
grep -q "^chdef -t node -o $NODE provmethod=$" "$CALLS"
grep -q "^chdef -t node -o $NODE provmethod= profile=compute$" "$CALLS"
}
# A control: the helper already restores the state when its own assertion fails. It holds the
@@ -209,3 +223,113 @@ STUB
done
done
}
# nodeset stat reports chain.currstate verbatim, and a state can carry an argument:
# "runcmd=bmcsetup" is one state, not the state "runcmd". The helper matched ${before%% *}
# against four names, so a node in any other state kept the installation this case configured
# and the case still printed IPXE_SHIM_OK.
@test "a runcmd state goes back with its command argument" {
STUB_BEFORE='runcmd=bmcsetup'
run "$SCRIPT" "$NODE"
[ "$status" -eq 0 ]
[[ "$output" == *IPXE_SHIM_OK* ]]
grep -q "^nodeset $NODE runcmd=bmcsetup$" "$CALLS"
}
# The saved image is not the image the helper sets, or the assertion matches the helper's own
# forward call and cannot fail.
@test "an osimage state goes back with its image name" {
STUB_BEFORE="osimage=$OS-x86_64-netboot-compute"
run "$SCRIPT" "$NODE"
[ "$status" -eq 0 ]
[[ "$output" == *IPXE_SHIM_OK* ]]
grep -q "^nodeset $NODE osimage=$OS-x86_64-netboot-compute$" "$CALLS"
}
# install, netboot and statelite are deprecated: destiny.pm answers "The options install,
# netboot and statelite have been deprecated" and sets errorabort, so replaying one fails and
# leaves the node configured for installation. The helper cannot put such a state back, so it
# must refuse while the node is still untouched.
@test "a saved state the helper cannot replay stops it before the first mutation" {
STUB_BEFORE=install
STUB_NETBOOT=xnba
run "$SCRIPT" "$NODE"
[ "$status" -ne 0 ]
[[ "$output" != *IPXE_SHIM_OK* ]]
[[ "$output" == *"state [install]"* ]]
refute_grep -q "^chdef " "$CALLS"
refute_grep -q "^nodeset $NODE osimage" "$CALLS"
}
# A pipeline hides the exit status of its first command, so "nodeset stat | sed | head" reported
# success with an empty state. The helper then read the node as stateless and restored nothing.
@test "a nodeset stat that fails stops the helper before the first mutation" {
STUB_STAT_RC=1
STUB_NETBOOT=xnba
run "$SCRIPT" "$NODE"
[ "$status" -ne 0 ]
[[ "$output" != *IPXE_SHIM_OK* ]]
[[ "$output" == *"nodeset $NODE stat returned non-zero"* ]]
refute_grep -q "^chdef " "$CALLS"
refute_grep -q "^nodeset $NODE osimage" "$CALLS"
}
# lsdef prints nothing for an attribute that is unset, so a failed lookup and an unset attribute
# were the same empty string. The helper clears the provmethod it believes was unset, so a
# failed lookup made it delete the provmethod the node really had.
@test "a provmethod lookup that fails does not clear the provmethod" {
STUB_LSDEF_FAIL_ATTR=provmethod
STUB_PROVMETHOD=alma9.8-x86_64-install-compute
run "$SCRIPT" "$NODE"
[ "$status" -ne 0 ]
[[ "$output" != *IPXE_SHIM_OK* ]]
[[ "$output" == *"-i provmethod"* ]]
refute_grep -q "^chdef " "$CALLS"
refute_grep -q "^nodeset $NODE osimage" "$CALLS"
}
# The same read, the same damage: a netboot method read as empty is put back as empty, which
# clears the method the cluster boots the node with.
@test "a netboot lookup that fails does not change the netboot method" {
STUB_LSDEF_FAIL_ATTR=netboot
run "$SCRIPT" "$NODE"
[ "$status" -ne 0 ]
[[ "$output" != *IPXE_SHIM_OK* ]]
[[ "$output" == *"-i netboot"* ]]
refute_grep -q "^chdef " "$CALLS"
refute_grep -q "^nodeset $NODE osimage" "$CALLS"
}
# A control for the two above: an attribute that is readable and unset is not a failed lookup,
# and the helper still runs. Without this the tests above are satisfied by a helper that refuses
# every empty attribute.
@test "a provmethod that is unset but readable is not a failed lookup" {
STUB_PROVMETHOD=
run "$SCRIPT" "$NODE"
[ "$status" -eq 0 ]
[[ "$output" == *IPXE_SHIM_OK* ]]
grep -q "^nodeset $NODE osimage=$OS-x86_64-install-compute$" "$CALLS"
}
# setdestiny writes nodetype.provmethod, profile, os and arch from the osimage row it resolved
# (destiny.pm, "my $updateattribs"). On the path where the helper names its own
# <os>-<arch>-install-compute image, os and arch come back as the node's own values by
# construction of that name, and profile does not: it becomes the row's profile.
@test "the profile that nodeset osimage overwrites goes back too" {
STUB_PROVMETHOD=
STUB_PROFILE=service
run "$SCRIPT" "$NODE"
[ "$status" -eq 0 ]
[[ "$output" == *IPXE_SHIM_OK* ]]
grep -q "^chdef -t node -o $NODE provmethod= profile=service$" "$CALLS"
}
# An arch that cannot be read is not an arch that is wrong, and the message has to say which.
@test "an arch lookup that fails is reported as a failed lookup" {
STUB_LSDEF_FAIL_ATTR=arch
run "$SCRIPT" "$NODE"
[ "$status" -ne 0 ]
[[ "$output" == *"-i arch"* ]]
[[ "$output" != *"only x86_64 has a UEFI shim"* ]]
}