chore: initial import from KNEL/PFVCluster@041d311 [#769]

Split per O&M lane work order. Full history: KNEL/PFVCluster.
https://projects.knownelement.com/issues/769#note-4152
This commit is contained in:
2026-09-03 21:39:15 -05:00
commit 5d02177e63
20 changed files with 1468 additions and 0 deletions
+104
View File
@@ -0,0 +1,104 @@
#!/bin/bash
#
# to-glpi.sh — seed GLPI from the CMDB CSV + create the scoped agent user [#705]
#
# Prereqs: ~/.creds/glpi.env with GLPI_URL, GLPI_APP_TOKEN, and a VALID
# GLPI_USER_TOKEN (glpi admin). Run cmdb/seed/from-inventory.sh first
# to produce systems.csv.
#
# Usage:
# to-glpi.sh [--dry-run] [systems.csv]
#
# What it does:
# 1. initSession as the admin user token.
# 2. Creates local user 'cmdb' (Read-Only profile, random password +
# random api_token) — the scoped agent identity per Charles's ruling.
# Writes ~/.creds/glpi-agent.env (0600). Skipped if the user exists.
# 3. Imports systems.csv rows as GLPI Computers (batch; skips names that
# already exist). comment carries category/specs/ts_ip provenance.
#
set -euo pipefail
DRY=0
[ "${1:-}" = "--dry-run" ] && { DRY=1; shift; }
CSV="${1:-$(dirname "$0")/systems.csv}"
[ -r "$CSV" ] || { echo "no CSV at $CSV" >&2; exit 2; }
CREDS="${HOME}/.creds/glpi.env"
# shellcheck disable=SC1090
. "$CREDS"
: "${GLPI_URL:?}" "${GLPI_APP_TOKEN:?}" "${GLPI_USER_TOKEN:?}"
API="$GLPI_URL/apirest.php"
hdr() { printf 'Content-Type: application/json\nApp-Token: %s\nSession-Token: %s\n' "$GLPI_APP_TOKEN" "$SESSION"; }
echo "— initSession"
SESSION=$(curl -sS --max-time 20 -H "Content-Type: application/json" \
-H "App-Token: $GLPI_APP_TOKEN" \
-H "Authorization: user_token $GLPI_USER_TOKEN" \
"$API/initSession" | jq -re '.session_token')
echo " session ok (${#SESSION} chars)"
# --- 2. scoped agent user -------------------------------------------------
if curl -sS -H "$(hdr)" "$API/User?searchText%5Bname%5D=cmdb" | jq -e 'if type=="object" then (.totalcount > 0) else (length > 0) end' >/dev/null; then
echo "— user 'cmdb' already exists (skipping create)"
else
AGENT_PASS=$(head -c 24 /dev/urandom | base64 | tr -d '/+=')
AGENT_TOKEN=$(head -c 24 /dev/urandom | od -An -tx1 | tr -d ' \n')
if [ "$DRY" = "1" ]; then
echo "— DRY: would create user cmdb"
else
UID_JSON=$(curl -sS -X POST -H "$(hdr)" -d '{"input":{"name":"cmdb","realname":"CMDB agent (core-IT)","password":"'"$AGENT_PASS"'","api_token":"'"$AGENT_TOKEN"'"}}' "$API/User")
NEWUID=$(echo "$UID_JSON" | jq -r '.id // .users_id // empty')
echo " created users_id=$NEWUID"
PROF_ID=$(curl -sS -H "$(hdr)" "$API/Profile?range=0-50" | jq -r '.[] | select(.name=="Read-Only") | .id' | head -1)
[ -n "$PROF_ID" ] && curl -sS -X POST -H "$(hdr)" \
-d '{"input":{"users_id":"'"$NEWUID"'","profiles_id":"'"$PROF_ID"'","entities_id":0,"is_recursive":1}}' \
"$API/Profile_User" > /dev/null && echo " profile Read-Only ($PROF_ID) @ root entity"
umask 077
printf 'GLPI_URL=%s\nGLPI_APP_TOKEN=%s\nGLPI_USER_TOKEN=%s\n' \
"$GLPI_URL" "$GLPI_APP_TOKEN" "$AGENT_TOKEN" > "${HOME}/.creds/glpi-agent.env"
echo " agent creds written to ~/.creds/glpi-agent.env (0600)"
fi
fi
# --- 3. seed import -------------------------------------------------------
echo "— existing Computers"
EXIST=$(curl -sS -H "$(hdr)" "$API/Computer?range=0-999&is_deleted=0" | jq -r '[.[].name] | join("\n")')
# CSV -> JSON objects (pure jq; header names become keys)
jq -Rn '
def strip: gsub("^\"";"") | gsub("\"$";"");
(input | split(",") | map(strip)) as $keys |
[ inputs | split(",") | map(strip) as $v |
reduce range(0; ($keys | length)) as $i
({}; . + {($keys[$i]): ($v[$i] // "")}) ]
' "$CSV" > /tmp/glpi-rows.json
# GLPI Computer input objects; skip names already present
jq -c --arg existing "$EXIST" '
[ .[] | select(.ci_name != "") | select(.ci_name as $n | ($existing | split("\n")) | index($n) | not)]
' /tmp/glpi-rows.json > /tmp/glpi-batch.json
# Map to GLPI Computer fields
jq -c '[ .[] | {name: .ci_name,
comment: ((.category // "") + " | " + (.specs // "") + " | ts=" + (.ts_ip // "") +
" | " + (.extra // "") + " | src=" + (.source_section // "") +
" | status=" + (.status // ""))} ]' /tmp/glpi-batch.json > /tmp/glpi-input.json
mv /tmp/glpi-input.json /tmp/glpi-batch.json
TOTAL=$(jq 'length' /tmp/glpi-batch.json)
skipped=$(( $(wc -l < "$CSV") - 1 - TOTAL ))
echo "— import: $TOTAL to create, $skipped already present"
if [ "$DRY" = "1" ]; then echo "— DRY: no changes made"; exit 0; fi
# Batch-create in chunks of 25 (API limits)
SPLIT=25; i=0
while [ "$i" -lt "$TOTAL" ]; do
jq ".[$i:$((i+SPLIT))]" /tmp/glpi-batch.json > /tmp/glpi-chunk.json
curl -sS -X POST -H "$(hdr)" \
-d "$(jq -c '{input: .}' /tmp/glpi-chunk.json)" "$API/Computer" \
| jq -r 'if type=="array" then " +\(length) created" else " ERR: \(tostring)" end'
i=$((i+SPLIT))
done
echo "done — verify count via GET /Computer?range=0-200"