Skip to content

Instantly share code, notes, and snippets.

@mwoodpatrick
Forked from lcrilly/README.md
Created September 6, 2022 12:31
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mwoodpatrick/ffc860792b9f695a873511815b75768f to your computer and use it in GitHub Desktop.
Save mwoodpatrick/ffc860792b9f695a873511815b75768f to your computer and use it in GitHub Desktop.
unitc - a curl wrapper for configuring NGINX Unit

unitc

A curl wrapper for configuring NGINX Unit

Just provide the configuration URI (e.g. /config/routes) and unitc will find the control socket to construct the full address in curl syntax.

USAGE: unitc [HTTP method] [--quiet] URI

Providing a JSON configuration on stdin will use the PUT method unless a specific method is specified. Otherwise a GET is used to read the configuration. HTTP methods can be specified in lower case. jq is used to prettify the output, if available.

When making changes, the error log is monitored and new log entries are shown.

Examples:

unitc /config
unitc /control/applications/my_app/restart
echo '{"*:8080": {"pass": "routes"}}' | unitc /config/listeners
unitc /config < unitconf.json
unitc delete /config/routes
#!/bin/bash
# unitc - a curl wrapper for configuring NGINX Unit
# [v1.3 30-Jul-2022] Liam Crilly <liam@nginx.com>
#
# CHANGELOG
# v1.3 Bug fixes and improved error handling
# v1.2 Accepts lower-case HTTP methods, simpler/portable cache format
# v1.1 Uses jq(1) if available for prettified output, added --help
# v1.0 Initial version with socket detection and log monitoring
#
# TODO
# - Iteratively scan for new log entries
# - Optionally provide JSON config as filename on command line
# Defaults
#
QUIET=0
METHOD=PUT
SHOW_LOG=1
while [ $# -gt 1 ]; do
OPTION=`echo $1 | tr '[a-z]' '[A-Z]'`
case $OPTION in
"-H" | "--HELP")
shift
;;
"-Q" | "--QUIET")
QUIET=1
shift
;;
"GET" | "PUT" | "POST" | "DELETE")
METHOD=$OPTION
shift
;;
"HEAD" | "PATCH" | "PURGE" | "OPTIONS")
echo "${0##*/}: ERROR: Invalid HTTP method ($OPTION)"
exit 1
;;
*)
echo "${0##*/}: ERROR: Invalid option ($1)"
exit 1
;;
esac
done
if [ $# -lt 1 ] || [ "${1:0:1}" = "-" ]; then
echo "USAGE: ${0##*/} [HTTP method] [--quiet] URI"
echo " - Configuration JSON is read from stdin"
echo " - Default method is PUT with stdin, else GET"
echo " - The control socket is automatically detected"
exit 1
fi
if [ "${1:0:1}" != "/" ]; then
echo "${0##*/}: ERROR: Invalid configuration URI"
exit 1
fi
# Check if Unit is running, find the main process
#
PID=(`ps ax | grep unit:\ main | grep -v \ grep | awk '{print $1}'`)
if [ ${#PID[@]} -eq 0 ]; then
echo "${0##*/}: ERROR: unitd not running"
exit 1
elif [ ${#PID[@]} -gt 1 ]; then
echo "${0##*/}: ERROR: multiple unitd processes detected (${PID[@]})"
exit 1
fi
# Read the significant unitd conifuration from cache file (or create it)
#
if [[ -f /tmp/${0##*/}.$PID ]]; then
source /tmp/${0##*/}.$PID
else
PARAMS=`ps -p $PID | grep unitd | cut -f2- -dv | tr '[]' ' ' | cut -f4- -d ' ' | sed -e 's/ --/\n--/g'`
# Get control address
#
CTRL_ADDR=`echo "$PARAMS" | grep '\--control' | cut -f2 -d' '`
if [ "$CTRL_ADDR" = "" ]; then
CTRL_ADDR=`unitd --help | grep -A1 '\--control' | tail -1 | cut -f2 -d\"`
fi
# Prepare for network or Unix socket addressing
#
if [ `echo $CTRL_ADDR | grep -c ^unix:` -eq 1 ]; then
CURL_ADDR="--unix-socket `echo $CTRL_ADDR | cut -f2- -d:` _"
else
CURL_ADDR="http://$CTRL_ADDR"
fi
# Get error log filename
#
ERROR_LOG=`echo "$PARAMS" | grep '\--log' | cut -f2 -d' '`
if [ "$ERROR_LOG" = "" ]; then
ERROR_LOG=`unitd --help | grep -A1 '\--log' | tail -1 | cut -f2 -d\"`
fi
# Cache the discovery for this unit PID (and cleanup any old files)
#
rm /tmp/${0##*/}.* 2> /dev/null
echo CURL_ADDR=\"${CURL_ADDR}\" > /tmp/${0##*/}.$PID
echo ERROR_LOG=${ERROR_LOG} >> /tmp/${0##*/}.$PID
fi
# Test for jq
#
if hash jq 2> /dev/null; then
PRETTY="jq"
else
PRETTY="cat"
fi
# Get current length of error log before we make any changes
#
if [ -f $ERROR_LOG ]; then
LOG_LEN=`wc -l < $ERROR_LOG`
else
QUIET=1
fi
# Adjust HTTP method and curl params based on presence of stdin payload
#
if [ -t 0 ]; then
if [ "$METHOD" = "DELETE" ]; then
curl -s -X $METHOD $CURL_ADDR$1 | $PRETTY
else
SHOW_LOG=0
curl -s $CURL_ADDR$1 | $PRETTY
fi
else
echo "$(cat)" | curl -s -X $METHOD --data-binary @- $CURL_ADDR$1 | $PRETTY
fi
if [ ${PIPESTATUS[0]} -ne 0 ]; then
echo "${0##*/}: ERROR: curl exited with an error"
fi
if [[ $SHOW_LOG -gt 0 && $QUIET -eq 0 ]]; then
echo -n "${0##*/}: Waiting for log..."
sleep $SHOW_LOG
echo ""
sed -n $((LOG_LEN+1)),\$p $ERROR_LOG
fi
# vim: syntax=bash
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment