wait-for-it.sh 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. #!/usr/bin/env bash
  2. # Use this script to test if a given TCP host/port are available
  3. cmdname=$(basename $0)
  4. echoerr() { if [[ $QUIET -ne 1 ]]; then echo "$@" 1>&2; fi }
  5. usage()
  6. {
  7. cat << USAGE >&2
  8. Usage:
  9. $cmdname host:port [-s] [-t timeout] [-- command args]
  10. -h HOST | --host=HOST Host or IP under test
  11. -p PORT | --port=PORT TCP port under test
  12. Alternatively, you specify the host and port as host:port
  13. -s | --strict Only execute subcommand if the test succeeds
  14. -q | --quiet Don't output any status messages
  15. -t TIMEOUT | --timeout=TIMEOUT
  16. Timeout in seconds, zero for no timeout
  17. -- COMMAND ARGS Execute command with args after the test finishes
  18. USAGE
  19. exit 1
  20. }
  21. wait_for()
  22. {
  23. if [[ $TIMEOUT -gt 0 ]]; then
  24. echoerr "$cmdname: waiting $TIMEOUT seconds for $HOST:$PORT"
  25. else
  26. echoerr "$cmdname: waiting for $HOST:$PORT without a timeout"
  27. fi
  28. start_ts=$(date +%s)
  29. while :
  30. do
  31. if [[ $ISBUSY -eq 1 ]]; then
  32. nc -z $HOST $PORT
  33. result=$?
  34. else
  35. (echo > /dev/tcp/$HOST/$PORT) >/dev/null 2>&1
  36. result=$?
  37. fi
  38. if [[ $result -eq 0 ]]; then
  39. end_ts=$(date +%s)
  40. echoerr "$cmdname: $HOST:$PORT is available after $((end_ts - start_ts)) seconds"
  41. break
  42. fi
  43. sleep 1
  44. done
  45. return $result
  46. }
  47. wait_for_wrapper()
  48. {
  49. # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692
  50. if [[ $QUIET -eq 1 ]]; then
  51. timeout $BUSYTIMEFLAG $TIMEOUT $0 --quiet --child --host=$HOST --port=$PORT --timeout=$TIMEOUT &
  52. else
  53. timeout $BUSYTIMEFLAG $TIMEOUT $0 --child --host=$HOST --port=$PORT --timeout=$TIMEOUT &
  54. fi
  55. PID=$!
  56. trap "kill -INT -$PID" INT
  57. wait $PID
  58. RESULT=$?
  59. if [[ $RESULT -ne 0 ]]; then
  60. echoerr "$cmdname: timeout occurred after waiting $TIMEOUT seconds for $HOST:$PORT"
  61. fi
  62. return $RESULT
  63. }
  64. # process arguments
  65. while [[ $# -gt 0 ]]
  66. do
  67. case "$1" in
  68. *:* )
  69. hostport=(${1//:/ })
  70. HOST=${hostport[0]}
  71. PORT=${hostport[1]}
  72. shift 1
  73. ;;
  74. --child)
  75. CHILD=1
  76. shift 1
  77. ;;
  78. -q | --quiet)
  79. QUIET=1
  80. shift 1
  81. ;;
  82. -s | --strict)
  83. STRICT=1
  84. shift 1
  85. ;;
  86. -h)
  87. HOST="$2"
  88. if [[ $HOST == "" ]]; then break; fi
  89. shift 2
  90. ;;
  91. --host=*)
  92. HOST="${1#*=}"
  93. shift 1
  94. ;;
  95. -p)
  96. PORT="$2"
  97. if [[ $PORT == "" ]]; then break; fi
  98. shift 2
  99. ;;
  100. --port=*)
  101. PORT="${1#*=}"
  102. shift 1
  103. ;;
  104. -t)
  105. TIMEOUT="$2"
  106. if [[ $TIMEOUT == "" ]]; then break; fi
  107. shift 2
  108. ;;
  109. --timeout=*)
  110. TIMEOUT="${1#*=}"
  111. shift 1
  112. ;;
  113. --)
  114. shift
  115. CLI=("$@")
  116. break
  117. ;;
  118. --help)
  119. usage
  120. ;;
  121. *)
  122. echoerr "Unknown argument: $1"
  123. usage
  124. ;;
  125. esac
  126. done
  127. if [[ "$HOST" == "" || "$PORT" == "" ]]; then
  128. echoerr "Error: you need to provide a host and port to test."
  129. usage
  130. fi
  131. TIMEOUT=${TIMEOUT:-15}
  132. STRICT=${STRICT:-0}
  133. CHILD=${CHILD:-0}
  134. QUIET=${QUIET:-0}
  135. # check to see if timeout is from busybox?
  136. # check to see if timeout is from busybox?
  137. TIMEOUT_PATH=$(realpath $(which timeout))
  138. if [[ $TIMEOUT_PATH =~ "busybox" ]]; then
  139. ISBUSY=1
  140. BUSYTIMEFLAG="-t"
  141. else
  142. ISBUSY=0
  143. BUSYTIMEFLAG=""
  144. fi
  145. if [[ $CHILD -gt 0 ]]; then
  146. wait_for
  147. RESULT=$?
  148. exit $RESULT
  149. else
  150. if [[ $TIMEOUT -gt 0 ]]; then
  151. wait_for_wrapper
  152. RESULT=$?
  153. else
  154. wait_for
  155. RESULT=$?
  156. fi
  157. fi
  158. if [[ $CLI != "" ]]; then
  159. if [[ $RESULT -ne 0 && $STRICT -eq 1 ]]; then
  160. echoerr "$cmdname: strict mode, refusing to execute subprocess"
  161. exit $RESULT
  162. fi
  163. exec "${CLI[@]}"
  164. else
  165. exit $RESULT
  166. fi