2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-08-04 16:36:58 +00:00
Files
xcat-core/xCAT-server/share/xcat/install/scripts/post.xcat.ng
T
Vinícius Ferrão 886db49e27 fix(postscripts): disable xcatpostinit1 before running the postscripts
The generated /opt/xcat/xcatinstallpost ran the install postscripts first and
only disabled the xcatpostinit1 service afterwards.  If one of those postscripts
rebooted the node (for example a firmware or kernel update), the service was
still enabled, so on the next boot the whole postscript set ran again from the
start.  Disable the service *before* running the postscripts so a mid-postscript
reboot cannot re-trigger them.

The disable decision reads OSVER (base variant only), RUNBOOTSCRIPTS and
NODESTATUS, which the included xcatinstallpost script would otherwise set.
Moving the INCLUDE below the disable block leaves those variables unset, so read
them up front (the included script re-reads them) and source xcatlib.sh so
msgutil_r is available; the disable decision is then identical to before.

The original change (lenovobuild 9184cbe0) touched only the legacy post.xcat.
Modern EL uses the systemd variants: post.xcat.ng (RHEL/CentOS 8 and 9) and
post.xcat.rhels10 (RHEL 10).  Apply the same reorder to all three so the fix
actually takes effect on current platforms.

Lab-validated with a full AlmaLinux 9.8 stateful install (post.xcat.ng path):
the generated xcatinstallpost disables the service before running the
postscripts, the postscripts run exactly once, the node reaches "booted", and
with the default NODESTATUS=1 the service is left enabled just as before.

Recovered from the unmerged lenovobuild branch (original 9184cbe0), adapted and
extended to the .ng and .rhels10 variants.

Co-authored-by: Jarrod Johnson <10814490+jjohnson42@users.noreply.github.com>
2026-07-22 22:54:20 -03:00

466 lines
15 KiB
Bash

