2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-07-31 18:19:40 +00:00

fix(dhcp): reuse Kea control socket paths

This commit is contained in:
Vinícius Ferrão
2026-07-18 13:27:40 -03:00
parent 3191b874a3
commit 543eab3bdc
2 changed files with 128 additions and 21 deletions
+126 -19
View File
@@ -7,6 +7,7 @@ use JSON;
use File::Basename;
use File::Path qw/make_path/;
use Math::BigInt;
use Text::ParseWords qw/shellwords/;
use xCAT::DHCP::Range;
use xCAT::NetworkUtils;
@@ -50,6 +51,12 @@ sub ddns_config_file {
return $self->{ddns_config_file} || '/etc/kea/kea-dhcp-ddns.conf';
}
sub control_socket_path {
my ( $self, $socket_name ) = @_;
return $self->_kea_socket_dir() . "/$socket_name";
}
sub render_dhcp4_config {
my ( $self, $intent ) = @_;
@@ -154,19 +161,19 @@ sub render_ctrl_agent_config {
my %sockets = (
dhcp4 => {
'socket-type' => 'unix',
'socket-name' => $intent->{'dhcp4-socket'} || $self->_kea_control_socket('kea4-ctrl-socket'),
'socket-name' => $intent->{'dhcp4-socket'} || $self->control_socket_path('kea4-ctrl-socket'),
},
);
if ( $intent->{dhcp6} || $intent->{'dhcp6-socket'} ) {
$sockets{dhcp6} = {
'socket-type' => 'unix',
'socket-name' => $intent->{'dhcp6-socket'} || $self->_kea_control_socket('kea6-ctrl-socket'),
'socket-name' => $intent->{'dhcp6-socket'} || $self->control_socket_path('kea6-ctrl-socket'),
};
}
if ( $intent->{ddns} || $intent->{'ddns-socket'} ) {
$sockets{d2} = {
'socket-type' => 'unix',
'socket-name' => $intent->{'ddns-socket'} || $self->_kea_control_socket('kea-ddns-ctrl-socket'),
'socket-name' => $intent->{'ddns-socket'} || $self->control_socket_path('kea-ddns-ctrl-socket'),
};
}
@@ -911,15 +918,7 @@ sub kea_version {
return $self->{kea_version} if defined $self->{kea_version};
return $self->{_detected_kea_version} if defined $self->{_detected_kea_version};
my $command = $self->{kea_dhcp4_command} || _command_path('kea-dhcp4');
return unless $command;
my $output = '';
if ( open( my $version_fh, '-|', $command, '-V' ) ) {
local $/;
$output = <$version_fh> || '';
close($version_fh);
}
my $output = $self->_kea_command_output('-V') || '';
if ( $output =~ /(\d+(?:\.\d+){1,2})/ ) {
$self->{_detected_kea_version} = $1;
@@ -928,6 +927,34 @@ sub kea_version {
return $self->{_detected_kea_version};
}
sub _kea_build_report {
my ($self) = @_;
return $self->{kea_build_report} if defined $self->{kea_build_report};
return $self->{_detected_kea_build_report} if defined $self->{_detected_kea_build_report};
my $output = $self->_kea_command_output('-W') || '';
$self->{_detected_kea_build_report} = $output;
return $output;
}
sub _kea_command_output {
my ( $self, @args ) = @_;
my $command = $self->{kea_dhcp4_command} || _command_path('kea-dhcp4');
return unless $command;
my $output = '';
if ( open( my $command_fh, '-|', $command, @args ) ) {
local $/;
$output = <$command_fh> || '';
close($command_fh);
}
return $output;
}
sub _first_defined {
my @values = @_;
foreach my $value (@values) {
@@ -1028,21 +1055,101 @@ sub _kea_socket_dir {
return $self->{kea_socket_dir} if defined $self->{kea_socket_dir};
if ( defined $self->{kea_socket_dirs} ) {
foreach my $dir ( @{ $self->{kea_socket_dirs} || [] } ) {
return $dir if -d $dir;
}
return '/var/run/kea';
}
my $build_report = $self->_kea_build_report();
if ($build_report) {
my $prefix = _kea_build_option( $build_report, 'prefix' );
if ( !defined($prefix) && $build_report =~ /^\s*Prefix:\s*(\/\S+)/m ) {
$prefix = $1;
}
$prefix = _expand_kea_build_path( $prefix, {} );
# Kea's Meson build unconditionally overrides the installed runtime
# directory for the /usr/local prefix, even when state directories
# are supplied as build options.
if ( defined($prefix) && $prefix eq '/usr/local' && $build_report =~ /^\s*Meson Version:/m ) {
return '/usr/local/var/run/kea';
}
my $local_state = _kea_build_option( $build_report, 'localstatedir' );
$local_state = _expand_kea_build_path( $local_state, { prefix => $prefix }, $prefix );
if ( !defined($local_state) && defined($prefix) ) {
if ( $build_report =~ /^\s*Meson Version:/m ) {
$local_state = '/var' if $prefix eq '/usr';
}
# Kea reverts Meson's /usr/local => /var/local default.
$local_state = _expand_kea_build_path( 'var', {}, $prefix ) unless defined($local_state);
}
my $run_state = _kea_build_option( $build_report, 'runstatedir' );
$run_state = _expand_kea_build_path(
$run_state,
{
prefix => $prefix,
localstatedir => $local_state,
},
$prefix,
);
$run_state = "$local_state/run" if !defined($run_state) && defined($local_state);
return $run_state eq '/' ? '/kea' : "$run_state/kea" if defined($run_state);
}
# Kea validates Control Agent sockets against its packaged runtime
# directory, and newer packages reject /var/run/kea even when it resolves
# to /run/kea. Keep the legacy path as the unknown-state fallback for
# older Kea builds that validate before the runtime directory exists.
foreach my $dir ( @{ $self->{kea_socket_dirs} || [ '/run/kea', '/var/run/kea' ] } ) {
# directory, and newer packages reject a symlink-equivalent spelling.
# Filesystem probing is only a fallback for builds without a usable report.
foreach my $dir ( '/run/kea', '/var/run/kea' ) {
return $dir if -d $dir;
}
return '/var/run/kea';
}
sub _kea_control_socket {
my ( $self, $socket_name ) = @_;
sub _kea_build_option {
my ( $build_report, $option ) = @_;
return $self->_kea_socket_dir() . "/$socket_name";
return unless defined($build_report);
my $options = $build_report;
if ( $build_report =~ /^\s*(?:Configure arguments|Build Options):[ \t]*(.*?)(?=\n[ \t]*\n|^\s*C\+\+ Compiler:|\z)/ms ) {
$options = $1;
}
my @tokens = eval { shellwords($options) };
return if $@;
my $value;
for ( my $index = 0; $index < @tokens; $index++ ) {
my $token = $tokens[$index];
if ( $token =~ /^(?:--|-D)\Q$option\E=(.+)$/ ) {
$value = $1;
} elsif ( $token eq "--$option" && $index + 1 < @tokens ) {
$value = $tokens[ ++$index ];
}
}
return $value;
}
sub _expand_kea_build_path {
my ( $path, $variables, $relative_base ) = @_;
return unless defined($path);
foreach my $variable (qw/prefix localstatedir/) {
next unless defined( $variables->{$variable} );
$path =~ s/\$\{$variable\}/$variables->{$variable}/g;
}
if ( $path !~ m{^/} && defined($relative_base) ) {
$path = $relative_base eq '/' ? "/$path" : "$relative_base/$path";
}
$path =~ s{/$}{} if length($path) > 1;
return $path if $path =~ m{^/};
return;
}
sub _command_path {
+2 -2
View File
@@ -2615,7 +2615,7 @@ sub kea_build_dhcp4_intent
if (kea_control_agent_enabled()) {
$intent->{'control-socket'} = {
'socket-type' => 'unix',
'socket-name' => '/var/run/kea/kea4-ctrl-socket',
'socket-name' => $backend->control_socket_path('kea4-ctrl-socket'),
};
my $hook = $backend->host_cmds_hook_path();
if ($hook) {
@@ -2670,7 +2670,7 @@ sub kea_build_dhcp6_intent
if (kea_control_agent_enabled()) {
$intent->{'control-socket'} = {
'socket-type' => 'unix',
'socket-name' => '/var/run/kea/kea6-ctrl-socket',
'socket-name' => $backend->control_socket_path('kea6-ctrl-socket'),
};
my $hook = $backend->host_cmds_hook_path();
if ($hook) {