From 1b81af0d1da2c83b07e1d4e22dbf36f802648b8c Mon Sep 17 00:00:00 2001 From: Daniel Hilst <392820+dhilst@users.noreply.github.com> Date: Mon, 24 Aug 2026 14:39:49 -0300 Subject: [PATCH] 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=). 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> --- xCAT-test/unit/makentp_ntp_deps.t | 58 +++++++++++++++++++++ xCAT-test/unit/ntp_backend_selection.t | 72 ++++++++++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 xCAT-test/unit/makentp_ntp_deps.t create mode 100644 xCAT-test/unit/ntp_backend_selection.t diff --git a/xCAT-test/unit/makentp_ntp_deps.t b/xCAT-test/unit/makentp_ntp_deps.t new file mode 100644 index 000000000..68180ee34 --- /dev/null +++ b/xCAT-test/unit/makentp_ntp_deps.t @@ -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(); diff --git a/xCAT-test/unit/ntp_backend_selection.t b/xCAT-test/unit/ntp_backend_selection.t new file mode 100644 index 000000000..3f86cf0a2 --- /dev/null +++ b/xCAT-test/unit/ntp_backend_selection.t @@ -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();