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

test(xCAT-test): cover RISC-V UEFI HTTP boot in both DHCP backends

This commit is contained in:
Vinícius Ferrão
2026-08-21 00:55:27 -03:00
parent 5d1010bc97
commit aade148d49
3 changed files with 130 additions and 1 deletions
+72
View File
@@ -145,4 +145,76 @@ is_deeply(
'xNBA network policy requires a next server'
);
# UEFI HTTP boot: firmware that boots over HTTP sends architecture id 28 and only
# accepts an offer whose boot file is a URL and whose reply is tagged HTTPClient.
my $httpboot = xCAT::DHCP::BootPolicy->kea_httpboot_network_classes(
net => '10.0.0.0',
prefix => 24,
next_server => '10.0.0.1',
tftpdir => '/tftpboot',
);
is_deeply(
$httpboot,
[
{
name => 'xcat-riscv64-http-10.0.0.0_24',
test => 'option[93].hex == 0x001c',
additional_only => 1,
'boot-file-name' => 'http://10.0.0.1/tftpboot/boot/grub2/grub2.riscv64',
'option-data' => [
{
name => 'vendor-class-identifier',
data => 'HTTPClient',
'always-send' => 1,
},
],
},
],
'RISC-V HTTP boot clients are offered the boot loader as a URL, tagged HTTPClient'
);
my $httpboot_port = xCAT::DHCP::BootPolicy->kea_httpboot_network_classes(
net => '10.0.0.0',
prefix => 24,
next_server => '10.0.0.1',
httpport => '8080',
tftpdir => '/srv/tftpboot',
);
is(
$httpboot_port->[0]{'boot-file-name'},
'http://10.0.0.1:8080/srv/tftpboot/boot/grub2/grub2.riscv64',
'the HTTP boot URL follows the configured HTTP port and TFTP root'
);
is_deeply(
xCAT::DHCP::BootPolicy->kea_httpboot_network_classes(
net => '10.0.0.0',
prefix => 24,
next_server => '10.0.0.1',
loader_present => sub { 0 },
),
[],
'no HTTP boot class is offered while the boot loader is missing'
);
is_deeply(
xCAT::DHCP::BootPolicy->kea_httpboot_network_classes( net => '10.0.0.0', prefix => 24 ),
[],
'HTTP boot classes need a next server'
);
is(
scalar @{ xCAT::DHCP::BootPolicy->kea_httpboot_network_classes(
net => '10.0.0.0',
prefix => 24,
next_server => '10.0.0.1',
loader_present => sub { $_[0] eq '/tftpboot/boot/grub2/grub2.riscv64' },
) },
1,
'the boot loader of the architecture is what is looked for'
);
unlike(
join( ' ', map { $_->{test} } @$classes ),
qr/0x001c/,
'the global class list keeps HTTP boot out: it needs the address of the management node',
);
done_testing();
+18 -1
View File
@@ -42,7 +42,24 @@ SKIP: {
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;
is_deeply( \@riscv_ids, ['00:1b'], 'only the RISC-V 64-bit UEFI architecture id (27) is mapped' );
is_deeply(
[ sort @riscv_ids ],
[ '00:1b', '00:1c' ],
'only the RISC-V 64-bit UEFI architecture ids (27 and 28) are mapped',
);
done_testing();
+40
View File
@@ -87,12 +87,39 @@ my $json = $backend->render_dhcp4_config(
{ name => 'conf-file', data => 'http://10.0.0.1/tftpboot/pxelinux.cfg/p/10.0.0.0_24' },
],
},
{
name => 'xcat-riscv64-http-10.0.0.0_24',
test => 'option[93].hex == 0x001c',
additional_only => 1,
'boot-file-name' => 'http://10.0.0.1/tftpboot/boot/grub2/grub2.riscv64',
'option-data' => [
{
name => 'vendor-class-identifier',
data => 'HTTPClient',
'always-send' => 1,
},
],
},
],
}
);
my $config = decode_json($json);
ok( $config->{Dhcp4}, 'renderer creates a Dhcp4 document' );
# Kea reads the option flags as booleans, so a caller that sets them the plain
# Perl way still produces a configuration the server parses.
my ($httpboot_class) =
grep { $_->{name} eq 'xcat-riscv64-http-10.0.0.0_24' } @{ $config->{Dhcp4}{'client-classes'} || [] };
ok( $httpboot_class, 'a client class carrying option data is rendered' );
is(
ref( $httpboot_class->{'option-data'}[0]{'always-send'} ),
'JSON::PP::Boolean',
'the always-send option flag is rendered as a boolean, not as a number',
);
ok( $httpboot_class->{'option-data'}[0]{'always-send'}, 'and it is true' );
is( $httpboot_class->{'option-data'}[0]{data}, 'HTTPClient', 'the option value is left alone' );
is( $httpboot_class->{'boot-file-name'}, 'http://10.0.0.1/tftpboot/boot/grub2/grub2.riscv64', 'the boot file URL is left alone' );
is_deeply( $config->{Dhcp4}{'interfaces-config'}{interfaces}, ['eth0'], 'interfaces are rendered' );
is( $config->{Dhcp4}{'valid-lifetime'}, 600, 'valid lifetime is rendered' );
is( $config->{Dhcp4}{'lease-database'}{type}, 'memfile', 'memfile lease backend is the default' );
@@ -158,6 +185,19 @@ is_deeply(
{ name => 'conf-file', data => 'http://10.0.0.1/tftpboot/pxelinux.cfg/p/10.0.0.0_24' },
],
},
{
name => 'xcat-riscv64-http-10.0.0.0_24',
test => 'option[93].hex == 0x001c',
'only-if-required' => JSON::true,
'boot-file-name' => 'http://10.0.0.1/tftpboot/boot/grub2/grub2.riscv64',
'option-data' => [
{
name => 'vendor-class-identifier',
data => 'HTTPClient',
'always-send' => JSON::true,
},
],
},
],
'client classes are preserved, including subnet-specific OPAL conf-file class'
);