The sim's routing config existed only as running state on the VMs. It was applied by hand over SSH, so rebuilding a VM lost the rehearsal and nothing recorded why any of it was shaped the way it was. The two ISP VMs were not referenced anywhere in the repo at all. sim-net-config.py generates all four roles; sim-net-apply.sh applies them over the serial console, or diffs them against the running VMs. Verified reproducing live state exactly before committing: primary 40/40 commands, secondary 16/16, isp-dhcp 19/19, isp-pppoe 21/21. Carries the reasoning that was previously nowhere: RFC 8212 needing policy in both directions or the session carries zero prefixes; probe targets that must not double as system name-servers; default-route-distance 210 rather than no-default-route, which blanks new_routers and hands the default route to the backup line; and the WI-8 bootstrap bug that pinned /32s fix. Dropped a stale `pppoe-server interface eth0` on isp-pppoe (a NIC that does not exist there) so a green drift check stays meaningful. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DMVzWZgiKW2wquf5z8S1yH
60 lines
2.9 KiB
Bash
Executable File
60 lines
2.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Apply -- or drift-check -- the labsim routing config on all four VMs.
|
|
#
|
|
# ./sim-net-apply.sh check what the VMs run vs what sim-net-config.py says
|
|
# ./sim-net-apply.sh apply push the generated config over the serial console
|
|
#
|
|
# `check` is the one you want most of the time. The whole failure mode this
|
|
# guards against is somebody (including me) fixing something on a VM over SSH
|
|
# and never writing it down, so the next rebuild silently loses it.
|
|
#
|
|
# Applied over the serial console rather than SSH because a freshly installed
|
|
# sim router holds the same addresses as its peer -- there is a window where it
|
|
# is not safely reachable over the network at all. See console-apply.py.
|
|
set -uo pipefail
|
|
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
ACTION="${1:-check}"
|
|
WORK="$(mktemp -d)"; trap 'rm -rf "$WORK"' EXIT
|
|
|
|
# role : vm : address : regex selecting the subtrees this generator owns
|
|
TARGETS=(
|
|
"primary:labsim-vyos:172.31.1.252:^set (protocols (bgp|failover|static)|policy (prefix-list|route-map)|nat source rule 1[12]0|interfaces (pppoe|bonding bond0 vif 5[13]))"
|
|
"secondary:labsim-vyos2:172.31.1.253:^set (protocols bgp|policy (prefix-list|route-map))"
|
|
"isp-dhcp:labsim-isp-dhcp:192.168.122.136:^set (interfaces ethernet|nat source|service dhcp-server|firewall ipv4 forward|system host-name)"
|
|
"isp-pppoe:labsim-isp-pppoe:192.168.122.63:^set (interfaces ethernet|nat source|service pppoe-server|firewall ipv4 forward|system host-name)"
|
|
)
|
|
# Sim-only credential; these VMs hold nothing real and are not reachable from
|
|
# outside the hypervisor.
|
|
SSH_OPTS=(-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null
|
|
-o LogLevel=ERROR -o PreferredAuthentications=password -o ConnectTimeout=5)
|
|
live() { timeout 30 sshpass -p vyos ssh "${SSH_OPTS[@]}" "vyos@$1" \
|
|
"/opt/vyatta/bin/vyatta-op-cmd-wrapper show configuration commands" 2>/dev/null; }
|
|
norm() { sed "s/'//g" | grep -v 'hw-id\|offload' | sort -u; }
|
|
|
|
rc=0
|
|
for t in "${TARGETS[@]}"; do
|
|
IFS=: read -r role vm addr rx <<<"$t"
|
|
"$HERE/sim-net-config.py" --role "$role" >"$WORK/$role.conf" 2>/dev/null || {
|
|
printf ' %-11s GENERATE FAILED\n' "$role"; rc=1; continue; }
|
|
|
|
if [ "$ACTION" = apply ]; then
|
|
printf ' %-11s applying to %s over console...\n' "$role" "$vm"
|
|
"$HERE/console-apply.py" --vm "$vm" --config "$WORK/$role.conf" || rc=1
|
|
continue
|
|
fi
|
|
|
|
if ! live "$addr" >"$WORK/$role.live" || [ ! -s "$WORK/$role.live" ]; then
|
|
printf ' %-11s UNREACHABLE (%s)\n' "$role" "$addr"; rc=1; continue
|
|
fi
|
|
grep -E '^set ' "$WORK/$role.conf" | norm >"$WORK/$role.g"
|
|
grep -E "$rx" "$WORK/$role.live" | norm >"$WORK/$role.l"
|
|
if d="$(diff "$WORK/$role.g" "$WORK/$role.l")" && [ -z "$d" ]; then
|
|
printf ' %-11s in sync (%s commands)\n' "$role" "$(wc -l <"$WORK/$role.g")"
|
|
else
|
|
printf ' %-11s DRIFT — "<" only in code, ">" only on the VM:\n' "$role"
|
|
printf '%s\n' "$d" | sed 's/^/ /'
|
|
rc=1
|
|
fi
|
|
done
|
|
exit $rc
|