igneum/infra/seed-nodes/health.sh
igneum-labs 72351e8270 Testnet seeds: NET=testnet profile for the seed scripts, seeds-testnet.tsv (3 Hetzner VMs), dns.sh (deSEC), the public RPC allowlist and nginx site, build-job.mjs forwards --node-tests
seed1.testnet nbg1 195.201.35.33, seed2.testnet ash 5.161.232.205, seed3.testnet sin 5.223.52.210 (5 October 2026). Ports 26810/26811/28810/26890
from seed.env; provision-seed.sh BUILD_WHERE=cross takes the PC build job's Linux igneumd from infra/cross/out.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-05 15:46:22 +00:00

38 lines
3.4 KiB
Bash
Executable file

#!/usr/bin/env bash
# Health check for every seed in seeds.tsv (or one name). One line per seed, exit 1 if any check fails.
# Checks: p2p port reachable from here (nc), unit active (igneumd, or igneumd-v4 after switch-v4.sh: shown as active-v4), RPC answers, synced flag, blocks and headers, connected
# peers, known addresses (the peer-exchange table), disk and memory. Add --watch to repeat every 60 s.
. "$(dirname "$0")/lib.sh"
only="${1:-}"; [ "$only" = --watch ] && only=""
fail=0
check_one() {
local name="$1" ip; ip=$(seed_ip "$name")
local port=FAIL unit=? info= dag= peers=? known=? disk=? mem=? synced=? ver=? blocks=? headers=? sink=?
if nc -z -w 5 "$ip" "$P2P_PORT" >/dev/null 2>&1; then port=open; fi
local raw
raw=$(sssh "$ip" "export IGNEUM_RPC=ws://127.0.0.1:$RPC_JSON_PORT; if systemctl is-active igneumd-v4 >/dev/null 2>&1; then echo active-v4; else systemctl is-active igneumd 2>/dev/null; fi; echo '|'; python3 /opt/igneum/bin/wrpc.py call getInfo 2>/dev/null; echo '|'; python3 /opt/igneum/bin/wrpc.py call getBlockDagInfo 2>/dev/null; echo '|'; python3 /opt/igneum/bin/wrpc.py call getConnectedPeerInfo 2>/dev/null | python3 -c 'import json,sys; print(len(json.load(sys.stdin).get(\"peerInfo\",[])))' 2>/dev/null; echo '|'; python3 /opt/igneum/bin/wrpc.py call getPeerAddresses 2>/dev/null | python3 -c 'import json,sys; j=json.load(sys.stdin); print(len(j.get(\"knownAddresses\",[])), len(j.get(\"bannedAddresses\",[])))' 2>/dev/null; echo '|'; df -h / | awk 'NR==2 { print \$5 }'; echo '|'; free -m | awk 'NR==2 { print \$3 \"/\" \$2 \"MB\" }'" 2>/dev/null) || raw=""
unit=$(printf '%s' "$raw" | awk -F'|' 'NR==1 { gsub(/\n/, "", $1); print $1 }' | tr -d '\n')
info=$(printf '%s' "$raw" | awk 'BEGIN{RS="|"} NR==2' | tr -d '\n')
dag=$(printf '%s' "$raw" | awk 'BEGIN{RS="|"} NR==3' | tr -d '\n')
peers=$(printf '%s' "$raw" | awk 'BEGIN{RS="|"} NR==4' | tr -d '\n ')
known=$(printf '%s' "$raw" | awk 'BEGIN{RS="|"} NR==5' | tr -d '\n')
disk=$(printf '%s' "$raw" | awk 'BEGIN{RS="|"} NR==6' | tr -d '\n ')
mem=$(printf '%s' "$raw" | awk 'BEGIN{RS="|"} NR==7' | tr -d '\n ')
if [ -n "$info" ]; then
synced=$(printf '%s' "$info" | python3 -c 'import json,sys; j=json.load(sys.stdin); print(j.get("isSynced"))' 2>/dev/null || echo ?)
ver=$(printf '%s' "$info" | python3 -c 'import json,sys; j=json.load(sys.stdin); print(j.get("serverVersion"))' 2>/dev/null || echo ?)
fi
if [ -n "$dag" ]; then
read -r blocks headers sink <<< "$(printf '%s' "$dag" | python3 -c 'import json,sys; j=json.load(sys.stdin); print(j.get("blockCount"), j.get("headerCount"), str(j.get("sink",""))[:12])' 2>/dev/null || echo "? ? ?")"
fi
local ok=OK
case "$unit" in active|active-v4) ;; *) ok=FAIL; fail=1 ;; esac # active-v4: the devnet-v4 unit (igneumd-v4) serves instead of igneumd
if [ "$port" != open ] || [ -z "$info" ]; then ok=FAIL; fail=1; fi
printf '%s %-14s %-15s p2p=%s unit=%s rpc=%s synced=%s blocks=%s headers=%s sink=%s peers=%s known/banned=%s disk=%s mem=%s version=%s\n' \
"$ok" "$name" "$ip" "$port" "${unit:-?}" "$([ -n "$info" ] && echo yes || echo no)" "$synced" "${blocks:-?}" "${headers:-?}" "${sink:-?}" "$peers" "${known:-?}" "$disk" "$mem" "$ver"
}
run() {
[ -s "$SEEDS_TSV" ] || die "no seeds.tsv"
if [ -n "$only" ]; then check_one "$only"; else for n in $(seed_names); do check_one "$n"; done; fi
}
if [ "${1:-}" = --watch ] || [ "${2:-}" = --watch ]; then while true; do run; sleep 60; done; else run; exit $fail; fi