mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-15 17:11:30 +00:00
7003168bc5
Move spinifex/network/* to spinifex/domains/network/* as one enclosing move so the L0-L5 layer invariants keep classifying every package from a single root. Package names and dependency direction are unchanged; invariant scan roots, the RG-10 sudo allow-list path, CODEOWNERS and the repo-root walk in the IMDS netns unit test follow the new path.
141 lines
6.2 KiB
Bash
Executable File
141 lines
6.2 KiB
Bash
Executable File
#!/bin/sh
|
|
# setup-ovn_test.sh — tests for the teardown path and its documentation.
|
|
#
|
|
# Only --teardown --dry-run and --help are exercised. Both return before the
|
|
# script changes anything, which matters more here than usual: the script under
|
|
# test wires the node's datapath, and a test that ran the real teardown would
|
|
# delete the bridges of the machine running CI.
|
|
set -eu
|
|
|
|
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
|
SETUP="$SCRIPT_DIR/setup-ovn.sh"
|
|
TMP=$(mktemp -d)
|
|
trap 'rm -rf "$TMP"' EXIT
|
|
|
|
fails=0
|
|
pass() { echo " ok - $1"; }
|
|
fail() { echo " FAIL - $1"; fails=$((fails + 1)); }
|
|
|
|
echo "-- setup-ovn.sh"
|
|
|
|
# --------------------------------------------------------------------------
|
|
# Help.
|
|
# --------------------------------------------------------------------------
|
|
help_out=$("$SETUP" --help 2>&1) && rc=0 || rc=$?
|
|
[ "$rc" = 0 ] && pass "--help exits 0" || fail "--help exited $rc, want 0"
|
|
|
|
for flag in --teardown --dry-run --management --nat-uplink; do
|
|
case "$help_out" in
|
|
*"$flag"*) pass "--help documents $flag" ;;
|
|
*) fail "--help does not document $flag" ;;
|
|
esac
|
|
done
|
|
|
|
# --teardown is the flag an operator reaches for when a node is already
|
|
# tangled, so the help has to say what it keeps. Somebody who reads it as
|
|
# "removes everything" will not run it, and will hand-edit OVS instead.
|
|
case "$help_out" in
|
|
*"NB/SB databases"*) pass "--help says what --teardown preserves" ;;
|
|
*) fail "--help does not say what --teardown preserves" ;;
|
|
esac
|
|
|
|
# --------------------------------------------------------------------------
|
|
# Teardown, dry run. Every mutation must go through run(), so a dry run can
|
|
# report the whole plan without performing any of it.
|
|
# --------------------------------------------------------------------------
|
|
out=$("$SETUP" --teardown --dry-run 2>&1) && rc=0 || rc=$?
|
|
[ "$rc" = 0 ] && pass "--teardown --dry-run exits 0" || fail "--teardown --dry-run exited $rc, want 0"
|
|
|
|
case "$out" in
|
|
*"nothing is changed"*) pass "dry run says it changes nothing" ;;
|
|
*) fail "dry run does not announce itself" ;;
|
|
esac
|
|
|
|
# The four groups the teardown exists to remove. A silently skipped group is
|
|
# the failure mode that leaves a node still tangled after a clean-looking run.
|
|
for step in "Removing veth pairs" "Removing systemd-networkd persistence" \
|
|
"Removing routed-NAT egress rules" "Removing OVS bridges"; do
|
|
case "$out" in
|
|
*"$step"*) pass "dry run covers: $step" ;;
|
|
*) fail "dry run skips: $step" ;;
|
|
esac
|
|
done
|
|
|
|
# The OVS port goes before the veth: deleting one end of a pair deletes the
|
|
# peer, and an OVS port left naming a device the kernel no longer has is
|
|
# exactly the state a re-run cannot unpick.
|
|
port_line=$(printf '%s\n' "$out" | grep -n 'del-port veth-wan-ovs' | head -1 | cut -d: -f1 || true)
|
|
link_line=$(printf '%s\n' "$out" | grep -n 'ip link del veth-wan-br' | head -1 | cut -d: -f1 || true)
|
|
if [ -n "$port_line" ] && [ -n "$link_line" ] && [ "$port_line" -lt "$link_line" ]; then
|
|
pass "the OVS port is removed before its veth"
|
|
else
|
|
fail "veth teardown order is wrong (port=$port_line link=$link_line)"
|
|
fi
|
|
|
|
# A dry run that reported a real mutation would be the worst kind of bug here.
|
|
if printf '%s\n' "$out" | grep -E '^[[:space:]]+(sudo|ip|ovs-vsctl|iptables) ' >/dev/null 2>&1; then
|
|
fail "dry run printed a bare command, not a 'would run:' line"
|
|
else
|
|
pass "every dry-run mutation is reported, not executed"
|
|
fi
|
|
|
|
# --------------------------------------------------------------------------
|
|
# Static checks on the teardown body.
|
|
# --------------------------------------------------------------------------
|
|
# Comments and echoed prose name the things the teardown deliberately spares,
|
|
# so match against the commands alone or every such sentence reads as a hit.
|
|
body=$(sed -n '/^teardown() {/,/^}/p' "$SETUP")
|
|
body_cmds=$(printf '%s\n' "$body" | grep -vE '^[[:space:]]*(#|echo )' || true)
|
|
|
|
# Deleting a Linux bridge would take the host's own addressing with it: on a
|
|
# cloud node br-wan is a netplan-owned Linux bridge holding the VNIC's address
|
|
# and the default route, and this script never created it.
|
|
case "$body" in
|
|
*is_linux_bridge*) pass "teardown refuses to delete a Linux bridge" ;;
|
|
*) fail "teardown does not check for a Linux bridge before del-br" ;;
|
|
esac
|
|
|
|
# The databases are the control plane's state. A teardown that took them could
|
|
# not be used for its actual purpose, which is re-running this script.
|
|
for forbidden in "ovnnb_db" "ovnsb_db" "/etc/spinifex" "rm -rf"; do
|
|
case "$body_cmds" in
|
|
*"$forbidden"*) fail "teardown touches $forbidden" ;;
|
|
*) pass "teardown leaves $forbidden alone" ;;
|
|
esac
|
|
done
|
|
|
|
# --------------------------------------------------------------------------
|
|
# The transit veth MAC.
|
|
# --------------------------------------------------------------------------
|
|
# OVN keeps one MAC binding for the transit nexthop across the cluster, so a
|
|
# random per-node MAC sends every chassis's egress to whichever node seeded it.
|
|
# The address must therefore be a literal the script sets, and it must survive a
|
|
# reboot or the node goes dark the next time systemd-networkd recreates the pair.
|
|
nat_mode_body=$(sed -n '/^ nat)/,/^ ;;/p' "$SETUP")
|
|
|
|
case "$nat_mode_body" in
|
|
*'ip link set spx-nat-host address'*) pass "nat mode pins the transit host MAC" ;;
|
|
*) fail "nat mode does not set a MAC on spx-nat-host" ;;
|
|
esac
|
|
|
|
case "$nat_mode_body" in
|
|
*'MACAddress=$NAT_TRANSIT_HOST_MAC'*) pass "the netdev unit persists the transit MAC" ;;
|
|
*) fail "the netdev unit does not persist the transit MAC" ;;
|
|
esac
|
|
|
|
# The script and the Go constant must agree: vpcd repairs a veth made before
|
|
# this existed, and a disagreement would have the two fighting every pass.
|
|
script_mac=$(printf '%s\n' "$nat_mode_body" | sed -n 's/.*NAT_TRANSIT_HOST_MAC="\([^"]*\)".*/\1/p' | head -1)
|
|
go_mac=$(sed -n 's/.*NATTransitHostMAC = "\([^"]*\)".*/\1/p' "$SCRIPT_DIR/../spinifex/domains/network/host/routed.go" | head -1)
|
|
if [ -n "$script_mac" ] && [ "$script_mac" = "$go_mac" ]; then
|
|
pass "the transit MAC matches host.NATTransitHostMAC"
|
|
else
|
|
fail "transit MAC disagrees: script=$script_mac go=$go_mac"
|
|
fi
|
|
|
|
if [ "$fails" -ne 0 ]; then
|
|
echo " setup-ovn.sh: $fails failure(s)"
|
|
exit 1
|
|
fi
|
|
echo " setup-ovn.sh ok"
|