Files
dashboards/scripts/capture-node-exporter.sh
T
ducoterra c4bb374ccc Add homelab dashboards: system, LLM, and UPS on one domain
Three dashboards served by one FastAPI app with a SQLite history store
(raw / 1m / 1h) and hand-written SVG charts: no Prometheus, no Grafana,
no CDN, no build step. Nothing is fetched from the internet at runtime.

* system: a stdlib-only agent (agent/host_agent.py) reports /proc and
  /sys counters; the dashboard turns them into rates over a labelled
  window, so every number says how it was measured.
* llm: gufo/llama.cpp and vLLM /metrics are parsed by an in-house
  exposition parser. Measured delta/elapsed throughput beats a native
  per-request gauge, and each value carries its provenance.
* ups: a NUT wire-protocol client plus health checks that name what
  they looked at. Commands are gated by NUT_ALLOW_ACTIONS,
  DASH_READ_ONLY and a DANGER confirmation, re-checked server-side.

Missing values render as n/a rather than 0, and an unconfigured source
answers 404 {"configured": false} without dialling anything, so "not
deployed here" never looks like an outage.

253 tests at 94% coverage against captured real fixtures; ruff and
pyright clean.

LLM-Generated: true
2026-10-16 17:20:45 -04:00

47 lines
2.1 KiB
Bash
Executable File

#!/usr/bin/env bash
# Capture a REAL node_exporter exposition from each monitored host into tests/fixtures/.
#
# Runs node_exporter in the foreground on the remote host for a few seconds, scrapes it
# over loopback there, and saves the text. Nothing is installed as a service and no port
# is opened: the only network hop is ssh.
#
# ./scripts/capture-node-exporter.sh # all hosts
# ./scripts/capture-node-exporter.sh driveripper-ops # one host
#
# Why: metric names must be verified against the deployed exporter (see AGENTS.md), never
# guessed from the upstream README.
set -uo pipefail
VERSION="${NODE_EXPORTER_VERSION:-1.12.1}"
OUT="$(cd "$(dirname "$0")/.." && pwd)/tests/fixtures"
HOSTS=("${@:-driveripper-ops deskwork-ops gateway-ops}")
PORT=9199
ARGS="--collector.drm --collector.thermal_zone --collector.cpufreq --collector.hwmon --web.listen-address=127.0.0.1:${PORT}"
mkdir -p "$OUT"
command -v ssh >/dev/null || { echo "ssh not found"; exit 1; }
for host in $HOSTS; do
echo "=== $host"
ssh -n -o ConnectTimeout=10 "$host" "set -e
mkdir -p \$HOME/exporters && cd \$HOME/exporters
if [ ! -x node_exporter ]; then
curl -sSL -o ne.tgz https://github.com/prometheus/node_exporter/releases/download/v${VERSION}/node_exporter-${VERSION}.linux-amd64.tar.gz
tar xzf ne.tgz && mv node_exporter-${VERSION}.linux-amd64/node_exporter .
rm -rf ne.tgz node_exporter-${VERSION}.linux-amd64
fi
timeout 8 ./node_exporter ${ARGS} >/dev/null 2>&1 &
sleep 3
curl -s --max-time 5 127.0.0.1:${PORT}/metrics
" > "$OUT/node_exporter_${host}.txt" 2>/dev/null
lines=$(wc -l < "$OUT/node_exporter_${host}.txt")
if [ "$lines" -lt 20 ]; then
echo " FAILED (only $lines lines) — check ssh access to $host"
rm -f "$OUT/node_exporter_${host}.txt"
continue
fi
echo " saved $lines lines -> tests/fixtures/node_exporter_${host}.txt"
echo " gpu: $(grep -cE '^node_gpu' "$OUT/node_exporter_${host}.txt") node_gpu series"
grep -oE '^node_gpu[a-z_]*' "$OUT/node_exporter_${host}.txt" | sort -u | sed 's/^/ /' | head -20
done