cluster: stable hostname for mam-api, jq-based smoke test

mam-api self-heartbeat now reads NODE_HOSTNAME so primary rows survive container restarts instead of resurrecting with the random container ID. test-cluster.sh rewritten to use jq (the python f-strings had a parse bug that silently passed the IP check) and limited the docker-bridge alarm to 172.17.x since the user LAN occupies 172.18.0.0/16.
This commit is contained in:
Zac Gaetano 2026-05-21 11:50:52 +00:00
parent 8aa378348e
commit 4a3a672cbe
3 changed files with 14 additions and 17 deletions

View file

@ -72,7 +72,7 @@ nodes = json.load(sys.stdin)
seen = {} seen = {}
dups = [] dups = []
for n in nodes: for n in nodes:
h = n.get("hostname") h = n.get('hostname')
if h in seen: dups.append(h) if h in seen: dups.append(h)
seen[h] = True seen[h] = True
print(",".join(sorted(set(dups))))' 2>/dev/null) print(",".join(sorted(set(dups))))' 2>/dev/null)
@ -82,16 +82,16 @@ print(",".join(sorted(set(dups))))' 2>/dev/null)
fail "duplicate hostnames: $DUP — run migration 007" fail "duplicate hostnames: $DUP — run migration 007"
fi fi
# No private docker IPs # No private docker IPs (172.16.0.0/12 reserved for docker bridges)
BAD_IPS=$(echo "$NODES_JSON" | python3 -c ' BAD_IPS=""
import sys, json, re while IFS=$'\t' read -r host ip; do
docker = re.compile(r"^172\.(1[6-9]|2\d|3[01])\.") [[ -z "$ip" ]] && continue
bad = [] first="${ip%%.*}"; rest="${ip#*.}"; second="${rest%%.*}"
for n in json.load(sys.stdin): if [[ "$first" == "172" && "$second" == "17" ]]; then
ip = n.get("ip_address") or "" BAD_IPS+="${host}=${ip},"
if docker.match(ip): fi
bad.append(f"{n.get(\"hostname\")}={ip}") done < <(echo "$NODES_JSON" | jq -r '.[] | [.hostname, (.ip_address // "")] | @tsv')
print(",".join(bad))' 2>/dev/null) BAD_IPS="${BAD_IPS%,}"
if [[ -z "$BAD_IPS" ]]; then if [[ -z "$BAD_IPS" ]]; then
pass "all node IPs are real LAN addresses" pass "all node IPs are real LAN addresses"
else else
@ -162,11 +162,7 @@ BMD_JSON=$(api GET /api/v1/cluster/devices/blackmagic || echo '[]')
BMD_COUNT=$(echo "$BMD_JSON" | python3 -c 'import sys,json; print(len(json.load(sys.stdin)))' 2>/dev/null || echo 0) BMD_COUNT=$(echo "$BMD_JSON" | python3 -c 'import sys,json; print(len(json.load(sys.stdin)))' 2>/dev/null || echo 0)
if [[ "$BMD_COUNT" -gt 0 ]]; then if [[ "$BMD_COUNT" -gt 0 ]]; then
pass "$BMD_COUNT DeckLink port(s) registered" pass "$BMD_COUNT DeckLink port(s) registered"
echo "$BMD_JSON" | python3 -c ' echo "$BMD_JSON" | jq -r '.[] | " \(.hostname) port=\(.index) model=\(.model // "unknown") online=\(.online)"'
import sys, json
for d in json.load(sys.stdin):
print(f" {d.get(\"hostname\")} port={d.get(\"index\")} model={d.get(\"model\") or \"unknown\"} online={d.get(\"online\")}")
'
else else
warn "no DeckLink devices reported by any node" warn "no DeckLink devices reported by any node"
fi fi

View file

@ -48,6 +48,7 @@ services:
AUTH_ENABLED: ${AUTH_ENABLED:-false} AUTH_ENABLED: ${AUTH_ENABLED:-false}
DOCKER_NETWORK: wild-dragon_wild-dragon DOCKER_NETWORK: wild-dragon_wild-dragon
NODE_IP: ${NODE_IP} NODE_IP: ${NODE_IP}
NODE_HOSTNAME: ${NODE_HOSTNAME:-}
deploy: deploy:
resources: resources:
reservations: reservations:

View file

@ -163,7 +163,7 @@ async function selfHeartbeat() {
capabilities = EXCLUDED.capabilities, capabilities = EXCLUDED.capabilities,
last_seen = NOW()`, last_seen = NOW()`,
[ [
os.hostname(), process.env.NODE_HOSTNAME || os.hostname(),
getLocalIp(), getLocalIp(),
process.env.npm_package_version || null, process.env.npm_package_version || null,
`http://${getLocalIp()}:${PORT}`, `http://${getLocalIp()}:${PORT}`,