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

Preserve OPAL conf-file handling for Kea

This commit is contained in:
Vinícius Ferrão
2026-04-23 19:19:29 -03:00
parent c2a90293ea
commit 714c0785b6
7 changed files with 91 additions and 32 deletions

View File

@@ -660,10 +660,12 @@ sub _render_subnet4 {
$rendered{'next-server'} = _first_defined( $subnet->{'next-server'}, $subnet->{next_server} );
$rendered{'boot-file-name'} = _first_defined( $subnet->{'boot-file-name'}, $subnet->{boot_file_name} );
$rendered{'option-data'} = _first_defined( $subnet->{'option-data'}, $subnet->{option_data} );
$rendered{'require-client-classes'} = _first_defined( $subnet->{'require-client-classes'}, $subnet->{require_client_classes} );
$rendered{reservations} = $subnet->{reservations} if $subnet->{reservations};
delete $rendered{'next-server'} unless defined $rendered{'next-server'};
delete $rendered{'boot-file-name'} unless defined $rendered{'boot-file-name'};
delete $rendered{'option-data'} unless defined $rendered{'option-data'};
delete $rendered{'require-client-classes'} unless defined $rendered{'require-client-classes'};
if ( $subnet->{pools} ) {
$rendered{pools} = $subnet->{pools};

View File

@@ -37,7 +37,7 @@ sub kea_client_classes {
},
{
name => 'xcat-ppc64',
test => '(option[93].hex == 0x000c or option[93].hex == 0x000e)',
test => 'option[93].hex == 0x000c',
'boot-file-name' => '/boot/grub2/grub2.ppc',
},
{

View File

@@ -2388,6 +2388,7 @@ sub kea_build_dhcp4_intent
my @routes = kea_ipv4_routes(@vnets);
my @subnets;
my @opal_classes;
my $id = 1;
foreach my $route (@routes) {
my ( $net, $netif, $mask, $flags ) = @$route;
@@ -2406,6 +2407,7 @@ sub kea_build_dhcp4_intent
my $subnet = kea_subnet4_intent($nettab, $net, $mask, $interface, $remote, $id, $httpport);
return $subnet if $subnet->{error};
push @opal_classes, @{ delete $subnet->{client_classes} || [] };
push @subnets, $subnet;
$id++;
}
@@ -2416,7 +2418,7 @@ sub kea_build_dhcp4_intent
valid_lifetime => kea_dhcp_lease_time(),
'option-def' => kea_option_defs(),
'option-data' => kea_global_option_data(),
'client-classes' => kea_boot_client_classes(),
'client-classes' => [ @{ kea_boot_client_classes() }, @opal_classes ],
subnets => \@subnets,
};
@@ -2765,6 +2767,7 @@ sub kea_subnet4_intent
push @option_data, { name => 'domain-search', data => $domainstring } if $domainstring;
my $prefix = kea_mask_to_prefix($mask);
my $opal_class = kea_opal_client_class($net, $prefix, $tftp, $httpport);
my %subnet = (
id => $id,
subnet => "$net/$prefix",
@@ -2773,10 +2776,36 @@ sub kea_subnet4_intent
next_server => $tftp,
);
$subnet{interface} = $interface unless $remote;
if ($opal_class) {
$subnet{'require-client-classes'} = [ $opal_class->{name} ];
$subnet{client_classes} = [$opal_class];
}
return \%subnet;
}
sub kea_opal_client_class
{
my ( $net, $prefix, $tftp, $httpport ) = @_;
return unless $net && defined($prefix) && $tftp;
my $class_name = "xcat-opal-v3-$net-$prefix";
$class_name =~ s/[^A-Za-z0-9_.-]/_/g;
return {
name => $class_name,
test => 'option[93].hex == 0x000e',
'only-if-required' => JSON::true,
'option-data' => [
{
name => 'conf-file',
data => "http://$tftp:$httpport/tftpboot/pxelinux.cfg/p/" . $net . "_" . $prefix,
},
],
};
}
sub kea_expand_request_nodes
{
my ( $req, $opt ) = @_;

View File

@@ -19,6 +19,8 @@ sub usage{
print " dhcphelper -r|--rm -m|--mac <mac address> [ -a|--ip <ip address>] [ -n|--name <node name>]\n";
print " delete the dhcp lease of specified <mac>,<ip address> and <node name>\n";
print "\n";
return;
}
my $help;
@@ -46,7 +48,7 @@ if($help){
}
mkdir "/tmp/xcat" unless -d "/tmp/xcat";
open(my $dhcplockfd, ">", "/tmp/xcat/dhcplock") or die "Unable to lock DHCP state: $!";
open(my $dhcplockfd, ">", "/tmp/xcat/dhcplock") or die "Unable to lock DHCP state: $!"; ## no critic (InputOutput::RequireBriefOpen)
flock($dhcplockfd, LOCK_EX);
my $config4 = $backend->load_dhcp4_config();
@@ -103,41 +105,38 @@ if($help){
exit 1;
}
my $omshell;
open($omshell, '|-', '/bin/sh', '-c', '/usr/bin/omshell >/dev/null')
or die "Unable to start omshell: $!";
print $omshell "key "
. $id . " \""
. $passwd . "\"\n";
print $omshell "connect\n";
my $omshell_commands = "key " . $id . " \"" . $passwd . "\"\n";
$omshell_commands .= "connect\n";
if($hostname){
print $omshell "new host\n";
print $omshell
"set name = \"$hostname\"\n"; #Find and destroy conflict name
print $omshell "open\n";
print $omshell "remove\n";
print $omshell "close\n";
$omshell_commands .= "new host\n";
$omshell_commands .= "set name = \"$hostname\"\n"; #Find and destroy conflict name
$omshell_commands .= "open\n";
$omshell_commands .= "remove\n";
$omshell_commands .= "close\n";
}
if ($mac)
{
print $omshell "new host\n";
print $omshell "set hardware-address = " . $mac
. "\n"; #find and destroy mac conflict
print $omshell "open\n";
print $omshell "remove\n";
print $omshell "close\n";
$omshell_commands .= "new host\n";
$omshell_commands .= "set hardware-address = " . $mac . "\n"; #find and destroy mac conflict
$omshell_commands .= "open\n";
$omshell_commands .= "remove\n";
$omshell_commands .= "close\n";
}
if($ip){
print $omshell "new host\n";
print $omshell
"set ip-address = $ip\n"; #find and destroy ip conflict
print $omshell "open\n";
print $omshell "remove\n";
print $omshell "close\n";
$omshell_commands .= "new host\n";
$omshell_commands .= "set ip-address = $ip\n"; #find and destroy ip conflict
$omshell_commands .= "open\n";
$omshell_commands .= "remove\n";
$omshell_commands .= "close\n";
}
my $omshell;
open($omshell, '|-', '/bin/sh', '-c', '/usr/bin/omshell >/dev/null')
or die "Unable to start omshell: $!";
print $omshell $omshell_commands;
close($omshell);
}else{
&usage;

View File

@@ -13,7 +13,6 @@ is( scalar @$fallback_classes, 4, 'Kea boot policy omits xNBA classes when xNBA
my %fallback_by_name = map { $_->{name} => $_ } @$fallback_classes;
is( $fallback_by_name{'xcat-bios'}{'boot-file-name'}, 'pxelinux.0', 'BIOS clients fall back to pxelinux.0 without xNBA loaders' );
ok( !exists $fallback_by_name{'xcat-xnba-bios'}, 'xNBA user-class is not advertised without xNBA kpxe' );
like( $fallback_by_name{'xcat-ppc64'}{test}, qr/0x000e/, 'POWER class covers OPAL-v3 client architecture' );
my $classes = xCAT::DHCP::BootPolicy->kea_client_classes(xnba_kpxe => 1, xnba_efi => 1);
is( scalar @$classes, 5, 'Kea boot policy renders expected xNBA client classes' );
@@ -26,8 +25,7 @@ like( $by_name{'xcat-uefi-x64'}{test}, qr/0x0009/, 'UEFI x64 class matches archi
like( $by_name{'xcat-uefi-x64'}{test}, qr/not \(\(option\[77\]\.exists/, 'generic UEFI class excludes xNBA second-stage clients' );
is( $by_name{'xcat-aarch64'}{'boot-file-name'}, 'boot/grub2/grub2.aarch64', 'AArch64 clients receive grub2 boot file' );
is( $by_name{'xcat-ppc64'}{'boot-file-name'}, '/boot/grub2/grub2.ppc', 'POWER clients receive grub2 Open Firmware boot file' );
like( $by_name{'xcat-ppc64'}{test}, qr/0x000c/, 'POWER class matches existing POWER architecture id' );
like( $by_name{'xcat-ppc64'}{test}, qr/0x000e/, 'POWER class matches OPAL-v3 architecture id' );
is( $by_name{'xcat-ppc64'}{test}, 'option[93].hex == 0x000c', 'POWER class keeps existing POWER architecture id' );
my $xnba_classes = xCAT::DHCP::BootPolicy->kea_xnba_node_classes(
xnba_efi => 1,

View File

@@ -32,6 +32,14 @@ my $json = $backend->render_dhcp4_config(
test => "(option[77].exists and (option[77].text == 'xNBA' or option[77].hex == 0x784e4241 or substring(option[77].hex,1,4) == 'xNBA')) and option[93].hex == 0x0000 and pkt4.mac == 0x525400123456",
'boot-file-name' => 'http://192.168.122.1:80/tftpboot/xcat/xnba/nodes/node01',
},
{
name => 'xcat-opal-v3-192.168.122.0-24',
test => 'option[93].hex == 0x000e',
'only-if-required' => JSON::true,
'option-data' => [
{ name => 'conf-file', data => 'http://192.168.122.1:80/tftpboot/pxelinux.cfg/p/192.168.122.0_24' },
],
},
{
name => 'xcat-uefi-x64',
test => "(option[93].hex == 0x0007 or option[93].hex == 0x0009) and not ((option[77].exists and (option[77].text == 'xNBA' or option[77].hex == 0x784e4241 or substring(option[77].hex,1,4) == 'xNBA')))",
@@ -56,6 +64,7 @@ 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',
'require-client-classes' => ['xcat-opal-v3-192.168.122.0-24'],
option_data => [
{ name => 'routers', data => '192.168.122.1' },
{ name => 'domain-name', data => 'cluster.test' },

View File

@@ -22,6 +22,7 @@ my $json = $backend->render_dhcp4_config(
interface => 'eth0',
dynamicrange => '10.0.0.100-10.0.0.120;10.0.0.130,10.0.0.140',
next_server => '10.0.0.1',
'require-client-classes' => ['xcat-opal-v3-10.0.0.0-24'],
option_data => [
{ name => 'routers', data => '10.0.0.1' },
{ name => 'domain-name-servers', data => '10.0.0.2, 10.0.0.3' },
@@ -42,6 +43,14 @@ my $json = $backend->render_dhcp4_config(
test => 'option[93].hex == 0x0007',
'boot-file-name' => 'xcat/xnba.efi',
},
{
name => 'xcat-opal-v3-10.0.0.0-24',
test => 'option[93].hex == 0x000e',
'only-if-required' => JSON::true,
'option-data' => [
{ name => 'conf-file', data => 'http://10.0.0.1/tftpboot/pxelinux.cfg/p/10.0.0.0_24' },
],
},
],
}
);
@@ -76,6 +85,11 @@ is_deeply(
],
'subnet option-data is preserved'
);
is_deeply(
$subnet->{'require-client-classes'},
['xcat-opal-v3-10.0.0.0-24'],
'subnet requests second-pass OPAL class evaluation for subnet-specific conf-file'
);
is_deeply(
$subnet->{reservations},
@@ -97,8 +111,16 @@ is_deeply(
test => 'option[93].hex == 0x0007',
'boot-file-name' => 'xcat/xnba.efi',
},
{
name => 'xcat-opal-v3-10.0.0.0-24',
test => 'option[93].hex == 0x000e',
'only-if-required' => JSON::true,
'option-data' => [
{ name => 'conf-file', data => 'http://10.0.0.1/tftpboot/pxelinux.cfg/p/10.0.0.0_24' },
],
},
],
'client classes are preserved'
'client classes are preserved, including subnet-specific OPAL conf-file class'
);
my $empty_boot_json = $backend->render_dhcp4_config(