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

test(ddns): cover Net::DNS version thresholds

This commit is contained in:
Vinícius Ferrão
2026-07-22 01:39:20 -03:00
parent ad9ac6db8a
commit 55606618fd
+203 -3
View File
@@ -7,18 +7,20 @@ use lib "$FindBin::Bin/../../xCAT-server/lib";
use lib "$FindBin::Bin/../../xCAT-server/lib/perl";
use lib "$FindBin::Bin/../../perl-xCAT";
use File::Temp qw(tempfile);
use Test::More;
$ENV{XCATCFG} ||= 'SQLite:/tmp';
$ENV{XCATROOT} ||= "$FindBin::Bin/../../xCAT-server";
my $source_ddns_plugin =
my $ddns_plugin_path =
"$FindBin::Bin/../../xCAT-server/lib/xcat/plugins/ddns.pm";
if ( -f $source_ddns_plugin ) {
require $source_ddns_plugin;
if ( -f $ddns_plugin_path ) {
require $ddns_plugin_path;
}
else {
require xCAT_plugin::ddns;
$ddns_plugin_path = $INC{'xCAT_plugin/ddns.pm'};
}
sub omapi_settings {
@@ -41,6 +43,15 @@ local %XCATSITEVALS = (
dhcpomshellpath => '/opt/site/bin/omshell',
);
my @net_dns_versions = (
[ '1.09', 0 ],
[ '1.35', 0 ],
[ '1.36', 1 ],
[ '1.40', 1 ],
[ '1.100', 1 ],
[ '2.0', 1 ],
);
my $defaults = omapi_settings();
is(
xCAT_plugin::ddns::ddns_key_contents(
@@ -79,4 +90,193 @@ is(
'custom DDNS key name and algorithm are rendered'
);
subtest 'all Net::DNS thresholds share the dotted version policy' => sub {
open( my $source_fh, '<', $ddns_plugin_path )
or die "Unable to read $ddns_plugin_path: $!";
local $/;
my $source = <$source_fh>;
close($source_fh)
or die "Unable to close $ddns_plugin_path: $!";
my @raw_comparisons =
( $source =~ /^(?!\s*#)[^\n]*(?:<|>=)\s*1\.36\b/gm );
is( scalar(@raw_comparisons), 0,
'no Net::DNS threshold uses Perl numeric comparison' );
my @policy_calls = ( $source =~ /net_dns_uses_keyfile\(\)/g );
is( scalar(@policy_calls), 4,
'all four Net::DNS threshold sites use the shared policy' );
};
subtest 'Net::DNS threshold controls DDNS policy and signing' => sub {
my $implicit_sha256 = {
algorithm => 'hmac-sha256',
algorithm_explicit => 0,
};
foreach my $case (@net_dns_versions) {
my ( $version, $uses_keyfile ) = @{$case};
my $expected_algorithm = $uses_keyfile ? 'hmac-sha256' : 'hmac-md5';
is(
with_net_dns_version(
$version,
sub {
xCAT_plugin::ddns::ddns_tsig_algorithm(
{ omapi_settings => $implicit_sha256 }
);
}
),
$expected_algorithm,
"Net::DNS $version selects the expected implicit algorithm"
);
my $update = Local::DDNS::Update->new();
with_net_dns_version(
$version,
sub {
xCAT_plugin::ddns::ddns_sign_update(
{
omapi_settings => $defaults,
privkey => 'legacy-secret',
},
$update
);
}
);
my $expected_call = $uses_keyfile
? [ '/etc/xcat/ddns.key' ]
: [ 'xcat_key', 'legacy-secret' ];
is_deeply(
$update->{sign_tsig_calls},
[$expected_call],
"Net::DNS $version signs through the expected interface"
);
my $tracker = tie my %key_context, 'Local::DDNS::TrackingHash';
with_net_dns_version(
$version,
sub {
xCAT_plugin::ddns::ensure_ddns_key_file(\%key_context);
}
);
is_deeply(
$tracker->{fetches},
$uses_keyfile ? ['privkey'] : [],
"Net::DNS $version applies the expected keyfile write gate"
);
}
};
subtest 'Net::DNS threshold controls named key reconciliation' => sub {
foreach my $case (@net_dns_versions) {
my ( $version, $uses_keyfile ) = @{$case};
my ( $named_contents, $restartneeded ) =
reconcile_named_key($version);
my $expected_algorithm = $uses_keyfile ? 'hmac-sha256' : 'hmac-md5';
like(
$named_contents,
qr/^\s*algorithm\s+\Q$expected_algorithm\E\s*;/m,
"Net::DNS $version keeps the expected named key algorithm"
);
is(
$restartneeded ? 1 : 0,
$uses_keyfile ? 0 : 1,
"Net::DNS $version records the expected named restart state"
);
}
};
done_testing();
sub with_net_dns_version {
my ( $version, $code ) = @_;
local $Net::DNS::VERSION = $version;
return $code->();
}
sub reconcile_named_key {
my ($version) = @_;
my ( $named_fh, $named_path ) = tempfile(UNLINK => 1);
print {$named_fh}
"options {\n};\n"
. "key \"xcat_key\" {\n"
. "\talgorithm hmac-sha256;\n"
. "\tsecret \"legacy-secret\";\n"
. "};\n";
close($named_fh) or die "Unable to close $named_path: $!";
my $ctx = {
omapi_settings => omapi_settings(),
privkey => 'legacy-secret',
zonesdir => '/tmp',
dbdir => '/tmp',
zonestotouch => {},
adzones => {},
dnsupdaters => [],
adservers => [],
restartneeded => 0,
};
no warnings qw(redefine once);
local *xCAT_plugin::ddns::get_conf = sub { return $named_path; };
local *xCAT_plugin::ddns::ensure_ddns_key_file = sub { return; };
local *xCAT::TableUtils::get_site_attribute = sub { return; };
local *xCAT::Utils::runcmd = sub { return (); };
local *xCAT::Utils::isAIX = sub { return 0; };
local *xCAT::Utils::isLinux = sub { return 1; };
local *xCAT::Table::new = sub {
return bless {}, 'Local::DDNS::PasswdTable';
};
with_net_dns_version(
$version,
sub { xCAT_plugin::ddns::update_namedconf( $ctx, 0 ); }
);
open( my $result_fh, '<', $named_path )
or die "Unable to read $named_path: $!";
local $/;
my $contents = <$result_fh>;
close($result_fh) or die "Unable to close $named_path: $!";
return ( $contents, $ctx->{restartneeded} );
}
{
package Local::DDNS::Update;
sub new {
return bless { sign_tsig_calls => [] }, shift;
}
sub sign_tsig {
my ( $self, @args ) = @_;
push @{ $self->{sign_tsig_calls} }, \@args;
return;
}
}
{
package Local::DDNS::PasswdTable;
sub setAttribs {
return 1;
}
}
{
package Local::DDNS::TrackingHash;
sub TIEHASH {
return bless { fetches => [] }, shift;
}
sub FETCH {
my ( $self, $key ) = @_;
push @{ $self->{fetches} }, $key;
return;
}
}