uce/scripts/uce-cli

157 lines
3.6 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
default_socket="/run/uce/cli.sock"
if [[ -z "${UCE_CLI_SOCKET:-}" && -r /etc/uce/settings.cfg ]]; then
configured_socket=$(awk -F= '/^[[:space:]]*CLI_SOCKET_PATH[[:space:]]*=/ {gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); print $2; exit}' /etc/uce/settings.cfg)
if [[ -n "${configured_socket:-}" ]]; then
default_socket="$configured_socket"
fi
fi
socket_path="${UCE_CLI_SOCKET:-$default_socket}"
method="auto"
raw_json=""
usage() {
cat <<'USAGE'
Usage:
scripts/uce-cli [options] <unit-or-hook> [key=value ...]
Options:
--socket PATH Unix socket path (default: CLI_SOCKET_PATH from /etc/uce/settings.cfg,
UCE_CLI_SOCKET, or /run/uce/cli.sock)
--get Send key=value parameters as a query string
--post Send key=value parameters as a JSON POST (default when params exist)
--json JSON Send raw JSON as POST body
-h, --help Show this help
Examples:
scripts/uce-cli /ping
scripts/uce-cli /tests/cli.uce action=echo message=hello
scripts/uce-cli --json '{"action":"echo","message":"hello"}' /tests/cli.uce
scripts/uce-cli --get /tests/cli.uce action=echo message=hello
USAGE
}
while [[ $# -gt 0 ]]; do
case "$1" in
--socket)
[[ $# -ge 2 ]] || { echo "--socket requires a path" >&2; exit 2; }
socket_path="$2"
shift 2
;;
--get)
method="get"
shift
;;
--post)
method="post"
shift
;;
--json)
[[ $# -ge 2 ]] || { echo "--json requires a JSON value" >&2; exit 2; }
raw_json="$2"
method="post"
shift 2
;;
-h|--help)
usage
exit 0
;;
--)
shift
break
;;
-*)
echo "unknown option: $1" >&2
usage >&2
exit 2
;;
*)
break
;;
esac
done
[[ $# -ge 1 ]] || { usage >&2; exit 2; }
path="$1"
shift
if [[ "$path" != /* ]]; then
path="/$path"
fi
if [[ ! -S "$socket_path" ]]; then
echo "UCE CLI socket not found: $socket_path" >&2
exit 1
fi
if [[ "$method" == "auto" ]]; then
if [[ $# -gt 0 || -n "$raw_json" ]]; then
method="post"
else
method="get"
fi
fi
if [[ -n "$raw_json" ]]; then
printf '%s' "$raw_json" | python3 -m json.tool >/dev/null
curl -sS --fail-with-body --unix-socket "$socket_path" \
-X POST \
-H 'Content-Type: application/json' \
--data-binary "$raw_json" \
"http://localhost$path"
exit $?
fi
if [[ "$method" == "get" ]]; then
url="http://localhost$path"
if [[ $# -gt 0 ]]; then
query=$(python3 - "$@" <<'PY'
import sys, urllib.parse
pairs = []
for arg in sys.argv[1:]:
if '=' not in arg:
raise SystemExit(f"argument is not key=value: {arg}")
key, value = arg.split('=', 1)
pairs.append((key, value))
print(urllib.parse.urlencode(pairs))
PY
)
url="$url?$query"
fi
curl -sS --fail-with-body --unix-socket "$socket_path" "$url"
else
json=$(python3 - "$@" <<'PY'
import json, sys
payload = {}
for arg in sys.argv[1:]:
if '=' not in arg:
raise SystemExit(f"argument is not key=value: {arg}")
key, value = arg.split('=', 1)
lowered = value.lower()
if lowered == 'true':
parsed = True
elif lowered == 'false':
parsed = False
elif lowered in ('null', 'none'):
parsed = None
else:
try:
parsed = int(value)
except ValueError:
try:
parsed = float(value)
except ValueError:
parsed = value
payload[key] = parsed
print(json.dumps(payload, separators=(',', ':')))
PY
)
curl -sS --fail-with-body --unix-socket "$socket_path" \
-X POST \
-H 'Content-Type: application/json' \
--data-binary "$json" \
"http://localhost$path"
fi