Moved to GitHub repo https://github.com/lcrilly/unitc
Last active
November 25, 2022 17:45
-
-
Save lcrilly/2c2ed15bf2f7895d354a8e96be05b71d to your computer and use it in GitHub Desktop.
unitc - a curl wrapper for configuring NGINX Unit
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
#!/bin/bash | |
# unitc - a curl wrapper for configuring NGINX Unit | |
# NGINX, Inc. (c) 2022 | |
# Defaults | |
# | |
ERROR_LOG=/dev/null | |
REMOTE=0 | |
QUIET=0 | |
METHOD=PUT | |
SHOW_LOG=1 | |
URI="" | |
while [ $# -gt 0 ]; do | |
OPTION=$(echo $1 | tr '[a-z]' '[A-Z]') | |
case $OPTION in | |
"-H" | "--HELP") | |
shift | |
;; | |
"-Q" | "--QUIET") | |
QUIET=1 | |
shift | |
;; | |
"GET" | "PUT" | "POST" | "DELETE" | "INSERT") | |
METHOD=$OPTION | |
shift | |
;; | |
"HEAD" | "PATCH" | "PURGE" | "OPTIONS") | |
echo "${0##*/}: ERROR: Invalid HTTP method ($OPTION)" | |
exit 1 | |
;; | |
*) | |
if [ "${1:0:1}" = "/" ] || [ "${1:0:4}" = "http" ]; then | |
URI=$1 | |
shift | |
else | |
echo "${0##*/}: ERROR: Invalid option ($1)" | |
exit 1 | |
fi | |
;; | |
esac | |
done | |
if [ "$URI" = "" ]; then | |
echo "${0##*/} - a curl wrapper for configuring NGINX Unit" | |
echo "" | |
echo "USAGE: ${0##*/} [--quiet] [HTTP method] URI" | |
echo "" | |
echo " URI is for the Unit configuration API, e.g. /config" | |
echo " URI with protocol (e.g. http://...) can be used for remote configuration" | |
echo " --quiet (-q) Will not monitor the error log after config changes" | |
echo "" | |
echo " • Environment variable \$UNIT_CTRL may specify remote host" | |
echo " • Configuration JSON is read from stdin" | |
echo " • Default HTTP method is PUT for config changes, else GET" | |
echo " • Virtual method INSERT adds to beginning of array" | |
echo " • Options can appear in any position, e.g. method after URI" | |
echo " • The control socket is automatically detected for local installations" | |
echo "" | |
exit 1 | |
fi | |
# Figure out if we're running on the Unit host, or remotely | |
# | |
if [ "$UNIT_CTRL" = "" ]; then | |
if [ "${URI:0:4}" = "http" ]; then | |
REMOTE=1 | |
UNIT_CTRL=$(echo "$URI" | cut -f1-3 -d/) | |
URI=/$(echo "$URI" | cut -f4- -d/) | |
fi | |
elif [ "${URI:0:1}" = "/" ]; then | |
REMOTE=1 | |
fi | |
if [ $REMOTE -eq 0 ]; then | |
# 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 [ -r /tmp/${0##*/}.$PID.env ]; then | |
source /tmp/${0##*/}.$PID.env | |
else | |
# Check we have all the tools we need in $PATH | |
# | |
MISSING=$(hash curl ps grep tr sed tail sleep 2>&1 | cut -f4 -d: | tr -d '\n') | |
if [ "$MISSING" != "" ]; then | |
echo "${0##*/}: ERROR: cannot find$MISSING: please install or add to \$PATH" | |
exit 1 | |
fi | |
PARAMS=$(ps $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 | |
SOCK_FILE=$(echo $CTRL_ADDR | cut -f2- -d:) | |
if [ -r $SOCK_FILE ]; then | |
UNIT_CTRL="--unix-socket $SOCK_FILE _" | |
else | |
echo "${0##*/}: ERROR: cannot read unitd control socket: $SOCK_FILE" | |
ls -l $SOCK_FILE | |
exit 2 | |
fi | |
else | |
UNIT_CTRL="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 UNIT_CTRL=\"${UNIT_CTRL}\" > /tmp/${0##*/}.$PID.env | |
echo ERROR_LOG=${ERROR_LOG} >> /tmp/${0##*/}.$PID.env | |
fi | |
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 ] && [ -r $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 -X $METHOD $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $PRETTY | |
else | |
SHOW_LOG=$(echo $URI | grep -c ^/control/) | |
curl $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $PRETTY | |
fi | |
else | |
if [ "$METHOD" = "INSERT" ]; then | |
if [ "$PRETTY" != "jq" ]; then | |
echo "${0##*/}: ERROR: jq(1) is required to use INSERT method, install at <https://stedolan.github.io/jq/>" | |
exit 1 | |
fi | |
CURR_VAL=$(curl -s $UNIT_CTRL$URI) | |
if [ "$(echo $CURR_VAL | jq -r type)" = "array" ]; then | |
SUFFIX=$(cat) | |
echo $CURR_VAL | jq ". |= [$SUFFIX] + ." | curl -X PUT --data-binary @- $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $PRETTY | |
else | |
echo "${0##*/}: ERROR: INSERT method must be used with an array" | |
exit 3 | |
fi | |
else | |
echo "$(cat)" | curl -X $METHOD --data-binary @- $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $PRETTY | |
fi | |
fi | |
CURL_STATUS=${PIPESTATUS[0]} | |
if [ $CURL_STATUS -ne 0 ]; then | |
echo "${0##*/}: ERROR: curl(1) exited with an error ($CURL_STATUS)" | |
if [ $CURL_STATUS -eq 7 ]; then | |
echo "${0##*/}: Check that you have permission to access the Unit control socket, or try again with sudo(8)" | |
else | |
echo "${0##*/}: Trying to access $UNIT_CTRL$URI" | |
cat /tmp/${0##*/}.$$ && rm /tmp/${0##*/}.$$ | |
fi | |
exit 4 | |
fi | |
rm /tmp/${0##*/}.$$ 2> /dev/null | |
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