diff --git a/deploy.sh b/deploy.sh index feb7fcc..313ad66 100755 --- a/deploy.sh +++ b/deploy.sh @@ -8,6 +8,7 @@ # ./deploy.sh --post-check [conf] # read-only live checks (units, br0, LAN, NAT, dnsmasq, radios, uplink); exit 1 on any warning # # POSTCHECK_WAIT=: seconds retried probes may wait in total (default 15; 0 = single attempt) # ./deploy.sh --classify-unit # prints ok|finished|wait|warn (used by post_check; for tests) +# ./deploy.sh --classify-radio # reads `iw dev info` text on stdin, prints beaconing|silent (no ssid line = silent; used by post_check; for tests) # ./deploy.sh render # preview a templated file on stdout # ./deploy.sh --redact # filter stdin, masking secret values (used by --diff; for tests) # Idempotent. Netplan (wlan0 + Starlink NIC = NM-managed WANs; eth0 is a LAN @@ -141,6 +142,15 @@ classify_unit() { # classify_unit -> ok esac } +classify_radio() { # stdin: `iw dev info` text -> beaconing (has an ssid line) | silent + local line + while IFS= read -r line || [ -n "$line" ]; do + line=${line#"${line%%[![:space:]]*}"} + case "$line" in "ssid "*) echo beaconing; return 0 ;; esac + done + echo silent +} + post_check() { # read-only live checks; every probe is guarded, warns instead of aborting set_units echo "== post-deploy check ==" @@ -204,11 +214,16 @@ post_check() { # read-only live checks; every probe is guarded, warns instead o has_dhcp() { local o; o=$(ss -ulnH 2>/dev/null | awk '{print $4}') || true; [[ $'\n'$o == *:67$'\n'* || $o == *:67 ]]; } if retry has_dhcp; then echo " ok dnsmasq bound to UDP 67" else warn "post-deploy: nothing bound to UDP port 67 (dnsmasq DHCP)"; fi - # f. AP radios + # f. AP radios (present but no ssid = hostapd is not beaconing) + radio_beaconing() { out=$(iw dev "$1" info 2>/dev/null) || return 1 + [ "$(classify_radio <<<"$out")" = beaconing ]; } for n in "$WIFI_5G_IFACE" "$WIFI_2G_IFACE"; do - if out=$(iw dev "$n" info 2>/dev/null); then + u=hostapd; [ "$n" = "$WIFI_5G_IFACE" ] || u=hostapd-2g + out= + if retry radio_beaconing "$n"; then echo " ok radio $n: $(echo "$out" | grep -E 'ssid|channel' | sed 's/^[[:space:]]*//' | tr '\n' ';')" - else warn "post-deploy: radio $n not present (its hostapd keeps retrying until it appears)"; fi + elif [ -z "$out" ]; then warn "post-deploy: radio $n not present (its hostapd keeps retrying until it appears)" + else warn "post-deploy: radio $n is present but not beaconing (no ssid) — check: journalctl -u $u -n 30"; fi done # g. uplink out=$(ip route show default 2>/dev/null) || true @@ -265,6 +280,9 @@ case "${1:-}" in --classify-unit) # ./deploy.sh --classify-unit classify_unit "${2:-}" "${3:-}" "${4:-}" exit 0 ;; + --classify-radio) # ./deploy.sh --classify-radio < `iw dev info` text + classify_radio + exit 0 ;; --post-check) # ./deploy.sh --post-check [conf] — live checks, no root, no install; exit 1 on any warning load_conf "${2:-$VANLINK_CONF}" post_check diff --git a/tests/check-templates.sh b/tests/check-templates.sh index edb2001..78992f6 100755 --- a/tests/check-templates.sh +++ b/tests/check-templates.sh @@ -193,4 +193,13 @@ for row in "active success 0:ok" "inactive success 0:finished" "failed exit-code if [ "$got" = "$want" ]; then ok "--classify-unit $args -> $want"; else bad "--classify-unit $args gave '$got', want '$want'"; fi done +# 13. radio beaconing classification used by post_check (present but no ssid = not beaconing) +r_ok=$'Interface wlan1\n\tifindex 5\n\ttype AP\n\tssid VanLink2\n\tchannel 149 (5745 MHz), width: 80 MHz, center1: 5775 MHz' +r_bad=$'Interface wlxd8ec5e2faa8c\n\tifindex 6\n\twdev 0x100000001\n\taddr d8:ec:5e:2f:aa:8c\n\ttype AP\n\twiphy 39\n\ttxpower 30.00 dBm' +for row in "beaconing:$r_ok" "silent:$r_bad" "silent:"; do + want=${row%%:*}; inp=${row#*:} + got=$(printf '%s\n' "$inp" | ./deploy.sh --classify-radio 2>&1) || true + if [ "$got" = "$want" ]; then ok "--classify-radio -> $want"; else bad "--classify-radio gave '$got', want '$want'"; fi +done + exit "$fail"