Every server has an imaging NIC (static, the only one that serves DHCP/TFTP/HTTP boot/SMB) and a GE corporate NIC (DHCP client, SSH and the webapp on 9009). The playbook guessed the PXE NIC and the installer put 172.16.9.1/24 on every en* NIC, so a two-NIC box could answer on the GE network. - New per-site vars pxe_nic_mac / corp_nic_mac (required, from playbook/site-vars.yml or -e; template site-vars.example.yml), stable names pxe_nic_name / corp_nic_name (default pxe0 / corp0, overridable), pxe_server_ip, pxe_subnet, DHCP range. pxe_imaging_mac / pxe_ge_mac are derived from them. The play stops before touching anything if a MAC is unset, malformed, duplicated or not on the box (lists the box's NICs). - Heuristic NIC detection and the single-NIC netplan task replaced by a two-NIC netplan template (match macaddress + set-name), installed by pxe-netplan-apply.sh: validate in a scratch root, back up, generate, rename, apply, restore the previous config on any failure. cloud-init network config disabled so it cannot rewrite it. - dnsmasq: /etc/dnsmasq.d/pxe-nic-only.conf from the vars (interface=, except-interface=, no-dhcp-interface=); dnsmasq.conf IP/range from vars. - UFW per interface: imaging NIC 22, 67/udp, 69/udp, 80, 4433, 445, 139, 137/udp, 138/udp, 9009; GE NIC 22 and 9009 only. Old any-interface rules and the stale 9011 rule removed after the new ones are in. - sysctl drop-in: IPv4/IPv6 forwarding off; ip_nonlocal_bind so Apache can bind the imaging IP before the address is up. - Samba [global]: interfaces = 127.0.0.0/8 <imaging NIC>, bind interfaces only. Apache 80 and 4433 on the imaging IP only; 9009 stays on all (TODO: the webapp has no auth). - autoinstall: DHCP only on en*, no static 172.16.9.1; apt geoip off and offline-install fallback now that the corp NIC may have a lease. - Blancco UEFI/Secure Boot: blancco_kver (7.0.0-34-generic) drives the kernel, initramfs and modules builds instead of the running kernel; outputs vmlinuz-ubuntu-70, kexec-initrd-70.img, kmod-<kver>.tar.gz as the menu and blancco-init.sh expect; creates: guards keyed on the full kver. Ubuntu's shimx64.efi.signed published as blancco/shimx64.efi. download-packages.sh adds shim-signed, linux-generic-hwe-24.04 and the pinned linux-image/modules/modules-extra for BLANCCO_KVER. Rendered with the live MACs and names, netplan generate output is identical to the live config; pxe-nic-only.conf and the Samba binding match live directive for directive.
150 lines
4.7 KiB
Bash
Executable File
150 lines
4.7 KiB
Bash
Executable File
#!/bin/bash
|
|
# pxe-netplan-apply.sh - install the two-NIC netplan config without ever
|
|
# leaving the box unreachable on the corporate NIC.
|
|
#
|
|
# Usage: pxe-netplan-apply.sh STAGED_YAML PXE_NAME PXE_MAC CORP_NAME CORP_MAC
|
|
#
|
|
# Called by pxe_server_setup.yml. Steps:
|
|
# 1. validate STAGED_YAML in a scratch root (netplan generate --root-dir);
|
|
# nothing on the box changes if it is invalid
|
|
# 2. stop here (prints UNCHANGED) if it is already installed, no other
|
|
# file configures wired NICs, and both NICs carry their stable names
|
|
# 3. back up /etc/netplan to /var/backups/netplan-<timestamp>/
|
|
# 4. install it (other wired configs moved aside), netplan generate
|
|
# (restore on failure)
|
|
# 5. rename the NICs to their stable names (the .link files netplan
|
|
# writes do it on every later boot), netplan apply (restore on failure)
|
|
# 6. check the imaging address and the corp NIC (warning only: the corp
|
|
# cable may simply be unplugged)
|
|
# Prints CHANGED or UNCHANGED as the last line. Exit 1 = nothing applied
|
|
# (the previous config is back in place).
|
|
|
|
set -u
|
|
|
|
if [ $# -ne 5 ]; then
|
|
echo "usage: $0 STAGED_YAML PXE_NAME PXE_MAC CORP_NAME CORP_MAC" >&2
|
|
exit 2
|
|
fi
|
|
STAGED=$1
|
|
PXE_NAME=$2
|
|
PXE_MAC=${3,,}
|
|
CORP_NAME=$4
|
|
CORP_MAC=${5,,}
|
|
NETPLAN_DIR=${NETPLAN_DIR:-/etc/netplan}
|
|
TARGET=$NETPLAN_DIR/50-cloud-init.yaml
|
|
|
|
log() { echo "pxe-netplan-apply: $*"; }
|
|
|
|
# Name of the physical NIC that has MAC $1 (empty if none).
|
|
iface_of() {
|
|
local d
|
|
for d in /sys/class/net/*; do
|
|
[ -e "$d/device" ] || continue
|
|
if [ "$(cat "$d/address" 2>/dev/null)" = "$1" ]; then
|
|
basename "$d"
|
|
return 0
|
|
fi
|
|
done
|
|
return 0
|
|
}
|
|
|
|
names_ok() {
|
|
[ "$(iface_of "$PXE_MAC")" = "$PXE_NAME" ] &&
|
|
[ "$(iface_of "$CORP_MAC")" = "$CORP_NAME" ]
|
|
}
|
|
|
|
# Other netplan files that configure wired NICs (installer leftovers, an
|
|
# en* DHCP match): they would put a second config on the two NICs. Files
|
|
# without "ethernets" (WiFi, NetworkManager wifi profiles) are left alone.
|
|
other_files() {
|
|
find "$NETPLAN_DIR" -maxdepth 1 -type f \( -name '*.yaml' -o -name '*.yml' \) \
|
|
! -path "$TARGET" -exec grep -l 'ethernets' {} + 2>/dev/null | sort
|
|
}
|
|
|
|
# 1. validate in a scratch root
|
|
SCRATCH=$(mktemp -d)
|
|
trap 'rm -rf "$SCRATCH"' EXIT
|
|
mkdir -p "$SCRATCH/etc/netplan"
|
|
install -m 600 "$STAGED" "$SCRATCH/etc/netplan/50-cloud-init.yaml"
|
|
if ! netplan generate --root-dir "$SCRATCH"; then
|
|
log "ERROR: $STAGED does not validate; nothing changed"
|
|
exit 1
|
|
fi
|
|
|
|
# 2. already in place?
|
|
if cmp -s "$STAGED" "$TARGET" && [ -z "$(other_files)" ] && names_ok; then
|
|
log "netplan already in place, $PXE_NAME and $CORP_NAME present"
|
|
echo UNCHANGED
|
|
exit 0
|
|
fi
|
|
|
|
# 3. back up
|
|
BACKUP=/var/backups/netplan-$(date +%Y%m%d-%H%M%S)
|
|
mkdir -p "$BACKUP"
|
|
cp -a "$NETPLAN_DIR/." "$BACKUP/"
|
|
log "previous config saved in $BACKUP"
|
|
|
|
restore() {
|
|
log "restoring the previous config from $BACKUP"
|
|
find "$NETPLAN_DIR" -maxdepth 1 -type f \( -name '*.yaml' -o -name '*.yml' \) -delete
|
|
cp -a "$BACKUP/." "$NETPLAN_DIR/"
|
|
netplan generate && netplan apply
|
|
}
|
|
|
|
# 4. install, moving aside the other wired configs (an en* DHCP match would
|
|
# put a DHCP client on the imaging NIC too)
|
|
other_files | while IFS= read -r f; do
|
|
log "moving aside $f (copy in $BACKUP)"
|
|
rm -f "$f"
|
|
done
|
|
install -m 600 "$STAGED" "$TARGET"
|
|
if ! netplan generate; then
|
|
log "ERROR: netplan generate failed"
|
|
restore
|
|
exit 1
|
|
fi
|
|
|
|
# 5. stable names now, so dnsmasq/UFW/Samba (which use them) work before
|
|
# the next reboot. Does not depend on the netplan version renaming.
|
|
rename() {
|
|
local mac=$1 want=$2 cur
|
|
cur=$(iface_of "$mac")
|
|
if [ -z "$cur" ]; then
|
|
log "WARNING: no NIC with MAC $mac"
|
|
return 0
|
|
fi
|
|
[ "$cur" = "$want" ] && return 0
|
|
log "renaming $cur ($mac) to $want"
|
|
if ! { ip link set dev "$cur" down &&
|
|
ip link set dev "$cur" name "$want" &&
|
|
ip link set dev "$want" up; }; then
|
|
log "WARNING: rename $cur -> $want failed; it applies at the next reboot"
|
|
ip link set dev "$cur" up 2>/dev/null
|
|
fi
|
|
return 0
|
|
}
|
|
rename "$PXE_MAC" "$PXE_NAME"
|
|
rename "$CORP_MAC" "$CORP_NAME"
|
|
|
|
if ! netplan apply; then
|
|
log "ERROR: netplan apply failed"
|
|
restore
|
|
exit 1
|
|
fi
|
|
|
|
# 6. check
|
|
for _ in $(seq 1 20); do
|
|
ip -4 -br addr show dev "$PXE_NAME" 2>/dev/null | grep -q ' [0-9]' && break
|
|
sleep 1
|
|
done
|
|
ip -br addr show dev "$PXE_NAME" 2>/dev/null ||
|
|
log "WARNING: $PXE_NAME not present yet (reboot to apply the .link names)"
|
|
for _ in $(seq 1 30); do
|
|
ip -4 -br addr show dev "$CORP_NAME" 2>/dev/null | grep -q ' [0-9]' && break
|
|
sleep 1
|
|
done
|
|
ip -4 -br addr show dev "$CORP_NAME" 2>/dev/null | grep -q ' [0-9]' ||
|
|
log "WARNING: $CORP_NAME has no IPv4 address yet (corp cable unplugged or DHCP slow)"
|
|
echo CHANGED
|
|
exit 0
|