Skip to content

Commit

Permalink
Implement non-interactive mode to abort on repeated UserInput calls
Browse files Browse the repository at this point in the history
in the absence of user interaction.
  • Loading branch information
codefritzel authored and schlomo committed May 14, 2023
1 parent 3333cf8 commit 9cbd22d
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 31 deletions.
23 changes: 12 additions & 11 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -209,17 +209,18 @@ Relax-and-Recover comes with ABSOLUTELY NO WARRANTY; for details see
the GNU General Public License at: http://www.gnu.org/licenses/gpl.html
Available options:
-h --help usage information
-c DIR alternative config directory; instead of /etc/rear
-C CONFIG additional config file; absolute path or relative to config directory
-d debug mode; log debug messages
-D debugscript mode; log every function call (via 'set -x')
--debugscripts SET same as -d -v -D but debugscript mode with 'set -SET'
-r KERNEL kernel version to use; current: '3.12.49-3-default'
-s simulation mode; show what scripts rear would include
-S step-by-step mode; acknowledge each script individually
-v verbose mode; show more output
-V --version version information
-h --help usage information
-c DIR alternative config directory; instead of /etc/rear
-C CONFIG additional config file; absolute path or relative to config directory
-d debug mode; log debug messages
-D debugscript mode; log every function call (via 'set -x')
--debugscripts SET same as -d -v -D but debugscript mode with 'set -SET'
-r KERNEL kernel version to use; current: '3.12.49-3-default'
-s simulation mode; show what scripts rear would include
-S step-by-step mode; acknowledge each script individually
-v verbose mode; show more output
-V --version version information
-n --non-interactive non-interactive mode; aborts when any user input is required
List of commands:
checklayout check if the disk layout has changed
Expand Down
5 changes: 4 additions & 1 deletion doc/rear.8.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ rear - bare metal disaster recovery and system migration tool


== SYNOPSIS
*rear* [*-h*|*--help*] [*-V*|*--version*] [*-dsSv*] [*-D*|*--debugscripts* _SET_] [*-c* _DIR_] [*-C* _CONFIG_] [*-r* _KERNEL_] [--] _COMMAND_ [_ARGS_...]
*rear* [*-h*|*--help*] [*-V*|*--version*] [*-dsSv*] [*-D*|*--debugscripts* _SET_] [*-c* _DIR_] [*-C* _CONFIG_] [*-r* _KERNEL_] [*-n*|*--non-interactive*] [--] _COMMAND_ [_ARGS_...]


== DESCRIPTION
Expand Down Expand Up @@ -83,6 +83,9 @@ the GNU General Public License at: http://www.gnu.org/licenses/gpl.html
-v::
*verbose mode* (show messages what ReaR is doing on the terminal)

-n --non-interactive::
*non-interactive mode* (aborts when any user input is required, experimental)

-V --version::
version information

Expand Down
6 changes: 5 additions & 1 deletion usr/sbin/rear
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ DEBUG=""
DEBUGSCRIPTS=""
DEBUGSCRIPTS_ARGUMENT="x"
DEBUG_OUTPUT_DEV="null"
NON_INTERACTIVE=""
DISPENSABLE_OUTPUT_DEV="null"
KEEP_BUILD_DIR=""
KERNEL_VERSION=""
Expand All @@ -141,7 +142,7 @@ WORKFLOW=""

