Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add REBOOT_COMMANDS (issue 3068) #3070

Merged
merged 12 commits into from Nov 21, 2023
Merged
34 changes: 34 additions & 0 deletions usr/share/rear/conf/default.conf
Expand Up @@ -3871,6 +3871,40 @@ PRE_BACKUP_SCRIPT=
POST_BACKUP_SCRIPT=
####

####
# REBOOT_COMMANDS
# REBOOT_COMMANDS_LABEL
#
# The REBOOT_COMMANDS array specifies the commands
# that are called after "rear recover" succeeded to recreate the system
# when "rear recover" is run in 'auto_recover'/'automatic' or 'unattended' mode
# which evaluate like this:
# for command in "${REBOOT_COMMANDS[@]}" ; do
# eval "$command"
# done
# For details see the [skel/default]/etc/scripts/system-setup script.
# Normally a single command 'reboot' is called to reboot the recreated system:
REBOOT_COMMANDS=( 'reboot' )
# But in unattended mode an automated 'reboot' call could lead to an endless loop
# when the ReaR recovery system is booted by default by the BIOS
# so that "rear recover" and 'reboot' would run automatically in an endless loop.
# In this case REBOOT_COMMANDS=( 'poweroff' ) could be the right way
# to get an as much as possible automated recovery via the unattended mode
# with 'poweroff' after successful "rear recover" to be able to remove
# the ReaR recovery system medium before booting the recreated system
# so no login into the ReaR recovery system is needed.
# For special cases more than a single command can be called,
# in particular when additional commands are neded to prepare the reboot
# for example on machines with more sophisticated firmware one may need
# some complicated dance with firmware settings before rebooting,
# cf. https://github.com/rear/rear/pull/3070#issuecomment-1802901263
#
# The REBOOT_COMMANDS_LABEL string (normally a single meaningful word) specifies
# what is shown to the user when the REBOOT_COMMANDS will be run
# which is by default to reboot the recreated system:
REBOOT_COMMANDS_LABEL="Reboot"
####

# Some external backup software request user input
# (e.g. to enter paths to exclude or date and time values for point in time restore).
# We use here the same default timeout as USER_INPUT_TIMEOUT was set above
Expand Down
101 changes: 70 additions & 31 deletions usr/share/rear/skel/default/etc/scripts/system-setup
Expand Up @@ -40,11 +40,13 @@ function automatic_recovery() {
return 1
}

# The 'sleep 1' is used as workaround to avoid whatever inexplicable actual reason
# The hardcoded 'sleep 1' is used as workaround to avoid whatever inexplicable actual reason
# that at least on SLES12 some initial output lines of this script would get lost
# (perhaps somewhere in systemd's nowhere land) which results that in particular
# in Relax-and-Recover debug mode the user sits in front of an empty screen wondering
# why nothing happens because in particular the read prompt "Press ENTER ..." was lost,
# (perhaps somewhere in systemd's nowhere land) and even in unattended_recovery mode
# all output should always appear regardless if someone is actually watching.
# In particular in Relax-and-Recover debug mode missing initial output lines results
# that the user sits in front of an empty screen wondering why nothing happens
# because in particular the read prompt "Press ENTER ..." was lost,
# cf. the 'if rear_debug' part below:
sleep 1

Expand All @@ -66,20 +68,38 @@ if rear_debug ; then
esac
fi

# Because "rear recover" won't work without default.conf
# we abort when there is no default.conf (or when it is empty),
# cf. https://github.com/rear/rear/pull/3070#discussion_r1389361339
if ! test -s /usr/share/rear/conf/default.conf ; then
echo -e "\nERROR: ReaR recovery cannot work without /usr/share/rear/conf/default.conf\n"
# Wait hardcoded 10 seconds in any case so that the user can notice the
# 'ERROR: ReaR recovery cannot work without /usr/share/rear/conf/default.conf'
# on his screen before the screen gets cleared and replaced by the login screen
# also in unattended mode regardless if someone is actually watching:
sleep 10
# Replace the usual /etc/motd message
# 'Welcome to Relax-and-Recover. Run "rear recover" to restore your system !'
# because it does not make sense to run "rear recover" without default.conf:
echo -e "\nRelax-and-Recover cannot work without /usr/share/rear/conf/default.conf\n" >/etc/motd
# exiting this script proceeds directly to the login screen:
exit 1
fi

