mirror of
https://github.com/xcat2/xcat-core.git
synced 2026-09-04 20:17:55 +00:00
fix(xcat-core): configure a server-capable NTP daemon on Ubuntu MNs
Add xCAT::NTP::Backend, a selector for the NTP daemon xCAT configures, in the same spirit as xCAT::DHCP::Backend. It honours site.ntpbackend, defaults per distro family (EL7+/SLES15+ chrony, older ntpd, Ubuntu/Debian chrony), and downgrades to whichever of chrony/ntpd is actually installed rather than installing a second daemon. makentp selects through it instead of probing /usr/sbin/chronyd directly, so the choice is one unit-tested code path. Guarantee the daemon at install time: the xcat metapackage now Depends on "chrony | ntp" and the xCAT rpm Requires "(chrony or ntp)". Both sit beside the existing service dependencies the metapackage already declares -- isc-dhcp-server|kea, apache2, nfs-kernel-server -- because an MN that cannot serve time cannot serve its compute nodes, and Ubuntu's default systemd-timesyncd is a client only. Stop requiring hwclock in setupntp. It only persists the already-stepped system clock to the RTC, and Ubuntu 24.04 moved it to util-linux-extra, absent on minimal images -- so a fatal check_exec_or_exit aborted the entire NTP setup, including the clock step that does not use it. Use it when present, log and continue when not, and pull util-linux-extra through Recommends and the diskless pkglist so it usually is. Disable systemd-timesyncd there too. It ships as part of systemd rather than a time-daemon package, so nothing displaces it, and it keeps disciplining the clock against the daemon being configured. Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
package xCAT::NTP::Backend;
|
||||
|
||||
# Selector for the NTP daemon xCAT configures on a node (chrony vs. ntpd), in the same spirit as
|
||||
# xCAT::DHCP::Backend (ISC vs. Kea). makentp/setupntp support chronyd and ntpd only -- there is no
|
||||
# systemd-timesyncd path (timesyncd is an SNTP client and cannot serve time to compute nodes), so an
|
||||
# xCAT MN always needs chrony or ntpd. This module centralizes and unit-tests the choice.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my %valid_backend = map { $_ => 1 } qw(auto chrony ntpd);
|
||||
|
||||
# Accept common aliases so site.ntpbackend / callers can say chronyd or ntp.
|
||||
my %alias = (
|
||||
chronyd => 'chrony',
|
||||
ntp => 'ntpd',
|
||||
ntpsec => 'ntpd',
|
||||
);
|
||||
|
||||
sub normalize {
|
||||
my ( $class, $backend ) = @_;
|
||||
|
||||
$backend = 'auto' unless defined($backend) && $backend ne '';
|
||||
$backend =~ s/^\s+|\s+$//g;
|
||||
$backend = lc($backend);
|
||||
$backend = $alias{$backend} if exists $alias{$backend};
|
||||
|
||||
return $backend if $valid_backend{$backend};
|
||||
return;
|
||||
}
|
||||
|
||||
# choose: resolve the effective backend for this node.
|
||||
# requested -- override (default: site.ntpbackend, else 'auto')
|
||||
# os_name/version -- OS identity (default: detected)
|
||||
# available -- optional { chrony => 0/1, ntpd => 0/1 } to bypass command detection (tests)
|
||||
# check_available -- when true, downgrade chrony->ntpd (or ntpd->chrony) if the chosen one is
|
||||
# absent but the other is present, and flag install=1 when neither is present.
|
||||
sub choose {
|
||||
my ( $class, %args ) = @_;
|
||||
|
||||
my $requested = exists $args{requested} ? $args{requested} : $class->_site_backend();
|
||||
my $normalized = $class->normalize($requested);
|
||||
unless ($normalized) {
|
||||
return { error => "Invalid site.ntpbackend value '$requested'. Valid values are auto, chrony, and ntpd." };
|
||||
}
|
||||
|
||||
my $selected = $normalized eq 'auto' ? $class->default_backend(%args) : $normalized;
|
||||
my $result = { requested => $normalized, name => $selected, install => 0 };
|
||||
|
||||
return $result unless $args{check_available};
|
||||
|
||||
my $other = $selected eq 'chrony' ? 'ntpd' : 'chrony';
|
||||
if ( $class->available( $selected, %args ) ) {
|
||||
return $result;
|
||||
} elsif ( $class->available( $other, %args ) ) {
|
||||
# respect what is actually installed rather than installing a second daemon
|
||||
$result->{name} = $other;
|
||||
$result->{downgraded} = $selected;
|
||||
return $result;
|
||||
}
|
||||
|
||||
# neither present: keep the preferred choice and tell the caller to install it
|
||||
$result->{install} = 1;
|
||||
return $result;
|
||||
}
|
||||
|
||||
# default_backend: table-driven per distro family.
|
||||
# EL/RHEL & clones: >= 7 -> chrony, 6 -> ntpd
|
||||
# SLES/SUSE: >= 15 -> chrony, 12 -> ntpd
|
||||
# Ubuntu/Debian: chrony (timesyncd is the OOB client but cannot serve; chrony from 18.04+)
|
||||
sub default_backend {
|
||||
my ( $class, %args ) = @_;
|
||||
|
||||
my $os_name = exists $args{os_name} ? $args{os_name} : $class->_osver('os');
|
||||
my $version = exists $args{version} ? $args{version} : ( split /,/, $class->_osver('all'), 2 )[1];
|
||||
my ($major) = ( defined($version) ? $version : '' ) =~ /^(\d+)/;
|
||||
|
||||
if ( defined($os_name) && $os_name =~ /^(?:rhel|rhels|rocky|alma|centos|ol|fedora)$/i ) {
|
||||
return 'ntpd' if defined($major) && $major <= 6;
|
||||
return 'chrony';
|
||||
}
|
||||
if ( defined($os_name) && $os_name =~ /^(?:sles|sled|suse|opensuse|leap)$/i ) {
|
||||
return 'ntpd' if defined($major) && $major <= 12;
|
||||
return 'chrony';
|
||||
}
|
||||
if ( defined($os_name) && $os_name =~ /^(?:ubuntu|debian)$/i ) {
|
||||
return 'chrony';
|
||||
}
|
||||
|
||||
return 'chrony';
|
||||
}
|
||||
|
||||
sub available {
|
||||
my ( $class, $backend, %args ) = @_;
|
||||
|
||||
if ( exists $args{available} && ref( $args{available} ) eq 'HASH' && exists $args{available}{$backend} ) {
|
||||
return $args{available}{$backend} ? 1 : 0;
|
||||
}
|
||||
|
||||
return _command_exists('chronyd') if $backend eq 'chrony';
|
||||
return _command_exists('ntpd') if $backend eq 'ntpd';
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub _site_backend {
|
||||
my $backend = eval {
|
||||
require xCAT::TableUtils;
|
||||
return xCAT::TableUtils->get_site_attribute( 'ntpbackend', 'auto' );
|
||||
};
|
||||
|
||||
return $backend || 'auto';
|
||||
}
|
||||
|
||||
sub _osver {
|
||||
my ( $class, $type ) = @_;
|
||||
|
||||
my $osver = eval {
|
||||
require xCAT::Utils;
|
||||
return defined($type) ? xCAT::Utils->osver($type) : xCAT::Utils->osver();
|
||||
};
|
||||
|
||||
return $osver || 'unknown';
|
||||
}
|
||||
|
||||
sub _command_exists {
|
||||
my ($command) = @_;
|
||||
|
||||
foreach my $dir ( split /:/, $ENV{PATH} || '' ) {
|
||||
next unless $dir;
|
||||
return 1 if -x "$dir/$command";
|
||||
}
|
||||
foreach my $path ( "/usr/sbin/$command", "/usr/bin/$command", "/sbin/$command", "/bin/$command" ) {
|
||||
return 1 if -x $path;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -252,9 +252,19 @@ sub process_request {
|
||||
$ntp_servers = $retdata->{'master'};
|
||||
}
|
||||
|
||||
# Pick the NTP daemon (chrony vs ntpd) via the shared, unit-tested selector -- the same spirit
|
||||
# as xCAT::DHCP::Backend (ISC vs Kea). It honors site.ntpbackend, defaults per distro, and
|
||||
# downgrades chrony->ntpd (or vice versa) to whichever is actually installed.
|
||||
require xCAT::NTP::Backend;
|
||||
my $ntp_backend = xCAT::NTP::Backend->choose(check_available => 1);
|
||||
if ($ntp_backend->{error}) {
|
||||
send_msg(\%request, 1, $ntp_backend->{error});
|
||||
return 1;
|
||||
}
|
||||
my $have_systemctl = (-x "/usr/bin/systemctl" || -x "/bin/systemctl");
|
||||
|
||||
# Handle chronyd here,
|
||||
if (-x "/usr/sbin/chronyd" &&
|
||||
(-x "/usr/bin/systemctl" || -x "/bin/systemctl")) {
|
||||
if ($ntp_backend->{name} eq 'chrony' && $have_systemctl) {
|
||||
send_msg(\%request, 0, "Will configure chronyd instead.");
|
||||
|
||||
my $cmd = "/install/postscripts/setupntp " .
|
||||
|
||||
@@ -16,6 +16,7 @@ gzip
|
||||
xz-utils
|
||||
cpio
|
||||
chrony
|
||||
util-linux-extra
|
||||
iproute2
|
||||
dracut
|
||||
dracut-network
|
||||
|
||||
+2
-2
@@ -9,8 +9,8 @@ Homepage: https://xcat.org/
|
||||
|
||||
Package: xcat
|
||||
Architecture: amd64 ppc64el
|
||||
Depends: ${perl:Depends}, goconserver(>= 0.3.3-snap000000000000), xcat-server (>= 2.13-snap000000000000), xcat-client (>= 2.13-snap000000000000), libdbd-sqlite3-perl, isc-dhcp-server | kea, bind9, apache2, nfs-kernel-server, libxml-parser-perl, rsync, tftpd-hpa, libnet-telnet-perl, xcat-genesis-scripts-amd64 (>= 2.13-snap000000000000)
|
||||
Recommends: net-tools, nmap, kea, tftp-hpa, ipmitool-xcat (>= 1.8.17-1), syslinux[any-amd64], libsys-virt-perl, syslinux-xcat, xnba-undi, elilo-xcat, xcat-buildkit (>= 2.13-snap000000000000), xcat-probe (>= 2.13-snap000000000000), xcat-genesis-openembedded-x86-64, xcat-genesis-openembedded-ppc64le, xcat-genesis-openembedded-riscv64
|
||||
Depends: ${perl:Depends}, goconserver(>= 0.3.3-snap000000000000), xcat-server (>= 2.13-snap000000000000), xcat-client (>= 2.13-snap000000000000), libdbd-sqlite3-perl, isc-dhcp-server | kea, bind9, apache2, nfs-kernel-server, libxml-parser-perl, rsync, tftpd-hpa, libnet-telnet-perl, chrony | ntp, xcat-genesis-scripts-amd64 (>= 2.13-snap000000000000)
|
||||
Recommends: net-tools, nmap, kea, tftp-hpa, ipmitool-xcat (>= 1.8.17-1), syslinux[any-amd64], libsys-virt-perl, syslinux-xcat, xnba-undi, elilo-xcat, util-linux-extra, xcat-buildkit (>= 2.13-snap000000000000), xcat-probe (>= 2.13-snap000000000000), xcat-genesis-openembedded-x86-64, xcat-genesis-openembedded-ppc64le, xcat-genesis-openembedded-riscv64
|
||||
Suggests: yaboot-xcat
|
||||
Description: Metapackage for a common, default xCAT setup
|
||||
xCAT is Extreme Cluster/Cloud Administration Toolkit. xCAT offers complete
|
||||
|
||||
@@ -146,7 +146,10 @@ unset MASTER
|
||||
unset NTPSERVERS
|
||||
|
||||
check_exec_or_exit cp cat logger grep
|
||||
check_exec_or_exit systemctl timedatectl hwclock
|
||||
# hwclock is NOT required: it only persists the (already chronyd-stepped) system clock to the RTC
|
||||
# below, and it is optional -- on Ubuntu 24.04+ it moved to util-linux-extra, which is absent on
|
||||
# minimal cloud images. Requiring it here aborted the whole NTP setup (and the clock step) on noble.
|
||||
check_exec_or_exit systemctl timedatectl
|
||||
|
||||
systemctl stop ntp.service 2>/dev/null
|
||||
systemctl disable ntp.service 2>/dev/null
|
||||
@@ -156,6 +159,13 @@ systemctl disable ntpd.service 2>/dev/null
|
||||
systemctl disable ntp-wait.service 2>/dev/null
|
||||
systemctl disable ntpdate.service 2>/dev/null
|
||||
|
||||
# systemd-timesyncd is an SNTP client that also disciplines the system clock. It is part of systemd
|
||||
# (not a "time-daemon" package), so it coexists with chrony/ntpd at the package level but must be
|
||||
# stopped or it fights the NTP daemon we are configuring. This is the default time-sync stack on
|
||||
# Ubuntu, where it must yield to chrony (timesyncd cannot serve time to compute nodes).
|
||||
systemctl stop systemd-timesyncd.service 2>/dev/null
|
||||
systemctl disable systemd-timesyncd.service 2>/dev/null
|
||||
|
||||
# On Ubuntu 18.04
|
||||
systemctl stop chrony.service 2>/dev/null
|
||||
# On RHEL 7, 8
|
||||
@@ -177,10 +187,14 @@ chronyd -f /dev/null -q "$(
|
||||
fi
|
||||
)"
|
||||
|
||||
rm -f /etc/adjtime
|
||||
# Set the hardware clock from the system clock
|
||||
hwclock --systohc --utc
|
||||
warn_if_bad "$?" "Failed to set the hardware clock"
|
||||
# Set the hardware clock from the system clock, when hwclock is available (optional; see above).
|
||||
if command -v hwclock >/dev/null 2>&1; then
|
||||
rm -f /etc/adjtime
|
||||
hwclock --systohc --utc
|
||||
warn_if_bad "$?" "Failed to set the hardware clock"
|
||||
else
|
||||
logger -t $log_label -p local4.info "setupntp: hwclock not present; skipping RTC persist (system clock already set via chronyd)"
|
||||
fi
|
||||
|
||||
## On RHEL 8
|
||||
#CHRONY_USER="chrony"
|
||||
|
||||
@@ -73,6 +73,9 @@ Requires: httpd nfs-utils nmap bind perl(CGI)
|
||||
# on RHEL7, need to specify it explicitly
|
||||
Requires: net-tools
|
||||
Requires: /usr/bin/killall
|
||||
# makentp/setupntp configure the MN as an NTP server for its compute nodes and support chronyd/ntpd
|
||||
# only. chrony is the default on EL7+/SLES15+ (and the only option on EL8+); ntp covers the rest.
|
||||
Requires: (chrony or ntp)
|
||||
# DHCP backend resolved at INSTALL time (not build time) via an RPM rich
|
||||
# dependency, so a single flat xcat-core build is correct on every EL: el10+
|
||||
# dropped ISC dhcp from its distro and uses Kea; el8/el9 use ISC dhcpd. SLES
|
||||
|
||||
Reference in New Issue
Block a user