NICs: pick the imaging port at install, GE can go into any other port

Sites no longer need either MAC in site-vars.

pxe_nic_mac empty: before anything changes, the playbook runs
pxe-pick-nic --auto. It takes the one wired port with a link, accepts it
only if pxe-nic-check calls it isolated (no LLDP/CDP/802.1X, no other
DHCP server, at most 10 hosts heard in 65 s), and pins it. The choice is
saved in /etc/pxe-server/nic-pick.conf and never re-guessed at boot.
When it cannot tell (no link, two links, not isolated) nothing changes,
and the console banner says why and to run sudo pxe-pick-nic: pull the
imaging cable and plug it back in, and the port that blinked is the
imaging one. Both helpers are installed before the pick, so that works
after a refused first boot. The site's corp domains and allowed
switches are passed to the check.

corp_nic_mac empty: every other wired port (en*, eth*) is a catch-all
DHCP client, so GE can be plugged in at install or later.
- dnsmasq stays pinned with interface=pxe0. A new check refuses any
  dhcp-range outside the imaging subnet, and proxy ranges.
- The catch-all ports ignore offers from 172.16.9.1.
- UFW allows SSH and 9009 by source on any interface, and keeps those
  rules when the old any-interface rules are removed.
- pxe_nic_name must not look like en*/eth* in this mode.

pxe-netplan-apply.sh takes 3 or 5 args. Without a pinned GE NIC it:
- renames stray names (the old pxe0 after a re-pick, a leftover corp0)
  to enx<mac>, so the catch-all takes them, and restores them on revert;
- checks that every NIC that had a DHCP address before has one after,
  tracked by MAC.

With both MACs set (the WJ server), netplan, the dnsmasq pin and UFW
render byte-for-byte as before.

Tested in the pxetest VMs:
- Fresh install with no MACs and the GE link down: the imaging port was
  picked and pinned as pxe0 with 172.16.9.1, and dnsmasq bound DHCP to
  pxe0 only. GE plugged in afterwards got a lease, SSH worked, and the
  guard reported pxe0 isolated.
- --auto refuses with two links.
- The interactive pick works by pulling and replugging the link.
- A 3-arg re-apply is UNCHANGED.

Unit tests (fake sysfs) cover the re-pick and pinned-to-catch-all renames.
This commit is contained in:
cproudlock
2026-10-16 15:56:47 -04:00
parent 9af1c6d89a
commit b11e678297
12 changed files with 774 additions and 108 deletions

View File

@@ -4,16 +4,22 @@
# loads it on first boot; -e on the command line still overrides it.
# site-vars.yml is git-ignored: each site's MACs stay with that site.
#
# REQUIRED: the two NICs, by MAC (ip -br link on the box, or the label).
# imaging NIC = cable to the isolated imaging switch (serves DHCP/PXE/SMB)
# corp NIC = cable to the GE corporate network (SSH + webapp 9009 only)
# The playbook changes nothing on the network until both are set, differ,
# and are both present on the box.
# The NICs, by MAC (ip -br link on the box, or the label). Both optional:
# pxe_nic_mac imaging NIC = cable to the isolated imaging switch (serves
# DHCP/PXE/SMB). Empty: the first boot picks the one wired
# port with a link, if pxe-nic-check calls it isolated, and
# pins it. So during the install plug in ONLY the imaging
# switch. If it cannot tell, the console says to log in and
# run: sudo pxe-pick-nic (pull the imaging cable, plug it in).
# corp_nic_mac GE corporate NIC (SSH + webapp 9009). Empty: every other
# wired port is a DHCP client, so GE can be plugged into any
# of them, now or later. Set: only that port, named corp0.
pxe_nic_mac: "" # e.g. "34:c8:d6:b1:10:10"
corp_nic_mac: "" # e.g. "20:88:10:af:0d:e5"
# Optional: stable interface names (default pxe0 / corp0). Keep a box's
# existing names instead, e.g. on the WJ server:
# Optional: stable interface names (default pxe0 / corp0). With corp_nic_mac
# empty, pxe_nic_name must not start with en or eth. With both MACs set a
# box may keep its existing names, e.g. on the WJ server:
# pxe_nic_name: enx34c8d6b11010
# corp_nic_name: enp0s31f6