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,79 @@
|
||||
#!/usr/bin/bash
|
||||
#
|
||||
# from-inventory.sh — convert the Discourse #307 system inventory (raw
|
||||
# markdown of its wiki post) into the CMDB seed CSV [#705]
|
||||
#
|
||||
# Input: raw markdown of https://community.turnsys.com/t/307 (post 385),
|
||||
# fetched e.g. via the discourse-cli raw-API escape hatch
|
||||
# Output: cmdb/seed/systems.csv (normalized CI rows; v0 schema)
|
||||
#
|
||||
# Re-run whenever #307 changes; the CSV is the GLPI import candidate, the
|
||||
# markdown topic stays the human-readable inventory.
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
if [ $# -ne 1 ] || [ ! -r "$1" ]; then
|
||||
echo "usage: $0 <inv307-raw.md >systems.csv" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
echo 'category,ci_name,host_node,vmid,specs,ts_ip,extra_ip,tuned,access,extra,status,source_section'
|
||||
|
||||
awk -F'|' '
|
||||
function trim(s) { gsub(/^[ \t]+|[ \t]+$/, "", s); return s }
|
||||
function strip(s) { gsub(/"/, "", s); return trim(s) }
|
||||
function csv(s) { gsub(/"/, "", s); return "\"" trim(s)"\"" }
|
||||
# canon(s) — apply the section-7 VM-name -> Tailscale/DNS-name map so
|
||||
# ci_name always uses the canonical fleet name [#705]
|
||||
function canon(s) { s = strip(s); return (s in map) ? map[s] : s }
|
||||
/^## / {
|
||||
sec = substr($0, 4)
|
||||
sub(/\(.*/, "", sec)
|
||||
gsub(/^[ \t]+|[ \t]+$/, "", sec)
|
||||
next
|
||||
}
|
||||
/^\|/ {
|
||||
# pass 1 (same file read twice): capture only the section-7 rename map
|
||||
if (FNR == NR) {
|
||||
if (sec ~ /^7\./) {
|
||||
for (i = 1; i <= NF; i++) f[i] = trim($i)
|
||||
if (f[2] == "" || f[2] ~ /^-+$/ || f[2] == "VM Name") next
|
||||
key = f[2]; sub(/[ (].*/, "", key)
|
||||
map[key] = trim(f[3])
|
||||
}
|
||||
next
|
||||
}
|
||||
if (sec ~ /^7\./) next
|
||||
if (sec !~ /^[1-6]\./) next
|
||||
for (i = 1; i <= NF; i++) f[i] = trim($i)
|
||||
if (f[2] == "" || f[2] ~ /^-+$/) next
|
||||
if (f[2] == "Host" || f[2] == "VMID" || f[2] == "Name" || f[2] == "DNS Name") next
|
||||
status = (index($0, "RETIRED") > 0) ? "retired" : "active"
|
||||
if (sec ~ /^1\./)
|
||||
printf "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n",
|
||||
"hypervisor", csv(canon(f[2])), "", "",
|
||||
csv(f[3] "; CPU " f[4] "; RAM " f[5]), csv(f[6]), csv(f[8]),
|
||||
csv(f[9]), csv(f[10]), csv("mgmt " f[7]), status, csv("307 s1")
|
||||
else if (sec ~ /^2\./)
|
||||
printf "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n",
|
||||
"vm-prod", csv(canon(f[3])), csv(f[4]), csv(f[2]),
|
||||
csv("CPU " f[5] "; RAM " f[6] "; TS? " f[7]), csv(f[8]), "",
|
||||
csv(f[10]), csv(f[9]), "", status, csv("307 s2")
|
||||
else if (sec ~ /^3\./)
|
||||
printf "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n",
|
||||
"vm-sectestbed", csv(canon(f[3])), "pfv-tsys5", csv(f[2]), "", csv(f[5]),
|
||||
"", csv(f[7]), csv(f[6]), "", status, csv("307 s3")
|
||||
else if (sec ~ /^4\./)
|
||||
printf "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n",
|
||||
"vm-preprod", csv(canon(f[3])), "pfv-tsys5", csv(f[2]), "", csv(f[5]),
|
||||
"", csv(f[7]), csv(f[6]), "", status, csv("307 s4")
|
||||
else if (sec ~ /^5\./)
|
||||
printf "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n",
|
||||
"physical-sbc", csv(canon(f[2])), "", "", "", csv(f[3]), "",
|
||||
"", csv(f[5]), csv("dns " f[4]), status, csv("307 s5")
|
||||
else if (sec ~ /^6\./)
|
||||
printf "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n",
|
||||
"stale-dns-record", csv(f[2]), "", "", "", "", "",
|
||||
"", "", "", "retired", csv("307 s6: " f[4])
|
||||
}
|
||||
' "$1" "$1"
|
||||
@@ -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"
|
||||
@@ -0,0 +1,76 @@
|
||||
category,ci_name,host_node,vmid,specs,ts_ip,extra_ip,tuned,access,extra,status,source_section
|
||||
hypervisor,"pfv-tsys1",,,"OptiPlex 9020; CPU 8c; RAM 31Gi","100.121.189.98","10.100.100.1","virtual-host","root","mgmt 192.168.3.11",active,"307 s1"
|
||||
hypervisor,"pfv-tsys3",,,"Precision 7510; CPU 8c; RAM 31Gi","100.66.186.10","10.100.100.3","virtual-host","root","mgmt 192.168.2.5",active,"307 s1"
|
||||
hypervisor,"pfv-tsys4",,,"Precision T1700; CPU 8c; RAM 15Gi","100.70.77.93","10.100.100.4","virtual-host","root","mgmt 192.168.3.251",active,"307 s1"
|
||||
hypervisor,"pfv-tsys5",,,"Precision T7500; CPU 8c; RAM 94Gi","100.87.135.12","10.100.100.5","virtual-host","root","mgmt 192.168.3.250",active,"307 s1"
|
||||
hypervisor,"pfv-tsys6",,,"PowerEdge R610; CPU 16c; RAM 125Gi","100.73.35.111","(bond)","virtual-host","root","mgmt 192.168.3.169",active,"307 s1"
|
||||
hypervisor,"pfv-tsys7",,,"PowerEdge R620; CPU 24c; RAM 188Gi","100.110.146.27","10.100.100.7","virtual-host","root","mgmt 192.168.0.250",active,"307 s1"
|
||||
hypervisor,"pfv-tsys9",,,"OptiPlex 7080; CPU 12c; RAM 23Gi","100.101.158.76","10.100.100.9","virtual-host","root","mgmt 192.168.3.58",active,"307 s1"
|
||||
vm-prod,"pfv-bms","tsys1","100","CPU 4c; RAM 6GB; TS? Yes","100.67.108.125",,"-","SSH 22222 (LAN: pfv-bms-lan.knel.net)",,active,"307 s2"
|
||||
vm-prod,"tsys-ca","tsys1","101","CPU 2c; RAM 4GB; TS? No (DNS: 100.102.96.24)","-",,"-","NO",,active,"307 s2"
|
||||
vm-prod,"pfv-k8s-cnode1","tsys1","102","CPU 2c; RAM 4GB; TS? Yes","100.125.134.53",,"network-latency","localuser",,active,"307 s2"
|
||||
vm-prod,"pfv-netinfra-01","tsys1","103","CPU 2c; RAM 4GB; TS? Yes","100.70.181.72",,"network-latency","localuser",,active,"307 s2"
|
||||
vm-prod,"tsys-librenms","tsys1","104","CPU 2c; RAM 4GB; TS? No (DNS: 100.86.204.77)","-",,"-","NO",,active,"307 s2"
|
||||
vm-prod,"tsys-proxmox-datacenter","tsys1","105","CPU 2c; RAM 2GB; TS? No (DNS: 100.125.183.68)","-",,"-","NO",,active,"307 s2"
|
||||
vm-prod,"tsys-ucs-01","tsys1","108","CPU 2c; RAM 6GB; TS? No (DNS: 100.109.13.110)","-",,"-","NO",,active,"307 s2"
|
||||
vm-prod,"pfv-k8s-wnode-tsys3","tsys3","313","CPU 8c; RAM 28GB; TS? Yes","100.126.9.112",,"-","localuser",,active,"307 s2"
|
||||
vm-prod,"pfv-k8s-wnode-tsys5","tsys5","500","CPU 2c; RAM 12GB; TS? Yes","100.122.252.116",,"-","localuser",,retired,"307 s2"
|
||||
vm-prod,"devbox-cloudron","tsys5","501","CPU 2c; RAM 4GB; TS? Yes","100.119.72.25",,"-","NO",,active,"307 s2"
|
||||
vm-prod,"hfnoc-uisp-preprod","tsys5","515","CPU 2c; RAM 2GB; TS? No","-",,"-","NO",,active,"307 s2"
|
||||
vm-prod,"ultix-streaming","tsys5","5111","CPU 4c; RAM 25GB; TS? Yes","100.101.187.119",,"-","NO (do-not-reboot)",,active,"307 s2"
|
||||
vm-prod,"ultix-offstage","tsys5","5112","CPU 4c; RAM 22GB; TS? Yes","100.70.119.59",,"-","localuser (do-not-reboot)",,retired,"307 s2"
|
||||
vm-prod,"tsys-awx","tsys6","600","CPU 2c; RAM 12GB; TS? No (DNS: 100.91.39.53)","-",,"-","NO",,active,"307 s2"
|
||||
vm-prod,"pfv-k8s-wnode-tsys6","tsys6","601","CPU 2c; RAM 98GB; TS? Yes","100.83.49.75",,"-","localuser",,active,"307 s2"
|
||||
vm-prod,"pfv-rr-middleware-02","tsys6","602","CPU 2c; RAM 6GB; TS? Yes","100.93.47.4",,"-","NO",,active,"307 s2"
|
||||
vm-prod,"pfv-k8s-cnode3","tsys6","603","CPU 4c; RAM 4GB; TS? Yes","100.106.222.18",,"network-latency","localuser",,active,"307 s2"
|
||||
vm-prod,"tsys-proxmox-mailgw-01","tsys6","604","CPU 2c; RAM 4GB; TS? No (DNS: 100.68.129.71)","-",,"-","NO",,active,"307 s2"
|
||||
vm-prod,"pfv-k8s-wnode-tsys7","tsys7","701","CPU 2c; RAM 98GB; TS? Yes","100.119.240.11",,"-","localuser",,active,"307 s2"
|
||||
vm-prod,"hfnoc-uisp","tsys7","702","CPU 2c; RAM 8GB; TS? Yes","100.94.188.89",,"-","NO",,active,"307 s2"
|
||||
vm-prod,"pfv-rr-middleware-01","tsys7","703","CPU 2c; RAM 6GB; TS? Yes","100.106.54.59",,"-","NO",,active,"307 s2"
|
||||
vm-prod,"pfv-k8s-cnode2","tsys7","705","CPU 4c; RAM 4GB; TS? Yes","100.109.34.72",,"network-latency","localuser",,active,"307 s2"
|
||||
vm-prod,"kali-rd","tsys7","706","CPU 2c; RAM 6GB; TS? Yes","100.105.136.23",,"-","NO",,active,"307 s2"
|
||||
vm-prod,"tsys-siem","tsys7","707","CPU 2c; RAM 8GB; TS? No (DNS: 100.72.35.113)","-",,"-","NO",,active,"307 s2"
|
||||
vm-prod,"kali-tsys","tsys7","708","CPU 4c; RAM 6GB; TS? Yes","100.82.30.115",,"-","NO",,active,"307 s2"
|
||||
vm-prod,"tsys-voip","tsys7","709","CPU 4c; RAM 4GB; TS? No (DNS: 100.83.126.67)","-",,"-","NO",,active,"307 s2"
|
||||
vm-prod,"tsys-umbrel","tsys7","710","CPU 2c; RAM 26GB; TS? No (DNS: 100.66.182.14)","-",,"-","NO",,active,"307 s2"
|
||||
vm-prod,"tsys-proxmox-mailgw-02","tsys7","711","CPU 2c; RAM 4GB; TS? No (DNS: 100.126.29.88)","-",,"-","NO",,active,"307 s2"
|
||||
vm-prod,"tsys-ucs-02","tsys9","902","CPU 2c; RAM 4GB; TS? No (DNS: 100.68.10.17)","-",,"-","NO",,active,"307 s2"
|
||||
vm-prod,"pfv-netinfra-02","tsys9","904","CPU 2c; RAM 4GB; TS? Yes","100.71.171.20",,"network-latency","localuser",,active,"307 s2"
|
||||
vm-prod,"pfv-k8s-wnode-tsys9","tsys9","905","CPU 4c; RAM 14GB; TS? Yes","100.95.201.66",,"-","localuser",,active,"307 s2"
|
||||
vm-sectestbed,"sectestbed-sandbox",pfv-tsys5,"5000",,"100.64.20.60",,"-","NO",,active,"307 s3"
|
||||
vm-sectestbed,"sectestbed-siem",pfv-tsys5,"5101",,"100.108.121.18",,"-","NO",,active,"307 s3"
|
||||
vm-sectestbed,"sectestbed-proxmox-pve",pfv-tsys5,"5102",,"100.80.72.71",,"-","NO",,active,"307 s3"
|
||||
vm-sectestbed,"sectestbed-proxmox-datacenter",pfv-tsys5,"5103",,"100.94.1.34",,"-","NO",,active,"307 s3"
|
||||
vm-sectestbed,"sectestbed-proxmox-pbs",pfv-tsys5,"5104",,"100.127.238.29",,"-","NO",,active,"307 s3"
|
||||
vm-sectestbed,"sectestbed-awx",pfv-tsys5,"5105",,"100.64.56.24",,"-","NO",,active,"307 s3"
|
||||
vm-sectestbed,"sectestbed-k8s-cnode",pfv-tsys5,"5106",,"100.68.155.111",,"-","NO",,active,"307 s3"
|
||||
vm-sectestbed,"sectestbed-k8s-wnode",pfv-tsys5,"5107",,"100.107.110.89",,"-","NO",,active,"307 s3"
|
||||
vm-sectestbed,"sectestbed-librenms",pfv-tsys5,"5108",,"100.92.94.87",,"-","NO",,active,"307 s3"
|
||||
vm-sectestbed,"sectestbed-netinfra",pfv-tsys5,"5109",,"100.100.220.117",,"-","NO",,active,"307 s3"
|
||||
vm-sectestbed,"sectestbed-cloudron",pfv-tsys5,"51011",,"100.97.140.105",,"-","NO",,active,"307 s3"
|
||||
vm-sectestbed,"sectestbed-hfnoc-uisp",pfv-tsys5,"51012",,"100.101.168.80",,"-","NO",,active,"307 s3"
|
||||
vm-sectestbed,"sectestbed-rancherplatform",pfv-tsys5,"51013",,"100.88.171.10",,"-","NO",,active,"307 s3"
|
||||
vm-sectestbed,"sectestbed-proxmox-mailgw",pfv-tsys5,"51014",,"100.117.24.21",,"-","NO",,active,"307 s3"
|
||||
vm-sectestbed,"sectestbed-ca",pfv-tsys5,"51015",,"100.113.245.124",,"-","NO",,active,"307 s3"
|
||||
vm-sectestbed,"sectestbed-voip",pfv-tsys5,"51016",,"100.86.176.105",,"-","NO",,active,"307 s3"
|
||||
vm-preprod,"preprod-awx",pfv-tsys5,"53100",,"100.77.216.36",,"-","NO",,active,"307 s4"
|
||||
vm-preprod,"preprod-siem",pfv-tsys5,"53101",,"100.98.162.14",,"-","NO",,active,"307 s4"
|
||||
vm-preprod,"preprod-rancherplatform",pfv-tsys5,"53102",,"100.126.231.121",,"-","NO",,active,"307 s4"
|
||||
vm-preprod,"preprod-proxmox-mailgw",pfv-tsys5,"53103",,"100.114.9.49",,"-","NO",,active,"307 s4"
|
||||
vm-preprod,"preprod-ca",pfv-tsys5,"53104",,"100.94.119.5",,"-","NO",,active,"307 s4"
|
||||
vm-preprod,"preprod-proxmox-datacenter",pfv-tsys5,"53105",,"100.101.250.10",,"-","NO",,active,"307 s4"
|
||||
vm-preprod,"preprod-librenms",pfv-tsys5,"53106",,"100.79.52.34",,"-","NO",,active,"307 s4"
|
||||
vm-preprod,"preprod-voip",pfv-tsys5,"53107",,"100.109.99.109",,"-","NO",,active,"307 s4"
|
||||
vm-preprod,"preprod-cloudron",pfv-tsys5,"53108",,"100.95.69.89",,"-","NO",,active,"307 s4"
|
||||
physical-sbc,"pfvsvrpi",,,,"100.91.151.113",,,"Raspberry Pi","dns pfvsvrpi.knel.net",active,"307 s5"
|
||||
physical-sbc,"pfv-jetson-nano-1",,,,"100.82.230.119",,,"NVIDIA Jetson","dns pfv-jetson-nano-1.knel.net",active,"307 s5"
|
||||
physical-sbc,"subopi-dev-3",,,,"100.64.231.65",,,"SBC (Pi?)","dns subopi-dev-3.knel.net",active,"307 s5"
|
||||
physical-sbc,"subopi-dev-4",,,,"-",,,"SBC","dns subopi-dev-4.knel.net (100.65.224.85)",active,"307 s5"
|
||||
physical-sbc,"subopi3",,,,"-",,,"SBC","dns subopi3.knel.net (100.93.17.77)",active,"307 s5"
|
||||
physical-sbc,"stlpc-artroom",,,,"100.120.77.113",,,"Linux PC","dns stlpc-artroom.knel.net",active,"307 s5"
|
||||
physical-sbc,"stlpc-garage",,,,"100.72.192.22",,,"Linux PC","dns stlpc-garage.knel.net",active,"307 s5"
|
||||
physical-sbc,"stlp-3dscanner",,,,"100.125.14.37",,,"OFFLINE 184d","dns stlp-3dscanner.knel.net",active,"307 s5"
|
||||
physical-sbc,"tailscale-router",,,,"-",,,"**RETIRED 2026-09-02** — subnet-router role replaced by pfv-netinfra-01/02; host removed from tailnet; no DNS records remain","dns ~~tailscale-router.knel.net (100.103.48.57)~~",retired,"307 s5"
|
||||
physical-sbc,"netbird",,,,"100.123.45.23",,,"NetBird VPN","dns -",active,"307 s5"
|
||||
physical-sbc,"pfv-proxmox-backup-server",,,,"100.114.81.107",,,"PBS","dns pfv-proxmox-backup-server.knel.net",active,"307 s5"
|
||||
physical-sbc,"stlpc-bizoffice",,,,"100.96.130.53",,,"WINDOWS (not Linux)","dns stlpc-bizoffice.knel.net",active,"307 s5"
|
||||
|
+104
@@ -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"
|
||||
Reference in New Issue
Block a user