mirror of
https://github.com/xcat2/xcat-core.git
synced 2026-10-02 08:51:44 +00:00
fix(xcat-server): a Debian service node's named serves the wrong configuration
Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
This commit is contained in:
@@ -2528,4 +2528,31 @@ sub searchcompressedrootimg{
|
||||
}
|
||||
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
=head3 named_service_action
|
||||
|
||||
Which service action brings a freshly written named configuration into effect.
|
||||
|
||||
Linux gets a restart, not a start. On Debian the package already runs the daemon, so a start
|
||||
is a no-op and named keeps serving the configuration it read at install time: the zone
|
||||
makenamed.conf has just written is never loaded, and a compute node cannot resolve its
|
||||
service node. AIX keeps the start it has always used.
|
||||
|
||||
Arguments: the platform, 'aix' or 'linux'
|
||||
Returns: 'start', 'restart', or '' for a platform with no action
|
||||
|
||||
=cut
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
sub named_service_action {
|
||||
my ($platform) = @_;
|
||||
$platform = '' unless defined $platform;
|
||||
return 'start' if $platform eq 'aix';
|
||||
return 'restart' if $platform eq 'linux';
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
||||
@@ -788,6 +788,8 @@ sub setup_FTP
|
||||
=cut
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
sub setup_DNS
|
||||
{
|
||||
my $srvclist = shift;
|
||||
@@ -827,11 +829,15 @@ sub setup_DNS
|
||||
#}
|
||||
|
||||
#my $rc = xCAT::Utils->startService($serv);
|
||||
# Restart, not start. makenamed.conf has just rewritten named.conf, and a start is a no-op
|
||||
# where the package already runs the daemon -- Debian does -- so the service keeps serving the
|
||||
# configuration it read at install time.
|
||||
my $rc = 0;
|
||||
if (xCAT::Utils->isAIX()) {
|
||||
my $action = xCAT::SvrUtils::named_service_action(xCAT::Utils->isAIX() ? 'aix' : 'linux');
|
||||
if ($action eq 'start') {
|
||||
$rc = xCAT::Utils->startService("named");
|
||||
} elsif (xCAT::Utils->isLinux()) {
|
||||
$rc = xCAT::Utils->startservice("named");
|
||||
} elsif ($action eq 'restart') {
|
||||
$rc = xCAT::Utils->restartservice("named");
|
||||
}
|
||||
|
||||
if ($rc != 0)
|
||||
|
||||
@@ -19,7 +19,7 @@ is_lsb_ubuntu ()
|
||||
exit 1 # Not Ubuntu
|
||||
}
|
||||
|
||||
' /etc/lsb-release >/dev/null 2>&1
|
||||
' "${1:-/etc/lsb-release}" >/dev/null 2>&1
|
||||
|
||||
# Routine exit status is exit status of the last command -- the awk script.
|
||||
#
|
||||
@@ -28,14 +28,60 @@ is_lsb_ubuntu ()
|
||||
}
|
||||
|
||||
|
||||
DIRECTORY=/var/named
|
||||
# forwarder_addresses [<resolv.conf> [<systemd-resolved uplink>]]
|
||||
#
|
||||
# The addresses named must forward to, one per line.
|
||||
#
|
||||
# A loopback address is not a forwarder. On a host managed by systemd-resolved /etc/resolv.conf
|
||||
# holds the 127.0.0.53 stub, and that stub points back at this named for the link, so
|
||||
# "forward only" to it answers nothing. systemd-resolved writes the real servers to its own
|
||||
# uplink file, which is the fallback.
|
||||
forwarder_addresses()
|
||||
{
|
||||
_fa_resolv=${1:-/etc/resolv.conf}
|
||||
_fa_uplink=${2:-/run/systemd/resolve/resolv.conf}
|
||||
_fa_addrs=$(_fa_usable "$_fa_resolv")
|
||||
if [ -z "$_fa_addrs" ]; then
|
||||
_fa_addrs=$(_fa_usable "$_fa_uplink")
|
||||
fi
|
||||
[ -n "$_fa_addrs" ] && printf '%s\n' "$_fa_addrs"
|
||||
return 0
|
||||
}
|
||||
|
||||
# check for SLES
|
||||
grep -s -q sles /etc/os-release
|
||||
IS_SLES=$?
|
||||
if [ -f /etc/SuSE-release ] || [ $IS_SLES -eq 0 ]; then
|
||||
DIRECTORY=/var/lib/named
|
||||
fi
|
||||
_fa_usable()
|
||||
{
|
||||
[ -r "$1" ] || return 0
|
||||
awk '$1 == "nameserver" && $2 !~ /^127\./ && $2 != "::1" { print $2 }' "$1" 2>/dev/null
|
||||
}
|
||||
|
||||
# named_directory [<lsb-release> [<os-release> [<SuSE-release>]]]
|
||||
#
|
||||
# The working directory for named. It must be writable by the user named drops to: Debian runs
|
||||
# it as "bind" and ships /var/cache/bind for this, while /var/named is created root-owned. named
|
||||
# writes its managed-keys database there, and when that write fails it answers NXDOMAIN to every
|
||||
# query, forwarded ones included.
|
||||
named_directory()
|
||||
{
|
||||
_nd_lsb=${1:-/etc/lsb-release}
|
||||
_nd_os=${2:-/etc/os-release}
|
||||
_nd_suse=${3:-/etc/SuSE-release}
|
||||
|
||||
if is_lsb_ubuntu "$_nd_lsb"; then
|
||||
echo /var/cache/bind
|
||||
return 0
|
||||
fi
|
||||
if [ -f "$_nd_suse" ] || grep -s -q sles "$_nd_os"; then
|
||||
echo /var/lib/named
|
||||
return 0
|
||||
fi
|
||||
echo /var/named
|
||||
}
|
||||
|
||||
# A test loads this file for the routine above and must not run the rest, which writes
|
||||
# named.conf and restarts the service.
|
||||
[ "${MAKENAMED_LIB:-}" = 1 ] && return 0
|
||||
|
||||
DIRECTORY=$(named_directory)
|
||||
FILE=/etc/named.conf
|
||||
|
||||
if ( is_lsb_ubuntu ); then
|
||||
@@ -58,7 +104,7 @@ echo "options {
|
||||
forward only;
|
||||
forwarders {" >$FILE
|
||||
|
||||
for i in $(grep "^nameserver" /etc/resolv.conf | awk '{print $2}')
|
||||
forwarder_addresses | while read -r i
|
||||
do
|
||||
echo " $i;"
|
||||
done >>$FILE
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env bats
|
||||
#
|
||||
# makenamed.conf builds the forwarder list of a service node's named from /etc/resolv.conf.
|
||||
#
|
||||
# On a host managed by systemd-resolved that file holds the 127.0.0.53 stub, and the stub points
|
||||
# back at this named for the link. forward-only to it is a loop: the service node answers
|
||||
# nothing, and every compute node behind it fails to resolve. Measured on xcat22-sn, where
|
||||
# "dig @<sn> xcat22-sn.xcat22.lab" returned nothing while the same query to the management node
|
||||
# answered. The EL service node has the real upstream in /etc/resolv.conf, which is why it works.
|
||||
#
|
||||
# systemd-resolved writes the real servers to /run/systemd/resolve/resolv.conf.
|
||||
|
||||
load 'helpers/shell_source'
|
||||
|
||||
setup()
|
||||
{
|
||||
SCRIPT="$(require_repo_file 'xCAT-server/sbin/makenamed.conf')"
|
||||
RESOLV="${BATS_TEST_TMPDIR}/resolv.conf"
|
||||
UPLINK="${BATS_TEST_TMPDIR}/uplink.conf"
|
||||
# MAKENAMED_LIB stops the script before it writes anything, so only the routine is loaded.
|
||||
MAKENAMED_LIB=1 . "$SCRIPT"
|
||||
export -f forwarder_addresses _fa_usable
|
||||
}
|
||||
|
||||
@test "a real nameserver is a forwarder" {
|
||||
printf 'nameserver 192.168.222.1\nsearch xcat22.lab\n' >"$RESOLV"
|
||||
run forwarder_addresses "$RESOLV" "$UPLINK"
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$output" = "192.168.222.1" ]
|
||||
}
|
||||
|
||||
@test "the systemd-resolved stub is not a forwarder, and the uplink answers instead" {
|
||||
printf 'nameserver 127.0.0.53\noptions edns0 trust-ad\n' >"$RESOLV"
|
||||
printf 'nameserver 192.168.222.1\nsearch xcat22.lab\n' >"$UPLINK"
|
||||
run forwarder_addresses "$RESOLV" "$UPLINK"
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$output" = "192.168.222.1" ]
|
||||
}
|
||||
|
||||
@test "any loopback address is rejected, not only the stub" {
|
||||
printf 'nameserver 127.0.0.1\nnameserver ::1\n' >"$RESOLV"
|
||||
printf 'nameserver 10.0.0.1\n' >"$UPLINK"
|
||||
run forwarder_addresses "$RESOLV" "$UPLINK"
|
||||
[ "$output" = "10.0.0.1" ]
|
||||
}
|
||||
|
||||
@test "several real nameservers are all forwarders, in order" {
|
||||
printf 'nameserver 192.168.222.1\nnameserver 10.0.0.2\n' >"$RESOLV"
|
||||
run forwarder_addresses "$RESOLV" "$UPLINK"
|
||||
[ "$output" = "192.168.222.1
|
||||
10.0.0.2" ]
|
||||
}
|
||||
|
||||
@test "a real nameserver wins over the uplink, which is only the fallback" {
|
||||
printf 'nameserver 192.168.222.1\n' >"$RESOLV"
|
||||
printf 'nameserver 10.9.9.9\n' >"$UPLINK"
|
||||
run forwarder_addresses "$RESOLV" "$UPLINK"
|
||||
[ "$output" = "192.168.222.1" ]
|
||||
}
|
||||
|
||||
@test "no usable address anywhere prints nothing rather than a blank forwarder" {
|
||||
printf 'nameserver 127.0.0.53\n' >"$RESOLV"
|
||||
: >"$UPLINK"
|
||||
# Count the lines. A blank line reaches named.conf as an empty forwarder entry, which bind
|
||||
# rejects as a syntax error, and $output cannot tell one from no output at all.
|
||||
run bash -c "forwarder_addresses '$RESOLV' '$UPLINK' | wc -l"
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$output" = "0" ]
|
||||
}
|
||||
|
||||
@test "an absent uplink file is not an error" {
|
||||
printf 'nameserver 127.0.0.53\n' >"$RESOLV"
|
||||
run forwarder_addresses "$RESOLV" "${BATS_TEST_TMPDIR}/absent"
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$output" = "" ]
|
||||
}
|
||||
|
||||
# named runs as "bind" on Debian and writes its managed-keys database into the configured
|
||||
# directory. /var/named is created root-owned, so the write fails, DNSSEC initialisation fails
|
||||
# with it, and the server answers NXDOMAIN to every query -- including forwarded ones, which is
|
||||
# how a correct forwarder list still resolved nothing on xcat22-sn.
|
||||
|
||||
@test "Ubuntu names the directory its named can write" {
|
||||
printf 'DISTRIB_ID=Ubuntu\nDISTRIB_RELEASE=24.04\n' >"${BATS_TEST_TMPDIR}/lsb"
|
||||
run named_directory "${BATS_TEST_TMPDIR}/lsb" "${BATS_TEST_TMPDIR}/absent-os" "${BATS_TEST_TMPDIR}/absent-suse"
|
||||
[ "$output" = "/var/cache/bind" ]
|
||||
}
|
||||
|
||||
@test "SLES keeps its own directory" {
|
||||
: >"${BATS_TEST_TMPDIR}/lsb"
|
||||
printf 'ID="sles"\n' >"${BATS_TEST_TMPDIR}/os"
|
||||
run named_directory "${BATS_TEST_TMPDIR}/lsb" "${BATS_TEST_TMPDIR}/os" "${BATS_TEST_TMPDIR}/absent-suse"
|
||||
[ "$output" = "/var/lib/named" ]
|
||||
}
|
||||
|
||||
@test "EL keeps /var/named" {
|
||||
: >"${BATS_TEST_TMPDIR}/lsb"
|
||||
printf 'ID="almalinux"\n' >"${BATS_TEST_TMPDIR}/os"
|
||||
run named_directory "${BATS_TEST_TMPDIR}/lsb" "${BATS_TEST_TMPDIR}/os" "${BATS_TEST_TMPDIR}/absent-suse"
|
||||
[ "$output" = "/var/named" ]
|
||||
}
|
||||
|
||||
@test "an absent lsb-release is not Ubuntu" {
|
||||
printf 'ID="almalinux"\n' >"${BATS_TEST_TMPDIR}/os"
|
||||
run named_directory "${BATS_TEST_TMPDIR}/absent-lsb" "${BATS_TEST_TMPDIR}/os" "${BATS_TEST_TMPDIR}/absent-suse"
|
||||
[ "$output" = "/var/named" ]
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
# setup_DNS writes named.conf through makenamed.conf and then brings the daemon up. It used to
|
||||
# START the service. On Debian the package already runs named, so a start is a no-op: the daemon
|
||||
# keeps serving the configuration it read at install time, the zone xCAT has just written is
|
||||
# never loaded, and a compute node cannot resolve its service node.
|
||||
#
|
||||
# A minimization of this change set dropped that fix, because no fast test could see it. The
|
||||
# decision lives in xCAT::SvrUtils, which a test can load; AAsn.pm cannot be loaded from a source
|
||||
# tree at all, since it pulls in xCAT::Table and the rest of the server.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use FindBin;
|
||||
use Test::More;
|
||||
|
||||
use lib "$FindBin::Bin/../../perl-xCAT";
|
||||
use lib "$FindBin::Bin/../../xCAT-server/lib/perl";
|
||||
use xCAT::SvrUtils;
|
||||
|
||||
can_ok('xCAT::SvrUtils', 'named_service_action') or do { done_testing(); exit 1 };
|
||||
|
||||
is(xCAT::SvrUtils::named_service_action('linux'), 'restart',
|
||||
'Linux restarts named, so the configuration just written is the one it serves');
|
||||
is(xCAT::SvrUtils::named_service_action('aix'), 'start',
|
||||
'AIX keeps the start it has always used');
|
||||
is(xCAT::SvrUtils::named_service_action(''), '',
|
||||
'an unknown platform does nothing rather than guessing an action');
|
||||
is(xCAT::SvrUtils::named_service_action(undef), '',
|
||||
'an undefined platform does nothing');
|
||||
|
||||
done_testing();
|
||||
Reference in New Issue
Block a user