# Set SECRET_OUTPUT_DEV because secret default values are set via
# { VARIABLE='secret value' ; } 2>>/dev/$SECRET_OUTPUT_DEV
# cf. https://github.com/rear/rear/pull/3034#issuecomment-1691609782
SECRET_OUTPUT_DEV="null"
jsmeix marked this conversation as resolved.
Show resolved Hide resolved
# Sourcing of the conf/default.conf file as we may use some defined variables or arrays
# E.g. UDEV_NET_MAC_RULE_FILES is used by script 55-migrate-network-devices.sh
if test -f /usr/share/rear/conf/default.conf ; then
# Set SECRET_OUTPUT_DEV because secret default values are set via
# { VARIABLE='secret value' ; } 2>>/dev/$SECRET_OUTPUT_DEV
# cf. https://github.com/rear/rear/pull/3034#issuecomment-1691609782
SECRET_OUTPUT_DEV="null"
source /usr/share/rear/conf/default.conf
fi
source /usr/share/rear/conf/default.conf || echo -e "\n'source /usr/share/rear/conf/default.conf' failed with exit code $?\n"
# Sourcing user and rescue configuration as we need some variables
# (EXCLUDE_MD5SUM_VERIFICATION right now and other variables in the system setup scripts):
# The order of sourcing should be 'site' then 'local' and as last 'rescue'
for conf in site local rescue ; do
test -f /etc/rear/$conf.conf && source /etc/rear/$conf.conf
if test -s /etc/rear/$conf.conf ; then
jsmeix marked this conversation as resolved.
Show resolved Hide resolved
source /etc/rear/$conf.conf || echo -e "\n'source /etc/rear/$conf.conf' failed with exit code $?\n"
fi
done

