#!/bin/bash # # software-catalog.sh — seed the GLPI software catalog [#705] # # Usage: software-catalog.sh [--dry-run] # Needs: ~/.creds/glpi.env (GLPI_URL, GLPI_APP_TOKEN, GLPI_USER_TOKEN) # ~/.creds/wazuh.env optional (WAZUH_API_PASS) — for live agent installs # # Creates Software assets + SoftwareVersions and links installations to # Computer CIs. Idempotent at all three levels (software, version, install). # Versions are recorded ONLY where verified; unknowns say so — GLPI Agent # auto-inventory (proposed) is the durable fix for version drift. # set -euo pipefail DRY=0 [ "${1:-}" = "--dry-run" ] && DRY=1 CREDS="${HOME}/.creds/glpi.env" # shellcheck disable=SC1090 . "$CREDS" : "${GLPI_URL:?}" "${GLPI_APP_TOKEN:?}" "${GLPI_USER_TOKEN:?}" API="$GLPI_URL/apirest.php" api() { local method="$1" path="$2" body="${3:-}" if [ -n "$body" ]; then curl -sS --max-time 30 -X "$method" -H "App-Token: $GLPI_APP_TOKEN" \ -H "Session-Token: $SESSION" -H "Content-Type: application/json" \ -d "$body" "$API/$path" else curl -sS --max-time 30 -X "$method" -H "App-Token: $GLPI_APP_TOKEN" \ -H "Session-Token: $SESSION" "$API/$path" fi } 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" # software_id — existing id or empty sw_id() { api GET "Software?searchText%5Bname%5D=$(printf %s "$1" | sed 's/ /%20/g')" \ | jq -r --arg n "$1" '[.[] | select(.name==$n)][0].id // empty' } # version_id — GLPI ignores softwares_id as a search param, # so pull the full list and filter client-side (parent AND name) ver_id() { api GET "SoftwareVersion?range=0-999" \ | jq -r --arg s "$1" --arg v "$2" \ '[.[] | select((.softwares_id|tostring)==$s and .name==$v)][0].id // empty' } # computer_id pc_id() { api GET "Computer?searchText%5Bname%5D=$(printf %s "$1" | sed 's/ /%20/g')" \ | jq -r --arg n "$1" '[.[] | select(.name==$n)][0].id // empty' } # install_exists install_exists() { api GET "Item_SoftwareVersion?range=0-4999" \ | jq -e --arg v "$1" --arg p "$2" \ '[.[] | select(.softwareversions_id==($v|tonumber) and .items_id==($p|tonumber) and .itemtype=="Computer")] | length > 0' \ >/dev/null 2>&1 } # ensure — '-' = catalog only ensure() { local sw="$1" ver="$2" targets="$3" sid vid cid sid=$(sw_id "$sw") if [ -z "$sid" ]; then if [ "$DRY" = 1 ]; then echo " DRY: software '$sw'"; sid=0; else sid=$(api POST Software "{\"input\":{\"name\":\"$sw\",\"manufacturers_id\":0,\"comment\":\"seeded by software-catalog.sh (#705)\"}}" \ | jq -r '.id // empty') echo " + software '$sw' (id=$sid)" fi else echo " = software '$sw' (id=$sid)" fi [ "$sid" = 0 ] && [ "$DRY" = 1 ] && return 0 vid=$(ver_id "$sid" "$ver") if [ -z "$vid" ]; then if [ "$DRY" = 1 ]; then echo " DRY: version '$ver'"; else vid=$(api POST SoftwareVersion "{\"input\":{\"softwares_id\":\"$sid\",\"name\":\"$ver\",\"state\":0}}" \ | jq -r '.id // empty') echo " + version '$ver' (id=$vid)" fi else echo " = version '$ver' (id=$vid)" fi [ -z "$vid" ] && return 0 [ "$targets" = "-" ] && return 0 local IFS=',' for t in $targets; do cid=$(pc_id "$t") if [ -z "$cid" ]; then echo " ! no CI named '$t' (skipped)"; continue; fi if install_exists "$vid" "$cid"; then echo " = installed on $t"; continue; fi if [ "$DRY" = 1 ]; then echo " DRY: install on $t"; else api POST Item_SoftwareVersion \ "{\"input\":{\"itemtype\":\"Computer\",\"items_id\":\"$cid\",\"softwareversions_id\":\"$vid\"}}" \ | jq -re 'if type=="array" or .id then empty else . end' >/dev/null 2>&1 \ && echo " ! install POST failed on $t" || echo " + installed on $t" fi done } echo "— catalog rows" # name | version | targets (comma list, '-' = catalog only) while IFS='|' read -r sw ver targets; do [ -z "$sw" ] && continue ensure "$(echo "$sw" | xargs)" "$(echo "$ver" | xargs)" "$(echo "$targets" | xargs)" done < /tmp/wz-agents.txt while IFS= read -r a; do [ "$a" = "000" ] && continue cid=$(pc_id "$a") if [ -z "$cid" ]; then echo " ! agent '$a' has no CI (skipped)"; continue; fi if install_exists "$vid" "$cid"; then echo " = $a"; continue; fi if [ "$DRY" = 1 ]; then echo " DRY: install on $a"; else api POST Item_SoftwareVersion \ "{\"input\":{\"itemtype\":\"Computer\",\"items_id\":\"$cid\",\"softwareversions_id\":\"$vid\"}}" >/dev/null \ && echo " + $a" fi done < /tmp/wz-agents.txt fi echo "— done"