Add new function, rlWaitForSocket, that can wait for a network service to start. To be used instead of `sleep' when testing network-centric services.
Signed-off-by: Hubert Kario hkario@redhat.com --- is the fatal error handling OK?
src/synchronisation.sh | 182 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 src/synchronisation.sh
diff --git a/src/synchronisation.sh b/src/synchronisation.sh new file mode 100644 index 0000000..66078e3 --- /dev/null +++ b/src/synchronisation.sh @@ -0,0 +1,182 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Name: synchronisation.sh - part of the BeakerLib project +# Description: Process synchronisation routines +# +# Author: Hubert Kario hkario@redhat.com +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2013 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +getopt -T || ret=$? +if [ ${ret:-0} -ne 4 ]; then + echo "ERROR: Non enhanced getopt version detected" 1>&2 + exit 1 +fi + +: <<'=cut' +=pod + +=head1 NAME + +BeakerLib - synchronisation - Process synchronisation routines + +=head1 DESCRIPTION + +This is a library of helpers for process synchronisation +of applications. + +=head1 FUNCTIONS + +=cut + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# name of routine +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +: <<'=cut' +=pod + +=head2 Process Synchronisation + +=head3 rlWaitForSocket + +Pauses script execution until socket starts listening. + + rlWaitForSocket {port|path} [-p PID] [-t time] + +=over + +=item port|path + +Network port to wait for opening or a path to UNIX socket. +Regular expressions are also supported. + +=item -t time + +Timeout in seconds (optional, default=120). If the socket +isn't opened between the time elapses the command FAILs. + +=item -p PID + +PID of the process to check before running command. If the process +exits before the socket is opened, the command FAILs. + +=back + +=cut + +rlWaitForSocket(){ + + local timeout=120 + local proc_pid=1 + local socket="" + local child_pid=0 + + # that is the GNU extended getopt syntax! + TEMP=$(getopt -o t:p: -n 'rlWaitForSocket' -- "$@") + if [[ $? != 0 ]] ; then echo "Terminating..." >&2 ; exit 1 ; fi + + eval set -- "$TEMP" + + while true ; do + case "$1" in + -t) timeout="$2"; shift 2 + ;; + -p) proc_pid="$2"; shift 2 + ;; + --) shift 1 + break + ;; + *) echo "Internal error!" >&2; exit 1 + ;; + esac + done + socket="$1" + # 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]*) echo "rlWaitForSocket: Invalid timeout provided" 1>&2; exit 1;; + esac + case "$proc_pid" in + ''|*[!0-9]*) echo "rlWaitForSocket: Invalid PID provided" 1>&2; exit 1;; + esac + case "$socket" in + ''|*[!0-9]*) + #socket_type="network" + grep_opt=":$socket[[:space:]]" + ;; + "") echo "rlWaitForSocket: Empty socket specified" 1>&2 + exit 1 + ;; + *) + #socket_type="unix" + grep_opt="$socket" + ;; + esac + rlLog "Waiting max ${timeout}s for socket `$socket' to start listening" + + ( while true ; do + netstat -nl | grep -E "$grep_opt" >/dev/null + if [[ $? -eq 0 ]]; then + exit 0; + else + if [[ ! -e "/proc/$proc_pid" ]]; then + exit 1; + fi + sleep 1 + fi + done ) & + netstat_pid=$! + + ( sleep $timeout && kill -HUP $netstat_pid ) 2>/dev/null & + watcher=$! + + wait $netstat_pid + ret=$? + if [[ $ret -eq 0 ]]; then + kill -s SIGKILL $watcher 2>/dev/null + rlLog "Socket opened!" + else + if [[ $ret -eq 1 ]]; then + kill -s SIGKILL $watcher 2>/dev/null + rlLogWarning "PID terminated!" + else + rlLogWarning "Timeout elapsed" + fi + fi +} + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# AUTHORS +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +: <<'=cut' +=pod + +=head1 AUTHORS + +=over + +=item * + +Hubert Kario hkario@redhat.com + +=back + +=cut