ci / audit (push) Failing after 50s
lldp-topology.sh pulls the links table (hostnames + ports both ends) — input for GLPI NetworkEquipment + port-connection population under the Change being filed for phase 2a. https://projects.knownelement.com/issues/808
96 lines
4.9 KiB
Bash
Executable File
96 lines
4.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
TMP=$(mktemp -d); TMP_NE=$TMP/ne.json; TMP_PT=$TMP/port.json; TMP_CONN=$TMP/conn.json; TMP_PAIRS=$TMP/pairs.tsv; trap 'rm -rf $TMP' EXIT
|
|
# populate-netequip-from-librenms.sh — phase 2a of the GLPI x LibreNMS cross-feed [#808]
|
|
#
|
|
# Creates NetworkEquipment CIs in GLPI from LibreNMS discovery (skips hosts
|
|
# that already exist as Computers), then wires LLDP links as GLPI
|
|
# NetworkPort + NetworkPort_NetworkPort connections. Change 19 documents
|
|
# this operation (C2 ruling: agent CMDB writes approved).
|
|
#
|
|
# Inputs:
|
|
# /tmp/lldp_devices.tsv fqdn<TAB>hardware<TAB>os (network devices only)
|
|
# /tmp/lldp_links.tsv fqdnA<TAB>portA<TAB>fqdnB<TAB>portB
|
|
# Env: mglpi.env (Super-Admin session; Hotliner CANNOT write CIs).
|
|
# Exit: 0 ok | 1 error.
|
|
set -uo pipefail
|
|
|
|
# shellcheck disable=SC1091
|
|
[ -f "$HOME/.creds/mglpi.env" ] && . "$HOME/.creds/mglpi.env"
|
|
: "${MGLPI_URL:?}"; : "${MGLPI_APP_TOKEN:?}"; : "${MGLPI_USER_TOKEN:?}"
|
|
|
|
S=$(curl -sk --max-time 20 -H "Content-Type: application/json" \
|
|
-H "App-Token: ${MGLPI_APP_TOKEN}" -H "Authorization: user_token ${MGLPI_USER_TOKEN}" \
|
|
"${MGLPI_URL}/initSession" | jq -r '.session_token // empty')
|
|
[ -n "$S" ] || { echo "FAIL: GLPI session init" >&2; exit 1; }
|
|
api() { # method path payload-file -> body
|
|
local method=$1 path=$2 body=${3:-}
|
|
if [ -n "$body" ]; then
|
|
curl -sk --max-time 20 -X "$method" -H "App-Token: ${MGLPI_APP_TOKEN}" \
|
|
-H "Session-Token: $S" -H "Content-Type: application/json" \
|
|
-d "@$body" "${MGLPI_URL}/$path"
|
|
else
|
|
curl -sk --max-time 20 -X "$method" -H "App-Token: ${MGLPI_APP_TOKEN}" \
|
|
-H "Session-Token: $S" "${MGLPI_URL}/$path"
|
|
fi
|
|
}
|
|
|
|
# --- 1. NetworkEquipment CIs (dedupe by short hostname) ---
|
|
ne_created=0; ne_exists=0
|
|
declare -A NE_ID
|
|
while IFS=$'\t' read -r fqdn hw os; do
|
|
[ -n "$fqdn" ] || continue
|
|
short=${fqdn%%.*}
|
|
# exists already? (by name)
|
|
found=$(api GET "search/NetworkEquipment?criteria%5B0%5D%5Bfield%5D=1&criteria%5B0%5D%5Bsearchtype%5D=contains&criteria%5B0%5D%5Bvalue%5D=${short}&forcedisplay%5B%5D=2" \
|
|
| jq -r '.data[0]["2"] // empty')
|
|
if [ -n "$found" ]; then
|
|
NE_ID[$short]=$found; ne_exists=$((ne_exists+1)); continue
|
|
fi
|
|
jq -n --arg n "$short" --arg c "LibreNMS-discovered: hw=$hw os=$os (CR19/#808)" \
|
|
'{input: {name: $n, comment: $c}}' > "$TMP_NE" 2>/dev/null || {
|
|
printf '{"input": {"name": "%s", "comment": "LibreNMS-discovered hw=%s os=%s (CR19/#808)"}}' "$short" "$hw" "$os" > "$TMP_NE"
|
|
}
|
|
r=$(api POST NetworkEquipment "$TMP_NE")
|
|
id=$(echo "$r" | jq -r '.id // empty')
|
|
if [ -n "$id" ]; then NE_ID[$short]=$id; ne_created=$((ne_created+1));
|
|
else echo "ERR create NetEquipment $short: $(echo "$r" | head -c 120)" >&2; fi
|
|
done < /tmp/lldp_devices.tsv
|
|
echo "netequip: created=$ne_created existed=$ne_exists"
|
|
|
|
# --- 2. ports + connections from LLDP links ---
|
|
port_created=0; conn_created=0; conn_dup=0
|
|
declare -A PORT_ID
|
|
ensure_port() { # fqdn short ifname -> echoes port id
|
|
local fqdn=$1 ifname=$2 short=${1%%.*} key r pid
|
|
key="$short|$ifname"
|
|
[ -n "${PORT_ID[$key]:-}" ] && { echo "${PORT_ID[$key]}"; return; }
|
|
local ne=${NE_ID[$short]:-}
|
|
if [ -z "$ne" ]; then echo ""; return; fi
|
|
printf '{"input": {"itemtype": "NetworkEquipment", "items_id": %s, "name": "%s", "ifnum": "%s", "logical_number": 1}}' \
|
|
"$ne" "$ifname" "$ifname" > "$TMP_PT"
|
|
r=$(api POST NetworkPort "$TMP_PT")
|
|
pid=$(echo "$r" | jq -r '.id // empty')
|
|
if [ -n "$pid" ]; then PORT_ID[$key]=$pid; port_created=$((port_created+1)); fi
|
|
echo "$pid"
|
|
}
|
|
# dedupe undirected pairs
|
|
awk -F'\t' '{ if (($1 FS $3) < ($3 FS $1)) print $1"\t"$2"\t"$3"\t"$4; else print $3"\t"$4"\t"$1"\t"$2 }' \
|
|
/tmp/lldp_links.tsv | sort -u > "$TMP_PAIRS"
|
|
|
|
while IFS=$'\t' read -r fa pa fb pb; do
|
|
[ -n "$fa" ] || continue
|
|
pa=${pa:-unknown}; pb=${pb:-unknown}
|
|
ida=$(ensure_port "$fa" "$pa"); idb=$(ensure_port "$fb" "$pb")
|
|
[ -n "$ida" ] && [ -n "$idb" ] || { echo "SKIP link $fa/$pa <-> $fb/$pb (missing CI/port)" >&2; continue; }
|
|
lo=$(( ida < idb ? ida : idb )); hi=$(( ida < idb ? idb : ida ))
|
|
if api GET "search/NetworkPort_NetworkPort?criteria%5B0%5D%5Bfield%5D=13&criteria%5B0%5D%5Bsearchtype%5D=equals&criteria%5B0%5D%5Bvalue%5D=$lo" \
|
|
| grep -q "\"$hi\""; then conn_dup=$((conn_dup+1)); continue; fi
|
|
printf '{"input": {"networkports_id_1": %s, "networkports_id_2": %s}}' "$lo" "$hi" > "$TMP_CONN"
|
|
r=$(api POST NetworkPort_NetworkPort "$TMP_CONN")
|
|
st=$(echo "$r" | jq -r 'if type=="array" then .[0].id else .id end // empty' 2>/dev/null)
|
|
if [ -n "$st" ]; then conn_created=$((conn_created+1)); else conn_dup=$((conn_dup+1)); fi
|
|
done < "$TMP_PAIRS"
|
|
echo "ports: created=$port_created | connections: created=$conn_created dup/skip=$conn_dup"
|
|
curl -sk --max-time 15 -X DELETE -H "App-Token: ${MGLPI_APP_TOKEN}" -H "Session-Token: $S" "${MGLPI_URL}/killSession" -o /dev/null
|
|
exit 0
|