a95717e810
pfi-gx10 moved from desk Wi-Fi (10.100.10.226, VLAN 10) to the rack on 10.100.50.60 (nh3-servers, VLAN 50), reachable as pfi-gx10.nh3.internal. The address is a DHCP RESERVATION on the UDM, not a host static. Operator ruling during the move, and the better design: a host-side static works until the box moves and is then a stale netplan file on a machine whose address you no longer know. The pre-written playbook wrote a host static; it is kept for its safety ordering and annotated as retired. The port arrived on the native VLAN, not the server VLAN, so switch port 22 was repointed first. port_overrides is a whole-array PUT — two unrelated overrides on ports 21 and 23 were read, preserved and written back, with the original array backed up to a file before the change. Wi-Fi stayed up as the escape hatch until the wired path was proven from outside, and was downed last as its own step. The step worth keeping: while Wi-Fi was up, traffic to nh3-dev still preferred wlP9s9 because that interface sits directly on the userland subnet, so reachability proved nothing about the wired path. `ping -I enP7s7` across the VLAN boundary is what actually settled it before the hatch came down.
139 lines
6.6 KiB
YAML
139 lines
6.6 KiB
YAML
# pfi-gx10 — RETIRED 2026-09-03. Kept for its reasoning, not for running.
|
|
#
|
|
# ⚠ THE STATIC-IP APPROACH IN THIS FILE WAS NOT USED. Operator ruling on the
|
|
# day of the rack move: put the address on the SWITCH/FIREWALL side as a DHCP
|
|
# RESERVATION and leave the host on DHCP, so moving the box later does not mean
|
|
# unpicking a stale netplan static on a machine you may not be able to reach.
|
|
# The host-static this playbook writes is exactly the "interesting adventure"
|
|
# that ruling avoids.
|
|
#
|
|
# What was actually done instead (see docs/runbooks/gx10-rack-network.md):
|
|
# 1. UniFi switch port 22 native network -> nh3-servers (VLAN 50)
|
|
# 2. UniFi client reservation: 30:c5:99:3d:a7:45 -> 10.100.50.60
|
|
# 3. host DHCP renew; Wi-Fi left UP until the wired path was proven
|
|
# 4. dns/internal.yaml + dns-sync
|
|
# 5. nmcli radio wifi off, last, as its own step
|
|
#
|
|
# The safety ORDER below is still right and was followed: verify carrier,
|
|
# verify MAC not interface name, keep Wi-Fi up as the escape hatch, prove the
|
|
# new address from OUTSIDE, tear the hatch down separately and last.
|
|
#
|
|
# pfi-gx10 — move from desk (Wi-Fi + DHCP, VLAN 10) to rack (wired static,
|
|
# VLAN 50 nh3-servers). Run AFTER the box is racked and the switch port has
|
|
# been placed on nh3-servers.
|
|
#
|
|
# scripts/elway infra-ops@<current-ip> --playbook playbooks/gx10-rack-network.yaml
|
|
#
|
|
# Find <current-ip> without asking anyone — the wired NIC has its own MAC:
|
|
# curl -sk "https://10.100.0.1/proxy/network/api/s/default/stat/sta" \
|
|
# -H "X-API-KEY: $(secret get unifi/pfi-udmse-api-key)" \
|
|
# | python3 -c "import json,sys;[print(c['ip'],c.get('sw_port')) for c in json.load(sys.stdin)['data'] if c['mac']=='30:c5:99:3d:a7:45']"
|
|
#
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# WHY THIS IS SAFE TO RUN AGAINST A BOX IN A RACK
|
|
#
|
|
# The lockout risk in remote network reconfiguration is applying a static
|
|
# address that does not work and losing the only path back. This playbook never
|
|
# has one path: Wi-Fi (wlP9s9) STAYS UP THROUGHOUT. The wired interface is
|
|
# configured alongside it, verified from outside on the new address, and only
|
|
# then is Wi-Fi torn down — by a SEPARATE playbook run, after a human has seen
|
|
# the new address answer.
|
|
#
|
|
# So a botched netplan costs a retry over Wi-Fi, not a trip to the rack.
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
vars:
|
|
wired_if: enP7s7
|
|
wired_mac: "30:c5:99:3d:a7:45"
|
|
static_ip: 10.100.50.60
|
|
prefix: "24"
|
|
gateway: 10.100.50.1
|
|
dns_servers: "10.100.50.40" # nh3-docker / AdGuard, per dns/internal.yaml
|
|
search_domain: nh3.internal
|
|
|
|
steps:
|
|
- name: Refuse to proceed if the cable is not actually in
|
|
# carrier=0 means no link. Writing a static config for a dead interface and
|
|
# calling it done is the kind of green that costs a rack visit to discover.
|
|
shell: test "$(cat /sys/class/net/{{ wired_if }}/carrier 2>/dev/null)" = "1"
|
|
|
|
- name: Confirm the interface is the NIC we think it is
|
|
# Interface names can renumber across kernels. The MAC cannot.
|
|
shell: test "$(cat /sys/class/net/{{ wired_if }}/address)" = "{{ wired_mac }}"
|
|
|
|
- name: Back up the existing netplan
|
|
shell: sudo cp -an /etc/netplan /etc/netplan.bak-preRack 2>/dev/null || true
|
|
creates: /etc/netplan.bak-preRack
|
|
|
|
- name: Write the wired static config
|
|
# A SEPARATE file from whatever manages Wi-Fi. Wi-Fi keeps working while
|
|
# this lands; that is the escape hatch and it is deliberate.
|
|
shell: |
|
|
sudo tee /etc/netplan/60-wired-static.yaml >/dev/null <<'EOF'
|
|
network:
|
|
version: 2
|
|
ethernets:
|
|
{{ wired_if }}:
|
|
dhcp4: false
|
|
dhcp6: false
|
|
addresses: [{{ static_ip }}/{{ prefix }}]
|
|
routes:
|
|
- to: default
|
|
via: {{ gateway }}
|
|
metric: 100
|
|
nameservers:
|
|
addresses: [{{ dns_servers }}]
|
|
search: [{{ search_domain }}]
|
|
EOF
|
|
sudo chmod 600 /etc/netplan/60-wired-static.yaml
|
|
creates: /etc/netplan/60-wired-static.yaml
|
|
|
|
- name: Apply
|
|
# `netplan try` would be better but needs a TTY to accept or roll back;
|
|
# under elway there is nobody to press a key. Wi-Fi staying up is what
|
|
# substitutes for the auto-rollback.
|
|
shell: sudo netplan apply
|
|
|
|
- name: Wait for the address to come up locally
|
|
shell: |
|
|
for i in $(seq 1 15); do
|
|
ip -4 addr show {{ wired_if }} | grep -q "{{ static_ip }}/{{ prefix }}" && exit 0
|
|
sleep 2
|
|
done
|
|
exit 1
|
|
|
|
verify:
|
|
- name: Wired interface holds the static address
|
|
shell: ip -4 addr show {{ wired_if }} | grep -q "{{ static_ip }}/{{ prefix }}"
|
|
changed_when: "false"
|
|
|
|
- name: Default route is via the servers-VLAN gateway
|
|
shell: ip route get 1.1.1.1 | grep -q "via {{ gateway }}"
|
|
changed_when: "false"
|
|
|
|
- name: Gateway answers
|
|
shell: ping -c 2 -W 2 {{ gateway }} >/dev/null
|
|
changed_when: "false"
|
|
|
|
- name: DNS resolves through the fleet resolver
|
|
shell: getent hosts nh3-docker.nh3.internal >/dev/null
|
|
changed_when: "false"
|
|
|
|
- name: Wi-Fi is STILL UP — the escape hatch must survive this run
|
|
# If this fails, the box may be reachable only on an address that was just
|
|
# proven or just broken. Loudly not optional.
|
|
shell: ip link show wlP9s9 | grep -q "state UP"
|
|
changed_when: "false"
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# AFTERWARDS, and only once the new address has been confirmed from OUTSIDE:
|
|
#
|
|
# 1. ssh infra-ops@10.100.50.60 # prove it from another host first
|
|
# 2. update servers/pfi-gx10/ssh-target
|
|
# 3. add to dns/internal.yaml, then scripts/dns-sync.py --dry-run && ...sync
|
|
# 4. tear down Wi-Fi — a server with two default routes picks one at random
|
|
# and you find out later, in a way that looks like packet loss:
|
|
# sudo nmcli radio wifi off # or delete the wlP9s9 netplan stanza
|
|
# Do that as its own change, not bundled in here.
|
|
# ─────────────────────────────────────────────────────────────────────────────
|