Archived
pve-test was briefly clustered with pve1 then deliberately de-clustered so it could move to wifi-primary networking (4addr bridge mode, bonded with a wired LAN backup) - a change not achievable while clustered given corosync's latency requirements. Captures that as a reproducible script plus docs: cluster separation procedure, the wifi network design and the live-cutover pitfalls hit along the way, and node-role/history context. Also adds CLAUDE.md guardrails for pve1 (production) vs pve-test (sandbox) - this repo had none before, despite scripts here being able to make real changes to both. Separately: both nodes' mgmt firewalls were dropping ICMP by default (TCP 22/8006 only), which looked like an outage mid-troubleshooting even though SSH/web UI were fine. Added an explicit ping-allow rule to the firewall template, applied it live on both nodes, and added an audit.sh check so it stays enforced.
134 lines
4.5 KiB
Bash
Executable File
134 lines
4.5 KiB
Bash
Executable File
#!/bin/bash
|
|
# Reproduces pve-test's wifi-primary networking: vmbr0 bridged over a wifi
|
|
# NIC in 4addr (WDS) client-bridge mode, active-backup bonded with a wired
|
|
# NIC as an automatic LAN fallback. See docs/06-pve-test-wifi-network.md for
|
|
# why this exists and how it was validated. Idempotent - safe to re-run.
|
|
#
|
|
# Requires: a wifi NIC whose driver/AP both support 4addr mode (verify with
|
|
# docs/06-pve-test-wifi-network.md's isolated-namespace test *before*
|
|
# trusting this against a live management IP - a wifi NIC or AP that
|
|
# doesn't support 4addr will associate fine but silently drop bridged
|
|
# frames from any MAC other than the card's own).
|
|
#
|
|
# Usage (run as root on the target PVE host):
|
|
# WIFI_SSID="..." WIFI_PASSPHRASE="..." \
|
|
# MGMT_ADDR=192.168.2.251/24 MGMT_GATEWAY=192.168.2.254 \
|
|
# ./setup-wifi-bond-network.sh
|
|
#
|
|
# Optional overrides: WIFI_IFACE (default wlp3s0), LAN_IFACE (default nic0)
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
# shellcheck source=lib/common.sh
|
|
source "${SCRIPT_DIR}/lib/common.sh"
|
|
require_root
|
|
|
|
WIFI_IFACE="${WIFI_IFACE:-wlp3s0}"
|
|
LAN_IFACE="${LAN_IFACE:-nic0}"
|
|
|
|
for var in WIFI_SSID WIFI_PASSPHRASE MGMT_ADDR MGMT_GATEWAY; do
|
|
if [ -z "${!var:-}" ]; then
|
|
echo "$var is not set. See usage in this script's header." >&2
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
if ! ip link show "$WIFI_IFACE" >/dev/null 2>&1; then
|
|
echo "No interface named $WIFI_IFACE on this host. Run 'ip -br link' and set WIFI_IFACE=..." >&2
|
|
exit 1
|
|
fi
|
|
if ! ip link show "$LAN_IFACE" >/dev/null 2>&1; then
|
|
echo "No interface named $LAN_IFACE on this host. Run 'ip -br link' and set LAN_IFACE=..." >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "=== 1/4: wifi tooling ==="
|
|
apt-get install -y iw wpasupplicant >/dev/null
|
|
echo "installed iw, wpasupplicant"
|
|
|
|
echo
|
|
echo "=== 2/4: wpa_supplicant config (SSID: $WIFI_SSID, iface: $WIFI_IFACE) ==="
|
|
WPA_CONF="/etc/wpa_supplicant/wpa_supplicant-${WIFI_IFACE}.conf"
|
|
wpa_passphrase "$WIFI_SSID" "$WIFI_PASSPHRASE" > "$WPA_CONF"
|
|
sed -i '/^\s*#psk=/d' "$WPA_CONF"
|
|
chmod 600 "$WPA_CONF"
|
|
echo "wrote $WPA_CONF (passphrase hashed, not stored in plaintext)"
|
|
|
|
echo
|
|
echo "=== 3/4: systemd unit to set 4addr mode + start wpa_supplicant ==="
|
|
UNIT="/etc/systemd/system/wpa-4addr-${WIFI_IFACE}.service"
|
|
write_if_changed "$UNIT" "[Unit]
|
|
Description=wpa_supplicant on ${WIFI_IFACE} with 4addr mode enabled
|
|
Before=network-pre.target
|
|
Wants=network-pre.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
ExecStartPre=/sbin/ip link set ${WIFI_IFACE} down
|
|
ExecStartPre=/sbin/iw dev ${WIFI_IFACE} set 4addr on
|
|
ExecStartPre=/sbin/ip link set ${WIFI_IFACE} up
|
|
ExecStart=/sbin/wpa_supplicant -i ${WIFI_IFACE} -c ${WPA_CONF}
|
|
Restart=on-failure
|
|
RestartSec=3
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target"
|
|
systemctl daemon-reload
|
|
systemctl enable --now "wpa-4addr-${WIFI_IFACE}.service"
|
|
sleep 5
|
|
if ! iw dev "$WIFI_IFACE" link | grep -q "^Connected"; then
|
|
echo "WARNING: ${WIFI_IFACE} did not associate to '$WIFI_SSID' within 5s - check:" >&2
|
|
echo " systemctl status wpa-4addr-${WIFI_IFACE}.service" >&2
|
|
echo " journalctl -u wpa-4addr-${WIFI_IFACE}.service" >&2
|
|
exit 1
|
|
fi
|
|
echo "associated: $(iw dev "$WIFI_IFACE" link | grep '^Connected')"
|
|
|
|
echo
|
|
echo "=== 4/4: /etc/network/interfaces (bond0 active-backup: ${WIFI_IFACE} primary, ${LAN_IFACE} backup) ==="
|
|
IFACES_FILE="/etc/network/interfaces"
|
|
backup_file "$IFACES_FILE"
|
|
cat > "$IFACES_FILE" <<EOF
|
|
auto lo
|
|
iface lo inet loopback
|
|
|
|
iface ${LAN_IFACE} inet manual
|
|
|
|
iface ${WIFI_IFACE} inet manual
|
|
|
|
auto bond0
|
|
iface bond0 inet manual
|
|
bond-slaves ${WIFI_IFACE} ${LAN_IFACE}
|
|
bond-mode active-backup
|
|
bond-miimon 100
|
|
bond-primary ${WIFI_IFACE}
|
|
bond-updelay 200
|
|
bond-downdelay 200
|
|
|
|
auto vmbr0
|
|
iface vmbr0 inet static
|
|
address ${MGMT_ADDR}
|
|
gateway ${MGMT_GATEWAY}
|
|
bridge-ports bond0
|
|
bridge-stp off
|
|
bridge-fd 0
|
|
|
|
source /etc/network/interfaces.d/*
|
|
EOF
|
|
echo "wrote $IFACES_FILE"
|
|
|
|
echo
|
|
echo "Config staged but NOT applied yet - applying it live can drop your"
|
|
echo "current management connection for ~30-60s while the switch/AP"
|
|
echo "relearns MAC locations (expected, self-resolves; see"
|
|
echo "docs/06-pve-test-wifi-network.md). Recommended: run this from the"
|
|
echo "physical console, or arm a revert-on-timeout watchdog first, e.g.:"
|
|
echo
|
|
echo " cp ${IFACES_FILE}.bak.* /tmp/interfaces.orig # pick the backup just made"
|
|
echo " (sleep 45 && cp /tmp/interfaces.orig ${IFACES_FILE} && ifreload -a) &"
|
|
echo " ifreload -a"
|
|
echo " # then kill the backgrounded revert job once you confirm connectivity"
|
|
echo
|
|
echo "Apply now with: ifreload -a"
|
|
echo "Verify after with: cat /proc/net/bonding/bond0 ; ip -4 -br addr show vmbr0"
|