2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-09-09 05:00:44 +00:00

test(genesis): cover s390x network boot

This commit is contained in:
Vinícius Ferrão
2026-09-04 12:45:07 -03:00
parent a4109f6865
commit 36ca4a369f
9 changed files with 285 additions and 8 deletions
@@ -0,0 +1,52 @@
#!/usr/bin/env perl
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/../../perl-xCAT";
use File::Spec;
use File::Temp qw(tempdir);
use Test::More;
use xCAT::DHCP::BootPolicy;
my ($dhcpd) = grep { -x $_ } qw(/usr/sbin/dhcpd /usr/local/sbin/dhcpd);
plan skip_all => 'dhcpd is required for ISC configuration validation' unless $dhcpd;
plan skip_all => 'root is required to validate from the ISC configuration directory'
unless $> == 0;
my @config = (
"#xCAT generated dhcp configuration\n",
"\n",
"option conf-file code 209 = text;\n",
"option user-class-identifier code 77 = string;\n",
"option client-architecture code 93 = unsigned integer 16;\n",
"option www-server code 114 = string;\n",
"default-lease-time 600;\n",
"max-lease-time 600;\n",
"subnet 192.0.2.0 netmask 255.255.255.0 {\n",
" range 192.0.2.100 192.0.2.110;\n",
);
ok(
xCAT::DHCP::BootPolicy->ensure_isc_path_prefix_definition(\@config),
'the upgrade path adds option 210 to an existing configuration',
);
push @config, @{ xCAT::DHCP::BootPolicy->isc_client_architecture_lines(
next_server => '192.0.2.1',
portsuffix => '',
net => '192.0.2.0',
prefix => 24,
) }, "}\n";
my $configuration_root = -d '/etc/dhcp' ? '/etc/dhcp' : '/etc';
my $directory = tempdir(DIR => $configuration_root, CLEANUP => 1);
my $path = File::Spec->catfile($directory, 'dhcpd.conf');
open(my $config_file, '>', $path) or die "Cannot create $path: $!";
print {$config_file} @config;
close($config_file) or die "Cannot close $path: $!";
my $status = system($dhcpd, '-t', '-cf', $path);
is($status, 0, 'ISC accepts the upgraded s390x boot policy');
done_testing();
@@ -24,6 +24,7 @@ my $json = $backend->render_dhcp4_config(
interfaces => ['*'],
'option-def' => [
{ name => 'conf-file', code => 209, type => 'string', space => 'dhcp4' },
{ name => 'path-prefix', code => 210, type => 'string', space => 'dhcp4' },
{ name => 'iscsi-initiator-iqn', code => 203, type => 'string', space => 'dhcp4' },
{ name => 'cumulus-provision-url', code => 239, type => 'string', space => 'dhcp4' },
],
@@ -41,6 +42,15 @@ my $json = $backend->render_dhcp4_config(
{ name => 'conf-file', data => 'http://192.168.122.1:80/tftpboot/pxelinux.cfg/p/192.168.122.0_24' },
],
},
{
name => 'xcat-s390x-qemu-192.168.122.0_24',
test => 'option[93].hex == 0x001f',
additional_only => JSON::true,
'option-data' => [
{ name => 'conf-file', data => '192.168.122.0_24' },
{ name => 'path-prefix', data => 'pxelinux.cfg/s390x/' },
],
},
{
name => 'xcat-uefi-x64',
test => "(option[93].hex == 0x0007 or option[93].hex == 0x0009 or option[93].hex == 0x0010) and not ((option[77].exists and (option[77].text == 'xNBA' or option[77].hex == 0x784e4241 or substring(option[77].hex,1,4) == 'xNBA')))",
@@ -65,7 +75,10 @@ my $json = $backend->render_dhcp4_config(
subnet => '192.168.122.0/24',
dynamicrange => '192.168.122.100-192.168.122.120',
next_server => '192.168.122.1',
additional_client_classes => ['xcat-opal-v3-192.168.122.0-24'],
additional_client_classes => [
'xcat-opal-v3-192.168.122.0-24',
'xcat-s390x-qemu-192.168.122.0_24',
],
option_data => [
{ name => 'routers', data => '192.168.122.1' },
{ name => 'domain-name', data => 'cluster.test' },
+59
View File
@@ -217,4 +217,63 @@ unlike(
'the global class list keeps HTTP boot out: it needs the address of the management node',
);
my $s390x = xCAT::DHCP::BootPolicy->kea_s390x_network_classes(
net => '10.0.0.0',
prefix => 24,
);
is_deeply(
$s390x,
[
{
name => 'xcat-s390x-qemu-10.0.0.0_24',
test => 'option[93].hex == 0x001f',
additional_only => 1,
'option-data' => [
{
name => 'conf-file',
data => '10.0.0.0_24',
'always-send' => 1,
},
{
name => 'path-prefix',
data => 'pxelinux.cfg/s390x/',
'always-send' => 1,
},
],
},
],
'QEMU s390x stays within its architecture-specific configuration path',
);
is_deeply(
xCAT::DHCP::BootPolicy->kea_s390x_network_classes(prefix => 24),
[],
's390x classes require a network',
);
my @legacy_isc_config = (
"#xCAT generated dhcp configuration\n",
"\n",
"option conf-file code 209 = text;\n",
);
ok(
xCAT::DHCP::BootPolicy->ensure_isc_path_prefix_definition(
\@legacy_isc_config
),
'an older ISC configuration receives the path-prefix definition',
);
is(
$legacy_isc_config[1],
"option path-prefix code 210 = text;\n",
'the definition is inserted in the global configuration header',
);
ok(
!xCAT::DHCP::BootPolicy->ensure_isc_path_prefix_definition(
\@legacy_isc_config
),
'an existing path-prefix definition is preserved',
);
my $definition_count =
grep { /^\s*option\s+path-prefix\s+code\s+210\b/ } @legacy_isc_config;
is($definition_count, 1, 'repeated updates do not duplicate the definition');
done_testing();
+8 -1
View File
@@ -36,6 +36,11 @@ like(
qr/option conf-file = "http:\/\/192\.0\.2\.10:8080\/tftpboot\/pxelinux\.cfg\/p\/192\.0\.2\.0_24";/,
'the existing OPAL branch keeps its subnet URL',
);
like(
$rendered,
qr/client-architecture = 00:1f \{ #QEMU s390x\n\s+option path-prefix = "pxelinux\.cfg\/s390x\/";\n\s+option conf-file = "192\.0\.2\.0_24";/,
'QEMU s390x receives its subnet configuration and fallback path',
);
my @riscv_ids = $rendered =~ /client-architecture = (00:1[9a-e])/g;
is_deeply(
@@ -47,12 +52,14 @@ is_deeply(
my $aarch64_pos = index($rendered, 'client-architecture = 00:0b');
my $tftp_pos = index($rendered, 'client-architecture = 00:1b');
my $http_pos = index($rendered, 'client-architecture = 00:1c');
my $s390_qemu_pos = index($rendered, 'client-architecture = 00:1f');
my $opal_pos = index($rendered, 'client-architecture = 00:0e');
my $fallback_pos = index($rendered, 'substring(filename,0,1) = null');
cmp_ok($aarch64_pos, '<', $tftp_pos, 'riscv64 follows the aarch64 branch');
cmp_ok($tftp_pos, '<', $http_pos, 'the TFTP branch precedes the HTTP branch');
cmp_ok($http_pos, '<', $opal_pos, 'the HTTP branch precedes the OPAL branch');
cmp_ok($http_pos, '<', $s390_qemu_pos, 's390x follows the RISC-V HTTP branch');
cmp_ok($s390_qemu_pos, '<', $opal_pos, 's390x precedes the OPAL branch');
cmp_ok($http_pos, '<', $fallback_pos, 'the HTTP branch is reachable before the fallback');
like($rendered, qr/filename "\/yaboot";\n\s*\}\n\z/, 'the policy ends with the existing yaboot fallback');
+32
View File
@@ -120,6 +120,38 @@ my %network_entry = (
tftpserver => '<xcatmaster>',
);
{
no warnings 'redefine';
local *xCAT::NetworkUtils::thishostisnot = sub { return 0; };
my $nettab = DHCPKeaIntentNetTable->new(\%network_entry);
my $subnet = xCAT_plugin::dhcp::kea_subnet4_intent(
$nettab, '10.0.0.0', '255.255.255.0', 'eth0', 0, 1, 80
);
my %classes = map { $_->{name} => $_ } @{ $subnet->{client_classes} };
ok($classes{'xcat-s390x-qemu-10.0.0.0_24'}, 'the Kea subnet includes QEMU s390x boot policy');
is_deeply(
[ grep { /^xcat-s390x-/ } @{ $subnet->{additional_client_classes} } ],
['xcat-s390x-qemu-10.0.0.0_24'],
'the s390x policy is evaluated only for its subnet',
);
is_deeply(
$classes{'xcat-s390x-qemu-10.0.0.0_24'}{'option-data'},
[
{
name => 'conf-file',
data => '10.0.0.0_24',
'always-send' => 1,
},
{
name => 'path-prefix',
data => 'pxelinux.cfg/s390x/',
'always-send' => 1,
},
],
'the rendered subnet keeps s390x fallback lookups in their own path',
);
}
my @sysconfig_policy_cases = (
[ 'sles10', 0, 'SLES 10' ],
[ 'sles11', 1, 'SLES 11' ],
@@ -14,6 +14,7 @@ my $rpm_weak_dependencies = join(
'Recommends: xCAT-genesis-openembedded-x86_64',
'Recommends: xCAT-genesis-openembedded-ppc64le',
'Recommends: xCAT-genesis-openembedded-riscv64',
'Recommends: xCAT-genesis-openembedded-s390x',
'%endif',
);
@@ -45,6 +46,11 @@ like(
qr/^Recommends:.*\bxcat-genesis-openembedded-riscv64\b/m,
'DEB installations recommend the first-class riscv64 image',
);
like(
$deb_control,
qr/^Recommends:.*\bxcat-genesis-openembedded-s390x\b/m,
'DEB installations recommend the s390x image',
);
unlike(
$deb_control,
qr/^Depends:.*\bxcat-genesis-openembedded-/m,
@@ -74,6 +80,11 @@ like(
qr/^Recommends:.*\bxcat-genesis-openembedded-riscv64\b/m,
'DEB service nodes recommend the first-class riscv64 image',
);
like(
$sn_deb_control,
qr/^Recommends:.*\bxcat-genesis-openembedded-s390x\b/m,
'DEB service nodes recommend the s390x image',
);
my $go_xcat = slurp_repo_file('xCAT-server/share/xcat/tools/go-xcat');
unlike(
@@ -81,7 +92,7 @@ unlike(
qr/GO_XCAT_LIBRARY_ONLY/,
'go-xcat cannot be disabled by an inherited test environment variable',
);
for my $architecture (qw(x86 x86_64 ppc64 ppc64le armv7hf aarch64 riscv64)) {
for my $architecture (qw(x86 x86_64 ppc64 ppc64le armv7hf aarch64 riscv64 s390x)) {
like(
$go_xcat,
qr/\bxCAT-genesis-openembedded-\Q$architecture\E\b/,
+23
View File
@@ -156,6 +156,29 @@ ok(!-e "$tftpdir/xcat/genesis.exact-arch.ppc64le",
ok(-f "$tftpdir/xcat/genesis.kernel.ppc64",
'retiring ppc64le does not remove the legacy ppc64 fallback');
for my $artifact (qw(
genesis.kernel.s390x
genesis.fs.s390x.gz
genesis.fs.s390x.lzma
genesis.exact-arch.s390x
)) {
write_file("$tftpdir/xcat/$artifact", 'stale artifact');
}
make_path("$tftpdir/pxelinux.cfg/s390x");
write_file(
"$tftpdir/pxelinux.cfg/s390x/192.0.2.0_24",
"# pxelinux.cfg xCAT Genesis s390x\nstale config\n",
);
write_file("$tftpdir/pxelinux.cfg/s390x/default", "admin fallback\n");
($removed, $remove_error) =
xCAT_plugin::mknb::_remove_openembedded_genesis($tftpdir, 's390x');
is($remove_error, undef, 's390x boot artifacts can be retired cleanly');
is($removed, 5, 's390x image and generated discovery configuration are retired');
ok(!-e "$tftpdir/pxelinux.cfg/s390x/192.0.2.0_24",
'retiring s390x removes the generated discovery configuration');
is(read_file("$tftpdir/pxelinux.cfg/s390x/default"), "admin fallback\n",
'retiring s390x preserves administrator-owned configurations');
my $failed_kernel = "$tftpdir/xcat/genesis.kernel.aarch64";
make_path($failed_kernel);
for my $artifact (qw(
+79
View File
@@ -508,4 +508,83 @@ ok(
%xCAT::TableUtils::site_extra = ();
$xCAT::NetworkUtils::nic_ips = undef;
make_path("$::XCATROOT/share/xcat/netboot/genesis-openembedded/s390x");
use_reporter_address_maps();
prepare_tftpdir($tmpdir, 'tftpboot-s390x', 's390x');
$responses = run_mknb('s390x');
generation_succeeded($responses, 's390x configuration generation succeeds');
my $s390x_qemu_path =
"$xCAT::TableUtils::tftpdir/pxelinux.cfg/s390x/192.168.144.0_20";
ok(-f $s390x_qemu_path, 's390x writes a QEMU network IPL configuration');
is(
read_config($s390x_qemu_path),
"# pxelinux.cfg xCAT Genesis s390x\n"
. "DEFAULT xCAT\n"
. "LABEL xCAT\n"
. " KERNEL xcat/genesis.kernel.s390x\n"
. " INITRD xcat/genesis.fs.s390x.gz\n"
. " APPEND xcatd=192.168.148.10:3001 xcat.bootloader=s390-ccw console=ttysclp0\n",
'the QEMU configuration selects Genesis and the SCLP console',
);
unlike(
read_config($s390x_qemu_path),
qr/192\.168\.149\.100/,
's390x configurations do not use the later floating address',
);
write_text($s390x_qemu_path, "admin network configuration\n");
%xCAT::TableUtils::site_extra = ( dhcpinterfaces => 'eth0,eth1:noboot' );
$xCAT::NetworkUtils::nic_ips = { eth0 => '10.0.0.1', eth1 => '192.168.148.10' };
$responses = run_mknb('s390x');
generation_succeeded($responses, 's390x configuration generation accepts a :noboot interface');
is(
read_config($s390x_qemu_path),
"admin network configuration\n",
'a :noboot interface preserves an administrator-owned s390x configuration',
);
%xCAT::TableUtils::site_extra = ();
$xCAT::NetworkUtils::nic_ips = undef;
$responses = run_mknb('s390x');
generation_succeeded($responses, 's390x configuration is restored after removing :noboot');
my $s390x_failure_root = "$tmpdir/tftpboot-s390x-failure";
make_path("$s390x_failure_root/pxelinux.cfg/s390x/192.168.144.0_20");
my (undef, $s390x_write_error) =
xCAT_plugin::mknb::_write_s390x_discovery_config(
tftpdir => $s390x_failure_root,
network => '192.168.144.0_20',
xcatd_address => '192.168.148.10',
xcatdport => 3001,
consolecmdline => 'console=ttysclp0',
initrd => "$s390x_failure_root/xcat/genesis.fs.s390x.gz",
);
like(
$s390x_write_error,
qr/^Unable to write s390x Genesis configuration:/,
's390x configuration write failures are reported',
);
%xCAT::TableUtils::site_extra = (
defserialport => '2',
defserialspeed => '9600',
defserialflow => 'hard',
xcatdport => '3002',
);
$responses = run_mknb('s390x');
generation_succeeded($responses, 's390x ignores PC serial settings');
like(
read_config($s390x_qemu_path),
qr/^ APPEND xcatd=192\.168\.148\.10:3002 xcat\.bootloader=s390-ccw console=ttysclp0$/m,
's390x keeps its SCLP console and the configured xcatd port',
);
%xCAT::TableUtils::site_extra = ( dhcpinterfaces => 'eth0,eth1:noboot' );
$xCAT::NetworkUtils::nic_ips = { eth0 => '10.0.0.1', eth1 => '192.168.148.10' };
$responses = run_mknb('s390x');
generation_succeeded($responses, 's390x configuration generation honors :noboot');
ok(!-e $s390x_qemu_path, 'a :noboot network gets no QEMU s390x configuration');
%xCAT::TableUtils::site_extra = ();
$xCAT::NetworkUtils::nic_ips = undef;
done_testing();
@@ -27,6 +27,7 @@ make_path(
"$tmpdir/share/xcat/netboot/genesis/x86_64/fs",
"$tmpdir/share/xcat/netboot/genesis-openembedded/aarch64",
"$tmpdir/share/xcat/netboot/genesis-openembedded/ppc64le",
"$tmpdir/share/xcat/netboot/genesis-openembedded/s390x",
"$tmpdir/share/xcat/netboot/genesis-openembedded/x86_64",
);
my $symlink_target = "$tmpdir/openembedded-riscv64";
@@ -38,25 +39,25 @@ symlink(
is_deeply(
[ _installed_genesis_architectures($tmpdir) ],
[ qw(aarch64 ppc64 ppc64le x86_64) ],
[ qw(aarch64 ppc64 ppc64le s390x x86_64) ],
'xcatconfig ignores linked OpenEmbedded images and finds legacy images',
);
is_deeply(
[ _genesis_architectures_to_build($tmpdir, 0) ],
[ qw(aarch64 ppc64le x86_64) ],
[ qw(aarch64 ppc64le s390x x86_64) ],
'an ordinary xCAT update rebuilds only installed OpenEmbedded images',
);
is_deeply(
[ _genesis_architectures_to_build($tmpdir, 1) ],
[ qw(aarch64 ppc64 ppc64le x86_64) ],
[ qw(aarch64 ppc64 ppc64le s390x x86_64) ],
'a legacy package trigger rebuilds every installed Genesis image',
);
make_path("$tmpdir/share/xcat/netboot/genesis-openembedded/unsupported");
is_deeply(
[ _installed_genesis_architectures($tmpdir) ],
[ qw(aarch64 ppc64 ppc64le x86_64) ],
[ qw(aarch64 ppc64 ppc64le s390x x86_64) ],
'unknown directories are not passed to mknb',
);
@@ -67,7 +68,7 @@ symlink($legacy_target, "$tmpdir/share/xcat/netboot/genesis/ppc64")
or die "create legacy directory symlink: $!";
is_deeply(
[ _installed_genesis_architectures($tmpdir) ],
[ qw(aarch64 ppc64 ppc64le x86_64) ],
[ qw(aarch64 ppc64 ppc64le s390x x86_64) ],
'legacy Genesis directory symlinks remain supported',
);