2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-10-21 07:08:12 +00:00

test(dhcp): cover conditional SHA client requirements

This commit is contained in:
Vinícius Ferrão
2026-10-05 17:01:02 -03:00
parent b633f669c4
commit 923fe01d2d
2 changed files with 238 additions and 0 deletions
+199
View File
@@ -0,0 +1,199 @@
#!/usr/bin/env perl
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/../lib";
use lib "$FindBin::Bin/../../perl-xCAT";
use lib "$FindBin::Bin/../../xCAT-server/lib/perl";
use Config;
use File::Path qw(make_path);
use File::Slurper qw(read_text write_text);
use File::Temp qw(tempdir);
use Test::More;
use XCAT::Test::File qw(repo_path);
BEGIN {
$ENV{XCATROOT} = repo_path('xCAT-server');
$ENV{XCATCFG} = 'SQLite:' . tempdir(CLEANUP => 1);
}
use xCAT::DHCP::OmapiPolicy;
use xCAT::DHCP::OmapiRunner;
my $directory = tempdir(CLEANUP => 1);
my $client = "$directory/custom-omshell";
write_text($client, "#!$Config{perlpath}\n" . <<'PERL');
use strict;
use warnings;
my $input = do { local $/; <STDIN> };
open(my $trace, '>>', $ENV{OMAPI_TRACE}) or die $!;
print {$trace} $input or die $!;
close($trace) or die $!;
if ($input eq "key-algorithm\n") {
if ($ENV{OMAPI_CLIENT} eq 'legacy') {
warn "unknown token: key-algorithm\n";
print '> ';
} elsif ($ENV{OMAPI_CLIENT} eq 'silent') {
exit 0;
} else {
$| = 1;
my $command = $ENV{OMAPI_CLIENT} eq 'corrected' ? 'key-algorithm' : 'key-algoritm';
print "> missing or invalid algorithm name\nusage: $command <algorithm name>\n> ";
exit 1 if $ENV{OMAPI_CLIENT} eq 'failed';
if ($ENV{OMAPI_CLIENT} eq 'stalled') {
$SIG{TERM} = 'IGNORE';
open(my $pid, '>', $ENV{OMAPI_PID}) or die $!;
print {$pid} $$;
close($pid);
sleep 60;
}
}
}
PERL
chmod 0755, $client or die $!;
local $ENV{OMAPI_TRACE} = "$directory/trace";
local $ENV{OMAPI_PID} = "$directory/pid";
{
package FastCapabilityRunner;
use parent 'xCAT::DHCP::OmapiRunner';
sub _completion_delay { die 'a probe has no server state to settle'; }
sub _poll_interval { return 0.01; }
sub _completion_attempts { return 500; }
sub _termination_attempts { return 10; }
}
sub settings {
my ($algorithm, $fips) = @_;
return xCAT::DHCP::OmapiPolicy->settings(
fips_mode => $fips || 0,
site_values => { dhcpomapialgorithm => $algorithm, dhcpomshellpath => $client }
);
}
for my $algorithm (undef, 'hmac-md5') {
local $ENV{OMAPI_CLIENT} = 'legacy';
unlink $ENV{OMAPI_TRACE};
is(FastCapabilityRunner->key_algorithm_error(settings($algorithm)), undef,
'legacy MD5 does not require a SHA-capable client');
ok(!-e $ENV{OMAPI_TRACE}, 'MD5 does not execute the probe');
}
for my $mode (qw(modern corrected legacy silent failed stalled)) {
local $ENV{OMAPI_CLIENT} = $mode;
write_text($ENV{OMAPI_TRACE}, '');
my $error = FastCapabilityRunner->key_algorithm_error(settings('hmac-sha256'));
if ($mode eq 'modern' || $mode eq 'corrected') {
is($error, undef, "$mode omshell supports SHA selection");
} else {
like($error, qr/\Q$client\E.*hmac-sha256.*dhcpomshellpath/,
"$mode omshell is rejected with a remediation message");
}
is(read_text($ENV{OMAPI_TRACE}), "key-algorithm\n",
"$mode probe sends no connection command or secret");
}
my $stalled_pid = read_text($ENV{OMAPI_PID});
ok(!kill(0, $stalled_pid), 'the timed-out probe is reaped');
{
my $missing = settings('hmac-sha512');
$missing->{omshell_path} = "$directory/missing";
like(FastCapabilityRunner->key_algorithm_error($missing), qr/Cannot verify/,
'a missing custom client fails closed');
}
my $plugin = repo_path('xCAT-server/lib/xcat/plugins/dhcp.pm');
require $plugin;
{
package CapabilityBackend;
sub name { return $_[0]->{name}; }
sub check_services { return {error => 'service boundary'}; }
}
{
no warnings qw(redefine once);
local *xCAT::Utils::isServiceNode = sub { return 0; };
local *xCAT::Utils::isLinux = sub { return 1; };
local *xCAT::Utils::isFIPS = sub { return 0; };
local *xCAT::Utils::checkservicestatus = sub { return 1; };
local %::XCATSITEVALS = (dhcpomapialgorithm => 'hmac-sha256', dhcpomshellpath => $client);
for my $site (
['rhels8.0', '', 1],
['ubuntu20.04', '', 0], ['ubuntu20.04', '192.0.2.1', 1],
['ubuntu22.04', '', 0], ['ubuntu22.04', '192.0.2.1', 1]
) {
local $xCAT_plugin::dhcp::distro = $site->[0];
local $::XCATSITEVALS{externaldhcpservers} = $site->[1];
for my $backend (qw(isc kea)) {
local *xCAT::DHCP::Backend::new_backend = sub { return bless {name => $backend}, 'CapabilityBackend'; };
for my $mode (qw(legacy modern)) {
local $ENV{OMAPI_CLIENT} = $mode;
write_text($ENV{OMAPI_TRACE}, '');
my @messages;
my $mask = umask;
xCAT_plugin::dhcp::process_request({arg => ['-q'], node => ['node01']},
sub { push @messages, map { @{$_->{error} || []}, @{$_->{data} || []} } @_; });
umask $mask;
my $messages = join ' ', @messages;
my $probe = $backend eq 'isc' && $site->[2];
my $label = "$site->[0] external=$site->[1] $backend $mode";
if ($probe && $mode eq 'legacy') {
like($messages, qr/Cannot verify key-algorithm/, "$label rejects an unsupported SHA client");
} else {
like($messages, qr/dhcp server is not running|service boundary/,
"$label reaches the service check");
}
is(read_text($ENV{OMAPI_TRACE}), $probe ? "key-algorithm\n" : '',
"$label probes only when the query uses OMAPI");
}
}
}
}
my $root = "$directory/root";
make_path("$root/lib/perl/xCAT/DHCP", "$directory/commands");
write_text("$root/lib/perl/xCAT/DHCP/Backend.pm", <<'PERL');
package xCAT::DHCP::Backend;
sub new_backend { return bless {}, __PACKAGE__; }
sub name { return 'isc'; }
1;
PERL
write_text("$root/lib/perl/xCAT/Table.pm", <<'PERL');
package xCAT::Table;
sub new { return bless {}, __PACKAGE__; }
sub getAttribs { return {password => 'dGVzdA=='}; }
1;
PERL
my $wrapper = "$directory/dhcpop-wrapper";
write_text($wrapper, <<'PERL');
use xCAT::DHCP::OmapiRunner;
use xCAT::Utils;
no warnings 'redefine';
*xCAT::Utils::isFIPS = sub { return $ENV{OMAPI_FIPS}; };
*xCAT::DHCP::OmapiRunner::_completion_delay = sub { return 0; };
*xCAT::DHCP::OmapiRunner::_command_directory = sub { return $ENV{OMAPI_DIRECTORY}; };
our %XCATSITEVALS = (dhcpomapialgorithm => $ENV{OMAPI_ALGORITHM}, dhcpomshellpath => $ENV{OMAPI_PATH});
my $script = shift @ARGV;
do $script;
die $@ if $@;
PERL
for my $case (['hmac-md5', 0, 'legacy', 0], ['hmac-sha256', 0, 'legacy', 1],
['hmac-sha256', 0, 'modern', 0], ['', 1, 'legacy', 1]) {
local @ENV{qw(XCATROOT OMAPI_ALGORITHM OMAPI_FIPS OMAPI_CLIENT OMAPI_DIRECTORY OMAPI_PATH)} =
($root, $case->[0], $case->[1], $case->[2], "$directory/commands", $client);
write_text($ENV{OMAPI_TRACE}, '');
open(my $child, '-|', $Config{perlpath}, "-I$root/lib/perl",
'-I' . repo_path('perl-xCAT'), '-I' . repo_path('xCAT-server/lib/perl'),
'-I' . repo_path('xCAT-test/lib'), $wrapper,
repo_path('xCAT-server/share/xcat/tools/dhcpop'), '-r', '-n', 'node01') or die $!;
my $output = do { local $/; <$child> };
close($child);
is($? >> 8, $case->[3], "dhcpop: algorithm=$case->[0] FIPS=$case->[1] client=$case->[2]");
if ($case->[3]) {
like($output, qr/Cannot verify key-algorithm/, 'dhcpop reports the capability error');
unlike(read_text($ENV{OMAPI_TRACE}), qr/\bconnect\b|dGVzdA==/,
'dhcpop stops before sending a secret or changing a lease');
} else {
like(read_text($ENV{OMAPI_TRACE}), qr/connect\nnew host/, 'dhcpop continues with the lease operation');
}
}
done_testing();
+39
View File
@@ -0,0 +1,39 @@
#!/usr/bin/env perl
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/../lib";
use Test::More;
use XCAT::Test::File qw(repo_path);
my $rpmspec = qx(command -v rpmspec 2>/dev/null);
chomp($rpmspec);
plan skip_all => 'rpmspec is required' unless $rpmspec && -x $rpmspec;
foreach my $spec ('xCAT/xCAT.spec', 'xCATsn/xCATsn.spec') {
foreach my $build (
['EL8', 'rhel 8'], ['EL9', 'rhel 9'], ['EL10', 'rhel 10'],
['SLES15', 'suse_version 1500'], ['openEuler', 'openEuler 1'],
) {
foreach my $arch (qw(x86_64 ppc64le aarch64 s390x riscv64)) {
open(my $fh, '-|', $rpmspec, '-q', '--requires', '--target', $arch,
'--define', 'version 2.20.0', '--define', 'release 1',
'--undefine', 'rhel', '--undefine', 'suse_version',
'--undefine', 'openEuler', '--define', $build->[1],
repo_path($spec)) or die "run rpmspec: $!";
my @requires = <$fh>;
close($fh) or BAIL_OUT("rpmspec failed for $spec on $build->[0]/$arch");
chomp @requires;
is_deeply(
[grep { /\bdhcp-server\b/ } @requires], [],
"$spec built on $build->[0]/$arch adds no SHA-only DHCP package floor"
);
is(scalar(grep { m{/usr/sbin/dhcpd} } @requires), 1,
"$spec built on $build->[0]/$arch retains its DHCP backend requirement");
}
}
}
done_testing();