#!/bin/sh
# Auto-abort for a WAN failover drill. Armed on the router that is EXPECTED TO
# TAKE OVER, before the drill starts.
#
# The drill takes the internet down for as long as the new master needs to
# raise a WAN. If it never does, whoever is running the drill has no internet
# either -- and if that is an agent, it simply stops responding mid-incident.
# So the abort cannot depend on anyone being there.
#
# Rule: if I hold the VIP and have had NO WAN for HOLD consecutive seconds,
# stand down. force-fault sheds every VIP and the peer -- which is healthy and
# merely non-preempting -- takes them straight back.
#
# This is deliberately SHORTER than GRACE in vrrp-wan.conf (300s). GRACE is
# sized for a real hostile-ISP takeover that is still making progress; this is
# sized for "the drill failed, give the house its internet back". Anything the
# drill proves after two and a half minutes of downtime is not worth the
# downtime.
#
#   wan-drill-watchdog arm [seconds]     background it, then run the drill
#   wan-drill-watchdog disarm            cancel it (drill succeeded)

STATE=/run/vrrp-wan
VIP=192.168.1.1
[ -r /config/vrrp-wan.conf ] && . /config/vrrp-wan.conf
VIP="${VRRP_WAN_VIP:-$VIP}"
HOLD="${2:-150}"
PIDF=/run/wan-drill-watchdog.pid

have_vip() { ip -4 -o addr show 2>/dev/null | grep -q " ${VIP}/"; }
have_wan() {
    ip -4 addr show dev bond0.53 2>/dev/null | grep -q 'inet ' && return 0
    ip -4 addr show dev pppoe0   2>/dev/null | grep -q 'inet ' && return 0
    return 1
}

case "${1:-arm}" in
disarm)
    if [ -f "$PIDF" ]; then
        kill "$(cat "$PIDF")" 2>/dev/null
        rm -f "$PIDF"
        echo "  watchdog disarmed"
    else
        echo "  no watchdog armed"
    fi
    exit 0
    ;;
arm)
    [ -f "$PIDF" ] && kill "$(cat "$PIDF")" 2>/dev/null
    mkdir -p "$STATE" 2>/dev/null
    # setsid so it survives the ssh session that armed it going away -- the
    # whole point is that it outlives whoever started the drill.
    setsid sh -c '
        bad=0
        while :; do
            sleep 5
            if ip -4 -o addr show 2>/dev/null | grep -q " '"$VIP"'/"; then
                if ip -4 addr show dev bond0.53 2>/dev/null | grep -q "inet " ||
                   ip -4 addr show dev pppoe0 2>/dev/null | grep -q "inet "; then
                    bad=0
                else
                    bad=$((bad + 5))
                fi
            else
                bad=0
            fi
            if [ "$bad" -ge '"$HOLD"' ]; then
                logger -t wan-drill "ABORT: held the VIP with no WAN for '"$HOLD"'s -- standing down"
                touch '"$STATE"'/force-fault
                rm -f '"$PIDF"'
                exit 0
            fi
        done
    ' >/dev/null 2>&1 &
    echo $! > "$PIDF"
    echo "  watchdog armed (pid $(cat "$PIDF")): stand down after ${HOLD}s holding the VIP with no WAN"
    exit 0
    ;;
*)
    echo "usage: wan-drill-watchdog [arm [seconds]|disarm]" >&2
    exit 2
    ;;
esac
