From 2bb76b523e1c47432ff6fa28bc0b1db93f32de6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Ferr=C3=A3o?= <2031761+viniciusferrao@users.noreply.github.com> Date: Fri, 4 Sep 2026 14:42:42 -0300 Subject: [PATCH] test(genesis): cover s390x boot handoff --- .../integration/dhcp_isc_config_validation.t | 2 + .../integration/dhcp_kea_config_validation.t | 7 +++ xCAT-test/unit/dhcp_boot_policy.t | 36 ++++++++++++-- xCAT-test/unit/dhcp_isc_client_arch.t | 15 ++++-- xCAT-test/unit/dhcp_kea_plugin_intent.t | 47 ++++++++++++------- xCAT-test/unit/mknb_exported_genesis.t | 30 +++++++++++- xCAT-test/unit/mknb_xcatd_address.t | 16 +++++++ 7 files changed, 125 insertions(+), 28 deletions(-) diff --git a/xCAT-test/integration/dhcp_isc_config_validation.t b/xCAT-test/integration/dhcp_isc_config_validation.t index 35dc3bf0e..792739f48 100644 --- a/xCAT-test/integration/dhcp_isc_config_validation.t +++ b/xCAT-test/integration/dhcp_isc_config_validation.t @@ -37,6 +37,8 @@ push @config, @{ xCAT::DHCP::BootPolicy->isc_client_architecture_lines( portsuffix => '', net => '192.0.2.0', prefix => 24, + s390x_qemu_config_present => 1, + s390x_dpm_config_present => 1, ) }, "}\n"; my $configuration_root = -d '/etc/dhcp' ? '/etc/dhcp' : '/etc'; diff --git a/xCAT-test/integration/dhcp_kea_config_validation.t b/xCAT-test/integration/dhcp_kea_config_validation.t index 125189705..acc7e5d2d 100644 --- a/xCAT-test/integration/dhcp_kea_config_validation.t +++ b/xCAT-test/integration/dhcp_kea_config_validation.t @@ -51,6 +51,12 @@ my $json = $backend->render_dhcp4_config( { name => 'path-prefix', data => 'pxelinux.cfg/s390x/' }, ], }, + { + name => 'xcat-s390x-dpm-192.168.122.0_24', + test => 'option[93].hex == 0x0020', + additional_only => JSON::true, + 'boot-file-name' => 'pxelinux.cfg/s390x/192.168.122.0_24.dpm', + }, { 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')))", @@ -78,6 +84,7 @@ my $json = $backend->render_dhcp4_config( additional_client_classes => [ 'xcat-opal-v3-192.168.122.0-24', 'xcat-s390x-qemu-192.168.122.0_24', + 'xcat-s390x-dpm-192.168.122.0_24', ], option_data => [ { name => 'routers', data => '192.168.122.1' }, diff --git a/xCAT-test/unit/dhcp_boot_policy.t b/xCAT-test/unit/dhcp_boot_policy.t index 7dd200a1b..94e8477ff 100644 --- a/xCAT-test/unit/dhcp_boot_policy.t +++ b/xCAT-test/unit/dhcp_boot_policy.t @@ -218,8 +218,10 @@ unlike( ); my $s390x = xCAT::DHCP::BootPolicy->kea_s390x_network_classes( - net => '10.0.0.0', - prefix => 24, + net => '10.0.0.0', + prefix => 24, + qemu_config_present => 1, + dpm_config_present => 1, ); is_deeply( $s390x, @@ -241,13 +243,37 @@ is_deeply( }, ], }, + { + name => 'xcat-s390x-dpm-10.0.0.0_24', + test => 'option[93].hex == 0x0020', + additional_only => 1, + 'boot-file-name' => 'pxelinux.cfg/s390x/10.0.0.0_24.dpm', + }, ], - 'QEMU s390x stays within its architecture-specific configuration path', + 's390x firmware receives its supported network configuration method', ); is_deeply( - xCAT::DHCP::BootPolicy->kea_s390x_network_classes(prefix => 24), + xCAT::DHCP::BootPolicy->kea_s390x_network_classes( + net => '10.0.0.0', prefix => 24 + ), [], - 's390x classes require a network', + 's390x classes require a generated network configuration', +); +is_deeply( + xCAT::DHCP::BootPolicy->kea_s390x_network_classes( + net => '10.0.0.0', + prefix => 24, + dpm_config_present => 1, + ), + [ + { + name => 'xcat-s390x-dpm-10.0.0.0_24', + test => 'option[93].hex == 0x0020', + additional_only => 1, + 'boot-file-name' => 'pxelinux.cfg/s390x/10.0.0.0_24.dpm', + }, + ], + 's390x policies follow the configurations available on the network', ); my @legacy_isc_config = ( diff --git a/xCAT-test/unit/dhcp_isc_client_arch.t b/xCAT-test/unit/dhcp_isc_client_arch.t index dc584f8b2..f87bf4294 100644 --- a/xCAT-test/unit/dhcp_isc_client_arch.t +++ b/xCAT-test/unit/dhcp_isc_client_arch.t @@ -14,6 +14,8 @@ my $rendered = join '', @{ xCAT::DHCP::BootPolicy->isc_client_architecture_lines tftpdir => '/srv/tftp', net => '192.0.2.0', prefix => 24, + s390x_qemu_config_present => 1, + s390x_dpm_config_present => 1, ) }; like( @@ -38,8 +40,8 @@ like( ); 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', + 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";\n\s+\} else if option client-architecture = 00:20 \{ #IBM Z DPM\n\s+filename "pxelinux\.cfg\/s390x\/192\.0\.2\.0_24\.dpm";/, + 's390x firmware receives its supported network configuration method', ); my @riscv_ids = $rendered =~ /client-architecture = (00:1[9a-e])/g; @@ -52,15 +54,18 @@ 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, '<', $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'); +my $without_s390x = join '', @{ xCAT::DHCP::BootPolicy->isc_client_architecture_lines( + next_server => '192.0.2.10', net => '192.0.2.0', prefix => 24, + ) }; +unlike($without_s390x, qr/client-architecture = 00:(?:1f|20)/, + 'ISC does not advertise s390x without a generated network configuration'); + done_testing(); diff --git a/xCAT-test/unit/dhcp_kea_plugin_intent.t b/xCAT-test/unit/dhcp_kea_plugin_intent.t index eb117d740..f1285ca90 100644 --- a/xCAT-test/unit/dhcp_kea_plugin_intent.t +++ b/xCAT-test/unit/dhcp_kea_plugin_intent.t @@ -8,6 +8,7 @@ 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 Socket (); use Test::More; @@ -23,7 +24,8 @@ BEGIN { $INC{'xCAT/Table.pm'} = __FILE__; package xCAT::TableUtils; - sub getTftpDir { return '/tftpboot'; } + our $tftpdir; + sub getTftpDir { return $tftpdir; } sub get_site_attribute { return; } $INC{'xCAT/TableUtils.pm'} = __FILE__; @@ -83,6 +85,7 @@ require xCAT::Utils; *xCAT::Utils::runcmd = sub { return; }; } +$xCAT::TableUtils::tftpdir = tempdir(CLEANUP => 1); my $source_dhcp_plugin = repo_path('xCAT-server/lib/xcat/plugins/dhcp.pm'); require $source_dhcp_plugin; require xCAT::DHCP::Backend::Kea; @@ -120,6 +123,28 @@ my %network_entry = ( tftpserver => '', ); +{ + 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(!grep(/^xcat-s390x-/, keys %classes), + 'Kea omits s390x policy without a generated network configuration'); +} + +my $s390x_config_dir = + "$xCAT::TableUtils::tftpdir/pxelinux.cfg/s390x"; +make_path($s390x_config_dir); +open(my $s390x_config, '>', "$s390x_config_dir/10.0.0.0_24") + or die "Unable to create s390x test configuration: $!"; +close($s390x_config); +open($s390x_config, '>', "$s390x_config_dir/10.0.0.0_24.dpm") + or die "Unable to create s390x DPM test configuration: $!"; +close($s390x_config); + { no warnings 'redefine'; local *xCAT::NetworkUtils::thishostisnot = sub { return 0; }; @@ -129,26 +154,14 @@ my %network_entry = ( ); 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'); + ok($classes{'xcat-s390x-dpm-10.0.0.0_24'}, 'the Kea subnet includes IBM Z DPM 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, - }, + 'xcat-s390x-qemu-10.0.0.0_24', + 'xcat-s390x-dpm-10.0.0.0_24', ], - 'the rendered subnet keeps s390x fallback lookups in their own path', + 'the s390x policy is evaluated only for its subnet', ); } diff --git a/xCAT-test/unit/mknb_exported_genesis.t b/xCAT-test/unit/mknb_exported_genesis.t index 1cd01ada5..f9b0ae860 100644 --- a/xCAT-test/unit/mknb_exported_genesis.t +++ b/xCAT-test/unit/mknb_exported_genesis.t @@ -169,16 +169,44 @@ 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/192.0.2.0_24.dpm", + "# pxelinux.cfg xCAT Genesis s390x\nstale DPM 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'); +is($removed, 6, 's390x image and generated discovery configurations are retired'); ok(!-e "$tftpdir/pxelinux.cfg/s390x/192.0.2.0_24", 'retiring s390x removes the generated discovery configuration'); +ok(!-e "$tftpdir/pxelinux.cfg/s390x/192.0.2.0_24.dpm", + 'retiring s390x removes the generated DPM configuration'); is(read_file("$tftpdir/pxelinux.cfg/s390x/default"), "admin fallback\n", 'retiring s390x preserves administrator-owned configurations'); +my $special_tftpdir = "$tmpdir/tftp root {s390x}"; +make_path("$special_tftpdir/xcat", "$special_tftpdir/pxelinux.cfg/s390x"); +for my $artifact (qw(genesis.kernel.s390x genesis.fs.s390x.gz genesis.exact-arch.s390x)) { + write_file("$special_tftpdir/xcat/$artifact", "artifact\n"); +} +write_file( + "$special_tftpdir/pxelinux.cfg/s390x/192.0.2.0_24", + "# pxelinux.cfg xCAT Genesis s390x\nconfiguration\n", +); +write_file( + "$special_tftpdir/pxelinux.cfg/s390x/192.0.2.0_24.dpm", + "# pxelinux.cfg xCAT Genesis s390x\nDPM configuration\n", +); +($removed, $remove_error) = + xCAT_plugin::mknb::_remove_openembedded_genesis($special_tftpdir, 's390x'); +is($remove_error, undef, 's390x cleanup accepts a TFTP path with shell metacharacters'); +is($removed, 5, 's390x cleanup removes every generated artifact from that path'); +ok(!-e "$special_tftpdir/pxelinux.cfg/s390x/192.0.2.0_24", + 's390x cleanup does not expand the TFTP path as a glob'); +ok(!-e "$special_tftpdir/pxelinux.cfg/s390x/192.0.2.0_24.dpm", + 's390x cleanup removes DPM configurations from the literal path'); + my $failed_kernel = "$tftpdir/xcat/genesis.kernel.aarch64"; make_path($failed_kernel); for my $artifact (qw( diff --git a/xCAT-test/unit/mknb_xcatd_address.t b/xCAT-test/unit/mknb_xcatd_address.t index fc641e58a..c822d3651 100644 --- a/xCAT-test/unit/mknb_xcatd_address.t +++ b/xCAT-test/unit/mknb_xcatd_address.t @@ -511,8 +511,12 @@ $xCAT::NetworkUtils::nic_ips = undef; make_path("$::XCATROOT/share/xcat/netboot/genesis-openembedded/s390x"); use_reporter_address_maps(); prepare_tftpdir($tmpdir, 'tftpboot-s390x', 's390x'); +make_path("$xCAT::TableUtils::tftpdir/pxelinux.cfg"); +chmod(0700, "$xCAT::TableUtils::tftpdir/pxelinux.cfg"); $responses = run_mknb('s390x'); generation_succeeded($responses, 's390x configuration generation succeeds'); +is((stat "$xCAT::TableUtils::tftpdir/pxelinux.cfg")[2] & 07777, 0755, + 's390x configuration generation repairs the parent directory mode'); my $s390x_qemu_path = "$xCAT::TableUtils::tftpdir/pxelinux.cfg/s390x/192.168.144.0_20"; @@ -532,6 +536,17 @@ unlike( qr/192\.168\.149\.100/, 's390x configurations do not use the later floating address', ); +my $s390x_dpm_path = "$s390x_qemu_path.dpm"; +is( + read_config($s390x_dpm_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 DPM configuration uses the IBM Z network-boot syntax', +); write_text($s390x_qemu_path, "admin network configuration\n"); %xCAT::TableUtils::site_extra = ( dhcpinterfaces => 'eth0,eth1:noboot' ); @@ -584,6 +599,7 @@ $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'); +ok(!-e $s390x_dpm_path, 'a :noboot network gets no IBM Z DPM configuration'); %xCAT::TableUtils::site_extra = (); $xCAT::NetworkUtils::nic_ips = undef;