2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-09-04 20:17:55 +00:00

test(dhcp): exercise ISC client boot policy

This commit is contained in:
Vinícius Ferrão
2026-08-26 17:25:00 -03:00
parent 96b4e62fce
commit 6d32aa944c
+43 -48
View File
@@ -3,62 +3,57 @@ use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/../lib";
use lib "$FindBin::Bin/../../perl-xCAT";
use Test::More;
use XCAT::Test::File qw(repo_path slurp_repo_file);
use xCAT::DHCP::BootPolicy;
# The ISC dhcpd subnet block in dhcp.pm maps DHCP option 93 (client system
# architecture) to a boot file. The block is rendered inside a large
# database-backed subroutine, so this pins the shipped source text: every
# architecture branch must appear before the catch-all that hands unknown
# clients /yaboot, otherwise the branch is unreachable.
my $rendered = join '', @{ xCAT::DHCP::BootPolicy->isc_client_architecture_lines(
next_server => '192.0.2.10',
portsuffix => ':8080',
tftpdir => '/srv/tftp',
net => '192.0.2.0',
prefix => 24,
) };
my $plugin = repo_path('xCAT-server/lib/xcat/plugins/dhcp.pm');
plan skip_all => "$plugin not found" unless -r $plugin;
my $source = slurp_repo_file('xCAT-server/lib/xcat/plugins/dhcp.pm');
my %branch = (
aarch64 => qr/client-architecture = 00:0b \{[^\n]*\n\s*push \@netent, "\s*filename \\"boot\/grub2\/grub2\.aarch64\\";/,
riscv64 => qr/client-architecture = 00:1b \{[^\n]*\n\s*push \@netent, "\s*filename \\"boot\/grub2\/grub2\.riscv64\\";/,
opal => qr/client-architecture = 00:0e \{/,
yaboot => qr/substring\(filename,0,1\) = null \{[^\n]*\n\s*push \@netent, "\s*filename \\"\/yaboot\\";/,
like(
$rendered,
qr/client-architecture = 00:0b \{ #aaarch64\n\s+filename "boot\/grub2\/grub2\.aarch64";/,
'the ISC policy renders the aarch64 boot branch',
);
like(
$rendered,
qr/client-architecture = 00:1b \{ #riscv64 uefi\n\s+filename "boot\/grub2\/grub2\.riscv64";/,
'the ISC policy renders the riscv64 TFTP boot branch',
);
like(
$rendered,
qr/client-architecture = 00:1c \{ #riscv64 uefi http boot\n\s+option vendor-class-identifier "HTTPClient";\n\s+filename "http:\/\/192\.0\.2\.10:8080\/srv\/tftp\/boot\/grub2\/grub2\.riscv64";/,
'the ISC policy renders the riscv64 HTTP boot branch with the subnet URL',
);
like(
$rendered,
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',
);
my %pos;
for my $name ( sort keys %branch ) {
ok( $source =~ $branch{$name}, "the ISC subnet block renders the $name branch" )
or next;
$pos{$name} = $-[0];
}
SKIP: {
skip 'not every branch was found', 3 unless 4 == scalar keys %pos;
cmp_ok( $pos{aarch64}, '<', $pos{riscv64}, 'riscv64 follows the aarch64 branch' );
cmp_ok( $pos{riscv64}, '<', $pos{opal}, 'riscv64 is rendered before the POWER OPAL branch' );
cmp_ok( $pos{riscv64}, '<', $pos{yaboot}, 'riscv64 is rendered before the /yaboot fallback, so it is reachable' );
}
# HTTP boot firmware (architecture id 28) needs the boot file as a URL and only
# accepts an offer that is tagged HTTPClient
ok(
$source =~ /client-architecture = 00:1c \{[^\n]*\n\s*push \@netent, "\s*option vendor-class-identifier \\"HTTPClient\\";[^\n]*\n\s*push \@netent, "\s*filename \\"http:\/\/\$tftp\$portsuffix\$tftpdir\/boot\/grub2\/grub2\.riscv64\\";/,
'the ISC subnet block hands RISC-V HTTP boot clients the boot loader as a URL',
);
my $httpboot_pos = $-[0];
SKIP: {
skip 'the riscv64 branches were not both found', 2 unless defined $pos{riscv64} && defined $httpboot_pos;
cmp_ok( $pos{riscv64}, '<', $httpboot_pos, 'the PXE branch keeps its place before the HTTP boot branch' );
cmp_ok( $httpboot_pos, '<', $pos{yaboot}, 'the HTTP boot branch is rendered before the /yaboot fallback' );
}
my @riscv_ids = $source =~ /client-architecture = (00:1[9a-e])/g;
my @riscv_ids = $rendered =~ /client-architecture = (00:1[9a-e])/g;
is_deeply(
[ sort @riscv_ids ],
\@riscv_ids,
[ '00:1b', '00:1c' ],
'only the RISC-V 64-bit UEFI architecture ids (27 and 28) are mapped',
'only the RISC-V 64-bit UEFI architecture ids are mapped',
);
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 $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, '<', $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');
done_testing();