# Parse options
help_note_text="Use '$PROGRAM --help' or 'man $PROGRAM' for more information."
if ! OPTS="$( getopt -n $PROGRAM -o "c:C:dDhsSvVr:" -l "help,version,debugscripts:" -- "$@" )" ; then
if ! OPTS="$( getopt -n $PROGRAM -o "c:C:dDhsSvVrn:" -l "help,version,non-interactive,debugscripts:" -- "$@" )" ; then
echo "$help_note_text"
exit 1
fi
Expand All @@ -159,6 +160,9 @@ while true ; do
(-v)
VERBOSE=1
;;
(-n|--non-interactive)
NON_INTERACTIVE=1
;;
(-c)
if [[ "$2" == -* ]] ; then
# When the item that follows '-c' starts with a '-'
Expand Down
31 changes: 28 additions & 3 deletions usr/share/rear/lib/_input-output-functions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1069,6 +1069,13 @@ function cleanup_build_area_and_end_program () {
# which lets a 'UserInput -I BAR_CHOICE' call autorespond with 'third choice'.
# No USER_INPUT_BAR_CHOICE variable should exist to get real user input for a 'UserInput -I BAR_CHOICE' call
# or the user can interupt any automated response within a relatively short time (minimum is only 1 second).
# * The non-interactive feature works by erroring out in UserInput if the same user input ID is used more than once and
# if the first call to UserInput was not met by a human response. The idea is that if the first call ran into the
# timeout then the second call will not have a better chance of success and should be treated as an error.
# That way, ReaR will quickly abort in situations where human intervention is required but not provided.
# This is implemented via an associative Bash array USER_INPUT_SEEN_WITH_TIMEOUT which tracks which user input IDs
# were already used and ran into the timeout.
declare -A USER_INPUT_SEEN_WITH_TIMEOUT
function UserInput () {
# First and foremost log that UserInput was called (but be confidential here):
local caller_source="$( CallerSource )"
Expand All @@ -1088,6 +1095,8 @@ function UserInput () {
local automated_input_interrupt_timeout=10
# Avoid stderr if USER_INPUT_INTERRUPT_TIMEOUT is not set or empty and ignore wrong USER_INPUT_INTERRUPT_TIMEOUT:
test "$USER_INPUT_INTERRUPT_TIMEOUT" -ge 1 2>/dev/null && automated_input_interrupt_timeout=$USER_INPUT_INTERRUPT_TIMEOUT
# set timeouts to low but acceptable 3 seconds for non-interactive mode:
is_true "$NON_INTERACTIVE" && timeout=3 && automated_input_interrupt_timeout=3
local default_prompt="enter your input"
local prompt="$default_prompt"
# Avoid stderr if USER_INPUT_PROMPT is not set or empty:
Expand All @@ -1111,7 +1120,11 @@ function UserInput () {
case $option in
(t)
# Avoid stderr if OPTARG is not set or empty or not an integer value:
test "$OPTARG" -ge 0 2>/dev/null && timeout=$OPTARG || Log "UserInput: Invalid -$option argument '$OPTARG' using fallback '$timeout'"
if test "$OPTARG" -ge 0 2>/dev/null ; then
timeout=$OPTARG
else
Log "UserInput: Invalid -$option argument '$OPTARG' using fallback '$timeout'"
fi
;;
(p)
prompt="$OPTARG"
Expand All @@ -1121,7 +1134,11 @@ function UserInput () {
;;
(n)
# Avoid stderr if OPTARG is not set or empty or not an integer value:
test "$OPTARG" -ge 0 2>/dev/null && input_max_chars=$OPTARG || Log "UserInput: Invalid -$option argument '$OPTARG' using fallback '$input_max_chars'"
if test "$OPTARG" -ge 0 2>/dev/null ; then
input_max_chars=$OPTARG
else
Log "UserInput: Invalid -$option argument '$OPTARG' using fallback '$input_max_chars'"
fi
;;
(d)
input_delimiter="$OPTARG"
Expand Down Expand Up @@ -1151,7 +1168,11 @@ function UserInput () {
done
test $user_input_ID || BugError "UserInput: Option '-I user_input_ID' required"
test "$( echo $user_input_ID | tr -c -d '[:lower:]' )" && BugError "UserInput: Option '-I' argument '$user_input_ID' must not contain lower case letters"
declare $user_input_ID="dummy" || BugError "UserInput: Option '-I' argument '$user_input_ID' not a valid variable name"
declare $user_input_ID="dummy" 2>/dev/null || BugError "UserInput: Option '-I' argument '$user_input_ID' not a valid variable name"
# Check the non-interactive mode and throw an error if default_input was not set
if is_true "$NON_INTERACTIVE" && is_true "${USER_INPUT_SEEN_WITH_TIMEOUT[$user_input_ID]}" 2>/dev/null; then
Error "UserInput: non-interactive mode and repeat input for '$user_input_ID' requested while the previous attempt was answered with the default or timed out"
fi
# Shift away the options and arguments:
shift "$(( OPTIND - 1 ))"
# Everything that is now left in "$@" is neither an option nor an option argument
Expand Down Expand Up @@ -1294,6 +1315,8 @@ function UserInput () {
fi
else
input_string="${!predefined_input_variable_name}"
# non-interactive - remember that UserInput didn't get interactive user input
is_true "$NON_INTERACTIVE" && USER_INPUT_SEEN_WITH_TIMEOUT[$user_input_ID]=true
# When a (non empty) input_words_array_name was specified it must contain all user input words:
test "$input_words_array_name" && read -a "$input_words_array_name" <<<"$input_string"
fi
Expand All @@ -1308,6 +1331,8 @@ function UserInput () {
is_true "$confidential_mode" && Log "UserInput: 'read' got user input" || Log "UserInput: 'read' got as user input '$input_string'"
else
return_code=1
# non-interactive - remember that UserInput didn't get interactive user input
is_true "$NON_INTERACTIVE" && USER_INPUT_SEEN_WITH_TIMEOUT[$user_input_ID]=true
# Continue in any case because in case of errors the default input is used.
# Avoid stderr if timeout is not set or empty or not an integer value:
if test "$timeout" -ge 1 2>/dev/null ; then
Expand Down
25 changes: 13 additions & 12 deletions usr/share/rear/lib/help-workflow.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,24 @@ fi

# Output the help text to the original STDOUT but keep STDERR in the log file:
cat 1>&7 <<EOF
Usage: $PROGRAM [-h|--help] [-V|--version] [-dsSv] [-D|--debugscripts SET] [-c DIR] [-C CONFIG] [-r KERNEL] [--] COMMAND [ARGS...]
Usage: $PROGRAM [-h|--help] [-V|--version] [-dsSv] [-D|--debugscripts SET] [-c DIR] [-C CONFIG] [-r KERNEL] [-n|--non-interactive] [--] COMMAND [ARGS...]
$PRODUCT comes with ABSOLUTELY NO WARRANTY; for details see
the GNU General Public License at: http://www.gnu.org/licenses/gpl.html
Available options:
-h --help usage information (this text)
-c DIR alternative config directory; instead of $CONFIG_DIR
-C CONFIG additional config files; absolute path or relative to config directory
-d debug mode; run many commands verbosely with debug messages in log file (also sets -v)
-D debugscript mode; log executed commands via 'set -x' (also sets -v and -d)
--debugscripts SET same as -d -v -D but debugscript mode with 'set -SET'
-r KERNEL kernel version to use; currently '$KERNEL_VERSION'
-s simulation mode; show what scripts are run (without executing them)
-S step-by-step mode; acknowledge each script individually
-v verbose mode; show messages what $PRODUCT is doing on the terminal or show verbose help
-V --version version information
-h --help usage information (this text)
-c DIR alternative config directory; instead of $CONFIG_DIR
-C CONFIG additional config files; absolute path or relative to config directory
-d debug mode; run many commands verbosely with debug messages in log file (also sets -v)
-D debugscript mode; log executed commands via 'set -x' (also sets -v and -d)
--debugscripts SET same as -d -v -D but debugscript mode with 'set -SET'
-r KERNEL kernel version to use; currently '$KERNEL_VERSION'
-s simulation mode; show what scripts are run (without executing them)
-S step-by-step mode; acknowledge each script individually
-v verbose mode; show messages what $PRODUCT is doing on the terminal or show verbose help
-V --version version information
-n --non-interactive non-interactive mode; aborts when any user input is required (experimental)
List of commands:
EOF
Expand Down
4 changes: 1 addition & 3 deletions usr/share/rear/skel/default/etc/scripts/system-setup
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,6 @@ if automatic_recovery ; then
"Go to Relax-and-Recover shell"
)
echo -e "\nLaunching 'rear recover' automatically\n"
# The recover workflow is always verbose (see usr/sbin/rear):
if rear $rear_debug_options recover ; then
echo -e "\n'rear recover' finished successfully\n"
choices+=( "Reboot" )
Expand Down Expand Up @@ -188,8 +187,7 @@ if unattended_recovery ; then
"Go to Relax-and-Recover shell"
)
echo -e "\nLaunching 'rear recover' automatically in unattended mode\n"
# The recover workflow is always verbose (see usr/sbin/rear):
if rear $rear_debug_options recover ; then
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ elif test $qlist_ret -eq 2; then
Error "CommVault 'qlogin -u $GALAXY11_USER -clp GALAXY11_PASSWORD' failed with exit code $? (retry on command line to see error messages)"
fi
else
is_true "$NON_INTERACTIVE" && \
Error "Login is not possible in non-interactive mode. Set variables GALAXY11_USER and GALAXY11_PASSWORD."

# try to logon manually
Print "Please logon to your Commvault CommServe with suitable credentials:"
qlogin $(test "$GALAXY11_Q_ARGUMENTFILE" && echo "-af $GALAXY11_Q_ARGUMENTFILE") 0<&6 1>&7 2>&8 || \
Expand Down

0 comments on commit 9cbd22d

Please sign in to comment.