#!/bin/sh

# Run keepalived through systemd on one end of a veth pair, and a second
# instance in a network namespace on the other end.

set -eu

cleanup() {
    systemctl stop keepalived || true
    [ ! -f "$AUTOPKGTEST_TMP/peer.pid" ] || kill "$(cat "$AUTOPKGTEST_TMP/peer.pid")" || true
    ip link del veth0 2>/dev/null || true
    ip netns del peer 2>/dev/null || true
    rm -f /etc/keepalived/keepalived.conf /etc/keepalived/notify.sh
}
trap cleanup EXIT

# Wait until a command succeeds
wait_for() {
    for i in $(seq 30); do
        if "$@"; then
            return 0
        fi
        sleep 1
    done
    echo "Timeout waiting for: $*" >&2
    ip addr show veth0 >&2
    journalctl -u keepalived --no-pager -n 50 >&2
    return 1
}

has_vip() {
    ip -4 addr show dev veth0 | grep -qF "inet $1/"
}
no_vip() {
    ! has_vip "$1"
}
state_is() {
    [ "$(cat "$AUTOPKGTEST_TMP/state" 2>/dev/null)" = "$1" ]
}

ip netns add peer
ip link add veth0 type veth peer name veth1 netns peer
ip addr add 192.0.2.1/24 dev veth0
ip link set veth0 up
ip -n peer addr add 192.0.2.2/24 dev veth1
ip -n peer link set veth1 up
ip -n peer link set lo up

cat > /etc/keepalived/notify.sh <<END
#!/bin/sh
echo "\$3" > "$AUTOPKGTEST_TMP/state"
END
chmod 755 /etc/keepalived/notify.sh

write_config() {
    cat > /etc/keepalived/keepalived.conf <<END
global_defs {
    router_id test
    enable_script_security
    script_user root
}
vrrp_instance VI_1 {
    state BACKUP
    interface veth0
    virtual_router_id 51
    priority 100
    advert_int 1
    notify /etc/keepalived/notify.sh
    virtual_ipaddress {
        $1/24
    }
}
END
}

echo "Start keepalived, it should become master"
write_config 192.0.2.100
systemctl restart keepalived
wait_for has_vip 192.0.2.100
wait_for state_is MASTER
systemctl is-active keepalived

echo "Reload with a different virtual IP"
write_config 192.0.2.101
systemctl reload keepalived
wait_for has_vip 192.0.2.101
wait_for no_vip 192.0.2.100
systemctl is-active keepalived

echo "Start a peer with a higher priority, keepalived should become backup"
cat > "$AUTOPKGTEST_TMP/peer.conf" <<END
vrrp_instance VI_1 {
    state BACKUP
    interface veth1
    virtual_router_id 51
    priority 200
    advert_int 1
    virtual_ipaddress {
        192.0.2.101/24
    }
}
END
ip netns exec peer keepalived --vrrp --log-console \
   -f "$AUTOPKGTEST_TMP/peer.conf" \
   -p "$AUTOPKGTEST_TMP/peer.pid" \
   -r "$AUTOPKGTEST_TMP/peer-vrrp.pid" \
   -c "$AUTOPKGTEST_TMP/peer-checkers.pid"
wait_for state_is BACKUP
wait_for no_vip 192.0.2.101
ip -n peer -4 addr show dev veth1 | grep -qF "inet 192.0.2.101/"

echo "Stop the peer, keepalived should become master again"
kill "$(cat "$AUTOPKGTEST_TMP/peer.pid")"
wait_for has_vip 192.0.2.101
wait_for state_is MASTER

echo "Stop keepalived, the virtual IP should be removed"
systemctl stop keepalived
wait_for no_vip 192.0.2.101