#!/bin/bash
#
# Run xCAT post install
#
export MASTER_IP="#ENV:MASTER_IP#"
export MASTER="#XCATVAR:XCATMASTER#"
export NODESTATUS="#XCATVAR:NODESTATUS#"
export XCATIPORT="#TABLE:site:key=xcatiport:value#"
export INSTALLDIR="#TABLE:site:key=installdir:value#"
export TFTPDIR="#TABLE:site:key=tftpdir:value#"
export XCATDEBUGMODE="#TABLEBLANKOKAY:site:key=xcatdebugmode:value#"
export HTTPPORT="#TABLEBLANKOKAY:site:key=httpport:value#"
#INCLUDE:#ENV:XCATROOT#/share/xcat/install/scripts/scriptlib#
umask 0022
case "$XCATDEBUGMODE" in
"1"|"2")
set -x
;;
esac
if [ -z "$XCATIPORT" ]; then
XCATIPORT="3002"
fi
if [ -z "$INSTALLDIR" ]; then
INSTALLDIR="/install"
fi
if [ -z "$TFTPDIR" ]; then
TFTPDIR="/tftpboot"
fi
if [[ "${TFTPDIR:0:1}" != "/" ]]; then
TFTPDIR="/$TFTPDIR"
fi
if [ -z "$HTTPPORT" ]; then
HTTPPORT="80"
fi
NODESTATUS="$(echo "$NODESTATUS"| tr -d \'\" | tr A-Z a-z)"
(
cat <<'EOF'
#INCLUDE:#TABLE:site:key=installdir:value#/postscripts/updateflag.awk#
EOF
) >/tmp/updateflag
chmod 0755 /tmp/updateflag
cd /tmp
log_label="xcat.deployment"
msgutil_r "$MASTER_IP" "info" "Executing post.xcat to prepare for firstbooting ..." "/var/log/xcat/xcat.log" "$log_label"
RAND="$(perl -e 'print int(rand(50)). "\n"')"
case "$XCATDEBUGMODE" in
"1"|"2")
msgutil_r "$MASTER_IP" "debug" "sleep $RAND" "/var/log/xcat/xcat.log" "$log_label"
;;
esac
sleep "$RAND"
# Stop if no openssl to help the next bit
if ! type openssl >/dev/null 2>&1
then
msgutil_r "$MASTER_IP" "error" "/usr/bin/openssl does not exist, halt ..." "/var/log/xcat/xcat.log" "$log_label"
/tmp/updateflag "$MASTER" "$XCATIPORT" "installstatus failed"
sleep infinity
fi
# Save to /opt/xcat/xcatinfo file
mkdir -p /opt/xcat
touch /opt/xcat/xcatinfo
grep -q 'XCATSERVER=' /opt/xcat/xcatinfo >/dev/null 2>&1
if [ "$?" -eq "0" ]
then
sed -i "s/XCATSERVER=.*/XCATSERVER=$MASTER_IP/" /opt/xcat/xcatinfo
else
echo "XCATSERVER=$MASTER_IP" >>/opt/xcat/xcatinfo
fi
grep -q 'INSTALLDIR' /opt/xcat/xcatinfo >/dev/null 2>&1
if [ "$?" -eq "0" ]
then
sed -i "s/INSTALLDIR=.*/INSTALLDIR=$INSTALLDIR/" /opt/xcat/xcatinfo
else
echo "INSTALLDIR=$INSTALLDIR" >>/opt/xcat/xcatinfo
fi
grep 'HTTPPORT' /opt/xcat/xcatinfo > /dev/null 2>&1
if [ $? -eq 0 ]; then
sed -i "s/HTTPPORT=.*/HTTPPORT=$HTTPPORT/" /opt/xcat/xcatinfo
else
echo "HTTPPORT=$HTTPPORT" >> /opt/xcat/xcatinfo
fi
case "$XCATDEBUGMODE" in
"1"|"2")
msgutil_r "$MASTER_IP" "debug" "/opt/xcat/xcatinfo generated" "/var/log/xcat/xcat.log" "$log_label"
;;
esac
# Download the postscripts
msgutil_r "$MASTER_IP" "info" "trying to download postscripts from $MASTER_IP..." "/var/log/xcat/xcat.log" "$log_label"
# Stop if no curl to help the next bit
if ! type curl >/dev/null 2>&1
then
msgutil_r "$MASTER_IP" "error" "Command curl not found, halt ..." "/var/log/xcat/xcat.log" "$log_label"
/tmp/updateflag "$MASTER" "$XCATIPORT" "installstatus failed"
sleep infinity
fi
# $1 URL
# $2 Destination directory
function download_recursive()
{
local url="$1"
local dest_dir="$2"
local f
[ "${url: -1}" = "/" ] && url="${url:0:-1}"
[ "${dest_dir: -1}" = "/" ] && dest_dir="${dest_dir:0:-1}"
mkdir -p "${dest_dir}"
while read -r f
do
case "$f" in
*"/")
download_recursive "${url}/${f}" "${dest_dir}/${f:0:-1}"
[ "$?" -ne "0" ] && return 1
;;
*)
curl --fail --retry 20 --max-time 60 "${url}/${f}" -o "${dest_dir}/${f}"
[ "$?" -ne "0" ] && return 1
;;
esac
done < <(curl --fail --retry 20 --max-time 60 "${url}/" | grep -o '<a href="\([^"]*\)">.*</a>' | egrep -v "O=D|Directory" | cut -d '"' -f 2)
return 0
}
download_recursive "http://$MASTER_IP:${HTTPPORT}$INSTALLDIR/postscripts/" "/xcatpost" 2>/tmp/download.log
if [ "$?" -ne "0" ]
then
msgutil_r "$MASTER_IP" "error" "failed to download postscripts from http://$MASTER_IP$INSTALLDIR/postscripts/, check /tmp/download.log on the node, halt ..." "/var/log/xcat/xcat.log" "$log_label"
/tmp/updateflag "$MASTER" "$XCATIPORT" "installstatus failed"
sleep infinity
fi
# Add execute permision to all files recursively under /xcatpost.
chmod -R +x `find /xcatpost/ -maxdepth 1 -print | grep -E -v '^(/xcatpost/|/xcatpost/_xcat|/xcatpost/_ssh|/xcatpost/ca|/xcatpost/hostkeys)$'`
msgutil_r "$MASTER_IP" "info" "postscripts downloaded successfully" "/var/log/xcat/xcat.log" "$log_label"
# Get the precreated mypostscript file
rm -rf /xcatpost/mypostscript
export NODE="#TABLE:nodelist:THISNODE:node#"
msgutil_r "$MASTER_IP" "info" "trying to get mypostscript from $MASTER_IP..." "/var/log/xcat/xcat.log" "$log_label"
curl --fail --retry 20 --max-time 60 "http://$MASTER_IP:${HTTPPORT}$TFTPDIR/mypostscripts/mypostscript.$NODE" -o "/xcatpost/mypostscript.$NODE" 2> /tmp/download.log
if [ "$?" = "0" ]
then
case "$XCATDEBUGMODE" in
"1"|"2")
msgutil_r "$MASTER_IP" "debug" "precreated mypostscript downloaded successfully" "/var/log/xcat/xcat.log" "$log_label"
;;
esac
mv /xcatpost/mypostscript.$NODE /xcatpost/mypostscript
chmod 700 /xcatpost/mypostscript
fi
# Though this is the only method going forward, flag to allow backward compatibility with 2.2 generated netboot images
USEOPENSSLFORXCAT=1
export USEOPENSSLFORXCAT
XCATSERVER=$MASTER_IP:3001
export XCATSERVER
# If mypostscript doesn't exist, we will get it through getpostscript.awk
if [ ! -x /xcatpost/mypostscript ]; then
case "$XCATDEBUGMODE" in
"1"|"2")
msgutil_r "$MASTER_IP" "debug" "no pre-generated mypostscript.<nodename>, trying to get it with getpostscript.awk..." "/var/log/xcat/xcat.log" "$log_label"
;;
esac
# To support the postscripts in the subdirectories under /install/postscripts
# chmod +x /xcatpost/*
# Stop if no getpostscript.awk to help the next bit
if [ ! -x /xcatpost/getpostscript.awk ]; then
msgutil_r "$MASTER_IP" "error" "/xcatpost/getpostscript.awk does not exist, halt ..." "/var/log/xcat/xcat.log" "$log_label"
/tmp/updateflag "$MASTER" "$XCATIPORT" "installstatus failed"
sleep infinity
fi
/xcatpost/getpostscript.awk | egrep '<data>' | sed -e 's/<[^>]*>//g' | egrep -v '^ *$' | sed -e 's/^ *//' | sed -e 's/&lt;/</g' -e 's/&gt;/>/g' -e 's/&amp;/\&/g' -e 's/&quot;/"/g' -e "s/&apos;/'/g" >/xcatpost/mypostscript
MYCONT="$(grep '^MASTER=' /xcatpost/mypostscript)"
RETRY=0
while [ -z "$MYCONT" ]; do
RETRY=$(($RETRY + 1))
if [ "$RETRY" -eq "10" ]; then
break
fi
let SLI=$RANDOM%10+10
sleep $SLI
/xcatpost/getpostscript.awk |egrep '<data>'|sed -e 's/<[^>]*>//g'|egrep -v '^ *$'|sed -e 's/^ *//' | sed -e 's/&lt;/</g' -e 's/&gt;/>/g' -e 's/&amp;/\&/g' -e 's/&quot;/"/g' -e "s/&apos;/'/g" > /xcatpost/mypostscript
MYCONT="$(grep '^MASTER=' /xcatpost/mypostscript)"
done
fi
TMP="$(sed "/^#\s*postscripts-start-here/,/^#\s*postscripts-end-here/ s/\(.*\)/run_ps postscript \1/;s/run_ps postscript\s*#/#/;s/run_ps postscript\s*$//" /xcatpost/mypostscript)"
echo "$TMP" >/xcatpost/mypostscript
TMP="$(sed "/^#\s*postbootscripts-start-here/,/^#\s*postbootscripts-end-here/ s/\(.*\)/run_ps postbootscript \1/;s/run_ps postbootscript\s*#/#/;s/run_ps postbootscript\s*$//" /xcatpost/mypostscript)"
cd /xcatpost
# gunzip xcatpost.tar.gz
# tar -xvf xcatpost.tar
# /xcatpost/#TABLE:nodelist:THISNODE:node#
export PATH="$PATH:/xcatpost"
# use the run_ps subroutine to run the postscripts
case "$XCATDEBUGMODE" in
"1"|"2")
echo "set -x" >/xcatpost/mypostscript
;;
*)
>/xcatpost/mypostscript
;;
esac
echo "
. /xcatpost/xcatlib.sh
# global value to store the running status of the postbootscripts,the value is non-zero if one postbootscript failed
return_value=0
# subroutine used to run postscripts
# \$1 argument is the script type
# rest argument is the script name and arguments
run_ps () {
local ret_local=0
mkdir -p "\"/var/log/xcat\""
# On some Linux distro, the rsyslogd daemon write log files with permision
# other than root:root. And in some case, the directory /var/log/xcat was
# created by xCAT, and had root:root ownership. In this way, rsyslogd
# did not have enough permission to write to log files under this directory.
# As a dirty hack, change the ownership of directory /var/log/xcat to the
# same ownership of directory /var/log.
chown `ls -ld /var/log | awk '{ print \$3\":\"\$4 }'` "\"/var/log/xcat\""
local logfile=\"/var/log/xcat/xcat.log\"
local scriptype=\$1
shift;
if [ -z \"\$scriptype\" ]; then
scriptype=\"postscript\"
fi
log_label=\"xcat.deployment.\"\$scriptype
if [ -f \$1 ]; then
msgutil_r \"\$MASTER_IP\" \"info\" "\"Running \$scriptype: \$1\"" \"\$logfile\" \"\$log_label\"
if [ \"\$XCATDEBUGMODE\" = \"1\" ] || [ \"\$XCATDEBUGMODE\" = \"2\" ]; then
local compt=\$(file \$1)
local reg=\"shell script\"
if [[ \"\$compt\" =~ \$reg ]]; then
bash -x ./\$@ 2>&1
ret_local=\$?
else
./\$@ 2>&1 | logger -t xcat -p debug
ret_local=\${PIPESTATUS[0]}
fi
else
./\$@ 2>&1
ret_local=\${PIPESTATUS[0]}
fi
if [ \"\$ret_local\" -ne \"0\" ]; then
return_value=\$ret_local
fi
msgutil_r \"\$MASTER_IP\" \"info\" "\"\$scriptype \$1 return with \$ret_local\"" \"\$logfile\" \"\$log_label\"
else
msgutil_r \"\$MASTER_IP\" \"error\" "\"\$scriptype \$1 does NOT exist.\"" \"\$logfile\" \"\$log_label\"
return_value=-1
fi
return 0
}
# subroutine end
" >>/xcatpost/mypostscript
echo "$TMP" >>/xcatpost/mypostscript
case "$XCATDEBUGMODE" in
"1"|"2")
echo "set +x" >>/xcatpost/mypostscript
;;
esac
chmod 0755 /xcatpost/mypostscript
if [ ! -x /xcatpost/mypostscript ]; then
msgutil_r "$MASTER_IP" "error" "failed to generate mypostscript file, halt ..." "/var/log/xcat/xcat.log" "$log_label"
/tmp/updateflag "$MASTER" "$XCATIPORT" "installstatus failed"
sleep infinity
else
case "$XCATDEBUGMODE" in
"1"|"2")
msgutil_r "$MASTER_IP" "debug" "generate mypostscript file successfully" "/var/log/xcat/xcat.log" "$log_label"
;;
esac
fi
# Save the postboot scripts to /xcatpost/mypostscript.post
TMP=`sed "/^#\s*postscripts-start-here/,/^#\s*postscripts-end-here/ d" /xcatpost/mypostscript`
echo "$TMP" >/xcatpost/mypostscript.post
chmod 0755 /xcatpost/mypostscript.post
if [ ! -x /xcatpost/mypostscript.post ]
then
msgutil_r "$MASTER_IP" "error" "failed to generate /xcatpost/mypostscript.post" "/var/log/xcat/xcat.log" "$log_label"
else
case "$XCATDEBUGMODE" in
"1"|"2")
msgutil_r "$MASTER_IP" "debug" "generate mypostscript.post file successfully" "/var/log/xcat/xcat.log" "$log_label"
;;
esac
fi
export OSVER="#TABLE:nodetype:THISNODE:os#"
# Create the post init service as a hook to run PS and PBS, as well as status updating
cat >/etc/systemd/system/xcatpostinit1.service <<'EOF'
#INCLUDE:/install/postscripts/xcatpostinit1.service#
EOF
case "$XCATDEBUGMODE" in
"1"|"2")
msgutil_r "$MASTER_IP" "debug" "/etc/systemd/system/xcatpostinit1.service generated" "/var/log/xcat/xcat.log" "$log_label"
;;
esac
ln -s /etc/systemd/system/xcatpostinit1.service /etc/systemd/system/multi-user.target.wants/xcatpostinit1.service
case "$XCATDEBUGMODE" in
"1"|"2")
msgutil_r "$MASTER_IP" "debug" "xcatpostinit1.service enabled" "/var/log/xcat/xcat.log" "$log_label"
;;
esac
cat >/opt/xcat/xcatpostinit1 <<'EOF'
#INCLUDE:/install/postscripts/xcatpostinit1.install#
EOF
chmod 0755 /opt/xcat/xcatpostinit1
# Create the xcatinstallpost
mkdir -p /opt/xcat
cat >/opt/xcat/xcatinstallpost <<'EOF'
#!/bin/bash
# Disable the xcatpostinit1 service *before* running the postscripts (the
# INCLUDE at the end). If a postscript reboots the node, the service is
# already disabled, so the whole postscript set is not run again on reboot.
# The disable decision needs RUNBOOTSCRIPTS and NODESTATUS, which the included
# script would otherwise set; read them up front (it re-reads them), and source
# xcatlib.sh so msgutil_r is available for the debug message.
[ -f /xcatpost/xcatlib.sh ] && . /xcatpost/xcatlib.sh
if [ -f /xcatpost/mypostscript.post ]
then
RUNBOOTSCRIPTS=`grep 'RUNBOOTSCRIPTS=' /xcatpost/mypostscript.post | cut -d= -f2 | tr -d \'\" | tr A-Z a-z`
XCATDEBUGMODE=`grep 'XCATDEBUGMODE=' /xcatpost/mypostscript.post | cut -d= -f2 | tr -d \'\" | tr A-Z a-z`
MASTER_IP=`grep '^MASTER_IP=' /xcatpost/mypostscript.post | cut -d= -f2 | sed s/\'//g`
fi
[ -f /xcatpost/mypostscript ] && NODESTATUS=`grep 'NODESTATUS=' /xcatpost/mypostscript | awk -F = '{print $2}' | tr -d \'\" | tr A-Z a-z`
[ -z "$NODESTATUS" ] && NODESTATUS="1"
if [[ ! "$RUNBOOTSCRIPTS" =~ ^(1|yes|y)$ ]] && [[ ! "$NODESTATUS" =~ ^(1|yes|y)$ ]]; then
systemctl disable xcatpostinit1.service
case "$XCATDEBUGMODE" in
"1"|"2")
msgutil_r "$MASTER_IP" "debug" "systemctl disable xcatpostinit1.service" "/var/log/xcat/xcat.log" "xcat.xcatinstallpost"
;;
esac
fi
#INCLUDE:#TABLE:site:key=installdir:value#/postscripts/xcatinstallpost#
EOF
chmod 0755 /opt/xcat/xcatinstallpost
if [ ! -x /opt/xcat/xcatinstallpost ]
then
msgutil_r "$MASTER_IP" "error" "failed to generate /opt/xcat/xcatinstallpost" "/var/log/xcat/xcat.log" "$log_label"
else
case "$XCATDEBUGMODE" in
"1"|"2")
msgutil_r "$MASTER_IP" "debug" "/opt/xcat/xcatinstallpost generated" "/var/log/xcat/xcat.log" "$log_label"
;;
esac
fi
# Create the dskls post
cat >/opt/xcat/xcatdsklspost <<'EOF'
#INCLUDE:#TABLE:site:key=installdir:value#/postscripts/xcatdsklspost#
EOF
chmod 755 /opt/xcat/xcatdsklspost
if [ ! -x /opt/xcat/xcatdsklspost ]; then
msgutil_r "$MASTER_IP" "error" "failed to generate /opt/xcat/xcatdsklspost" "/var/log/xcat/xcat.log" "$log_label"
else
case "$XCATDEBUGMODE" in
"1"|"2")
msgutil_r "$MASTER_IP" "debug" "/opt/xcat/xcatdsklspost generated" "/var/log/xcat/xcat.log" "$log_label"
;;
esac
fi
#create the preboot script and run here
TMP="$(sed '/^#\s*postbootscripts-start-here/,/^#\s*postbootscripts-end-here/ d' /xcatpost/mypostscript)"
echo "$TMP" >/xcatpost/mypostscript
echo "
# Save bad return code to /opt/xcat/xcatinfo
if [ \"\$return_value\" -ne \"0\" ]; then
grep 'POSTSCRIPTS_RC' /opt/xcat/xcatinfo > /dev/null 2>&1
if [ \$? -eq 0 ]; then
sed -i \"s/POSTSCRIPTS_RC=.*/POSTSCRIPTS_RC=1/\" /opt/xcat/xcatinfo
else
echo \"POSTSCRIPTS_RC=1\" >>/opt/xcat/xcatinfo
fi
fi
" >>/xcatpost/mypostscript
chmod 0700 /xcatpost/mypostscript
export ARCH="#TABLE:nodetype:THISNODE:arch#"
export CONSOLEPORT="#TABLEBLANKOKAY:nodehm:THISNODE:serialport#"
# For redhat:
# place-holder for the code to save the repo info on compute node,pointing to the "pkgdir" of the osimage
# so that the provisioned node has the repo pointed to the distro path on MN
#WRITEREPO#
case "$XCATDEBUGMODE" in
"1"|"2")
msgutil_r "$MASTER_IP" "info" "running mypostscript" "/var/log/xcat/xcat.log" "$log_label"
;;
esac
/xcatpost/mypostscript
case "$XCATDEBUGMODE" in
"1"|"2")
msgutil_r "$MASTER_IP" "info" "mypostscript returned" "/var/log/xcat/xcat.log" "$log_label"
;;
esac
msgutil_r "$MASTER_IP" "info" "finished firstboot preparation, sending request to $MASTER:3002 for changing status..." "/var/log/xcat/xcat.log" "$log_label"
# The following command should always be run to prevent infinite installation loops
updateflag.awk "$MASTER" 3002
cd /
case "$XCATDEBUGMODE" in
"1"|"2")
set +x
;;
esac