Poll rabbitmq:3-management in Docker for liveliness
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# https://www.shellcheck.net/ || https://github.com/koalaman/shellcheck | |
# Use of undefined variables is an error. | |
set -u | |
# Any process in a pipeline reporting a failure is an error. | |
set -o pipefail | |
# Stop the script on errors. | |
set -e | |
# Echoing to the terminal will print credentials to the terminal. | |
# (echoing to the terminal will print credentials to log files in plain text!!!) | |
set -x | |
RMQ_CONTAINER=rabbitmq:3-management | |
RMQ_USER=guest | |
# | |
# If the password file does not exist, then "insecure" is assumed. | |
RMQ_PASSWORD_FILE=/path/to/password/file | |
# | |
# rabbitmqctl is too primitive and requires the password as a command line | |
# parameter anyway, despite best practices. | |
RMQ_PASSWORD="$( | |
cat "${RMQ_PASSWORD_FILE}" 2>/dev/null || | |
echo "insecure" | |
)" | |
MAXIMUM_WAIT_SECONDS=30 | |
WAIT_START=$(date +%s) | |
echo -n "Waiting for RMQ container to be responsive" | |
while true | |
do | |
ELAPSED=$(date -d@$(( $(date +%s) - WAIT_START )) +%s) | |
if [[ "${MAXIMUM_WAIT_SECONDS}" -lt "${ELAPSED}" ]]; then | |
>&2 echo "RMQ was not available within the time specified." | |
exit 1 | |
fi | |
sleep 1 | |
echo -n "." | |
# Goal: | |
# We want to connect to RMQ's management plugin (HTTP) and query that it's online. | |
# | |
# Problem: | |
# Container does not (at the time of this writing) expose ports for the host | |
# system to connect. | |
# | |
# Solution: | |
# Connect to HTTP inside container. | |
# | |
# Compounded problem: | |
# Container does not have curl installed. | |
# | |
# Solution: | |
# Bash can connect. | |
# | |
# This is arguably a hack. See also: | |
# https://www.tldp.org/LDP/abs/html/devref1.html | |
# https://www.linuxjournal.com/content/more-using-bashs-built-devtcp-file-tcpip | |
# | |
# Warning: this may expose sensitive information (RMQ credentials) on command | |
# line. If this is not permissible, then you must find another solution. | |
# Inline comments need special attention. | |
# https://stackoverflow.com/a/23872003/1111557 | |
# | |
# And remember that the inlined script is double-quoted; double quotes in | |
# the script need to be escaped, and variables & subshells come from the | |
# host; if you need them from the container you need to escape the dollar. | |
# Example: | |
# `# Comments in the script need backticks around them.` | |
# echo ${PATH} `# This will echo the host's PATH` | |
# echo \${PATH} `# This will echo the container's PATH` | |
set +e | |
STATUS_CODE=$(docker exec "${RMQ_CONTAINER}" bash -c "\ | |
`# Attempt to connect to fd3. Remember fd0=stdin, fd1=stdout, fd2=stderr` | |
`# If connection failure, exit the script.` | |
exec 3<>/dev/tcp/127.0.0.1/15671 || exit 1 | |
`# Generate HTTP request header. Include authorization.` | |
`# See API documentation: http://127.0.0.1:15672/api` | |
`# This grabs RMQ_USER and an insecure password from the host environment.` | |
HTTP_HEADER=\"\ | |
GET /api/aliveness-test/%2f HTTP/1.1\r\n\ | |
Host: 127.0.0.1:15672\r\n\ | |
Connection: close\r\n\ | |
Authorization: Basic $(echo -n "${RMQ_USER}:${RMQ_PASSWORD}" | base64)\r\n | |
\r\n\" | |
`# Attempt to write header. Again, failure will kill the script.` | |
echo -ne \"\${HTTP_HEADER}\" || exit 1 | |
`# Attempt to read the response status code. Again, failure will kill the script.` | |
RESPONSE=\$(cat <&3) || exit 1 | |
STATUS_CODE=\$(echo \"\${RESPONSE}\" | head -n 1 | cut -d \" \" -f 1) | |
`# 200 indicates success.` | |
if [[ \"\${STATUS_CODE}\" -eq 200 ]]; then | |
exit 0 | |
fi | |
`# 401 indicates permanent failure: server *might* be ready but our credentials will never work.` | |
if [[ \"\${STATUS_CODE}\" -eq 401 ]]; then | |
>&2 echo \"\${STATUS_CODE}\" | |
exit 1 | |
fi | |
`# Any other status code assumes not ready.` | |
exit 1 | |
") | |
EXIT_STATUS=$? | |
set -e | |
if [[ "${EXIT_STATUS}" -eq 0 ]]; then break; fi | |
if [[ "${STATUS_CODE}" -eq "401" ]]; then | |
>&2 echo "RMQ Authorization denied." | |
exit 1 | |
fi | |
done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment