pax_global_header00006660000000000000000000000064131351440400014505gustar00rootroot0000000000000052 comment=db049716e42767d39961e95dd9696103dca813f1 wait-for-it-master/000077500000000000000000000000001313514404000145045ustar00rootroot00000000000000wait-for-it-master/.gitignore000066400000000000000000000000301313514404000164650ustar00rootroot00000000000000**/*.pyc .pydevproject wait-for-it-master/.travis.yml000066400000000000000000000001141313514404000166110ustar00rootroot00000000000000language: python python: - "2.7" script: - python test/wait-for-it.py wait-for-it-master/LICENSE000066400000000000000000000020641313514404000155130ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2016 Giles Hall Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. wait-for-it-master/README.md000066400000000000000000000051201313514404000157610ustar00rootroot00000000000000## wait-for-it `wait-for-it.sh` is a pure bash script that will wait on the availability of a host and TCP port. It is useful for synchronizing the spin-up of interdependent services, such as linked docker containers. Since it is a pure bash script, it does not have any external dependencies. ## Usage ``` wait-for-it.sh 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 ``` ## Examples For example, let's test to see if we can access port 80 on www.google.com, and if it is available, echo the message `google is up`. ``` $ ./wait-for-it.sh www.google.com:80 -- echo "google is up" wait-for-it.sh: waiting 15 seconds for www.google.com:80 wait-for-it.sh: www.google.com:80 is available after 0 seconds google is up ``` You can set your own timeout with the `-t` or `--timeout=` option. Setting the timeout value to 0 will disable the timeout: ``` $ ./wait-for-it.sh -t 0 www.google.com:80 -- echo "google is up" wait-for-it.sh: waiting for www.google.com:80 without a timeout wait-for-it.sh: www.google.com:80 is available after 0 seconds google is up ``` The subcommand will be executed regardless if the service is up or not. If you wish to execute the subcommand only if the service is up, add the `--strict` argument. In this example, we will test port 81 on www.google.com which will fail: ``` $ ./wait-for-it.sh www.google.com:81 --timeout=1 --strict -- echo "google is up" wait-for-it.sh: waiting 1 seconds for www.google.com:81 wait-for-it.sh: timeout occurred after waiting 1 seconds for www.google.com:81 wait-for-it.sh: strict mode, refusing to execute subprocess ``` If you don't want to execute a subcommand, leave off the `--` argument. This way, you can test the exit condition of `wait-for-it.sh` in your own scripts, and determine how to proceed: ``` $ ./wait-for-it.sh www.google.com:80 wait-for-it.sh: waiting 15 seconds for www.google.com:80 wait-for-it.sh: www.google.com:80 is available after 0 seconds $ echo $? 0 $ ./wait-for-it.sh www.google.com:81 wait-for-it.sh: waiting 15 seconds for www.google.com:81 wait-for-it.sh: timeout occurred after waiting 15 seconds for www.google.com:81 $ echo $? 124 ``` wait-for-it-master/test/000077500000000000000000000000001313514404000154635ustar00rootroot00000000000000wait-for-it-master/test/wait-for-it.py000066400000000000000000000126271313514404000202070ustar00rootroot00000000000000import unittest import shlex from subprocess import Popen, PIPE import os import sys import socket import re MISSING_ARGS_TEXT = "Error: you need to provide a host and port to test." HELP_TEXT = "Usage:" # Start of help text DIVIDE_LINE = '-'*71 # Output line of dashes class TestWaitForIt(unittest.TestCase): """ TestWaitForIt tests the wait-for-it.sh shell script. The wait-for-it.sh script is assumed to be in the parent directory to the test script. """ def execute(self, cmd): """Executes a command and returns exit code, STDOUT, STDERR""" args = shlex.split(cmd) proc = Popen(args, stdout=PIPE, stderr=PIPE) out, err = proc.communicate() exitcode = proc.returncode return exitcode, out, err def open_local_port(self, host="localhost", port=8929, timeout=5): s = socket.socket() s.bind((host, port)) s.listen(timeout) return s def check_args(self, args, stdout_regex, stderr_regex, exitcode): command = self.wait_script + " " + args actual_exitcode, out, err = self.execute(command) # Check stderr msg = ("Failed check that STDERR:\n" + DIVIDE_LINE + "\n" + err + "\n" + DIVIDE_LINE + "\nmatches:\n" + DIVIDE_LINE + "\n" + stderr_regex + "\n" + DIVIDE_LINE) self.assertIsNotNone(re.match(stderr_regex, err, re.DOTALL), msg) # Check STDOUT msg = ("Failed check that STDOUT:\n" + DIVIDE_LINE + "\n" + out + "\n" + DIVIDE_LINE + "\nmatches:\n" + DIVIDE_LINE + "\n" + stdout_regex + "\n" + DIVIDE_LINE) self.assertIsNotNone(re.match(stdout_regex, out, re.DOTALL), msg) # Check exit code self.assertEqual(actual_exitcode, exitcode) def setUp(self): script_path = os.path.dirname(sys.argv[0]) parent_path = os.path.abspath(os.path.join(script_path, os.pardir)) self.wait_script = os.path.join(parent_path, "wait-for-it.sh") def test_no_args(self): """ Check that no aruments returns the missing args text and the correct return code """ self.check_args( "", "^$", MISSING_ARGS_TEXT, 1 ) # Return code should be 1 when called with no args exitcode, out, err = self.execute(self.wait_script) self.assertEqual(exitcode, 1) def test_help(self): """ Check that help text is printed with --help argument """ self.check_args( "--help", "", HELP_TEXT, 1 ) def test_no_port(self): """ Check with missing port argument """ self.check_args( "--host=localhost", "", MISSING_ARGS_TEXT, 1 ) def test_no_host(self): """ Check with missing hostname argument """ self.check_args( "--port=80", "", MISSING_ARGS_TEXT, 1 ) def test_host_port(self): """ Check that --host and --port args work correctly """ soc = self.open_local_port(port=8929) self.check_args( "--host=localhost --port=8929 --timeout=1", "", "wait-for-it.sh: waiting 1 seconds for localhost:8929", 0 ) soc.close() def test_combined_host_port(self): """ Tests that wait-for-it.sh returns correctly after establishing a connectionm using combined host and ports """ soc = self.open_local_port(port=8929) self.check_args( "localhost:8929 --timeout=1", "", "wait-for-it.sh: waiting 1 seconds for localhost:8929", 0 ) soc.close() def test_port_failure_with_timeout(self): """ Note exit status of 124 is exected, passed from the timeout command """ self.check_args( "localhost:8929 --timeout=1", "", ".*timeout occurred after waiting 1 seconds for localhost:8929", 124 ) def test_command_execution(self): """ Checks that a command executes correctly after a port test passes """ soc = self.open_local_port(port=8929) self.check_args( "localhost:8929 -- echo \"CMD OUTPUT\"", "CMD OUTPUT", ".*wait-for-it.sh: localhost:8929 is available after 0 seconds", 0 ) soc.close() def test_failed_command_execution(self): """ Check command failure. The command in question outputs STDERR and an exit code of 2 """ soc = self.open_local_port(port=8929) self.check_args( "localhost:8929 -- ls not_real_file", "", ".*No such file or directory\n", 2 ) soc.close() def test_command_after_connection_failure(self): """ Test that a command still runs even if a connection times out and that the return code is correct for the comand being run """ self.check_args( "localhost:8929 --timeout=1 -- echo \"CMD OUTPUT\"", "CMD OUTPUT", ".*timeout occurred after waiting 1 seconds for localhost:8929", 0 ) if __name__ == '__main__': unittest.main() wait-for-it-master/wait-for-it.sh000077500000000000000000000077571313514404000172250ustar00rootroot00000000000000#!/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 if [[ $ISBUSY -eq 1 ]]; then nc -z $HOST $PORT result=$? else (echo > /dev/tcp/$HOST/$PORT) >/dev/null 2>&1 result=$? fi 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 $BUSYTIMEFLAG $TIMEOUT $0 --quiet --child --host=$HOST --port=$PORT --timeout=$TIMEOUT & else timeout $BUSYTIMEFLAG $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} # check to see if timeout is from busybox? # check to see if timeout is from busybox? TIMEOUT_PATH=$(realpath $(which timeout)) if [[ $TIMEOUT_PATH =~ "busybox" ]]; then ISBUSY=1 BUSYTIMEFLAG="-t" else ISBUSY=0 BUSYTIMEFLAG="" fi 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