#!/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])|firewall (group interface-group LAN|ipv4|ipv6))" "secondary:labsim-vyos2:172.31.1.253:^set (protocols bgp|policy (prefix-list|route-map)|firewall (group interface-group LAN|ipv4|ipv6))" "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