2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-10-22 07:38:08 +00:00
Files
xcat-core/xCAT-test/unit/ubuntu_subiquity_storage.t
T
Daniel Hilst e82af69caf test(xcat-core): a missing fixture in two POWER install tests stops the whole suite
debian_install_prescript.t and ubuntu_subiquity_storage.t called BAIL_OUT
at eight places where an extraction or a fixture was not what they
expected. prove stops every remaining file on a bail-out, so one changed
script hides the results of every test that would have run after it. die
is just as loud and costs only its own file.

Three comments also carried the incident rather than the constraint. The
prescript test header named a build number, a cell, a case and the ssh
error the node produced nine times; the boot-file test repeated the
nodeset message and the media table below it.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-14 08:35:54 -03:00

157 lines
7.4 KiB
Perl

#!/usr/bin/env perl
# The partitioning pre.ubuntu.subiquity hands to Subiquity.
#
# Every assertion here used to be a regex against the script's own text, which
# passes when the block is moved somewhere it never runs and fails when the YAML
# is reindented or its keys reordered -- a pure reformat broke the old efi-part
# match while the emitted config was identical. The block is executed instead and
# the config it writes is parsed, so the assertions are about what Subiquity gets.
use strict;
use warnings;
use File::Spec;
use File::Temp ();
use Test::More;
my $pre_path = defined $ENV{XCATROOT} ? "$ENV{XCATROOT}/share/xcat/install/scripts/pre.ubuntu.subiquity" : '';
$pre_path = "xCAT-server/share/xcat/install/scripts/pre.ubuntu.subiquity"
unless -f $pre_path;
plan skip_all => "pre.ubuntu.subiquity not found" unless -f $pre_path;
my $script = do { local $/; open my $fh, '<', $pre_path or die $!; <$fh> };
is( system("bash -n $pre_path 2>/dev/null"), 0,
'pre.ubuntu.subiquity passes bash -n syntax check' );
# ------------------------------------------------------ the emitted partitioning --
# pre.ubuntu.subiquity cannot run here -- it stops syslog and carries xCAT template
# markers -- so the block that writes the partition file is lifted out and executed,
# with its one bracket test shadowed to choose the firmware branch and its output
# redirected into a scratch tree. Both substitutions are asserted: if either stops
# matching, this bails out rather than silently covering nothing or writing to /tmp.
my ($storage_block) = $script =~ /(^if \[ -d \/sys\/firmware\/efi \]; then\n.*?\n^fi$)/ms;
die('the firmware branch that writes the partition file no longer matches')
unless $storage_block;
die('the firmware test the shadow below answers is gone')
unless $storage_block =~ /\[ -d \/sys\/firmware\/efi \]/;
die('the block no longer asks uname for the machine architecture')
unless $storage_block =~ /uname -m/;
my $sandbox = File::Temp::tempdir( CLEANUP => 1 );
my $partfile = File::Spec->catfile( $sandbox, 'partitionfile' );
# One redirect per firmware branch. Counting the branches rather than naming a number
# keeps the guard true when a branch is added, and still fails loudly if a redirect
# escapes the sandbox.
my $branches = () = $storage_block =~ /^\s*cat <<EOF >\/tmp\/partitionfile$/mg;
my $rewrites = ( $storage_block =~ s{/tmp/partitionfile}{$partfile}g );
die("the block writes the partition file in $branches places and $rewrites were rewritten")
unless $branches >= 2 && $rewrites == $branches;
die('a partition-file path escaped the sandbox')
if $storage_block =~ m{/tmp/partitionfile};
my %YAML_FOR;
sub partition_yaml_for { return $YAML_FOR{ $_[0] }; }
sub partition_config_for {
my ($firmware) = @_;
my $script = File::Spec->catfile( $sandbox, 'storage.sh' );
open( my $fh, '>', $script ) or die "Unable to write $script: $!";
# `[` is shadowed rather than the condition rewritten: bash resolves a function
# ahead of the builtin, so the script's own test runs unmodified.
my $machine = $firmware eq 'prep' ? 'ppc64le' : 'x86_64';
print {$fh} <<"SHELL";
INSTALL_DISK=/dev/sdz
logger() { :; }
uname() { builtin echo $machine; }
# Only the firmware probe is answered here; every other test falls through to the builtin.
[() {
case "\$1 \$2" in
"-d /sys/firmware/efi") return @{[ $firmware eq 'uefi' ? 0 : 1 ]} ;;
*) builtin [ "\$@" ;;
esac
}
$storage_block
SHELL
close($fh);
unlink $partfile;
system( 'bash', $script ) == 0
or die("the extracted partitioning block failed to run for $firmware");
open( my $out_fh, '<', $partfile )
or die("the partitioning block wrote no file for $firmware: $!");
my $yaml = do { local $/; <$out_fh> };
close($out_fh);
$YAML_FOR{$firmware} = $yaml;
# Parse the curtin config into id => {key => value} so the assertions survive
# reordering and reindentation, which is what the source match could not do.
my %entry;
my $current;
foreach my $line ( split /\n/, $yaml ) {
if ( $line =~ /^\s+- id:\s*(\S+)/ ) {
$current = $1;
$entry{$current} = { id => $1 };
}
elsif ( defined $current && $line =~ /^\s+(\S+):\s*(\S*)\s*$/ ) {
$entry{$current}{$1} = $2;
}
}
return \%entry;
}
my $uefi = partition_config_for('uefi');
is( $uefi->{'efi-part'}{type}, 'partition', 'UEFI installs get an EFI partition' );
is( $uefi->{'efi-part'}{device}, 'disk-detected', 'on the detected install disk' );
is( $uefi->{'efi-part'}{size}, '512M', 'sized for an ESP' );
is( $uefi->{'efi-part'}{flag}, 'boot', 'flagged bootable' );
is( $uefi->{'efi-part'}{number}, '1', 'as the first partition' );
is( $uefi->{'efi-part'}{grub_device}, 'true', 'and it is where grub is installed' );
is( $uefi->{'efi-part-fs'}{type}, 'format', 'the ESP is formatted' );
is( $uefi->{'efi-part-fs'}{fstype}, 'fat32', 'as fat32, which firmware can read' );
is( $uefi->{'efi-part-fs'}{volume}, 'efi-part', 'on the partition just created' );
is( $uefi->{'efi-part-mount'}{path}, '/boot/efi', 'and mounted where the kernel expects it' );
# The BIOS branch must not carry the ESP, and puts grub on the disk itself.
my $bios = partition_config_for('bios');
ok( !exists $bios->{'efi-part'}, 'BIOS installs get no EFI partition' );
is( $bios->{'bios-grub'}{flag}, 'bios_grub', 'they get a bios_grub partition instead' );
is( $bios->{'disk-detected'}{grub_device}, 'true', 'and grub is installed to the disk' );
# POWER firmware reads neither an ESP nor a bios_grub partition. It boots from a PReP
# partition, and curtin installs grub to that partition rather than to the disk.
my $prep = partition_config_for('prep');
ok( !exists $prep->{'efi-part'}, 'POWER installs get no EFI partition' );
ok( !exists $prep->{'bios-grub'}, 'POWER installs get no bios_grub partition' );
is( $prep->{'prep-part'}{type}, 'partition', 'POWER installs get a PReP partition' );
is( $prep->{'prep-part'}{device}, 'disk-detected', 'on the detected install disk' );
is( $prep->{'prep-part'}{flag}, 'prep', 'flagged prep, which is what SLOF reads' );
is( $prep->{'prep-part'}{number}, '1', 'as the first partition' );
is( $prep->{'prep-part'}{grub_device}, 'true', 'and grub is installed to it' );
isnt( $prep->{'disk-detected'}{grub_device}, 'true',
'not to the disk, which leaves POWER with nothing to boot' );
ok( !exists $prep->{'prep-part-fs'},
'the PReP partition carries no filesystem' );
foreach my $firmware ( [ UEFI => $uefi ], [ BIOS => $bios ], [ PReP => $prep ] ) {
my ( $name, $config ) = @{$firmware};
is( $config->{'root-part-fs'}{fstype}, 'ext4', "$name root filesystem is ext4" );
is( $config->{'root-part-mount'}{path}, '/', "$name mounts root at /" );
is( $config->{'swap-part-fs'}{fstype}, 'swap', "$name has swap formatted" );
is( $config->{'root-part'}{size}, '-1',
"$name gives the remaining space to root" );
}
# Subiquity re-serializes autoinstall.yaml and appends this file, so the block has
# to start at column 0 -- asserted on what was written, not on the heredoc.
foreach my $firmware ( [ UEFI => 'uefi' ], [ BIOS => 'bios' ], [ PReP => 'prep' ] ) {
my ( $name, $key ) = @{$firmware};
like( partition_yaml_for($key), qr/\Astorage:\n version: 1\n/,
"$name config starts at column 0 with storage: version: 1" );
}
done_testing();