# Verifying md5sums must happen first of all during recovery system startup
Expand All @@ -94,17 +114,18 @@ done
# during "rear mkrescue/mkbackup" by the build/default/995_md5sums_rootfs.sh script:
if test -s "/md5sums.txt" ; then
echo -e "\nVerifying md5sums of the files in the Relax-and-Recover rescue system\n"
# /etc/issue is always excluded to avoid that verifying its md5sum fails with "./etc/issue: FAILED"
# /etc/motd is excluded because it was changed above when default.conf is missing.
# /etc/issue is excluded to avoid that verifying its md5sum fails with "./etc/issue: FAILED"
# when there is no rsa SSH host key /etc/ssh/ssh_host_rsa_key in the recovery system
# because then /etc/scripts/run-sshd creates one and adds its SSH fingerprint to /etc/issue
# and /etc/scripts/run-sshd is run by SysVinit or systemd
# (via /etc/inittab and /etc/init/start-sshd.conf or /usr/lib/systemd/system/sshd.service)
# so that /etc/issue may get modified before its md5sum is verified here.
# run-sshd also modifies /etc/ssh/sshd_config, so this is excluded as well.
# Also /etc/udev/rules.d/70-persistent-net.rules is always excluded to avoid false alarm
# Also /etc/udev/rules.d/70-persistent-net.rules is excluded to avoid false alarm
# because it seems it can be modified even before this md5sum verification here runs,
# see https://github.com/rear/rear/issues/1883#issuecomment-409875733
egrep_pattern="/etc/issue|/etc/ssh/sshd_config|/etc/udev/rules.d/70-persistent-net.rules"
egrep_pattern="/etc/motd|/etc/issue|/etc/ssh/sshd_config|/etc/udev/rules.d/70-persistent-net.rules"
test "$EXCLUDE_MD5SUM_VERIFICATION" && egrep_pattern+="|$EXCLUDE_MD5SUM_VERIFICATION"
# Regardless of '--quiet' md5sum shows "FAILED" messages nevertheless (cf. 'man md5sum'):
if grep -E -v "$egrep_pattern" md5sums.txt | md5sum --quiet --check ; then
Expand All @@ -116,9 +137,11 @@ if test -s "/md5sums.txt" ; then
# In debug mode let the user confirm to proceed:
read -p "Press ENTER to proceed 'bona fide' nevertheless "
else
# In non-debug mode wait 10 seconds so that the user can read the md5sum output:
# In non-debug mode wait USER_INPUT_INTERRUPT_TIMEOUT (by default 30 seconds)
# so that the user can read and understand the md5sum output (could be several lines)
# unless in unattended_recovery mode where there is normally no user who reads something:
echo -e "Proceeding 'bona fide' nevertheless...\n"
sleep 10
unattended_recovery || sleep $USER_INPUT_INTERRUPT_TIMEOUT
jsmeix marked this conversation as resolved.
Show resolved Hide resolved
fi
fi
fi
Expand All @@ -128,19 +151,29 @@ for system_setup_script in /etc/scripts/system-setup.d/*.sh ; do
if rear_debug ; then
read -p "Press ENTER to run $( basename $system_setup_script ) "
set -x
source $system_setup_script
source $system_setup_script || echo -e "\n'source $system_setup_script' results exit code $?\n"
# The only known way how to do 'set +x' after 'set -x' without a '+ set +x' output:
{ set +x ; } 2>/dev/null
echo
else
echo "Running $( basename $system_setup_script )..."
source $system_setup_script
# In non-debug mode when a system setup script results non-zero exit code
# do not show an 'exit code' message (like the above) to avoid false alarm
# cf. https://github.com/rear/rear/pull/3070#discussion_r1393738863
# but just wait USER_INPUT_UNATTENDED_TIMEOUT (by default 3 seconds)
# so that the user could at least notice potential error messages from the script
# unless in unattended_recovery mode where there is normally no watching user:
if ! source $system_setup_script ; then
unattended_recovery || sleep $USER_INPUT_UNATTENDED_TIMEOUT
fi
fi
done
echo -e "\nRelax-and-Recover rescue system is ready\n"
# Wait two seconds so that the user can read the 'Relax-and-Recover rescue system is ready' message
# on his screen before the screen gets cleared and replaced by the login screen:
sleep 2
# Wait USER_INPUT_UNATTENDED_TIMEOUT (by default 3 seconds)
# so that the user can notice the 'Relax-and-Recover rescue system is ready' message
# on his screen before the screen gets cleared and replaced by the login screen
# unless in unattended_recovery mode where there is normally no watching user:
unattended_recovery || sleep $USER_INPUT_UNATTENDED_TIMEOUT

# In debug mode run the automated 'rear recover' also with debug options.
# Because the kernel command line option 'debug' means 'set -x' for the system setup scripts
Expand All @@ -151,15 +184,15 @@ else
rear_debug_options=''
fi

# Launch rear recover automatically:
# Launch "rear recover" automatically:
if automatic_recovery ; then
choices=( "View Relax-and-Recover log file(s)"
"Go to Relax-and-Recover shell"
)
echo -e "\nLaunching 'rear recover' automatically\n"
if rear $rear_debug_options recover ; then
echo -e "\n'rear recover' finished successfully\n"
choices+=( "Reboot" )
choices+=( "$REBOOT_COMMANDS_LABEL" )
else
echo -e "\n'rear recover' failed, check the Relax-and-Recover log file(s)\n"
fi
Expand All @@ -177,7 +210,10 @@ if automatic_recovery ; then
break
;;
(3)
reboot
for command in "${REBOOT_COMMANDS[@]}" ; do
echo "Running REBOOT_COMMANDS '$command'"
eval "$command" || echo -e "\n'eval $command' results exit code $?\n"
done
;;
esac
for (( i=1 ; i <= ${#choices[@]} ; i++ )) ; do
Expand All @@ -186,18 +222,21 @@ if automatic_recovery ; then
done 2>&1
fi

# Launch rear recover automatically in unattended mode
# i.e. with automated reboot after successful 'rear recover':
# In unattended mode launch "rear --non-interactive recover" automatically
# i.e. with automated "reboot" (reboot_command) after successful recovery:
if unattended_recovery ; then
choices=( "View Relax-and-Recover log file(s)"
"Go to Relax-and-Recover shell"
)
echo -e "\nLaunching 'rear recover' automatically in unattended mode\n"
echo -e "\nLaunching 'rear recover' automatically in unattended (non-interactive) mode\n"
if rear $rear_debug_options --non-interactive recover ; then
echo -e "\n'rear recover' finished successfully\n"
echo -e "\nRebooting in 30 seconds (Ctrl-C to interrupt)\n"
sleep 30
reboot
echo -e "\n'$REBOOT_COMMANDS_LABEL' in $USER_INPUT_INTERRUPT_TIMEOUT seconds (Ctrl-C to interrupt)\n"
sleep $USER_INPUT_INTERRUPT_TIMEOUT
for command in "${REBOOT_COMMANDS[@]}" ; do
echo "Running REBOOT_COMMANDS '$command'"
eval "$command" || echo -e "\n'eval $command' results exit code $?\n"
done
else
echo -e "\n'rear recover' failed, check the Relax-and-Recover log file(s)\n"
PS3="Select what to do "
Expand Down