mirror of
https://github.com/xcat2/xcat-core.git
synced 2026-09-24 16:54:03 +00:00
test(xcat-core): a Genesis image with no /usr/bin/awk passes verification
verify-genesis-payload reads the names the dracut module installs back out of module-setup.sh and checks each one against the extracted payload. It drops every name that starts with "/", so the 609 absolute paths the EL module names are checked by nothing. An image built without /usr/bin/awk, /etc/services or /lib64/libnss_dns.so.2 passes. The Genesis debs carry the architecture in the package name. 2.19 renames the ppc64 debs to ppc64el, and neither builddeb-genesis-base nor debuild-xcat-genesis-base names the deb the new package supersedes. dpkg keeps xcat-genesis-base-ppc64 installed beside xcat-genesis-base-ppc64el, and the old package owns the same files under /opt/xcat/share/xcat/netboot/genesis. genesis_payload_verification.t drives the verifier against a payload missing /usr/bin/awk and one missing /etc/services. genesis_base_deb_arch.t asserts the Replaces and Breaks the alien path writes. genesis_base_deb_control_rewrite.t lifts rewrite_control() out of builddeb-genesis-base and runs it over the control file in the tree. Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
This commit is contained in:
@@ -2,7 +2,8 @@
|
||||
# debuild-xcat-genesis-base converts the EL Genesis base rpm to a deb. The rpm name carries the
|
||||
# Genesis target architecture, and the deb must carry the Debian architecture: ppc64 becomes
|
||||
# ppc64el, x86_64 becomes amd64. An unmapped architecture leaves the deb named after the rpm and
|
||||
# makes it break a genesis-scripts package that no repository publishes.
|
||||
# makes it break a genesis-scripts package that no repository publishes. The rename also has to
|
||||
# name the deb it supersedes, or an upgraded ppc node keeps xcat-genesis-base-ppc64 as well.
|
||||
#
|
||||
# The script is driven here with alien and dpkg-buildpackage shadowed by shell functions.
|
||||
use strict;
|
||||
@@ -75,6 +76,13 @@ my %expected = (
|
||||
'xCAT-genesis-base-ppc64-2.13.10-snap202601010000.noarch.rpm' => 'ppc64el',
|
||||
);
|
||||
|
||||
# The package the new deb takes over from. On ppc that is the deb this rename leaves behind:
|
||||
# without the relation dpkg keeps xcat-genesis-base-ppc64 and its copy of the same files.
|
||||
my %superseded = (
|
||||
'amd64' => 'xcat-genesis-amd64',
|
||||
'ppc64el' => 'xcat-genesis-ppc64, xcat-genesis-base-ppc64',
|
||||
);
|
||||
|
||||
for my $rpm (sort keys %expected) {
|
||||
my $arch = $expected{$rpm};
|
||||
my ($dir, $control) = convert($arch, $rpm);
|
||||
@@ -84,8 +92,12 @@ for my $rpm (sort keys %expected) {
|
||||
like($dir, qr/\Q-$arch-\E/, "$rpm builds in a $arch source tree");
|
||||
like($control, qr/^Package:\s*xcat-genesis-base-\Q$arch\E$/m,
|
||||
"$rpm builds the package xcat-genesis-base-$arch");
|
||||
like($control, qr/^Breaks:\s*xcat-genesis-scripts-\Q$arch\E\b/m,
|
||||
like($control, qr/^Breaks:.*\bxcat-genesis-scripts-\Q$arch\E\b/m,
|
||||
"xcat-genesis-base-$arch breaks the genesis scripts of its own architecture");
|
||||
like($control, qr/^Replaces:\s*\Q$superseded{$arch}\E\s*$/m,
|
||||
"xcat-genesis-base-$arch replaces $superseded{$arch}");
|
||||
like($control, qr/^Breaks:\s*\Q$superseded{$arch}\E\b/m,
|
||||
"xcat-genesis-base-$arch breaks $superseded{$arch}");
|
||||
}
|
||||
|
||||
done_testing();
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env perl
|
||||
# builddeb-genesis-base builds the Genesis base deb natively on Ubuntu. It writes the target
|
||||
# architecture into debian/control, which is held in the amd64 form in the tree. 2.19 renames
|
||||
# the ppc64 debs to ppc64el, so the ppc control must also name the deb it supersedes: without
|
||||
# the relation dpkg keeps xcat-genesis-base-ppc64 installed beside the new package, and that
|
||||
# old package owns the same files under /opt/xcat/share/xcat/netboot/genesis.
|
||||
#
|
||||
# The script needs dracut and root, so rewrite_control() is lifted out of it and run alone
|
||||
# against the control file the tree ships.
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
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 slurp_repo_file);
|
||||
|
||||
my $script = repo_path('xCAT-genesis-builder/builddeb-genesis-base');
|
||||
my $control = repo_path('xCAT-genesis-builder/debian/control');
|
||||
plan skip_all => 'builddeb-genesis-base not found' unless -f $script;
|
||||
plan tests => 8;
|
||||
|
||||
my $text = slurp_repo_file('xCAT-genesis-builder/builddeb-genesis-base');
|
||||
my ($function) = $text =~ /^(rewrite_control\(\)\s*\{.*?^\})/ms;
|
||||
BAIL_OUT('rewrite_control() no longer matches in builddeb-genesis-base')
|
||||
unless defined $function;
|
||||
|
||||
my $tmpdir = tempdir(CLEANUP => 1);
|
||||
|
||||
# What the ppc64el package has to take over from, and what amd64 already took over from.
|
||||
my %superseded = (
|
||||
'amd64' => 'xcat-genesis-amd64',
|
||||
'ppc64el' => 'xcat-genesis-ppc64, xcat-genesis-base-ppc64',
|
||||
);
|
||||
|
||||
for my $arch (sort keys %superseded) {
|
||||
my $out = rewrite($arch);
|
||||
|
||||
like($out, qr/^Package:\s*xcat-genesis-base-\Q$arch\E$/m,
|
||||
"$arch control names the package xcat-genesis-base-$arch");
|
||||
like($out, qr/^Replaces:\s*\Q$superseded{$arch}\E\s*$/m,
|
||||
"$arch control replaces $superseded{$arch}");
|
||||
like($out, qr/^Breaks:\s*\Q$superseded{$arch}\E\b/m,
|
||||
"$arch control breaks $superseded{$arch}");
|
||||
like($out, qr/^Breaks:.*\bxcat-genesis-scripts-\Q$arch\E \(<< 2\.13\.10\)/m,
|
||||
"$arch control breaks the genesis scripts of its own architecture");
|
||||
}
|
||||
|
||||
#---
|
||||
# rewrite: run the lifted rewrite_control() over a copy of the control file in the tree.
|
||||
#---
|
||||
sub rewrite {
|
||||
my ($arch) = @_;
|
||||
my $copy = "$tmpdir/control.$arch";
|
||||
write_text($copy, read_text($control));
|
||||
my $driver = "$tmpdir/driver.$arch.sh";
|
||||
write_text($driver, "#!/bin/bash\nset -eu\n$function\nrewrite_control \"\$1\" \"\$2\"\n");
|
||||
system('bash', $driver, $copy, $arch) == 0
|
||||
or BAIL_OUT("rewrite_control failed for $arch");
|
||||
return read_text($copy);
|
||||
}
|
||||
@@ -15,7 +15,7 @@ use XCAT::Test::File qw(repo_path);
|
||||
|
||||
my $verifier = repo_path('xCAT-genesis-builder/verify-genesis-payload');
|
||||
plan skip_all => 'verify-genesis-payload not found' unless -f $verifier;
|
||||
plan tests => 18;
|
||||
plan tests => 22;
|
||||
|
||||
my $tmpdir = tempdir(CLEANUP => 1);
|
||||
my $module_seq = 0;
|
||||
@@ -71,6 +71,23 @@ my $noopenssl = build_payload(sshd_execs_session => 1, session_helper => 1, tmux
|
||||
isnt($rc, 0, 'a payload without openssl fails');
|
||||
like($err, qr/openssl/, 'the missing openssl is named');
|
||||
|
||||
# dracut_install installs an absolute path at that same path. The verifier used to drop every
|
||||
# name that started with "/", so an image with no /usr/bin/awk passed. doxcat, getdestiny and
|
||||
# the firmware wrappers all run awk.
|
||||
my $noawk = build_payload(sshd_execs_session => 1, session_helper => 1, tmux => 1, locale => 1,
|
||||
dhclient => 1, mktemp => 1, commands => [qw(openssl wget tar)], absent => ['usr/bin/awk']);
|
||||
($rc, $err) = run_with_commands($module, $noawk);
|
||||
isnt($rc, 0, 'a payload without the absolute path /usr/bin/awk fails');
|
||||
like($err, qr{/usr/bin/awk}, 'the missing /usr/bin/awk is named');
|
||||
|
||||
# The module names data files by absolute path too. Genesis resolves service names with
|
||||
# /etc/services.
|
||||
my $noservices = build_payload(sshd_execs_session => 1, session_helper => 1, tmux => 1, locale => 1,
|
||||
dhclient => 1, mktemp => 1, commands => [qw(openssl wget tar)], absent => ['etc/services']);
|
||||
($rc, $err) = run_with_commands($module, $noservices);
|
||||
isnt($rc, 0, 'a payload without the absolute path /etc/services fails');
|
||||
like($err, qr{/etc/services}, 'the missing /etc/services is named');
|
||||
|
||||
# The DHCP client is release-dependent, so the module installs it inside a conditional. Those
|
||||
# names are not the contract; the spec passes the one it wants as a required path.
|
||||
my $conditional = write_module_setup(['wget'], ['dhclient']);
|
||||
@@ -112,6 +129,15 @@ sub build_payload {
|
||||
write_text("$root/usr/sbin/dhclient", "dhclient\n") if $opt{dhclient};
|
||||
write_text("$root/usr/bin/mktemp", "mktemp\n") if $opt{mktemp};
|
||||
write_text("$root/usr/bin/$_", "$_\n") for @{ $opt{commands} || [] };
|
||||
|
||||
# The module written by write_module_setup names these two by absolute path.
|
||||
my %absent = map { $_ => 1 } @{ $opt{absent} || [] };
|
||||
for my $path (qw(usr/bin/awk etc/services)) {
|
||||
next if $absent{$path};
|
||||
my ($dir) = $path =~ m{^(.*)/};
|
||||
make_path("$root/$dir");
|
||||
write_text("$root/$path", "$path\n");
|
||||
}
|
||||
return $root;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user