From 9ad207057c620f234f01483bd3a39176945ec202 Mon Sep 17 00:00:00 2001 From: Liam Crilly Date: Tue, 3 Oct 2023 14:57:17 +0100 Subject: Tools: unitc quiet mode fix for macOS. head -c 0 does not work on macOS (invalid byte count) but tail(1) is happy to accept zero bytes, and does not have a performance penalty. --- tools/unitc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/unitc') diff --git a/tools/unitc b/tools/unitc index 877e11d4..1db59faa 100755 --- a/tools/unitc +++ b/tools/unitc @@ -186,7 +186,7 @@ fi # Choose presentation style # if [ $QUIET -eq 1 ]; then - OUTPUT="head -c 0" # Equivalent to >/dev/null + OUTPUT="tail -c 0" # Equivalent to >/dev/null elif hash jq 2> /dev/null; then OUTPUT="jq" else -- cgit From 599b035a544ea27e9fe76cb79f7d672ef114c2d2 Mon Sep 17 00:00:00 2001 From: Liam Crilly Date: Tue, 10 Oct 2023 15:06:36 +0100 Subject: Tools: unitc YAML mode. Added --format option to manage configuration in other formats. Initially, YAML is the only supported conversion format. JSON/YAML conversion is performed with yq(1). Suggested by: Torstein Krause Johansen Closes: #958 --- tools/unitc | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 7 deletions(-) (limited to 'tools/unitc') diff --git a/tools/unitc b/tools/unitc index 1db59faa..e0e725ec 100755 --- a/tools/unitc +++ b/tools/unitc @@ -10,6 +10,7 @@ REMOTE=0 SHOW_LOG=1 NOLOG=0 QUIET=0 +CONVERT=0 URI="" SSH_CMD="" METHOD=PUT @@ -18,6 +19,30 @@ CONF_FILES=() while [ $# -gt 0 ]; do OPTION=$(echo $1 | tr '[a-z]' '[A-Z]') case $OPTION in + "-F" | "--FORMAT") + case $(echo $2 | tr '[a-z]' '[A-Z]') in + "YAML") + CONVERT=1 + if hash yq 2> /dev/null; then + CONVERT_TO_JSON="yq eval -P --output-format=json" + CONVERT_FROM_JSON="yq eval -P --output-format=yaml" + else + echo "${0##*/}: ERROR: yq(1) is required to use YAML format; install at " + exit 1 + fi + ;; + "") + echo "${0##*/}: ERROR: Must specify configuration format" + exit 1 + ;; + *) + echo "${0##*/}: ERROR: Invalid format ($2)" + exit 1 + ;; + esac + shift; shift + ;; + "-H" | "--HELP") shift ;; @@ -45,15 +70,22 @@ while [ $# -gt 0 ]; do *) if [ -f $1 ] && [ -r $1 ]; then CONF_FILES+=($1) + if [ "${1##*.}" = "yaml" ]; then + echo "${0##*/}: INFO: converting $1 to JSON" + shift; set -- "--format" "yaml" "$@" # Apply the command line option + else + shift + fi elif [ "${1:0:1}" = "/" ] || [ "${1:0:4}" = "http" ] && [ "$URI" = "" ]; then URI=$1 + shift elif [ "${1:0:6}" = "ssh://" ]; then UNIT_CTRL=$1 + shift else echo "${0##*/}: ERROR: Invalid option ($1)" exit 1 fi - shift ;; esac done @@ -67,16 +99,18 @@ USAGE: ${0##*/} [options] URI • URI is for Unit's control API target, e.g. /config • A local Unit control socket is detected unless a remote one is specified. • Configuration data is read from stdin. +• All options are case-insensitive (excluding filenames and URIs). General options - filename … # Read configuration data from files instead of stdin - HTTP method # Default=GET, or PUT with config data (case-insensitive) - EDIT # Opens the URI contents in \$EDITOR - INSERT # Virtual HTTP method to prepend data to an existing array - -q | --quiet # No output to stdout + filename … # Read configuration data from files instead of stdin + HTTP method # Default=GET, or PUT when config data is present + EDIT # Opens the URI contents in \$EDITOR + INSERT # Virtual HTTP method; prepend data to an array + -f | --format YAML # Convert configuration data to/from YAML format + -q | --quiet # No output to stdout Local options - -l | --nolog # Do not monitor the error log after applying config changes + -l | --nolog # Do not monitor the Unit log file after config changes Remote options ssh://[user@]remote_host[:port]/path/to/control.socket # Remote Unix socket @@ -187,6 +221,8 @@ fi # if [ $QUIET -eq 1 ]; then OUTPUT="tail -c 0" # Equivalent to >/dev/null +elif [ $CONVERT -eq 1 ]; then + OUTPUT=$CONVERT_FROM_JSON elif hash jq 2> /dev/null; then OUTPUT="jq" else @@ -224,6 +260,10 @@ if [ -t 0 ] && [ ${#CONF_FILES[@]} -eq 0 ]; then $SSH_CMD curl -fsSX DELETE $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ && \ printf "%s" "$(< $EDIT_FILENAME.js)" | $SSH_CMD curl -fX PUT --data-binary @- $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ && \ $SSH_CMD curl -X PUT --data-binary @/tmp/${0##*/}.$$_js_module $UNIT_CTRL/config/settings/js_module 2> /tmp/${0##*/}.$$ + elif [ $CONVERT -eq 1 ]; then + $CONVERT_FROM_JSON < $EDIT_FILENAME > $EDIT_FILENAME.yaml + $EDITOR $EDIT_FILENAME.yaml || exit 2 + $CONVERT_TO_JSON < $EDIT_FILENAME.yaml | $SSH_CMD curl -X PUT --data-binary @- $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT else tr -d '\r' < $EDIT_FILENAME > $EDIT_FILENAME.json # Remove carriage-return from newlines $EDITOR $EDIT_FILENAME.json || exit 2 @@ -249,6 +289,10 @@ else exit 3 fi else + if [ $CONVERT -eq 1 ]; then + cat ${CONF_FILES[@]} | $CONVERT_TO_JSON > /tmp/${0##*/}.$$_json + CONF_FILES=(/tmp/${0##*/}.$$_json) + fi cat ${CONF_FILES[@]} | $SSH_CMD curl -X $METHOD --data-binary @- $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT fi fi -- cgit From 43f140dfd318378f330ff019bb2a37c94d8f885c Mon Sep 17 00:00:00 2001 From: Liam Crilly Date: Mon, 16 Oct 2023 10:32:19 +0100 Subject: Tools: unitc Docker mode. Introduces a new remote host scheme docker:// that specifies a local container ID. By default, the control socket is assumed to be in the default location, as per the Docker Official Images for Unit. If not, the path to the control socket can be appended to the container ID. --- tools/unitc | 46 +++++++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 17 deletions(-) (limited to 'tools/unitc') diff --git a/tools/unitc b/tools/unitc index e0e725ec..e671f384 100755 --- a/tools/unitc +++ b/tools/unitc @@ -12,7 +12,7 @@ NOLOG=0 QUIET=0 CONVERT=0 URI="" -SSH_CMD="" +RPC_CMD="" METHOD=PUT CONF_FILES=() @@ -82,6 +82,9 @@ while [ $# -gt 0 ]; do elif [ "${1:0:6}" = "ssh://" ]; then UNIT_CTRL=$1 shift + elif [ "${1:0:9}" = "docker://" ]; then + UNIT_CTRL=$1 + shift else echo "${0##*/}: ERROR: Invalid option ($1)" exit 1 @@ -115,9 +118,10 @@ Local options Remote options ssh://[user@]remote_host[:port]/path/to/control.socket # Remote Unix socket http://remote_host:port/URI # Remote TCP socket + docker://container_ID[/non-default/control.socket] # Container on host - A remote Unit control socket may also be defined with the \$UNIT_CTRL - environment variable as http://remote_host:port -OR- ssh://… (as above) + A remote Unit instance may also be defined with the \$UNIT_CTRL environment + variable as http://remote_host:port or ssh://… or docker://… (as above). __EOF__ exit 1 @@ -133,8 +137,16 @@ if [ "$UNIT_CTRL" = "" ]; then fi elif [ "${UNIT_CTRL:0:6}" = "ssh://" ]; then REMOTE=1 - SSH_CMD="ssh $(echo $UNIT_CTRL | cut -f1-3 -d/)" + RPC_CMD="ssh $(echo $UNIT_CTRL | cut -f1-3 -d/)" UNIT_CTRL="--unix-socket /$(echo $UNIT_CTRL | cut -f4- -d/) _" +elif [ "${UNIT_CTRL:0:9}" = "docker://" ]; then + RPC_CMD="docker exec -i $(echo $UNIT_CTRL | cut -f3 -d/)" + DOCKSOCK=/$(echo "$UNIT_CTRL" | cut -f4- -d/) + if [ "$DOCKSOCK" = "/" ]; then + DOCKSOCK="/var/run/control.unit.sock" # Use default location if no path + fi + UNIT_CTRL="--unix-socket $DOCKSOCK _" + REMOTE=1 elif [ "${URI:0:1}" = "/" ]; then REMOTE=1 fi @@ -241,11 +253,11 @@ fi # if [ -t 0 ] && [ ${#CONF_FILES[@]} -eq 0 ]; then if [ "$METHOD" = "DELETE" ]; then - $SSH_CMD curl -X $METHOD $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT + $RPC_CMD curl -X $METHOD $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT elif [ "$METHOD" = "EDIT" ]; then EDITOR=$(test "$EDITOR" && printf '%s' "$EDITOR" || command -v editor || command -v vim || echo vi) EDIT_FILENAME=/tmp/${0##*/}.$$${URI//\//_} - $SSH_CMD curl -fsS $UNIT_CTRL$URI > $EDIT_FILENAME || exit 2 + $RPC_CMD curl -fsS $UNIT_CTRL$URI > $EDIT_FILENAME || exit 2 if [ "${URI:0:12}" = "/js_modules/" ]; then if ! hash jq 2> /dev/null; then echo "${0##*/}: ERROR: jq(1) is required to edit JavaScript modules; install at " @@ -255,23 +267,23 @@ if [ -t 0 ] && [ ${#CONF_FILES[@]} -eq 0 ]; then EDIT_FILE=$EDIT_FILENAME.js $EDITOR $EDIT_FILENAME.js || exit 2 # Remove the references, delete old config, push new config+reference - $SSH_CMD curl -fsS $UNIT_CTRL/config/settings/js_module > /tmp/${0##*/}.$$_js_module && \ - $SSH_CMD curl -X DELETE $UNIT_CTRL/config/settings/js_module && \ - $SSH_CMD curl -fsSX DELETE $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ && \ - printf "%s" "$(< $EDIT_FILENAME.js)" | $SSH_CMD curl -fX PUT --data-binary @- $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ && \ - $SSH_CMD curl -X PUT --data-binary @/tmp/${0##*/}.$$_js_module $UNIT_CTRL/config/settings/js_module 2> /tmp/${0##*/}.$$ + $RPC_CMD curl -fsS $UNIT_CTRL/config/settings/js_module > /tmp/${0##*/}.$$_js_module && \ + $RPC_CMD curl -X DELETE $UNIT_CTRL/config/settings/js_module && \ + $RPC_CMD curl -fsSX DELETE $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ && \ + printf "%s" "$(< $EDIT_FILENAME.js)" | $RPC_CMD curl -fX PUT --data-binary @- $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ && \ + $RPC_CMD curl -X PUT --data-binary @/tmp/${0##*/}.$$_js_module $UNIT_CTRL/config/settings/js_module 2> /tmp/${0##*/}.$$ elif [ $CONVERT -eq 1 ]; then $CONVERT_FROM_JSON < $EDIT_FILENAME > $EDIT_FILENAME.yaml $EDITOR $EDIT_FILENAME.yaml || exit 2 - $CONVERT_TO_JSON < $EDIT_FILENAME.yaml | $SSH_CMD curl -X PUT --data-binary @- $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT + $CONVERT_TO_JSON < $EDIT_FILENAME.yaml | $RPC_CMD curl -X PUT --data-binary @- $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT else tr -d '\r' < $EDIT_FILENAME > $EDIT_FILENAME.json # Remove carriage-return from newlines $EDITOR $EDIT_FILENAME.json || exit 2 - $SSH_CMD curl -X PUT --data-binary @$EDIT_FILENAME.json $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT + $RPC_CMD curl -X PUT --data-binary @$EDIT_FILENAME.json $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT fi else SHOW_LOG=$(echo $URI | grep -c ^/control/) - $SSH_CMD curl $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT + $RPC_CMD curl $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT fi else if [ "$METHOD" = "INSERT" ]; then @@ -281,9 +293,9 @@ else fi NEW_ELEMENT=$(cat ${CONF_FILES[@]}) echo $NEW_ELEMENT | jq > /dev/null || exit $? # Test the input is valid JSON before proceeding - OLD_ARRAY=$($SSH_CMD curl -s $UNIT_CTRL$URI) + OLD_ARRAY=$($RPC_CMD curl -s $UNIT_CTRL$URI) if [ "$(echo $OLD_ARRAY | jq -r type)" = "array" ]; then - echo $OLD_ARRAY | jq ". |= [$NEW_ELEMENT] + ." | $SSH_CMD curl -X PUT --data-binary @- $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT + echo $OLD_ARRAY | jq ". |= [$NEW_ELEMENT] + ." | $RPC_CMD curl -X PUT --data-binary @- $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT else echo "${0##*/}: ERROR: the INSERT method expects an array" exit 3 @@ -293,7 +305,7 @@ else cat ${CONF_FILES[@]} | $CONVERT_TO_JSON > /tmp/${0##*/}.$$_json CONF_FILES=(/tmp/${0##*/}.$$_json) fi - cat ${CONF_FILES[@]} | $SSH_CMD curl -X $METHOD --data-binary @- $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT + cat ${CONF_FILES[@]} | $RPC_CMD curl -X $METHOD --data-binary @- $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT fi fi -- cgit From d51f7def1442ff7519e14263559e3483a9a28f93 Mon Sep 17 00:00:00 2001 From: Liam Crilly Date: Wed, 18 Oct 2023 22:26:13 +0100 Subject: Tools: unitc remote mode edit fix. Previously, the edit method created a temporary file that was then sent to curl(1) as --data-binary @filename.tmp. This did not work with remote instances because the temporary file is not on the remote host. The edit method now passes the configuration to curl(1) using stdin, the same way as for all other configuration changes. --- tools/unitc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/unitc') diff --git a/tools/unitc b/tools/unitc index e671f384..4ab5f663 100755 --- a/tools/unitc +++ b/tools/unitc @@ -271,7 +271,7 @@ if [ -t 0 ] && [ ${#CONF_FILES[@]} -eq 0 ]; then $RPC_CMD curl -X DELETE $UNIT_CTRL/config/settings/js_module && \ $RPC_CMD curl -fsSX DELETE $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ && \ printf "%s" "$(< $EDIT_FILENAME.js)" | $RPC_CMD curl -fX PUT --data-binary @- $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ && \ - $RPC_CMD curl -X PUT --data-binary @/tmp/${0##*/}.$$_js_module $UNIT_CTRL/config/settings/js_module 2> /tmp/${0##*/}.$$ + cat /tmp/${0##*/}.$$_js_module | $RPC_CMD curl -X PUT --data-binary @- $UNIT_CTRL/config/settings/js_module 2> /tmp/${0##*/}.$$ elif [ $CONVERT -eq 1 ]; then $CONVERT_FROM_JSON < $EDIT_FILENAME > $EDIT_FILENAME.yaml $EDITOR $EDIT_FILENAME.yaml || exit 2 @@ -279,7 +279,7 @@ if [ -t 0 ] && [ ${#CONF_FILES[@]} -eq 0 ]; then else tr -d '\r' < $EDIT_FILENAME > $EDIT_FILENAME.json # Remove carriage-return from newlines $EDITOR $EDIT_FILENAME.json || exit 2 - $RPC_CMD curl -X PUT --data-binary @$EDIT_FILENAME.json $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT + cat $EDIT_FILENAME.json | $RPC_CMD curl -X PUT --data-binary @- $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT fi else SHOW_LOG=$(echo $URI | grep -c ^/control/) -- cgit