[PATCH v2 4/6] add rlWaitForCmd
Hubert Kario
hkario at redhat.com
Wed Nov 20 19:04:12 UTC 2013
add routine that allows waiting for any command to return
specified exit code
Signed-off-by: Hubert Kario <hkario at redhat.com>
---
src/synchronisation.sh | 185 ++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 184 insertions(+), 1 deletion(-)
diff --git a/src/synchronisation.sh b/src/synchronisation.sh
index e782481..2885058 100644
--- a/src/synchronisation.sh
+++ b/src/synchronisation.sh
@@ -57,6 +57,136 @@ __INTERNAL_killtree() {
return ${_ret:-0}
}
+# Since all "wait for something to happen" utilities are basically the same,
+# use a generic routine that can do all their work
+__INTERNAL_wait_for_cmd() {
+
+ # don't wait more than this many seconds
+ local timeout=120
+ # delay between command invocations
+ local delay=1
+ # abort if this process terminates
+ local proc_pid=1
+ # command to run
+ local cmd
+ # maximum number of command invocations
+ local max_invoc=""
+ # expected return code of command
+ local exp_retval=0
+ # name of routine to return errors for
+ local routine_name="$1"
+ shift 1
+
+ # that is the GNU extended getopt syntax!
+ local TEMP=$(getopt -o t:p:m:d:r: -n '$routine_name' -- "$@")
+ if [[ $? != 0 ]] ; then
+ rlLogError "$routine_name: Can't parse command options, terminating..."
+ return 127
+ fi
+
+ eval set -- "$TEMP"
+
+ while true ; do
+ case "$1" in
+ -t) timeout="$2"; shift 2
+ ;;
+ -p) proc_pid="$2"; shift 2
+ ;;
+ -m) max_invoc="$2"; shift 2
+ ;;
+ -d) delay="$2"; shift 2
+ ;;
+ -r) exp_retval="$2"; shift 2
+ ;;
+ --) shift 1
+ break
+ ;;
+ *) rlLogError "$routine_name: unrecognized option"
+ return 127
+ ;;
+ esac
+ done
+ cmd="$1"
+
+ if [[ $routine_name == "rlWaitForCmd" ]]; then
+ rlLogInfo "$routine_name: waiting for \`$cmd' to return $exp_retval in $timeout seconds"
+ fi
+
+ # the case statement is a portable way to check if variable contains only
+ # digits (regexps are not available in old, RHEL3-era, bash)
+ case "$timeout" in
+ ''|*[!0-9]*) rlLogError "${routine_name}: Invalid timeout provided"
+ return 127
+ ;;
+ esac
+ case "$proc_pid" in
+ ''|*[!0-9]*) rlLogError "${routine_name}: Invalid PID provided"
+ return 127
+ ;;
+ esac
+ if [[ -n "$max_invoc" ]]; then
+ case "$max_invoc" in
+ ''|*[!0-9]*) rlLogError "${routine_name}: Invalid maximum number of invocations provided"
+ return 127
+ ;;
+ esac
+ fi
+ # delay can be fractional, so "." is OK
+ case "$delay" in
+ ''|*[!0-9.]*) rlLogError "${routine_name}: Invalid delay specified"
+ return 127
+ ;;
+ esac
+ case "$exp_retval" in
+ ''|*[!0-9]*) rlLogError "${routine_name}: Invalid expected command return value provided"
+ return 127
+ ;;
+ esac
+
+ # we use two child processes to get the timeout and process execution
+ # one (command_pid) runs the command until it returns expected return value
+ # the other is just a timout (watcher)
+
+ # run command in loop
+ ( local i=0
+ while [[ -n $max_invoc && $i -lt $max_invoc ]] || [[ ! -n $max_invoc ]]; do
+ eval $cmd
+ if [[ $? -eq $exp_retval ]]; then
+ exit 0;
+ else
+ if [[ ! -e "/proc/$proc_pid" ]]; then
+ exit 1;
+ fi
+ sleep $delay
+ fi
+ i=$((i+1))
+ done
+ exit 1) &
+ local command_pid=$!
+
+ # kill command running in background if the timout has elapsed
+ ( sleep $timeout && __INTERNAL_killtree $command_pid SIGKILL) 2>/dev/null &
+ local watcher=$!
+
+ wait $command_pid 2> /dev/null
+ local ret=$?
+ if [[ $ret -eq 0 ]]; then
+ __INTERNAL_killtree $watcher SIGKILL 2>/dev/null
+ wait $watcher 2> /dev/null
+ rlLogInfo "${routine_name}: Wait successful!"
+ return 0
+ else
+ if [[ $ret -eq 1 ]]; then
+ __INTERNAL_killtree $watcher SIGKILL 2>/dev/null
+ wait $watcher 2> /dev/null
+ rlLogWarning "${routine_name}: PID terminated!"
+ else
+ rlLogWarning "${routine_name}: Timeout elapsed"
+ fi
+ return 1
+ fi
+}
+
: <<'=cut'
=pod
@@ -74,13 +204,66 @@ of applications.
=cut
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-# rlWaitForSocket
+# rlWaitForCmd
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
: <<'=cut'
=pod
=head2 Process Synchronisation
+=head3 rlWaitForCmd
+
+Pauses script execution until command exit status is the expeced value.
+Logs a WARNING and returns 1 if the command didn't exit successfully
+before timeout elapsed or a maximum number of invocations has been
+reached.
+
+ rlWaitForCmd command [-p PID] [-t time] [-n count] [-d delay] [-r retval]
+
+=over
+
+=item command
+
+Command that will be executed until its return code is equal 0 or value
+speciefied as option to `-r'.
+
+=item -t time
+
+Timeout in seconds, default=120. If the command doesn't return 0
+before time elapses, the command will be killed.
+
+=item -p PID
+
+PID of the process to check before running command. If the process
+exits before the socket is opened, the command will log a WARNING.
+
+=item -m count
+
+Maximum number of `command' executions before continuing anyway. Default is
+infite.
+
+=item -d delay
+
+Delay between `command' invocations. Default 1.
+
+=item -r retval
+
+Expected return value of command. Default 0.
+
+=back
+
+=cut
+rlWaitForCmd() {
+ __INTERNAL_wait_for_cmd rlWaitForCmd "$@"
+}
+
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# rlWaitForSocket
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+: <<'=cut'
+=pod
+
=head3 rlWaitForSocket
Pauses script execution until socket starts listening.
--
1.8.3.1
More information about the beakerlib-devel
mailing list