2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-10-21 15:18:19 +00:00

test(mknb): exercise compression and archive publication

This commit is contained in:
Vinícius Ferrão
2026-10-08 16:05:52 -03:00
parent 952787108e
commit 35d01515eb
4 changed files with 111 additions and 44 deletions
+1 -1
View File
@@ -9,7 +9,7 @@ jobs:
- name: Refresh package indexes
run: sudo apt-get update
- name: Install dependencies
run: sudo env DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends --no-install-suggests bats bubblewrap cpio gawk mawk rpm rsyslog build-essential fakeroot reprepro devscripts debhelper libcapture-tiny-perl libfile-slurper-perl libjson-perl libyaml-pp-perl libparallel-forkmanager-perl libsoap-lite-perl libdbi-perl libdbd-sqlite3-perl libcgi-pm-perl quilt openssh-server dpkg looptools genometools software-properties-common grub-common grub-efi-amd64-bin squashfs-tools pigz
run: sudo env DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends --no-install-suggests bats bubblewrap cpio xz-utils gzip gawk mawk rpm rsyslog build-essential fakeroot reprepro devscripts debhelper libcapture-tiny-perl libfile-slurper-perl libjson-perl libyaml-pp-perl libparallel-forkmanager-perl libsoap-lite-perl libdbi-perl libdbd-sqlite3-perl libcgi-pm-perl quilt openssh-server dpkg looptools genometools software-properties-common grub-common grub-efi-amd64-bin squashfs-tools pigz
- name: Enable postscript test namespaces
run: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
- name: Install lifecycle test dependencies
+26
View File
@@ -0,0 +1,26 @@
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/../../../perl-xCAT";
use lib "$FindBin::Bin/../../../xCAT-server/lib/perl";
use JSON qw(encode_json);
$ENV{XCATROOT} = "$FindBin::Bin/../../../xCAT-server";
$ENV{XCATCFG} = '/tmp/fixture/config';
my $plugin = "$FindBin::Bin/../../../xCAT-server/lib/xcat/plugins/mknb.pm";
require $plugin;
$::XCATROOT = '/tmp/fixture/source';
no warnings qw(redefine once);
local *xCAT::TableUtils::getTftpDir = sub { return '/tmp/fixture/tftp'; };
local *xCAT::TableUtils::get_site_attribute = sub { return; };
local *xCAT::NetworkUtils::my_nets = sub { return {}; };
local *xCAT::NetworkUtils::my_hexnets = sub { return {}; };
my @responses;
umask oct($ARGV[0]);
xCAT_plugin::mknb::process_request(
{ arg => ['x86_64'] }, sub { push @responses, @_; },
);
print encode_json(\@responses), "\n";
exit((grep { $_->{error} || $_->{errorcode} } @responses) ? 1 : 0);
@@ -0,0 +1,50 @@
#!/usr/bin/env bats
setup()
{
[ "$(uname -s)" = Linux ] || skip 'Genesis compression requires Linux namespaces'
fixture="$BATS_TEST_TMPDIR/build"
[ -n "$BATS_TEST_TMPDIR" ] || return 1
mkdir -p "$fixture"/{source/share/xcat/netboot/genesis/x86_64/fs,root/.ssh,etc/xcat,config,tftp,bin,unpacked}
printf 'fixture payload\n' > "$fixture/source/share/xcat/netboot/genesis/x86_64/fs/payload"
printf 'fixture kernel\n' > "$fixture/source/share/xcat/netboot/genesis/x86_64/kernel"
printf 'fixture public key\n' > "$fixture/root/.ssh/id_rsa.pub"
}
build_image()
{
bwrap --die-with-parent --unshare-net --ro-bind / / --dev /dev --proc /proc \
--tmpfs /tmp --ro-bind "$BATS_TEST_DIRNAME/../.." /tmp/source \
--bind "$fixture" /tmp/fixture --bind "$fixture/root" /root \
--bind "$fixture/etc" /etc --chdir /tmp/fixture \
--setenv PATH /tmp/fixture/bin:/usr/bin:/bin \
perl /tmp/source/xCAT-test/bats/fixtures/mknb-compress.pl "$1"
}
check_payload()
{
local image="$1" compression="$2" mode="$3"
[ "$(stat -c '%a' "$image")" = "$mode" ]
(cd "$fixture/unpacked" && "$compression" -dc "$image" | cpio -id)
[ "$(cat "$fixture/unpacked/payload")" = 'fixture payload' ]
[ "$(cat "$fixture/unpacked/.ssh/authorized_keys")" = 'fixture public key' ]
[ "$(stat -c '%a' "$fixture/unpacked/.ssh/authorized_keys")" = 600 ]
[ "$(cat "$fixture/tftp/xcat/genesis.kernel.x86_64")" = 'fixture kernel' ]
[ "$(find "$fixture/tftp/xcat" -maxdepth 1 -type f | wc -l)" -eq 2 ]
}
@test "mknb publishes a complete LZMA image with the caller's umask" {
run build_image 022
[ "$status" -eq 0 ] || { printf '%s\n' "$output"; return 1; }
check_payload "$fixture/tftp/xcat/genesis.fs.x86_64.lzma" xz 644
}
@test "mknb falls back to gzip and removes the failed LZMA staging file" {
printf '#!/bin/sh\nprintf partial\nexit 42\n' > "$fixture/bin/lzma"
cp "$fixture/bin/lzma" "$fixture/bin/xz"
chmod +x "$fixture/bin/lzma" "$fixture/bin/xz"
run build_image 027
[ "$status" -eq 0 ] || { printf '%s\n' "$output"; return 1; }
[[ "$output" == *'failed, falling back to gzip'* ]]
check_payload "$fixture/tftp/xcat/genesis.fs.x86_64.gz" gzip 640
}
+34 -43
View File
@@ -1,54 +1,45 @@
#!/usr/bin/env perl
use strict;
use warnings;
use FindBin;
use File::Spec;
use lib "$FindBin::Bin/../lib";
use lib "$FindBin::Bin/../../perl-xCAT";
use lib "$FindBin::Bin/../../xCAT-server/lib/perl";
use File::Path qw(make_path);
use File::Temp qw(tempdir);
use File::Slurper qw(read_binary write_text);
use Test::More;
use XCAT::Test::File qw(repo_path);
my $plugin = File::Spec->catfile( $FindBin::Bin, '..', '..',
'xCAT-server', 'lib', 'xcat', 'plugins', 'mknb.pm' );
plan skip_all => 'mknb.pm not found' unless -r $plugin;
my $root = tempdir(CLEANUP => 1);
$ENV{XCATROOT} = repo_path('xCAT-server');
$ENV{XCATCFG} = "$root/config";
make_path($ENV{XCATCFG});
require(repo_path('xCAT-server/lib/xcat/plugins/mknb.pm'));
open( my $fh, '<', $plugin ) or die "Unable to read $plugin: $!";
my $source = do { local $/; <$fh> };
close($fh);
# xz supports the lzma invocation name even where the distribution omits that link.
symlink('/usr/bin/xz', "$root/lzma") or die "create lzma alias: $!";
local $ENV{PATH} = "$root:$ENV{PATH}";
# mknb.pm needs a management node to load, so lift the routine out and drive
# the real code on its own.
my ($routine) = $source =~ /(sub genesis_lzma_command \{.*?\n\}\n)/s;
BAIL_OUT('could not extract genesis_lzma_command from mknb.pm') unless $routine;
eval "package MknbCompressor; $routine 1;" or BAIL_OUT("could not evaluate: $@");
write_text("$root/payload", "Genesis payload\n");
is(system("cd '$root' && printf 'payload\\n' | cpio -o -H newc > archive.cpio"), 0,
'builds an actual newc archive');
my $archive = read_binary("$root/archive.cpio");
like($archive, qr/^070701/, 'fixture is a newc archive');
sub command { return MknbCompressor::genesis_lzma_command(@_); }
# Debian and Ubuntu ship both names, and lzma is the one the plugin has always
# used, so nothing changes on those systems.
is( command( 1, 1 ), 'lzma -C crc32 -9', 'lzma is used when it is there' );
# Red Hat ships xz alone.
is( command( 0, 1 ), 'xz --format=lzma -C crc32 -9',
'xz stands in for lzma when only xz is there' );
# The gzip path below the caller handles a system with neither.
is( command( 0, 0 ), undef, 'nothing is returned when neither program is there' );
# The container has to stay the one the file name promises. "xz" on its own
# writes the xz container, which the file name does not describe and which a
# reader of a .lzma file cannot open.
my ($xz_form) = command( 0, 1 ) =~ /--format=(\S+)/;
is( $xz_form, 'lzma', 'xz is asked for the lzma container, not its own' );
# The caller has to take the command from the routine, and the name of the
# written file must not change with it.
like( $source, qr/genesis_lzma_command\(-x "\/usr\/bin\/lzma", -x "\/usr\/bin\/xz"\)/,
'the caller asks the routine which program to run' );
like( $source, qr/cpio -o -H newc \| \$lzma_command > \$tftpdir\/xcat\/genesis\.fs\.\$arch\.lzma\.\$suffix/,
'the chosen command writes the same file under the same suffix' );
# The fallback to gzip and the atomic rename both have to survive.
like( $source, qr/falling back to gzip/, 'the gzip fallback is still reported' );
like( $source, qr/move\("\$tftpdir\/xcat\/genesis\.fs\.\$arch\.lzma\.\$suffix"/,
'the finished image is still renamed into place' );
for my $case ([1, 1, 'lzma'], [1, 0, 'lzma'], [0, 1, 'xz']) {
my ($lzma, $xz, $name) = @$case;
subtest "$name with lzma=$lzma xz=$xz" => sub {
my $command = xCAT_plugin::mknb::genesis_lzma_command($lzma, $xz);
like($command, qr/^\Q$name\E /, 'selects the available compressor');
is(system("$command < '$root/archive.cpio' > '$root/archive.lzma'"), 0,
'selected command compresses the archive');
is(system("xz --format=lzma -dc '$root/archive.lzma' > '$root/decoded.cpio'"), 0,
'output has the promised LZMA container');
is(read_binary("$root/decoded.cpio"), $archive, 'decompression preserves every archive byte');
};
}
is(xCAT_plugin::mknb::genesis_lzma_command(0, 0), undef,
'no LZMA command is selected when neither compressor is available');
done_testing();