diff --git a/deploy.sh b/deploy.sh index 18fdffe..feb7fcc 100755 --- a/deploy.sh +++ b/deploy.sh @@ -7,6 +7,7 @@ # ./deploy.sh --diff [conf] # what would change in /etc # ./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 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 @@ -131,6 +132,15 @@ if [ "$ENABLE_FRIGATE" = 1 ]; then fi } +classify_unit() { # classify_unit -> ok | finished | wait | warn + case "$1" in + active) echo ok ;; + activating|reloading) echo wait ;; + inactive) if [ "${2:-}" = success ] && [ "${3:-}" = 0 ]; then echo finished; else echo warn; fi ;; + *) echo warn ;; + esac +} + post_check() { # read-only live checks; every probe is guarded, warns instead of aborting set_units echo "== post-deploy check ==" @@ -146,10 +156,19 @@ post_check() { # read-only live checks; every probe is guarded, warns instead o pending+=("$u") done still=("${pending[@]}") + local -A verdict=() detail=() + local k v as res st ls while :; do local next=() for u in "${still[@]}"; do - systemctl is-active --quiet "$u" 2>/dev/null || next+=("$u") + as= res= st= ls= + while IFS='=' read -r k v; do + case "$k" in LoadState) ls=$v ;; ActiveState) as=$v ;; Result) res=$v ;; ExecMainStatus) st=$v ;; esac + done < <(systemctl show -p LoadState,ActiveState,Result,ExecMainStatus "$u" 2>/dev/null || true) + verdict[$u]=$(classify_unit "$as" "$res" "$st") + [ "$ls" = loaded ] || { verdict[$u]=warn; as="${as:-?}(LoadState=${ls:-?})"; } + detail[$u]="ActiveState=${as:-?} Result=${res:-?}" + case "${verdict[$u]}" in ok|finished) ;; *) next+=("$u") ;; esac done still=("${next[@]}") [ ${#still[@]} -eq 0 ] && break @@ -157,8 +176,11 @@ post_check() { # read-only live checks; every probe is guarded, warns instead o sleep 1 done for u in "${pending[@]}"; do - if [[ " ${still[*]:-} " == *" $u "* ]]; then warn "post-deploy: unit $u is not active" - else echo " ok unit $u active"; fi + case "${verdict[$u]:-warn}" in + ok) echo " ok unit $u active" ;; + finished) echo " ok unit $u finished (exit 0)" ;; + *) warn "post-deploy: unit $u is not active (${detail[$u]:-state unknown})" ;; + esac done # b. bridge address has_br0_addr() { local o; o=$(ip -4 -br addr show dev br0 2>/dev/null) || true; [[ $o == *"$GATEWAY_IP/$GATEWAY_PREFIX"* ]]; } @@ -240,6 +262,9 @@ case "${1:-}" in --redact) # ./deploy.sh --redact — stdin through redact_secrets (no config, no root) redact_secrets exit 0 ;; + --classify-unit) # ./deploy.sh --classify-unit + classify_unit "${2:-}" "${3:-}" "${4:-}" + 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 ae7a69a..edb2001 100755 --- a/tests/check-templates.sh +++ b/tests/check-templates.sh @@ -184,4 +184,13 @@ elif echo "$pc" | grep -q 'van-nvme-watch'; then bad "--post-check mentions van- else ok "--post-check skips van-nvme-watch when ENABLE_NVME_WATCH=0"; fi if grep -q 'USB hub' deploy.sh; then bad "stale 'USB hub' text remains in deploy.sh"; else ok "no stale 'USB hub' text in deploy.sh"; fi +# 12. unit-state classification used by post_check (run-to-completion units are not failures) +for row in "active success 0:ok" "inactive success 0:finished" "failed exit-code 1:warn" \ + "activating success 0:wait" "inactive exit-code 1:warn" "inactive success 1:warn"; do + args=${row%%:*}; want=${row##*:} + # shellcheck disable=SC2086 + got=$(./deploy.sh --classify-unit $args 2>&1) || true + if [ "$got" = "$want" ]; then ok "--classify-unit $args -> $want"; else bad "--classify-unit $args gave '$got', want '$want'"; fi +done + exit "$fail"