diff --git a/perl-xCAT/debian/postrm b/perl-xCAT/debian/postrm index e9d178f89..6b983d64c 100644 --- a/perl-xCAT/debian/postrm +++ b/perl-xCAT/debian/postrm @@ -21,9 +21,9 @@ set -e case "$1" in upgrade) - if [ -x /etc/init.d/xcatd ] && [ -f "/proc/cmdline" ]; then + if [ -x /opt/xcat/sbin/restartxcatd ] && [ -f "/proc/cmdline" ]; then . /etc/profile.d/xcat.sh - /etc/init.d/xcatd reload + XCATROOT=/opt/xcat /opt/xcat/sbin/restartxcatd -r fi ;; purge|remove|failed-upgrade|abort-install|abort-upgrade|disappear) diff --git a/perl-xCAT/perl-xCAT.spec b/perl-xCAT/perl-xCAT.spec index 59aa744c2..aad2d042e 100644 --- a/perl-xCAT/perl-xCAT.spec +++ b/perl-xCAT/perl-xCAT.spec @@ -136,8 +136,8 @@ fi %post %ifos linux -if [ "$1" -gt 1 ]; then #Ugrade only, restart daemon and migrate settings - if [ -x /etc/init.d/xcatd ] && [ -f "/proc/cmdline" ]; then +if [ "$1" -gt 1 ]; then #Upgrade only; load the xCAT environment when the server is installed. + if [ -x $RPM_INSTALL_PREFIX0/sbin/xcatd ] && [ -f "/proc/cmdline" ]; then . /etc/profile.d/xcat.sh fi fi diff --git a/xCAT-OpenStack/debian/postinst b/xCAT-OpenStack/debian/postinst index 3e90d7ca7..8f9d4056e 100644 --- a/xCAT-OpenStack/debian/postinst +++ b/xCAT-OpenStack/debian/postinst @@ -21,8 +21,8 @@ set -e case "$1" in configure) if [ -f "/proc/cmdline" ];then - if [ -f "/opt/xcat/sbin/xcatd" ];then - /etc/init.d/xcatd reload + if [ -x /opt/xcat/sbin/restartxcatd ];then + XCATROOT=/opt/xcat /opt/xcat/sbin/restartxcatd -r fi fi ;; diff --git a/xCAT-OpenStack/xCAT-OpenStack.spec b/xCAT-OpenStack/xCAT-OpenStack.spec index a502b20d5..398bfdd09 100644 --- a/xCAT-OpenStack/xCAT-OpenStack.spec +++ b/xCAT-OpenStack/xCAT-OpenStack.spec @@ -87,8 +87,8 @@ rm -rf $RPM_BUILD_ROOT %post %ifos linux if [ -f "/proc/cmdline" ]; then # prevent running it during install into chroot image - if [ -f $RPM_INSTALL_PREFIX0/sbin/xcatd ]; then - /etc/init.d/xcatd restart + if [ -x $RPM_INSTALL_PREFIX0/sbin/restartxcatd ]; then + XCATROOT=$RPM_INSTALL_PREFIX0 $RPM_INSTALL_PREFIX0/sbin/restartxcatd fi fi %endif diff --git a/xCAT-UI/xCAT-UI.spec b/xCAT-UI/xCAT-UI.spec index a39fb564c..4a3e980c9 100644 --- a/xCAT-UI/xCAT-UI.spec +++ b/xCAT-UI/xCAT-UI.spec @@ -184,7 +184,9 @@ ln -sf ../bin/xcatclientnnr $RPM_BUILD_ROOT%{prefix}/bin/webportal if [ "$1" = 1 ] || [ "$1" = 2 ] # Install or upgrade then # Restart xCAT - /etc/init.d/xcatd restart + if [ -x $RPM_INSTALL_PREFIX0/sbin/restartxcatd ]; then + XCATROOT=$RPM_INSTALL_PREFIX0 $RPM_INSTALL_PREFIX0/sbin/restartxcatd + fi # Copy php.ini file into /opt/xcat/ui and turn off output_buffering if [ -e "/etc/redhat-release" ]; then diff --git a/xCAT-rmc/debian/postinst b/xCAT-rmc/debian/postinst index 01078ef32..3d40f8920 100644 --- a/xCAT-rmc/debian/postinst +++ b/xCAT-rmc/debian/postinst @@ -58,8 +58,8 @@ case "$1" in if [[ `uname -s` = "Linux" ]] ; then if [ -f "/proc/cmdline" ]; then # prevent running it during install into chroot image - if [ -f /opt/xcat/sbin/xcatd ]; then - /etc/init.d/xcatd reload + if [ -x /opt/xcat/sbin/restartxcatd ]; then + XCATROOT=/opt/xcat /opt/xcat/sbin/restartxcatd -r fi fi else diff --git a/xCAT-server/debian/dirs b/xCAT-server/debian/dirs index 2171d2d80..2bb20f45b 100644 --- a/xCAT-server/debian/dirs +++ b/xCAT-server/debian/dirs @@ -34,7 +34,6 @@ opt/xcat/lib/perl/xCAT_monitoring/pcp opt/xcat/xdsh opt/xcat/xdsh/Context opt/xcat/ws -etc/init.d lib/systemd/system etc/xcat etc/apache2/conf-enabled diff --git a/xCAT-server/debian/install b/xCAT-server/debian/install index 320403a55..6858f3764 100644 --- a/xCAT-server/debian/install +++ b/xCAT-server/debian/install @@ -28,7 +28,7 @@ lib/xcat/dsh/Context/* opt/xcat/xdsh/Context lib/xcat/Confluent/* opt/xcat/lib/perl/Confluent/ lib/xcat/shfunctions opt/xcat/lib -etc/init.d/xcatd etc/init.d +etc/init.d/xcatd opt/xcat/share/xcat/scripts etc/init.d/xcatd.service lib/systemd/system/ xCAT-wsapi/* opt/xcat/ws/ diff --git a/xCAT-server/debian/postinst b/xCAT-server/debian/postinst index 9adc9ce84..f303134c8 100644 --- a/xCAT-server/debian/postinst +++ b/xCAT-server/debian/postinst @@ -10,6 +10,14 @@ xcat_can_use_systemctl() [ -d /run/systemd/system ] && command -v systemctl >/dev/null 2>&1 } +xcatd_init_compat=/opt/xcat/share/xcat/scripts/xcatd-init-compat + +if "$xcatd_init_compat" uses-systemd && \ + command -v dpkg-maintscript-helper >/dev/null 2>&1 && \ + dpkg-maintscript-helper supports rm_conffile; then + dpkg-maintscript-helper rm_conffile /etc/init.d/xcatd -- "$@" +fi + # summary of how this script can be called: # * `configure' # * `abort-upgrade' @@ -26,28 +34,42 @@ xcat_can_use_systemctl() case "$1" in configure) . /etc/profile.d/xcat.sh + xcat_server_upgrade=0 if [ -f /tmp/xCAT-server_upgrade.tmp ]; then - if xcat_can_use_systemctl; then - if [ -f /run/systemd/generator.late/xcatd.service ]; then - # To cover the case upgrade from no xcatd systemd unit file (cannot enable by default for HA case) - if ls /etc/rc?.d/S??xcatd >/dev/null 2>&1; then - [ -x /usr/sbin/update-rc.d ] && /usr/sbin/update-rc.d xcatd remove - systemctl daemon-reload - systemctl enable xcatd.service - fi - else + xcat_server_upgrade=1 + fi + + if "$xcatd_init_compat" uses-systemd; then + legacy_xcatd_enabled=0 + if ls /etc/rc?.d/S??xcatd >/dev/null 2>&1; then + legacy_xcatd_enabled=1 + fi + if [ "$xcat_server_upgrade" = "1" ] && command -v update-rc.d >/dev/null 2>&1; then + update-rc.d -f xcatd remove + fi + + "$xcatd_init_compat" configure + if xcat_can_use_systemctl; then systemctl daemon-reload fi - fi - # No need to reload xcatd here as it will be covered by xCAT/xCATsn now - rm /tmp/xCAT-server_upgrade.tmp + if command -v systemctl >/dev/null 2>&1 && \ + { [ "$xcat_server_upgrade" = "0" ] || [ "$legacy_xcatd_enabled" = "1" ]; }; then + # Fresh installs are enabled by default. Upgrades preserve the + # legacy enabled state so HA nodes remain disabled. + systemctl enable xcatd.service + fi else - if xcat_can_use_systemctl; then - systemctl daemon-reload - systemctl enable xcatd.service - elif command -v update-rc.d >/dev/null 2>&1; then - update-rc.d xcatd defaults - fi + "$xcatd_init_compat" configure + if [ "$xcat_server_upgrade" = "0" ] && \ + [ -x /etc/init.d/xcatd ] && \ + command -v update-rc.d >/dev/null 2>&1; then + update-rc.d xcatd defaults + fi + fi + + if [ "$xcat_server_upgrade" = "1" ]; then + # No need to reload xcatd here as it will be covered by xCAT/xCATsn now. + rm -f /tmp/xCAT-server_upgrade.tmp fi ln -sf /opt/xcat/sbin/xcatd /usr/sbin/xcatd ;; diff --git a/xCAT-server/debian/postrm b/xCAT-server/debian/postrm index bdbefba81..955ded4d0 100644 --- a/xCAT-server/debian/postrm +++ b/xCAT-server/debian/postrm @@ -5,6 +5,60 @@ set -e +xcat_target_uses_systemd() +{ + if [ -d /run/systemd/system ]; then + return 0 + fi + + if [ -x /usr/lib/systemd/systemd ] || [ -x /lib/systemd/systemd ]; then + return 0 + fi + + if [ -L /sbin/init ]; then + init_target=$(readlink /sbin/init 2>/dev/null || true) + case "$init_target" in + *systemd*) return 0 ;; + esac + fi + + if [ -r /etc/os-release ]; then + os_id= + os_version= + while IFS='=' read -r key value; do + value=${value#\"} + value=${value%\"} + value=${value#\'} + value=${value%\'} + case "$key" in + ID) os_id=$value ;; + VERSION_ID) os_version=$value ;; + esac + done < /etc/os-release + + if [ "$os_id" = "debian" ] && [ -z "$os_version" ]; then + return 0 + fi + + os_major=${os_version%%.*} + case "$os_major" in + ''|*[!0-9]*) return 1 ;; + esac + case "$os_id" in + ubuntu) [ "$os_major" -ge 15 ] && return 0 ;; + debian) [ "$os_major" -ge 8 ] && return 0 ;; + esac + fi + + return 1 +} + +if xcat_target_uses_systemd && \ + command -v dpkg-maintscript-helper >/dev/null 2>&1 && \ + dpkg-maintscript-helper supports rm_conffile; then + dpkg-maintscript-helper rm_conffile /etc/init.d/xcatd -- "$@" +fi + # summary of how this script can be called: # * `remove' # * `purge' @@ -20,7 +74,11 @@ set -e case "$1" in - purge|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) + purge) + rm -f /etc/init.d/xcatd + ;; + + upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) ;; remove) diff --git a/xCAT-server/debian/preinst b/xCAT-server/debian/preinst index 139732e80..1aabad540 100644 --- a/xCAT-server/debian/preinst +++ b/xCAT-server/debian/preinst @@ -5,6 +5,60 @@ set -e +xcat_target_uses_systemd() +{ + if [ -d /run/systemd/system ]; then + return 0 + fi + + if [ -x /usr/lib/systemd/systemd ] || [ -x /lib/systemd/systemd ]; then + return 0 + fi + + if [ -L /sbin/init ]; then + init_target=$(readlink /sbin/init 2>/dev/null || true) + case "$init_target" in + *systemd*) return 0 ;; + esac + fi + + if [ -r /etc/os-release ]; then + os_id= + os_version= + while IFS='=' read -r key value; do + value=${value#\"} + value=${value%\"} + value=${value#\'} + value=${value%\'} + case "$key" in + ID) os_id=$value ;; + VERSION_ID) os_version=$value ;; + esac + done < /etc/os-release + + if [ "$os_id" = "debian" ] && [ -z "$os_version" ]; then + return 0 + fi + + os_major=${os_version%%.*} + case "$os_major" in + ''|*[!0-9]*) return 1 ;; + esac + case "$os_id" in + ubuntu) [ "$os_major" -ge 15 ] && return 0 ;; + debian) [ "$os_major" -ge 8 ] && return 0 ;; + esac + fi + + return 1 +} + +if xcat_target_uses_systemd && \ + command -v dpkg-maintscript-helper >/dev/null 2>&1 && \ + dpkg-maintscript-helper supports rm_conffile; then + dpkg-maintscript-helper rm_conffile /etc/init.d/xcatd -- "$@" +fi + # summary of how this script can be called: # * `install' # * `install' diff --git a/xCAT-server/debian/prerm b/xCAT-server/debian/prerm index 9a3c1d4dd..818be25a4 100644 --- a/xCAT-server/debian/prerm +++ b/xCAT-server/debian/prerm @@ -10,6 +10,8 @@ xcat_can_use_systemctl() [ -d /run/systemd/system ] && command -v systemctl >/dev/null 2>&1 } +xcatd_init_compat=/opt/xcat/share/xcat/scripts/xcatd-init-compat + # summary of how this script can be called: # * `remove' # * `upgrade' @@ -27,14 +29,18 @@ case "$1" in if [ -f "/proc/cmdline" ]; then # prevent running it during install into chroot image if xcat_can_use_systemctl; then systemctl stop xcatd.service - elif [ -x /etc/init.d/xcatd ]; then + elif ! "$xcatd_init_compat" uses-systemd && [ -x /etc/init.d/xcatd ]; then /etc/init.d/xcatd stop fi fi - if xcat_can_use_systemctl; then - systemctl disable xcatd.service - elif command -v update-rc.d >/dev/null 2>&1; then - update-rc.d -f xcatd remove + if "$xcatd_init_compat" uses-systemd; then + if command -v systemctl >/dev/null 2>&1; then + systemctl disable xcatd.service + fi + else + if command -v update-rc.d >/dev/null 2>&1; then + update-rc.d -f xcatd remove + fi fi ;; upgrade|deconfigure) diff --git a/xCAT-server/lib/xcat/plugins/imgport.pm b/xCAT-server/lib/xcat/plugins/imgport.pm index 620d7cf49..cf8b9cdd8 100644 --- a/xCAT-server/lib/xcat/plugins/imgport.pm +++ b/xCAT-server/lib/xcat/plugins/imgport.pm @@ -1990,8 +1990,8 @@ sub make_files { } if ($hasplugin) { - # Issue xcatd reload to load the new plugins - system("/etc/init.d/xcatd restart"); + # Fast restart xcatd to load the new plugins without dropping this request + system("$::XCATROOT/sbin/restartxcatd"); $hasplugin = 0; } @@ -2230,4 +2230,3 @@ sub moveExtra { } return 1; } - diff --git a/xCAT-server/share/xcat/scripts/xcatd-init-compat b/xCAT-server/share/xcat/scripts/xcatd-init-compat new file mode 100755 index 000000000..01e0dbf2c --- /dev/null +++ b/xCAT-server/share/xcat/scripts/xcatd-init-compat @@ -0,0 +1,148 @@ +#!/bin/sh +# Keep the xcatd SysV init script only on systems that actually use a +# legacy init implementation. XCAT_COMPAT_ROOT is used by image builders +# and tests to operate on a target root without chrooting into it. + +compat_root=${XCAT_COMPAT_ROOT:-} +compat_root=${compat_root%/} +xcat_root=${XCATROOT:-/opt/xcat} + +case "$xcat_root" in + /*) ;; + *) + echo "XCATROOT must be an absolute path" >&2 + exit 2 + ;; +esac + +legacy_init="$compat_root/etc/init.d/xcatd" +legacy_template="$compat_root$xcat_root/share/xcat/scripts/xcatd" + +uses_systemd_os_release() +{ + os_release="$compat_root/etc/os-release" + [ -r "$os_release" ] || return 1 + + os_id= + os_version= + while IFS='=' read -r key value; do + value=${value#\"} + value=${value%\"} + value=${value#\'} + value=${value%\'} + case "$key" in + ID) os_id=$value ;; + VERSION_ID) os_version=$value ;; + esac + done < "$os_release" + + # Debian testing/sid intentionally omits VERSION_ID. + if [ "$os_id" = "debian" ] && [ -z "$os_version" ]; then + return 0 + fi + + os_major=${os_version%%.*} + case "$os_major" in + ''|*[!0-9]*) return 1 ;; + esac + + case "$os_id" in + rhel|centos|rocky|almalinux|ol|scientific) + [ "$os_major" -ge 7 ] + ;; + fedora|ubuntu) + [ "$os_major" -ge 15 ] + ;; + debian) + [ "$os_major" -ge 8 ] + ;; + sles|sled|opensuse|opensuse-leap|opensuse-tumbleweed) + [ "$os_major" -ge 12 ] + ;; + *) + return 1 + ;; + esac +} + +uses_systemd() +{ + if [ -d "$compat_root/run/systemd/system" ]; then + return 0 + fi + + # Chroots and minimal images may have systemd installed without a running + # manager or an /sbin/init link. + if [ -x "$compat_root/usr/lib/systemd/systemd" ] || + [ -x "$compat_root/lib/systemd/systemd" ]; then + return 0 + fi + + if uses_systemd_os_release; then + return 0 + fi + + if [ -L "$compat_root/sbin/init" ]; then + init_target=$(readlink "$compat_root/sbin/init" 2>/dev/null || true) + case "$init_target" in + *systemd*) return 0 ;; + esac + fi + + return 1 +} + +configure_legacy_init() +{ + replace_existing=${1:-} + + if uses_systemd; then + rm -f "$legacy_init" + return + fi + + # A broken link cannot provide a usable init script. Replace it while + # preserving links whose administrator-managed target still exists. + if [ -L "$legacy_init" ] && [ ! -e "$legacy_init" ]; then + rm -f "$legacy_init" + fi + + if [ -e "$legacy_init" ] || [ -L "$legacy_init" ]; then + if [ "$replace_existing" != "--replace" ]; then + return + fi + rm -f "$legacy_init" + fi + + if [ ! -r "$legacy_template" ]; then + echo "Legacy xcatd init template not found: $legacy_template" >&2 + exit 1 + fi + + mkdir -p "$compat_root/etc/init.d" + cp "$legacy_template" "$legacy_init" + chmod 755 "$legacy_init" +} + +case "${1:-}" in + uses-systemd) + uses_systemd + ;; + configure) + case "${2:-}" in + ''|--replace) ;; + *) + echo "Usage: $0 {uses-systemd|configure [--replace]|remove}" >&2 + exit 2 + ;; + esac + configure_legacy_init "${2:-}" + ;; + remove) + rm -f "$legacy_init" + ;; + *) + echo "Usage: $0 {uses-systemd|configure [--replace]|remove}" >&2 + exit 2 + ;; +esac diff --git a/xCAT-server/xCAT-server.spec b/xCAT-server/xCAT-server.spec index bc1d82438..bdeeacfdc 100644 --- a/xCAT-server/xCAT-server.spec +++ b/xCAT-server/xCAT-server.spec @@ -361,10 +361,26 @@ cp lib/xcat/shfunctions $RPM_BUILD_ROOT/%{prefix}/lib chmod 644 $RPM_BUILD_ROOT/%{prefix}/lib/shfunctions %if %fsm %else +%ifos linux +cp etc/init.d/xcatd $RPM_BUILD_ROOT/%{prefix}/share/xcat/scripts/xcatd +chmod 755 $RPM_BUILD_ROOT/%{prefix}/share/xcat/scripts/xcatd +# Keep ownership continuity only on legacy RPM targets where the script is +# materialized at runtime. Modern RPM versions can create /etc/init.d from a +# ghost entry alone, which breaks later chkconfig/initscripts transactions. +%if 0%{?rhel} && 0%{?rhel} < 7 mkdir -p $RPM_BUILD_ROOT/etc/init.d -cp etc/init.d/xcatd $RPM_BUILD_ROOT/etc/init.d +touch $RPM_BUILD_ROOT/etc/init.d/xcatd +%endif +%if 0%{?suse_version} && 0%{?suse_version} < 1200 +mkdir -p $RPM_BUILD_ROOT/etc/init.d +touch $RPM_BUILD_ROOT/etc/init.d/xcatd +%endif mkdir -p $RPM_BUILD_ROOT/usr/lib/systemd/system cp etc/init.d/xcatd.service $RPM_BUILD_ROOT/usr/lib/systemd/system +%else +mkdir -p $RPM_BUILD_ROOT/etc/init.d +cp etc/init.d/xcatd $RPM_BUILD_ROOT/etc/init.d +%endif %endif #TODO: the next has to me moved to postscript, to detect /etc/xcat vs /etc/opt/xcat mkdir -p $RPM_BUILD_ROOT/etc/%httpconfigdir @@ -431,8 +447,17 @@ rm -rf $RPM_BUILD_ROOT /etc/%httpconfigdir %if %fsm %else -/etc/init.d/xcatd +%ifos linux +%if 0%{?rhel} && 0%{?rhel} < 7 +%ghost %attr(0755,root,root) /etc/init.d/xcatd +%endif +%if 0%{?suse_version} && 0%{?suse_version} < 1200 +%ghost %attr(0755,root,root) /etc/init.d/xcatd +%endif /usr/lib/systemd/system/xcatd.service +%else +/etc/init.d/xcatd +%endif /etc/apache2/conf.d/xcat-ws.conf /etc/httpd/conf.d/xcat-ws.conf %endif @@ -494,31 +519,73 @@ xcat_can_use_systemctl() [ -d /run/systemd/system ] && command -v systemctl >/dev/null 2>&1 } +xcatd_init_compat=$RPM_INSTALL_PREFIX0/share/xcat/scripts/xcatd-init-compat +export XCATROOT="$RPM_INSTALL_PREFIX0" + if [ "$1" = "1" ]; then #Only if installing for the first time.. - if xcat_can_use_systemctl; then - systemctl daemon-reload - systemctl enable xcatd.service - elif [ -x /sbin/chkconfig ]; then - /sbin/chkconfig --add xcatd - elif [ -x /usr/lib/lsb/install_initd ]; then - /usr/lib/lsb/install_initd /etc/init.d/xcatd + if "$xcatd_init_compat" uses-systemd; then + "$xcatd_init_compat" configure || exit 1 + if xcat_can_use_systemctl; then + systemctl daemon-reload + fi + if command -v systemctl >/dev/null 2>&1; then + systemctl enable xcatd.service + fi else - echo "Unable to register init scripts on this system" + "$xcatd_init_compat" configure || exit 1 + if [ -x /sbin/chkconfig ]; then + /sbin/chkconfig --add xcatd + elif [ -x /usr/lib/lsb/install_initd ]; then + /usr/lib/lsb/install_initd /etc/init.d/xcatd + else + echo "Unable to register init scripts on this system" + fi fi fi if [ "$1" -gt "1" ]; then #only on upgrade... - if xcat_can_use_systemctl; then - if [ -f /run/systemd/generator.late/xcatd.service ]; then - # To cover the case upgrade from no xcatd systemd unit file (cannot enable by default for HA case) - if ls /etc/rc.d/rc?.d/S??xcatd >/dev/null 2>&1; then - [ -x /sbin/chkconfig ] && /sbin/chkconfig --del xcatd - systemctl daemon-reload - systemctl enable xcatd.service + if "$xcatd_init_compat" uses-systemd; then + legacy_xcatd_enabled=0 + for legacy_xcatd_link in \ + /etc/rc.d/rc?.d/S??xcatd \ + /etc/rc?.d/S??xcatd \ + /etc/init.d/rc?.d/S??xcatd + do + if [ -e "$legacy_xcatd_link" ] || [ -L "$legacy_xcatd_link" ]; then + legacy_xcatd_enabled=1 + break fi - else + done + if [ -e /etc/init.d/xcatd ] || [ -L /etc/init.d/xcatd ]; then + if [ -x /sbin/chkconfig ]; then + /sbin/chkconfig --del xcatd + elif [ -x /usr/lib/lsb/remove_initd ]; then + /usr/lib/lsb/remove_initd /etc/init.d/xcatd + fi + fi + rm -f \ + /etc/rc.d/rc?.d/[SK]??xcatd \ + /etc/rc?.d/[SK]??xcatd \ + /etc/init.d/rc?.d/[SK]??xcatd + + "$xcatd_init_compat" configure || exit 1 +%if 0%{?suse_version} +%else + # Remove only an empty directory left by an older xCAT RPM. SUSE base + # packages own /etc/init.d, so leave that directory intact there. + rmdir /etc/init.d 2>/dev/null || true +%endif + if xcat_can_use_systemctl; then systemctl daemon-reload fi + if [ "$legacy_xcatd_enabled" = "1" ] && command -v systemctl >/dev/null 2>&1; then + # Preserve the previous enabled state without enabling HA nodes by default. + systemctl enable xcatd.service + fi + else + # This path was previously a regular RPM payload file, so upgrades replaced + # it with the current package version rather than retaining an older copy. + "$xcatd_init_compat" configure --replace || exit 1 fi #migration issue for monitoring XCATROOT=$RPM_INSTALL_PREFIX0 $RPM_INSTALL_PREFIX0/sbin/chtab filename=monitorctrl.pm notification -d @@ -560,22 +627,30 @@ xcat_can_use_systemctl() [ -d /run/systemd/system ] && command -v systemctl >/dev/null 2>&1 } +xcatd_init_compat=$RPM_INSTALL_PREFIX0/share/xcat/scripts/xcatd-init-compat +export XCATROOT="$RPM_INSTALL_PREFIX0" + if [ $1 == 0 ]; then #This means only on -e if [ -f "/proc/cmdline" ]; then # prevent running it during install into chroot image if xcat_can_use_systemctl; then systemctl stop xcatd.service - elif [ -x /etc/init.d/xcatd ]; then + elif ! "$xcatd_init_compat" uses-systemd && [ -x /etc/init.d/xcatd ]; then /etc/init.d/xcatd stop fi fi - if xcat_can_use_systemctl; then - systemctl disable xcatd.service - elif [ -x /sbin/chkconfig ]; then - /sbin/chkconfig --del xcatd - elif [ -x /usr/lib/lsb/remove_initd ]; then - /usr/lib/lsb/remove_initd /etc/init.d/xcatd + if "$xcatd_init_compat" uses-systemd; then + if command -v systemctl >/dev/null 2>&1; then + systemctl disable xcatd.service + fi + else + if [ -x /sbin/chkconfig ]; then + /sbin/chkconfig --del xcatd + elif [ -x /usr/lib/lsb/remove_initd ]; then + /usr/lib/lsb/remove_initd /etc/init.d/xcatd + fi fi + "$xcatd_init_compat" remove rm -f /usr/sbin/xcatd #remove the symbolic fi diff --git a/xCAT-test/autotest/testcase/xcatd/case0 b/xCAT-test/autotest/testcase/xcatd/case0 index d3788cfe2..e9f92e648 100644 --- a/xCAT-test/autotest/testcase/xcatd/case0 +++ b/xCAT-test/autotest/testcase/xcatd/case0 @@ -1,3 +1,11 @@ +start:xcatd_systemd_has_no_legacy_init_script +description:systemd installations do not retain the legacy xcatd init script +label:mn_only,ci_test,xcatd +cmd:test -d /run/systemd/system && test ! -f /etc/init.d/xcatd +check:rc==0 +end + + start:xcatd_start description:stop then start xcatd daemon, and check all the 6 processes are running label:mn_only,ci_test,xcatd diff --git a/xCAT-test/unit/xcatd_debian_service_packaging.t b/xCAT-test/unit/xcatd_debian_service_packaging.t new file mode 100644 index 000000000..e2e209918 --- /dev/null +++ b/xCAT-test/unit/xcatd_debian_service_packaging.t @@ -0,0 +1,75 @@ +#!/usr/bin/env perl +use strict; +use warnings; + +use File::Spec; +use FindBin; +use Test::More; + +my $repo_root = File::Spec->catdir( $FindBin::Bin, '..', '..' ); + +sub read_file { + my ($path) = @_; + open( my $fh, '<', $path ) or die "Unable to read $path: $!"; + my $contents = do { local $/; <$fh> }; + close($fh); + return $contents; +} + +my $deb_install = read_file( + File::Spec->catfile( $repo_root, 'xCAT-server', 'debian', 'install' ) +); +like( $deb_install, qr{^etc/init\.d/xcatd opt/xcat/share/xcat/scripts$}m, + 'Debian stages the legacy script as a compatibility template' ); +unlike( $deb_install, qr{^etc/init\.d/xcatd etc/init\.d$}m, + 'Debian does not install the legacy script directly' ); + +my $deb_dirs = read_file( + File::Spec->catfile( $repo_root, 'xCAT-server', 'debian', 'dirs' ) +); +unlike( $deb_dirs, qr{^etc/init\.d/?$}m, + 'Debian does not package an empty legacy init directory' ); + +foreach my $maintainer_script (qw(preinst postinst postrm)) { + my $script = read_file( + File::Spec->catfile( + $repo_root, 'xCAT-server', 'debian', $maintainer_script + ) + ); + like( $script, + qr{dpkg-maintscript-helper rm_conffile /etc/init\.d/xcatd -- "\$\@"}, + "Debian $maintainer_script participates in graceful conffile removal" ); +} + +my $deb_postinst = read_file( + File::Spec->catfile( $repo_root, 'xCAT-server', 'debian', 'postinst' ) +); +like( $deb_postinst, + qr{if "\$xcatd_init_compat" uses-systemd; then}, + 'Debian postinst delegates target init detection to the packaged helper' ); +unlike( $deb_postinst, qr{sub xcat_target_uses_systemd|xcat_target_uses_systemd\(\)}, + 'Debian postinst does not carry weaker duplicate init detection' ); +like( $deb_postinst, + qr{\[ -x /etc/init\.d/xcatd \].*?update-rc\.d xcatd defaults}s, + 'Debian postinst registers SysV only after materializing an executable script' ); + +foreach my $fallback_script (qw(preinst postrm)) { + my $script = read_file( + File::Spec->catfile( $repo_root, 'xCAT-server', 'debian', $fallback_script ) + ); + like( $script, qr{VERSION_ID.*?ubuntu.*?-ge 15.*?debian.*?-ge 8}s, + "Debian $fallback_script recognizes stripped modern targets" ); + like( $script, qr{\[ "\$os_id" = "debian" \].*?\[ -z "\$os_version" \]}s, + "Debian $fallback_script recognizes testing and sid without VERSION_ID" ); + like( $script, qr{value=\$\{value#\\'\}\s+value=\$\{value%\\'\}}s, + "Debian $fallback_script strips single-quoted os-release values" ); +} + +my $deb_prerm = read_file( + File::Spec->catfile( $repo_root, 'xCAT-server', 'debian', 'prerm' ) +); +like( $deb_prerm, + qr{if "\$xcatd_init_compat" uses-systemd; then.*?update-rc\.d -f xcatd remove}s, + 'Debian prerm removes registration through the detected init implementation' ); + +done_testing(); diff --git a/xCAT-test/unit/xcatd_restart_callers.t b/xCAT-test/unit/xcatd_restart_callers.t new file mode 100644 index 000000000..2cfdf73f5 --- /dev/null +++ b/xCAT-test/unit/xcatd_restart_callers.t @@ -0,0 +1,90 @@ +#!/usr/bin/env perl +use strict; +use warnings; + +use File::Spec; +use FindBin; +use Test::More; + +my $repo_root = File::Spec->catdir( $FindBin::Bin, '..', '..' ); + +sub read_file { + my ($path) = @_; + open( my $fh, '<', $path ) or die "Unable to read $path: $!"; + my $contents = do { local $/; <$fh> }; + close($fh); + return $contents; +} + +my $unit = read_file( + File::Spec->catfile( $repo_root, 'xCAT-server', 'etc', 'init.d', 'xcatd.service' ) +); +unlike( $unit, qr{/etc/init\.d/xcatd}, + 'the native systemd unit does not invoke the legacy script' ); +like( $unit, qr{^ExecStart=.*?/usr/sbin/xcatd}m, + 'the native systemd unit starts xcatd directly' ); + +my $imgport = read_file( + File::Spec->catfile( $repo_root, 'xCAT-server', 'lib', 'xcat', 'plugins', 'imgport.pm' ) +); +like( $imgport, qr{system\("\$::XCATROOT/sbin/restartxcatd"\)}, + 'imgport preserves the xcatd fast-restart path' ); +unlike( $imgport, qr{xCAT::Utils->restartservice\("xcatd"\)}, + 'imgport does not replace a fast restart with a full service restart' ); +unlike( $imgport, qr{system\("/etc/init\.d/xcatd}, + 'imgport no longer hard-codes the legacy init path' ); + +my %reload_callers = ( + 'xCAT-OpenStack Debian scriptlet' => 'xCAT-OpenStack/debian/postinst', + 'xCAT-rmc Debian scriptlet' => 'xCAT-rmc/debian/postinst', + 'perl-xCAT Debian scriptlet' => 'perl-xCAT/debian/postrm', +); + +foreach my $name ( sort keys %reload_callers ) { + my $caller = read_file( + File::Spec->catfile( $repo_root, split( '/', $reload_callers{$name} ) ) + ); + like( $caller, qr{/sbin/restartxcatd -r}, + "$name preserves xcatd fast-reload semantics" ); + unlike( $caller, qr{systemctl restart xcatd|/etc/init\.d/xcatd}, + "$name does not perform a full restart or require the legacy init path" ); +} + +my %restart_callers = ( + 'xCAT-OpenStack RPM scriptlet' => 'xCAT-OpenStack/xCAT-OpenStack.spec', + 'xCAT-UI RPM scriptlet' => 'xCAT-UI/xCAT-UI.spec', +); + +foreach my $name ( sort keys %restart_callers ) { + my $caller = read_file( + File::Spec->catfile( $repo_root, split( '/', $restart_callers{$name} ) ) + ); + like( $caller, qr{/sbin/restartxcatd}, + "$name preserves xcatd fast-restart semantics" ); + unlike( $caller, qr{systemctl restart xcatd|/etc/init\.d/xcatd}, + "$name does not perform a full restart or require the legacy init path" ); +} + +my $xcatsn_deb = read_file( + File::Spec->catfile( $repo_root, 'xCATsn', 'debian', 'postinst' ) +); +like( $xcatsn_deb, + qr{systemctl start xcatd\.service.*?elif \[ -x /etc/init\.d/xcatd \]}s, + 'xCATsn Debian starts xcatd under the native service manager' ); + +my $xcatsn_spec = read_file( + File::Spec->catfile( $repo_root, 'xCATsn', 'xCATsn.spec' ) +); +like( $xcatsn_spec, + qr{systemctl restart xcatd\.service.*?elif \[ -x /etc/init\.d/xcatd \]}s, + 'xCATsn RPM retains its existing service-node restart with a legacy fallback' ); + +my $perl_xcat_spec = read_file( + File::Spec->catfile( $repo_root, 'perl-xCAT', 'perl-xCAT.spec' ) +); +unlike( $perl_xcat_spec, qr{/etc/init\.d/xcatd}, + 'perl-xCAT upgrade logic no longer assumes the legacy init path exists' ); +like( $perl_xcat_spec, qr{\$RPM_INSTALL_PREFIX0/sbin/xcatd}, + 'perl-xCAT detects the installed server independently of its init system' ); + +done_testing(); diff --git a/xCAT-test/unit/xcatd_rpm_service_packaging.t b/xCAT-test/unit/xcatd_rpm_service_packaging.t new file mode 100644 index 000000000..0dc3785cc --- /dev/null +++ b/xCAT-test/unit/xcatd_rpm_service_packaging.t @@ -0,0 +1,197 @@ +#!/usr/bin/env perl +use strict; +use warnings; + +use File::Copy qw(copy); +use File::Path qw(make_path); +use File::Spec; +use File::Temp qw(tempdir); +use FindBin; +use Test::More; + +my $repo_root = File::Spec->catdir( $FindBin::Bin, '..', '..' ); +my $helper = File::Spec->catfile( + $repo_root, 'xCAT-server', 'share', 'xcat', 'scripts', 'xcatd-init-compat' +); +my $template = File::Spec->catfile( + $repo_root, 'xCAT-server', 'etc', 'init.d', 'xcatd' +); + +sub read_file { + my ($path) = @_; + open( my $fh, '<', $path ) or die "Unable to read $path: $!"; + my $contents = do { local $/; <$fh> }; + close($fh); + return $contents; +} + +sub stage_root { + my $root = tempdir( CLEANUP => 1 ); + my $scripts = File::Spec->catdir( + $root, 'opt', 'xcat', 'share', 'xcat', 'scripts' + ); + make_path($scripts); + copy( $template, File::Spec->catfile( $scripts, 'xcatd' ) ) + or die "Unable to stage legacy init template: $!"; + return $root; +} + +sub run_helper { + my ( $root, @arguments ) = @_; + local $ENV{XCAT_COMPAT_ROOT} = $root; + local $ENV{XCATROOT} = '/opt/xcat'; + system( '/bin/sh', $helper, @arguments ); + return $? >> 8; +} + +sub legacy_init { + my ($root) = @_; + return File::Spec->catfile( $root, 'etc', 'init.d', 'xcatd' ); +} + +my $active_systemd_root = stage_root(); +make_path( File::Spec->catdir( $active_systemd_root, 'run', 'systemd', 'system' ) ); +make_path( File::Spec->catdir( $active_systemd_root, 'etc', 'init.d' ) ); +open( my $old_init, '>', legacy_init($active_systemd_root) ) + or die "Unable to stage old init script: $!"; +print {$old_init} "old init script\n"; +close($old_init); +is( run_helper( $active_systemd_root, 'uses-systemd' ), 0, + 'an active systemd marker identifies a systemd target' ); +is( run_helper( $active_systemd_root, 'configure' ), 0, + 'systemd configuration succeeds' ); +ok( !-e legacy_init($active_systemd_root), + 'systemd configuration removes an upgraded legacy init script' ); + +my $systemd_image_root = stage_root(); +make_path( File::Spec->catdir( $systemd_image_root, 'sbin' ) ); +symlink( '../lib/systemd/systemd', File::Spec->catfile( $systemd_image_root, 'sbin', 'init' ) ) + or die "Unable to stage systemd init symlink: $!"; +is( run_helper( $systemd_image_root, 'uses-systemd' ), 0, + 'a target-root systemd init symlink identifies a systemd image' ); +is( run_helper( $systemd_image_root, 'configure' ), 0, + 'systemd image configuration succeeds without a running manager' ); +ok( !-e legacy_init($systemd_image_root), + 'systemd images do not receive the legacy init script' ); + +my $minimal_systemd_root = stage_root(); +my $systemd_binary = File::Spec->catfile( + $minimal_systemd_root, 'usr', 'lib', 'systemd', 'systemd' +); +make_path( File::Spec->catdir( $minimal_systemd_root, 'usr', 'lib', 'systemd' ) ); +open( my $minimal_systemd, '>', $systemd_binary ) + or die "Unable to stage minimal systemd binary: $!"; +close($minimal_systemd); +chmod 0755, $systemd_binary; +is( run_helper( $minimal_systemd_root, 'uses-systemd' ), 0, + 'an installed systemd binary identifies a stopped or minimal systemd target' ); +is( run_helper( $minimal_systemd_root, 'configure' ), 0, + 'minimal systemd target configuration succeeds' ); +ok( !-e legacy_init($minimal_systemd_root), + 'minimal systemd targets do not receive the legacy init script' ); + +my $modern_os_root = stage_root(); +make_path( File::Spec->catdir( $modern_os_root, 'etc' ) ); +open( my $modern_os_release, '>', File::Spec->catfile( $modern_os_root, 'etc', 'os-release' ) ) + or die "Unable to stage modern os-release: $!"; +print {$modern_os_release} qq{ID="rocky"\nVERSION_ID="9.6"\n}; +close($modern_os_release); +is( run_helper( $modern_os_root, 'uses-systemd' ), 0, + 'a modern supported distro is systemd even in a stripped-down environment' ); +is( run_helper( $modern_os_root, 'configure' ), 0, + 'stripped-down modern distro configuration succeeds' ); +ok( !-e legacy_init($modern_os_root), + 'stripped-down modern distros do not receive the legacy init script' ); + +my $legacy_os_root = stage_root(); +make_path( File::Spec->catdir( $legacy_os_root, 'etc' ) ); +open( my $legacy_os_release, '>', File::Spec->catfile( $legacy_os_root, 'etc', 'os-release' ) ) + or die "Unable to stage legacy os-release: $!"; +print {$legacy_os_release} qq{ID="sles"\nVERSION_ID="11.4"\n}; +close($legacy_os_release); +isnt( run_helper( $legacy_os_root, 'uses-systemd' ), 0, + 'SLES 11 remains classified as a legacy init target' ); + +my $debian_sid_root = stage_root(); +make_path( File::Spec->catdir( $debian_sid_root, 'etc' ) ); +open( my $debian_sid_release, '>', File::Spec->catfile( $debian_sid_root, 'etc', 'os-release' ) ) + or die "Unable to stage Debian sid os-release: $!"; +print {$debian_sid_release} qq{ID=debian\nVERSION_CODENAME=sid\n}; +close($debian_sid_release); +is( run_helper( $debian_sid_root, 'uses-systemd' ), 0, + 'Debian testing and sid remain systemd targets without VERSION_ID' ); + +my $legacy_root = stage_root(); +make_path( File::Spec->catdir( $legacy_root, 'sbin' ) ); +symlink( 'upstart', File::Spec->catfile( $legacy_root, 'sbin', 'init' ) ) + or die "Unable to stage upstart init symlink: $!"; +isnt( run_helper( $legacy_root, 'uses-systemd' ), 0, + 'an upstart target is not classified as systemd' ); +is( run_helper( $legacy_root, 'configure' ), 0, + 'legacy configuration succeeds' ); +ok( -x legacy_init($legacy_root), + 'legacy configuration materializes an executable init script' ); +is( read_file( legacy_init($legacy_root) ), read_file($template), + 'the materialized legacy init script matches the packaged template' ); + +my $dangling_legacy_root = stage_root(); +make_path( File::Spec->catdir( $dangling_legacy_root, 'etc', 'init.d' ) ); +symlink( '/missing/xcatd', legacy_init($dangling_legacy_root) ) + or die "Unable to stage dangling init symlink: $!"; +is( run_helper( $dangling_legacy_root, 'configure' ), 0, + 'legacy configuration replaces a dangling init symlink' ); +ok( !-l legacy_init($dangling_legacy_root), + 'the replacement for a dangling init symlink is a regular file' ); +is( read_file( legacy_init($dangling_legacy_root) ), read_file($template), + 'the dangling init symlink replacement matches the packaged template' ); + +open( my $custom_init, '>', legacy_init($legacy_root) ) + or die "Unable to customize staged init script: $!"; +print {$custom_init} "administrator customization\n"; +close($custom_init); +is( run_helper( $legacy_root, 'configure' ), 0, + 'reconfiguring a legacy target succeeds' ); +is( read_file( legacy_init($legacy_root) ), "administrator customization\n", + 'legacy reconfiguration preserves an existing init script' ); +is( run_helper( $legacy_root, 'configure', '--replace' ), 0, + 'RPM-style legacy upgrade configuration succeeds' ); +is( read_file( legacy_init($legacy_root) ), read_file($template), + 'RPM-style legacy upgrades refresh the init script from the packaged template' ); +is( run_helper( $legacy_root, 'remove' ), 0, + 'legacy cleanup succeeds' ); +ok( !-e legacy_init($legacy_root), + 'legacy cleanup removes the generated init script' ); + +my $rpm_spec = read_file( + File::Spec->catfile( $repo_root, 'xCAT-server', 'xCAT-server.spec' ) +); +like( $rpm_spec, + qr{cp etc/init\.d/xcatd \$RPM_BUILD_ROOT/%\{prefix\}/share/xcat/scripts/xcatd}, + 'RPM stages the legacy script as a compatibility template' ); +like( $rpm_spec, + qr{%if 0%\{\?rhel\} && 0%\{\?rhel\} < 7\n%ghost %attr\(0755,root,root\) /etc/init\.d/xcatd}, + 'RPM tracks the runtime-created init path only on legacy RHEL' ); +like( $rpm_spec, + qr{%if 0%\{\?suse_version\} && 0%\{\?suse_version\} < 1200\n%ghost %attr\(0755,root,root\) /etc/init\.d/xcatd}, + 'RPM tracks the runtime-created init path only on legacy SUSE' ); +like( $rpm_spec, qr{xcatd-init-compat.*uses-systemd}s, + 'RPM scriptlets select the init implementation at install time' ); +like( $rpm_spec, + qr{xcatd_init_compat=.*?"\$xcatd_init_compat" configure --replace}s, + 'RPM upgrades refresh an existing SysV init script' ); +my @xcatroot_exports = + ( $rpm_spec =~ /^export XCATROOT="\$RPM_INSTALL_PREFIX0"$/mg ); +is( scalar @xcatroot_exports, 2, + 'RPM install and erase scriptlets forward a relocated package root' ); +my @empty_init_cleanup = + ( $rpm_spec =~ /^\s*rmdir \/etc\/init\.d 2>\/dev\/null \|\| true$/mg ); +is( scalar @empty_init_cleanup, 1, + 'only RPM systemd upgrades remove an empty legacy init directory' ); +like( $rpm_spec, + qr{%if 0%\{\?suse_version\}\s+%else\s+# Remove only an empty directory.*?rmdir /etc/init\.d 2>/dev/null \|\| true\s+%endif}s, + 'RPM upgrades preserve the SUSE-owned init directory' ); +like( $rpm_spec, + qr{if \[ -e "\$legacy_xcatd_link" \] \|\| \[ -L "\$legacy_xcatd_link" \]}, + 'RPM upgrade recognizes enabled state through dangling legacy links' ); + +done_testing(); diff --git a/xCATsn/debian/postinst b/xCATsn/debian/postinst index 08f9629fa..c7056f716 100644 --- a/xCATsn/debian/postinst +++ b/xCATsn/debian/postinst @@ -57,7 +57,11 @@ case "$1" in update-rc.d $apachedaemon enable if [ -f "/proc/cmdline" ]; then # prevent running it during install into chroot image - XCATROOT=/opt/xcat /etc/init.d/xcatd start + if [ -d /run/systemd/system ] && command -v systemctl >/dev/null 2>&1; then + systemctl start xcatd.service + elif [ -x /etc/init.d/xcatd ]; then + XCATROOT=/opt/xcat /etc/init.d/xcatd start + fi /etc/init.d/$apachedaemon reload fi echo "xCATsn is now installed" diff --git a/xCATsn/xCATsn.spec b/xCATsn/xCATsn.spec index a24b6979d..697eb582e 100644 --- a/xCATsn/xCATsn.spec +++ b/xCATsn/xCATsn.spec @@ -225,12 +225,11 @@ if [ -e "/etc/redhat-release" ]; then else # SuSE apachedaemon='apache2' fi -# start xcatd on linux +# enable and reload the web server on linux [ -e "/etc/init.d/$apachedaemon" ] && chkconfig $apachedaemon on [ -e "/usr/lib/systemd/system/$apacheserviceunit" ] && systemctl enable $apacheserviceunit # prevent running it during install into chroot image if [ -f "/proc/cmdline" ] && [ "x$(stat -c '%i %d' /)" == "x$(stat -c '%i %d' /proc/1/root/. 2>/dev/null)" ]; then - XCATROOT=$RPM_INSTALL_PREFIX0 /etc/init.d/xcatd restart [ -e "/etc/init.d/$apachedaemon" ] && /etc/init.d/$apachedaemon reload [ -e "/usr/lib/systemd/system/$apacheserviceunit" ] && systemctl reload $apacheserviceunit fi @@ -267,10 +266,10 @@ fi # running system (skip the genimage/diskless chroot, where there is no systemd), and start via # systemctl: on EL10 the SysV path (/etc/init.d/xcatd) cannot start xcatd. if [ -f "/proc/cmdline" ] && [ "x$(stat -c '%i %d' /)" == "x$(stat -c '%i %d' /proc/1/root/. 2>/dev/null)" ]; then - if command -v systemctl >/dev/null 2>&1; then - systemctl restart xcatd - else - service xcatd restart + if [ -d /run/systemd/system ] && command -v systemctl >/dev/null 2>&1; then + systemctl restart xcatd.service + elif [ -x /etc/init.d/xcatd ]; then + XCATROOT=$RPM_INSTALL_PREFIX0 /etc/init.d/xcatd restart fi fi %endif