mirror of
https://github.com/xcat2/xcat-core.git
synced 2026-08-04 00:16:59 +00:00
283 lines
7.5 KiB
Perl
283 lines
7.5 KiB
Perl
#!/usr/bin/env perl
|
|
use strict;
|
|
use warnings;
|
|
|
|
use FindBin;
|
|
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 $ddns_plugin_path =
|
|
"$FindBin::Bin/../../xCAT-server/lib/xcat/plugins/ddns.pm";
|
|
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 {
|
|
my (%overrides) = @_;
|
|
return xCAT::DHCP::OmapiPolicy->settings(
|
|
site_values => {
|
|
dhcpomapialgorithm => undef,
|
|
dhcpomapikeyname => undef,
|
|
dhcpomshellpath => undef,
|
|
%overrides,
|
|
}
|
|
);
|
|
}
|
|
|
|
# Model a populated xCAT site and require each fixture to override it fully.
|
|
our %XCATSITEVALS;
|
|
local %XCATSITEVALS = (
|
|
dhcpomapialgorithm => 'hmac-sha256',
|
|
dhcpomapikeyname => 'site-key',
|
|
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(
|
|
{
|
|
omapi_settings => $defaults,
|
|
privkey => 'legacy-secret',
|
|
}
|
|
),
|
|
"key \"xcat_key\" {\n\talgorithm hmac-md5;\n\tsecret \"legacy-secret\";\n};\n\n",
|
|
'default DDNS key remains xcat_key with hmac-md5'
|
|
);
|
|
|
|
my $sha512 = omapi_settings(
|
|
dhcpomapialgorithm => 'hmac-sha512',
|
|
dhcpomapikeyname => 'provider.key',
|
|
);
|
|
|
|
is(
|
|
xCAT_plugin::ddns::ddns_tsig_algorithm(
|
|
{
|
|
omapi_settings => $sha512,
|
|
}
|
|
),
|
|
'hmac-sha512',
|
|
'explicit non-MD5 DDNS algorithm is honored'
|
|
);
|
|
|
|
is(
|
|
xCAT_plugin::ddns::ddns_key_contents(
|
|
{
|
|
omapi_settings => $sha512,
|
|
privkey => 'provider-secret',
|
|
}
|
|
),
|
|
"key \"provider.key\" {\n\talgorithm hmac-sha512;\n\tsecret \"provider-secret\";\n};\n\n",
|
|
'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;
|
|
}
|
|
}
|