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:
@@ -0,0 +1,169 @@
|
||||
#!/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 <name> — 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 <swid> <version> — 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 <ci-name>
|
||||
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 <verid> <pcid>
|
||||
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 <swname> <version> <targets-comma-list|-> — '-' = 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 <<EOF
|
||||
Proxmox VE|9.2.5|pfv-tsys1,pfv-tsys3,pfv-tsys4,pfv-tsys5,pfv-tsys6,pfv-tsys7,pfv-tsys9
|
||||
Wazuh Manager|4.14.7|tsys-siem
|
||||
Wazuh Indexer|4.14.7|tsys-siem
|
||||
Wazuh Dashboard|4.14.7|tsys-siem
|
||||
Wazuh Agent|4.14.7-1|-
|
||||
Docker Engine|unknown (GLPI Agent pending)|pfv-netinfra-01,pfv-netinfra-02,tsys-librenms,tsys-cloudron
|
||||
Pi-hole FTL (v6)|unknown (GLPI Agent pending)|pfv-netinfra-01,pfv-netinfra-02
|
||||
Technitium DNS Server|unknown (GLPI Agent pending)|pfv-netinfra-01,pfv-netinfra-02
|
||||
ISC dhcpd|unknown (GLPI Agent pending)|pfv-netinfra-01,pfv-netinfra-02
|
||||
nginx|unknown (GLPI Agent pending)|tsys-ca,tsys-librenms
|
||||
LibreNMS|unknown (GLPI Agent pending)|tsys-librenms
|
||||
NetDisco|unknown (GLPI Agent pending)|tsys-librenms
|
||||
Oxidized|unknown (GLPI Agent pending)|tsys-librenms
|
||||
SmokePing|unknown (GLPI Agent pending)|tsys-librenms
|
||||
unpoller|unknown (GLPI Agent pending)|tsys-librenms
|
||||
NUT (Network UPS Tools)|unknown (GLPI Agent pending)|-
|
||||
Proxmox Backup Server|4.x (dev, VM 5104)|-
|
||||
k3s|unknown (k8s lane)|-
|
||||
Uptime Kuma|unknown (Cloudron app)|tsys-cloudron
|
||||
GLPI|unknown (Cloudron app)|tsys-cloudron
|
||||
Vaultwarden|unknown (Cloudron app)|tsys-cloudron
|
||||
EOF
|
||||
|
||||
# Wazuh Agent installs: from the LIVE manager (ground truth), CI matched by name
|
||||
if [ -r "${HOME}/.creds/wazuh.env" ] && [ "${SKIP_AGENTS:-0}" != 1 ]; then
|
||||
# shellcheck disable=SC1090
|
||||
. "${HOME}/.creds/wazuh.env"
|
||||
echo "— wazuh agent installs (live manager)"
|
||||
sid=$(sw_id "Wazuh Agent")
|
||||
[ -z "$sid" ] && { echo " ! Wazuh Agent software missing"; exit 0; }
|
||||
vid=$(ver_id "$sid" "4.14.7-1")
|
||||
[ -z "$vid" ] && { echo " ! version 4.14.7-1 missing"; exit 0; }
|
||||
TOKEN=$(curl -sS --max-time 20 -u "wazuh:${WAZUH_API_PASS}" -k \
|
||||
-X POST "https://tsys-wazuh.knel.net:55000/security/user/authenticate?raw=true")
|
||||
curl -sS --max-time 30 -k -H "Authorization: Bearer $TOKEN" \
|
||||
"https://tsys-wazuh.knel.net:55000/agents?status=active&limit=500" \
|
||||
| jq -r '.data.affected_items[].name' > /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"
|
||||
Reference in New Issue
Block a user