mirror of
https://github.com/xcat2/xcat-core.git
synced 2026-09-21 08:33:20 +00:00
ff20388fed
A compute node fetches the legacy Genesis kernel and initramfs, the kernel starts, and then nothing else happens: doxcat never runs, the node acquires no address, sshd refuses every connection and the node stays at status=powering-on. The five genesis test cases in xCAT-test/autotest/testcase/genesis have never passed. VersatusHPC/xcat-internal#78. Three holes in the image, each fatal on its own. dracut_105/el/xcat-cmdline.sh ends in `while :; do tmux attach-session -t doxcat || tmux new-session -s doxcat doxcat; done`, and the image carries no locale data, so tmux exits with "need UTF-8 locale" and the loop spins without ever reaching doxcat. module-setup.sh does not install /usr/libexec/openssh/sshd-session, which OpenSSH 9.8 and later exec for every connection and which EL9 now ships. xCAT-genesis-base.spec does not BuildRequire dhcp-client, so dhclient is absent from the build chroot; dracut_install reports the missing binary and returns, and the module install function keeps going, so the image ships without it. xcat-cmdline.sh now resolves xcat_console_mode() once and runs doxcat directly when the terminal multiplexer cannot start a session; the same shape replaces the screen loop on Ubuntu. module-setup.sh installs the OpenSSH session helpers and the C.utf8 locale where they exist. The spec BuildRequires dhcp-client on the releases that package it, and runs the new xCAT-genesis-builder/verify-genesis-payload over the extracted payload, which fails the build when sshd needs a helper the image lacks, when tmux has no UTF-8 locale, or when a binary the caller named is missing. The same runs exposed four defects in the test cases themselves. test.sh defined its synthetic node as ppc64le whatever the management node was, so nodeset could not find a genesis kernel on x86_64. genesistest.pl get_os() matched neither AlmaLinux nor Rocky and reported the OS as unsupported. The -g check read $? instead of check_genesis_file()'s return value, so it could never fail. And testxdsh() met "REMOTE HOST IDENTIFICATION HAS CHANGED" from the second boot on, because Genesis makes new host keys every boot and nothing dropped the stale known_hosts entry. test.sh now derives the node arch from uname and takes the tftp root from TFTPDIR, get_os() recognises the redhat family, report_genesis_files() carries the result to an exit status, and forget_host_keys() runs makeknownhosts -r before each probe. Tests: genesis_console_mode.t drives xcat_console_mode() with the multiplexer shadowed; genesis_payload_verification.t drives the verifier over payload trees carrying each hole; genesis_testcase_helpers.t drives get_os(), check_genesis_file(), report_genesis_files() and testxdsh(); genesis_incorrectmasterip_check.t runs test.sh against a scratch tftp root. Each fails on the parent commit. The verifier also reports all three holes against the released xCAT-genesis-base-x86_64-2.19.0-snap202609021858 payload. Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com> (cherry picked from commit cb6021eb3cdb3abc75e4dd6704cb42b28074e140) Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
87 lines
3.2 KiB
Perl
87 lines
3.2 KiB
Perl
#!/usr/bin/env perl
|
|
# Drive xcat_console_mode() out of the Genesis dracut cmdline hook.
|
|
#
|
|
# The hook cannot be sourced: it mounts filesystems, starts udev and ends in an endless
|
|
# loop. Extract the one function and run it with the terminal multiplexer shadowed.
|
|
use strict;
|
|
use warnings;
|
|
|
|
use File::Path qw(make_path);
|
|
use File::Slurper qw(read_text write_text);
|
|
use File::Temp qw(tempdir);
|
|
use FindBin;
|
|
use lib "$FindBin::Bin/../lib";
|
|
use Test::More;
|
|
|
|
use XCAT::Test::File qw(repo_path);
|
|
|
|
my %HOOK = (
|
|
el => { path => 'xCAT-genesis-builder/dracut_105/el/xcat-cmdline.sh', mux => 'tmux' },
|
|
ubuntu => { path => 'xCAT-genesis-builder/dracut_105/ubuntu/xcat-cmdline.sh', mux => 'screen' },
|
|
);
|
|
|
|
plan tests => 5 * scalar(keys %HOOK) + 2;
|
|
|
|
my $tmpdir = tempdir(CLEANUP => 1);
|
|
|
|
# The failure this captures: with no UTF-8 locale in the image, tmux exits and the old
|
|
# unconditional `while :; do tmux ...; done` never reached doxcat.
|
|
my $el = read_text(repo_path($HOOK{el}{path}));
|
|
ok($el !~ qr/^while :; do tmux attach-session/m,
|
|
'el: no unguarded tmux loop is left at column 0');
|
|
ok($el =~ qr/^export LC_ALL=C\.UTF-8$/m,
|
|
'el: the hook exports a UTF-8 locale so tmux can start');
|
|
|
|
foreach my $family (sort keys %HOOK) {
|
|
my $hook = repo_path($HOOK{$family}{path});
|
|
my $mux = $HOOK{$family}{mux};
|
|
|
|
my $body = extract_function($hook, 'xcat_console_mode', $family);
|
|
|
|
is(run_mode($body, $mux, 0), 'direct',
|
|
"$family: xcat_console_mode reports direct when $mux cannot start a session");
|
|
is(run_mode($body, $mux, 1), $mux,
|
|
"$family: xcat_console_mode reports $mux when $mux can start a session");
|
|
|
|
my $text = read_text($hook);
|
|
ok($text =~ qr/^XCAT_CONSOLE_MODE="\$\(xcat_console_mode\)"$/m,
|
|
"$family: the hook resolves the console mode once");
|
|
my $guard = qq{if [ "\$XCAT_CONSOLE_MODE" = "$mux" ]; then};
|
|
ok(index($text, $guard) >= 0,
|
|
"$family: the doxcat loop is guarded by the console mode");
|
|
ok($text =~ qr/\Qelse\E\n\s+while :; do doxcat; sleep 5; done\n\Qfi\E/,
|
|
"$family: doxcat runs directly when $mux is not usable");
|
|
}
|
|
|
|
#---
|
|
# extract_function: lift one shell function out of a script that cannot be sourced.
|
|
# Bails out when the function stops being extractable, so a rename fails loudly instead of
|
|
# leaving the test asserting nothing.
|
|
#---
|
|
sub extract_function {
|
|
my ($path, $name, $label) = @_;
|
|
my $text = read_text($path);
|
|
my ($body) = $text =~ /^($name\(\)\s*\{.*?^\})$/ms;
|
|
BAIL_OUT("$label: $name() not found in $path") unless defined $body;
|
|
return $body;
|
|
}
|
|
|
|
#---
|
|
# run_mode: run the extracted function with the multiplexer shadowed by a stub that either
|
|
# starts a session or refuses, the way tmux refuses without a UTF-8 locale.
|
|
#---
|
|
sub run_mode {
|
|
my ($body, $mux, $mux_works) = @_;
|
|
my $dir = tempdir(DIR => $tmpdir, CLEANUP => 1);
|
|
my $bin = "$dir/bin";
|
|
make_path($bin);
|
|
write_text("$bin/$mux", $mux_works
|
|
? "#!/bin/sh\nexit 0\n"
|
|
: "#!/bin/sh\necho '$mux: need UTF-8 locale (LC_CTYPE) but have ANSI_X3.4-1968' >&2\nexit 1\n");
|
|
chmod 0755, "$bin/$mux";
|
|
write_text("$dir/probe.sh", "$body\nxcat_console_mode\n");
|
|
my $out = `PATH="$bin:\$PATH" /bin/bash "$dir/probe.sh" 2>/dev/null`;
|
|
chomp $out;
|
|
return $out;
|
|
}
|