post-check: failover check warns only on link without NM connection; retry, stub-nmcli tests

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KqhjP7nud5gdBg25zCiRk9
This commit is contained in:
2026-09-23 19:11:55 -04:00
co-authored by Claude Sonnet 5
parent 2601472576
commit 698f9ee446
3 changed files with 78 additions and 25 deletions
+31 -14
View File
@@ -22,6 +22,7 @@
# VANLINK_SYSNET=<dir> # test override: sysfs net dir used by --post-check (default /sys/class/net)
# VANLINK_FAILOVER_STATE=<file> # test override: van-failover state file read by --post-check (default /run/van-failover/state.json)
# VANLINK_APPLY_STATUS=<file> # test override: apply-network status file read by --post-check (default /var/lib/vanlink/apply-network.status)
# VANLINK_WAN_NETPLAN=<file> # test override: installed WAN netplan compared by nm_wan_state_netplan (default /etc/netplan/50-van-wan.yaml)
# VANLINK_NM_DIR=<dir> # test override: where existing NM *.nmconnection files are looked up (default /etc/NetworkManager/system-connections)
# Idempotent. Netplan (the NM-managed WANs; eth0 is a LAN port on br0) is never
# changed by a routine deploy (applying it flaps the uplinks). ENABLE_NM_WAN=0:
@@ -106,8 +107,9 @@ render_wan_netplan() { # ap/50-van-wan.yaml, plus the wifis stanza when the hos
}
nm_wan_state_netplan() { # missing | differs | matches (the installed WAN netplan vs the rendered one)
if [ ! -f /etc/netplan/50-van-wan.yaml ]; then echo missing
elif diff -q <(render_wan_netplan) /etc/netplan/50-van-wan.yaml >/dev/null 2>&1; then echo matches
local f=${VANLINK_WAN_NETPLAN:-/etc/netplan/50-van-wan.yaml}
if [ ! -f "$f" ]; then echo missing
elif diff -q <(render_wan_netplan) "$f" >/dev/null 2>&1; then echo matches
else echo differs; fi
}
@@ -294,29 +296,42 @@ post_check() { # read-only live checks; every probe is guarded, warns instead o
done
# i. cellular connection
if [ -n "${CELLULAR_APN:-}" ]; then
if { nmcli -t -f NAME connection show 2>/dev/null || true; } | grep -qxF "$CELLULAR_CONN_NAME" || cellular_profile_exists; then
if cellular_profile_exists; then
echo " ok NetworkManager connection $CELLULAR_CONN_NAME exists"
else warn "post-deploy: NetworkManager connection $CELLULAR_CONN_NAME not found"; fi
fi
# j. van-failover state: every WAN whose device exists must be present
# j. van-failover state: "present" = the device has an active NM connection, so an
# unplugged/out-of-range WAN is normal; only a device WITH link and present:false is actionable
fst=${VANLINK_FAILOVER_STATE:-/run/van-failover/state.json}
if out=$(python3 - "$fst" "$sysnet" 2>/dev/null <<'PY'
import json, os, sys
fo_read() { # parses the state file (needs a valid "updated" and "wans"); sets $out
out=$(python3 - "$fst" "$sysnet" 2>/dev/null <<'PY'
import json, os, sys, time
try:
with open(sys.argv[1]) as f:
wans = json.load(f)["wans"]
for w in wans:
d = json.load(f)
time.strptime(d["updated"], "%Y-%m-%dT%H:%M:%S%z")
for w in d["wans"]:
dev = w.get("device") or ""
if dev and os.path.exists(os.path.join(sys.argv[2], dev)):
print(("ok" if w.get("present") is True else "notpresent"), w.get("name", "?"), dev)
if not dev or not os.path.exists(os.path.join(sys.argv[2], dev)):
continue
try:
with open(os.path.join(sys.argv[2], dev, "carrier")) as c:
if c.read().strip() != "1":
continue
except Exception:
continue
print(("ok" if w.get("present") is True else "nocon"), w.get("name", "?"), dev)
except Exception:
sys.exit(3)
PY
); then
)
}
if ! command -v python3 >/dev/null 2>&1; then warn "post-deploy: python3 not available — cannot read the van-failover state"
elif retry fo_read; then
while read -r as_f as_l n; do
[ -n "$as_f" ] || continue
if [ "$as_f" = ok ]; then echo " ok van-failover: WAN $as_l ($n) present"
else warn "post-deploy: van-failover reports WAN $as_l ($n) not present although the device exists"; fi
if [ "$as_f" = ok ]; then echo " ok van-failover: WAN $as_l ($n) has an active NetworkManager connection"
else warn "post-deploy: $as_l ($n) has link but no active NetworkManager connection — not handed to NM yet (./deploy.sh --apply-network) or its profile is missing"; fi
done <<<"$out"
else warn "post-deploy: van-failover state $fst missing or unreadable"; fi
# k. netplan drift
@@ -325,10 +340,12 @@ PY
# l. last --apply-network
as_f=${VANLINK_APPLY_STATUS:-/var/lib/vanlink/apply-network.status}
if [ -r "$as_f" ]; then
as_l=$(head -n1 "$as_f" 2>/dev/null) || as_l=
as_l=$(grep -m1 '[^[:space:]]' "$as_f" 2>/dev/null) || as_l=
case "${as_l%% *}" in
"") ;;
ok) echo " ok last --apply-network: $as_l" ;;
running|rolled-back|rollback-failed) warn "post-deploy: last --apply-network status: $as_l — see /var/log/vanlink-apply-network.log" ;;
*) warn "post-deploy: unrecognised apply-network status: $as_l" ;;
esac
fi
fi