Permalink
#!/usr/bin/env bash | |
# Use this script to test if a given TCP host/port are available | |
cmdname=$(basename $0) | |
echoerr() { if [[ $QUIET -ne 1 ]]; then echo "$@" 1>&2; fi } | |
usage() | |
{ | |
cat << USAGE >&2 | |
Usage: | |
$cmdname host:port [-s] [-t timeout] [-- command args] | |
-h HOST | --host=HOST Host or IP under test | |
-p PORT | --port=PORT TCP port under test | |
Alternatively, you specify the host and port as host:port | |
-s | --strict Only execute subcommand if the test succeeds | |
-q | --quiet Don't output any status messages | |
-t TIMEOUT | --timeout=TIMEOUT | |
Timeout in seconds, zero for no timeout | |
-- COMMAND ARGS Execute command with args after the test finishes | |
USAGE | |
exit 1 | |
} | |
wait_for() | |
{ | |
if [[ $TIMEOUT -gt 0 ]]; then | |
echoerr "$cmdname: waiting $TIMEOUT seconds for $HOST:$PORT" | |
else | |
echoerr "$cmdname: waiting for $HOST:$PORT without a timeout" | |
fi | |
start_ts=$(date +%s) | |
while : | |
do | |
(echo > /dev/tcp/$HOST/$PORT) >/dev/null 2>&1 | |
result=$? | |
if [[ $result -eq 0 ]]; then | |
end_ts=$(date +%s) | |
echoerr "$cmdname: $HOST:$PORT is available after $((end_ts - start_ts)) seconds" | |
break | |
fi | |
sleep 1 | |
done | |
return $result | |
} | |
wait_for_wrapper() | |
{ | |
# In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692 | |
if [[ $QUIET -eq 1 ]]; then | |
timeout $TIMEOUT $0 --quiet --child --host=$HOST --port=$PORT --timeout=$TIMEOUT & | |
else | |
timeout $TIMEOUT $0 --child --host=$HOST --port=$PORT --timeout=$TIMEOUT & | |
fi | |
PID=$! | |
trap "kill -INT -$PID" INT | |
wait $PID | |
RESULT=$? | |
if [[ $RESULT -ne 0 ]]; then | |
echoerr "$cmdname: timeout occurred after waiting $TIMEOUT seconds for $HOST:$PORT" | |
fi | |
return $RESULT | |
} | |
# process arguments | |
while [[ $# -gt 0 ]] | |
do | |
case "$1" in | |
*:* ) | |
hostport=(${1//:/ }) | |
HOST=${hostport[0]} | |
PORT=${hostport[1]} | |
shift 1 | |
;; | |
--child) | |
CHILD=1 | |
shift 1 | |
;; | |
-q | --quiet) | |
QUIET=1 | |
shift 1 | |
;; | |
-s | --strict) | |
STRICT=1 | |
shift 1 | |
;; | |
-h) | |
HOST="$2" | |
if [[ $HOST == "" ]]; then break; fi | |
shift 2 | |
;; | |
--host=*) | |
HOST="${1#*=}" | |
shift 1 | |
;; | |
-p) | |
PORT="$2" | |
if [[ $PORT == "" ]]; then break; fi | |
shift 2 | |
;; | |
--port=*) | |
PORT="${1#*=}" | |
shift 1 | |
;; | |
-t) | |
TIMEOUT="$2" | |
if [[ $TIMEOUT == "" ]]; then break; fi | |
shift 2 | |
;; | |
--timeout=*) | |
TIMEOUT="${1#*=}" | |
shift 1 | |
;; | |
--) | |
shift | |
CLI="$@" | |
break | |
;; | |
--help) | |
usage | |
;; | |
*) | |
echoerr "Unknown argument: $1" | |
usage | |
;; | |
esac | |
done | |
if [[ "$HOST" == "" || "$PORT" == "" ]]; then | |
echoerr "Error: you need to provide a host and port to test." | |
usage | |
fi | |
TIMEOUT=${TIMEOUT:-15} | |
STRICT=${STRICT:-0} | |
CHILD=${CHILD:-0} | |
QUIET=${QUIET:-0} | |
if [[ $CHILD -gt 0 ]]; then | |
wait_for | |
RESULT=$? | |
exit $RESULT | |
else | |
if [[ $TIMEOUT -gt 0 ]]; then | |
wait_for_wrapper | |
RESULT=$? | |
else | |
wait_for | |
RESULT=$? | |
fi | |
fi | |
if [[ $CLI != "" ]]; then | |
if [[ $RESULT -ne 0 && $STRICT -eq 1 ]]; then | |
echoerr "$cmdname: strict mode, refusing to execute subprocess" | |
exit $RESULT | |
fi | |
exec $CLI | |
else | |
exit $RESULT | |
fi |