2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-09-04 20:17:55 +00:00

test(xcat-core): capture NTP setup failing on a stock Ubuntu management node

An xCAT management node must serve time to its compute nodes (they point at
ntpservers=<xcatmaster>). Ubuntu ships only systemd-timesyncd, an SNTP client that
disciplines the local clock but cannot serve time, and makentp supports chronyd and
ntpd only. On a stock Ubuntu MN makentp therefore fails outright with "Please make
sure ntpd is installed", reddening reg_linux_diskfull_installation_flat.

Two further defects compound it. setupntp hard-requires hwclock through
check_exec_or_exit, but Ubuntu 24.04 moved hwclock into util-linux-extra, which is
absent from minimal images -- so the whole NTP setup, including the clock step that
does not need hwclock at all, aborts. And systemd-timesyncd is part of systemd rather
than a time-daemon package, so it coexists at the package level and keeps disciplining
the clock against whichever daemon xCAT just configured.

Assert a shared, unit-tested daemon selector in the spirit of xCAT::DHCP::Backend, the
package dependencies that guarantee a server-capable daemon and hwclock, and the
setupntp changes. All fail today.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
This commit is contained in:
Daniel Hilst
2026-08-24 14:39:49 -03:00
parent 0589bdbc70
commit 1b81af0d1d
2 changed files with 130 additions and 0 deletions
+58
View File
@@ -0,0 +1,58 @@
#!/usr/bin/env perl
use strict;
use warnings;
use Test::More;
# Regression: makentp/setupntp configure a server-capable NTP daemon (chronyd/ntpd) on the MN.
# On a minimal Ubuntu 24.04 MN chrony was absent (Ubuntu ships only the client-only
# systemd-timesyncd), hwclock moved to util-linux-extra (absent) so setupntp aborted its whole NTP
# setup, and timesyncd was left fighting the NTP daemon -- reddening reg_linux_diskfull_installation_flat.
use File::Spec;
use FindBin;
my $repo_root = File::Spec->rel2abs( File::Spec->catdir( $FindBin::Bin, '..', '..' ) );
sub slurp {
my ($rel) = @_;
my $path = File::Spec->catfile( $repo_root, split m{/}, $rel );
local $/;
open my $fh, '<', $path or return undef;
<$fh>;
}
my $setupntp = slurp('xCAT/postscripts/setupntp');
SKIP: {
skip 'setupntp not found', 4 unless defined $setupntp;
unlike($setupntp, qr/check_exec_or_exit[^\n]*\bhwclock\b/,
'setupntp does NOT hard-require hwclock in check_exec_or_exit');
like($setupntp, qr/command -v hwclock/,
'setupntp guards its hwclock use so a missing hwclock is non-fatal');
like($setupntp, qr/systemctl\s+(?:stop|disable)\s+systemd-timesyncd/,
'setupntp stops/disables systemd-timesyncd so it does not fight the NTP daemon');
like($setupntp, qr/chronyd\s+-f\s+\S*\s+-q/,
'setupntp still steps the system clock via a one-shot chronyd -q');
}
my $ctrl = slurp('xCAT/debian/control');
SKIP: {
skip 'debian/control not found', 2 unless defined $ctrl;
like($ctrl, qr/^Depends:.*\bchrony \| ntp\b/m,
'xcat debian package Depends on chrony | ntp (server-capable NTP daemon)');
like($ctrl, qr/^Recommends:.*\butil-linux-extra\b/m,
'xcat debian package Recommends util-linux-extra (provides hwclock on noble+)');
}
my $spec = slurp('xCAT/xCAT.spec');
SKIP: {
skip 'xCAT.spec not found', 1 unless defined $spec;
like($spec, qr/^Requires:\s*\(chrony or ntp\)/m,
'xCAT rpm Requires (chrony or ntp) for makentp');
}
my $makentp = slurp('xCAT-server/lib/xcat/plugins/makentp.pm');
SKIP: {
skip 'makentp.pm not found', 1 unless defined $makentp;
like($makentp, qr/xCAT::NTP::Backend->choose/,
'makentp selects the NTP daemon through the xCAT::NTP::Backend selector');
}
done_testing();
+72
View File
@@ -0,0 +1,72 @@
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/../../perl-xCAT";
use Test::More;
use xCAT::NTP::Backend;
# --- normalize: aliases, trimming, case, validation --------------------------------------------
is( xCAT::NTP::Backend->normalize(undef), 'auto', 'undefined backend defaults to auto' );
is( xCAT::NTP::Backend->normalize(''), 'auto', 'empty backend defaults to auto' );
is( xCAT::NTP::Backend->normalize(' Chrony '), 'chrony', 'values are trimmed and lowercased' );
is( xCAT::NTP::Backend->normalize('chronyd'), 'chrony', 'chronyd aliases to chrony' );
is( xCAT::NTP::Backend->normalize('ntp'), 'ntpd', 'ntp aliases to ntpd' );
is( xCAT::NTP::Backend->normalize('ntpsec'), 'ntpd', 'ntpsec aliases to ntpd' );
is( xCAT::NTP::Backend->normalize('ntpd'), 'ntpd', 'ntpd is valid' );
is( xCAT::NTP::Backend->normalize('bogus'), undef, 'invalid backend is rejected' );
# --- default_backend: per-distro table ---------------------------------------------------------
is( xCAT::NTP::Backend->default_backend( os_name => 'rhel', version => 6 ), 'ntpd', 'EL6 defaults to ntpd' );
is( xCAT::NTP::Backend->default_backend( os_name => 'rhel', version => 7 ), 'chrony', 'EL7 defaults to chrony' );
is( xCAT::NTP::Backend->default_backend( os_name => 'rhels', version => 8 ), 'chrony', 'EL8 defaults to chrony' );
is( xCAT::NTP::Backend->default_backend( os_name => 'rocky', version => 9 ), 'chrony', 'EL9 clones default to chrony' );
is( xCAT::NTP::Backend->default_backend( os_name => 'alma', version => 10 ), 'chrony', 'EL10 clones default to chrony' );
is( xCAT::NTP::Backend->default_backend( os_name => 'sles', version => 12 ), 'ntpd', 'SLES12 defaults to ntpd' );
is( xCAT::NTP::Backend->default_backend( os_name => 'sles', version => 15 ), 'chrony', 'SLES15 defaults to chrony' );
is( xCAT::NTP::Backend->default_backend( os_name => 'sles', version => 16 ), 'chrony', 'SLES16 defaults to chrony' );
is( xCAT::NTP::Backend->default_backend( os_name => 'leap', version => '15.6' ), 'chrony', 'Leap 15.x defaults to chrony' );
is( xCAT::NTP::Backend->default_backend( os_name => 'ubuntu', version => '18.04' ), 'chrony', 'Ubuntu 18.04 defaults to chrony (timesyncd cannot serve)' );
is( xCAT::NTP::Backend->default_backend( os_name => 'ubuntu', version => '20.04' ), 'chrony', 'Ubuntu 20.04 defaults to chrony' );
is( xCAT::NTP::Backend->default_backend( os_name => 'ubuntu', version => '22.04' ), 'chrony', 'Ubuntu 22.04 defaults to chrony' );
is( xCAT::NTP::Backend->default_backend( os_name => 'ubuntu', version => '24.04' ), 'chrony', 'Ubuntu 24.04 defaults to chrony' );
is( xCAT::NTP::Backend->default_backend( os_name => 'ubuntu', version => '26.04' ), 'chrony', 'Ubuntu 26.04 defaults to chrony' );
is( xCAT::NTP::Backend->default_backend( os_name => 'debian', version => 12 ), 'chrony', 'Debian defaults to chrony' );
# --- choose: explicit override, auto, availability downgrade, install flag ----------------------
my $r;
$r = xCAT::NTP::Backend->choose( requested => 'ntpd', os_name => 'ubuntu', version => '24.04' );
is( $r->{name}, 'ntpd', 'explicit ntpd override is honored on Ubuntu' );
$r = xCAT::NTP::Backend->choose( requested => 'auto', os_name => 'ubuntu', version => '24.04' );
is( $r->{name}, 'chrony', 'auto resolves to the Ubuntu default (chrony)' );
$r = xCAT::NTP::Backend->choose( requested => 'bogus', os_name => 'ubuntu', version => '24.04' );
like( $r->{error}, qr/Invalid site\.ntpbackend/, 'invalid override returns an error' );
# chrony chosen but absent, ntpd present -> downgrade to ntpd (do not install a 2nd daemon)
$r = xCAT::NTP::Backend->choose(
requested => 'auto', os_name => 'ubuntu', version => '24.04',
check_available => 1, available => { chrony => 0, ntpd => 1 } );
is( $r->{name}, 'ntpd', 'chrony absent + ntpd present downgrades to ntpd' );
is( $r->{downgraded}, 'chrony', 'downgrade records the preferred backend' );
is( $r->{install}, 0, 'no install when a supported daemon is already present' );
# chrony chosen and present -> keep it, no install
$r = xCAT::NTP::Backend->choose(
requested => 'auto', os_name => 'ubuntu', version => '24.04',
check_available => 1, available => { chrony => 1, ntpd => 0 } );
is( $r->{name}, 'chrony', 'chrony present keeps chrony' );
is( $r->{install}, 0, 'chrony present needs no install' );
# neither present -> keep the preferred choice and flag install (stock Ubuntu MN)
$r = xCAT::NTP::Backend->choose(
requested => 'auto', os_name => 'ubuntu', version => '24.04',
check_available => 1, available => { chrony => 0, ntpd => 0 } );
is( $r->{name}, 'chrony', 'neither present keeps the preferred chrony' );
is( $r->{install}, 1, 'neither present flags install of the preferred daemon' );
done_testing();