feat: glpi-change.sh — log GLPI Change entries from the CLI (OQ7) [#769]

First entry created live (Change id=1, backfill of the repo split).
GLPI API allowlist resolved — sessions work from the workstation.

https://projects.knownelement.com/issues/769#note-4152
This commit is contained in:
2026-09-04 06:09:53 -05:00
parent 5d02177e63
commit 43d59fe48f
+70
View File
@@ -0,0 +1,70 @@
#!/usr/bin/env bash
# glpi-change.sh — create GLPI Change entries from the CLI [#769]
#
# Charles ruling (questions-v10 OQ7, 2026-09-03): GLPI Changes are logged
# from NOW ON for converge/infra work — no Redmine-only exception path.
# Pair this with the Redmine ticket: put the ticket ref in --title.
#
# Env (from ~/.creds/glpi.env): GLPI_URL, GLPI_USER_TOKEN, GLPI_APP_TOKEN
#
# Usage:
# echo "what changed, why, where" | \
# glpi-change.sh create --title "[#769] <change summary>" [--urgency 2]
# glpi-change.sh show <change-id>
set -euo pipefail
die() { printf 'FAIL: %s\n' "$*" >&2; exit 1; }
[ -f "$HOME/.creds/glpi.env" ] || die "'$HOME/.creds/glpi.env' missing"
set -a; . "$HOME/.creds/glpi.env"; set +a
BASE="${GLPI_URL%/}"
[ -n "${GLPI_USER_TOKEN:-}" ] && [ -n "${GLPI_APP_TOKEN:-}" ] || die "tokens missing in glpi.env"
sess_request() {
curl -s -m 30 -H "Content-Type: application/json" \
-H "App-Token: $GLPI_APP_TOKEN" \
-H "Authorization: user_token $GLPI_USER_TOKEN" \
"$BASE/apirest.php/initSession"
}
session="$(sess_request)"
S_TOKEN="$(printf '%s' "$session" | jq -r '.session_token // empty')"
[ -n "$S_TOKEN" ] || die "initSession failed: $session"
cleanup() { curl -s -m 15 -o /dev/null -H "Session-Token: $S_TOKEN" \
-H "App-Token: $GLPI_APP_TOKEN" "$BASE/apirest.php/killSession" || true; }
trap cleanup EXIT
auth=(-H "Session-Token: $S_TOKEN" -H "App-Token: $GLPI_APP_TOKEN" -H "Content-Type: application/json")
cmd="${1:-create}"; shift || true
case "$cmd" in
create)
title=""; urgency=3; impact=3; content=""
while [ $# -gt 0 ]; do
case "$1" in
--title) title="$2"; shift 2 ;;
--urgency) urgency="$2"; shift 2 ;;
--impact) impact="$2"; shift 2 ;;
*) die "unknown option $1" ;;
esac
done
[ -n "$title" ] || die "--title required"
content="$(cat)"
[ -n "$content" ] || die "change body required on stdin"
body="$(jq -n --arg t "$title" --arg c "$content" \
--argjson u "$urgency" --argjson i "$impact" \
'{input: {name: $t, content: $c, urgency: $u, impact: $i}}')"
resp="$(curl -s -m 30 -X POST "${auth[@]}" -d "$body" "$BASE/apirest.php/Change")"
cid="$(printf '%s' "$resp" | jq -r '.id // empty')"
[ -n "$cid" ] || die "create failed: $resp"
echo "created Change id=$cid$BASE/front/change.form.php?id=$cid"
;;
show)
cid="${1:?change-id}"
curl -s -m 30 "${auth[@]}" "$BASE/apirest.php/Change/$cid" | jq .
;;
*)
die "unknown command $cmd"
;;
esac