This commit is contained in:
2026-02-25 09:32:11 +02:00
parent 06ffc605f7
commit 08c6a089af

View File

@@ -20,17 +20,6 @@ NB_URL="${NB_URL:-http://netbox.gt-tiso.ikeja.co.za}"
# Tip: Prefer setting NB_TOKEN via environment. Leaving default blank avoids accidental leaks.
NB_TOKEN="${NB_TOKEN:-}"
# --- Optional performance knobs ---
# NB_PREREAD=1 enables extra GETs to print pre-change values (more load on NetBox).
NB_PREREAD="${NB_PREREAD:-0}"
# Device ID cache (per worker process)
# Cache entries are considered fresh for 60 minutes. After that, they may be used up to an
# additional random 3-10 minutes ("stale window") before a refresh is attempted.
NB_IDCACHE_TTL_SECS="${NB_IDCACHE_TTL_SECS:-3600}"
NB_IDCACHE_STALE_MIN_SECS="${NB_IDCACHE_STALE_MIN_SECS:-180}"
NB_IDCACHE_STALE_MAX_SECS="${NB_IDCACHE_STALE_MAX_SECS:-600}"
log() { echo "[netbox-reporter] $*"; }
warn(){ echo "[netbox-reporter][WARN] $*" >&2; }
err() { echo "[netbox-reporter][ERROR] $*" >&2; }
@@ -44,54 +33,6 @@ fi
# URL-encode for RabbitMQ HTTP API paths
urlenc() { printf '%s' "$1" | sed -e 's, ,%20,g' -e 's,/,%2F,g'; }
# --- helpers ---
now_epoch() { date +%s; }
rand_between() {
local min="$1" max="$2"
# inclusive range
echo $(( min + (RANDOM % (max - min + 1)) ))
}
# Device ID cache (associative arrays require bash 4+)
declare -A NB_DEV_ID_CACHE=()
declare -A NB_DEV_ID_CACHE_EXPIRES=()
declare -A NB_DEV_ID_CACHE_STALE_UNTIL=()
nb_get_device_id_cached() {
local name="$1"
local now exp stale id jitter
now="$(now_epoch)"
id="${NB_DEV_ID_CACHE[$name]:-}"
exp="${NB_DEV_ID_CACHE_EXPIRES[$name]:-0}"
stale="${NB_DEV_ID_CACHE_STALE_UNTIL[$name]:-0}"
# Fresh cache hit
if [[ -n "$id" && "$now" -lt "$exp" ]]; then
printf '%s' "$id"
return 0
fi
# Stale-but-usable cache hit (during jitter window): return cached ID, don't refresh yet
if [[ -n "$id" && "$now" -ge "$exp" && "$now" -lt "$stale" ]]; then
printf '%s' "$id"
return 0
fi
# Cache miss or refresh time: refresh via NetBox
id="$(nb_find_device_id "$name")" || true
if [[ -n "$id" ]]; then
NB_DEV_ID_CACHE["$name"]="$id"
NB_DEV_ID_CACHE_EXPIRES["$name"]=$(( now + NB_IDCACHE_TTL_SECS ))
jitter="$(rand_between "$NB_IDCACHE_STALE_MIN_SECS" "$NB_IDCACHE_STALE_MAX_SECS")"
NB_DEV_ID_CACHE_STALE_UNTIL["$name"]=$(( now + NB_IDCACHE_TTL_SECS + jitter ))
printf '%s' "$id"
return 0
fi
return 1
}
# Simple RabbitMQ HTTP call
rmq_api() {
local method="$1" path="$2" data="${3:-}"
@@ -110,7 +51,7 @@ nb_find_device_id() {
resp="$(curl -sS \
-H "Authorization: Token $NB_TOKEN" \
-H "Accept: application/json" \
"$NB_URL/api/dcim/devices/?name=$(printf '%s' "$name" | jq -sRr @uri)&limit=1&fields=id")" || return 1
"$NB_URL/api/dcim/devices/?name=$(printf '%s' "$name" | jq -sRr @uri)&limit=1")" || return 1
jq -r '.results[0].id // empty' <<<"$resp"
}
@@ -121,7 +62,7 @@ nb_read_custom_field() {
resp="$(curl -sS \
-H "Authorization: Token $NB_TOKEN" \
-H "Accept: application/json" \
"$NB_URL/api/dcim/devices/$dev_id/?fields=custom_fields")" || return 1
"$NB_URL/api/dcim/devices/$dev_id/")" || return 1
jq -r --arg k "$key" '
(.custom_fields[$k] // empty)
| (if type=="object" or type=="array" then tojson else . end)
@@ -132,15 +73,11 @@ nb_read_custom_field() {
nb_patch_update_wo_restart() {
local dev_id="$1" update_progress="$2" updating_to="$3"
# Pre-read current values and print (optional; enable with NB_PREREAD=1)
# Pre-read current values and print
local prev_p prev_u
if [[ "${NB_PREREAD}" == "1" ]]; then
prev_p="$(nb_read_custom_field "$dev_id" "update_progress" || true)"
prev_u="$(nb_read_custom_field "$dev_id" "updating_to" || true)"
echo ">>> Pre-change (id=$dev_id): update_progress='${prev_p:-<unset>}'; updating_to='${prev_u:-<unset>}'"
else
echo ">>> Pre-change (id=$dev_id): update_progress='<skipped>'; updating_to='<skipped>'"
fi
local body
body="$(jq -n --arg p "$update_progress" --arg u "$updating_to" \
@@ -166,14 +103,10 @@ nb_patch_update_wo_restart() {
nb_patch_wifidebug() {
local dev_id="$1" value="$2"
# Pre-read current value and print (optional; enable with NB_PREREAD=1)
# Pre-read current value and print
local prev
if [[ "${NB_PREREAD}" == "1" ]]; then
prev="$(nb_read_custom_field "$dev_id" "wifidebug" || true)"
echo ">>> Pre-change (id=$dev_id): wifidebug='${prev:-<unset>}'"
else
echo ">>> Pre-change (id=$dev_id): wifidebug='<skipped>'"
fi
local body
body="$(jq -n --arg v "$value" '{custom_fields: {wifidebug: $v}}')"
@@ -245,14 +178,10 @@ nb_add_journal_raw() {
nb_set_multiple_ssids_yes() {
local dev_id="$1"
# Pre-read current value and print (optional; enable with NB_PREREAD=1)
# Pre-read current value and print
local prev
if [[ "${NB_PREREAD}" == "1" ]]; then
prev="$(nb_read_custom_field "$dev_id" "multiple_ssids" || true)"
echo ">>> Pre-change (id=$dev_id): multiple_ssids='${prev:-<unset>}'"
else
echo ">>> Pre-change (id=$dev_id): multiple_ssids='<skipped>'"
fi
local body='{"custom_fields":{"multiple_ssids":"yes"}}'
@@ -312,7 +241,7 @@ nb_add_tag_by_slug() {
dev_detail="$(curl -sS \
-H "Authorization: Token $NB_TOKEN" \
-H "Accept: application/json" \
"$NB_URL/api/dcim/devices/$dev_id/?fields=tags")"
"$NB_URL/api/dcim/devices/$dev_id/")"
existing_objs_json="$(
jq -c '
(.tags // []) as $t |
@@ -365,7 +294,7 @@ nb_remove_tag_by_slug() {
dev_detail="$(curl -sS \
-H "Authorization: Token $NB_TOKEN" \
-H "Accept: application/json" \
"$NB_URL/api/dcim/devices/$dev_id/?fields=tags")" || return 1
"$NB_URL/api/dcim/devices/$dev_id/")" || return 1
# Normalize tags to objects: [{name, slug?}]
existing_objs_json="$(
@@ -424,14 +353,10 @@ nb_remove_tag_by_slug() {
nb_clear_update_progress() {
local dev_id="$1"
# Pre-read current value and print (optional; enable with NB_PREREAD=1)
# Pre-read current value and print
local prev
if [[ "${NB_PREREAD}" == "1" ]]; then
prev="$(nb_read_custom_field "$dev_id" "update_progress" || true)"
echo ">>> Pre-change (id=$dev_id): update_progress='${prev:-<unset>}'"
else
echo ">>> Pre-change (id=$dev_id): update_progress='<skipped>'"
fi
local body='{"custom_fields":{"update_progress":null}}'
local code
@@ -453,14 +378,10 @@ nb_clear_update_progress() {
nb_patch_custom_field() {
local dev_id="$1" key="$2" value="$3"
# Pre-read current value and print (optional; enable with NB_PREREAD=1)
# Pre-read current value and print
local prev
if [[ "${NB_PREREAD}" == "1" ]]; then
prev="$(nb_read_custom_field "$dev_id" "$key" || true)"
echo ">>> Pre-change (id=$dev_id): ${key}='${prev:-<unset>}'"
else
echo ">>> Pre-change (id=$dev_id): ${key}='<skipped>'"
fi
# Build {"custom_fields": { "<key>": "<value>" }}
local body
@@ -502,7 +423,7 @@ handle_payload() {
fi
local dev_id
dev_id="$(nb_get_device_id_cached "$device")"
dev_id="$(nb_find_device_id "$device")"
if [[ -z "$dev_id" ]]; then
err "Device '$device' not found in NetBox"
return 0