diff --git a/docs/changelog-20260713-opnsense-api-write-proven.md b/docs/changelog-20260713-opnsense-api-write-proven.md new file mode 100644 index 0000000..ca12e82 --- /dev/null +++ b/docs/changelog-20260713-opnsense-api-write-proven.md @@ -0,0 +1,64 @@ +# 2026-07-13 -- D-113(a2) write path PROVEN on the live edge + +The READ half was proven earlier today. This closes the other half: **configuration written +through the REST API reaches the running daemon.** (a2) is now demonstrated end to end, not +argued. + +## What was executed (live, operator-approved) + + POST kea/dhcpv4/set_subnet/93473635-f2aa-5c0a-986c-438e59088c6c -> {"result":"saved"} + POST kea/service/reconfigure -> {"status":"ok"} + GET kea/service/status -> {"status":"running"} + +Deliberately IDEMPOTENT: the payload was the exact values read back from the API moments before +(`subnet 10.10.0.0/24`, `pools 10.10.0.100-10.10.0.199`, `routers`/`domain_name_servers` +`10.10.0.1`, `description "LAN DHCP"`). Nothing about the edge's behaviour should change -- the +point was to exercise the WRITE path, not to alter the edge. + +## GROUND TRUTH after the write (not the API's self-report) + +The API saying `{"result":"saved"}` is the service's own verdict. What was actually measured on +the box: + + kea-dhcp4 pid 30027 (RESTARTED), bound udp4 10.10.0.1:67 + +Kea's OWN generated config (`/usr/local/etc/kea/kea-dhcp4.conf` -- the daemon's JSON, not +OPNsense's XML): + + interfaces : ['vtnet0'] + subnet : 10.10.0.0/24 + pools : ['10.10.0.100-10.10.0.199'] + routers : 10.10.0.1 + domain-name-servers : 10.10.0.1 + domain-name : office1.vr1.cloud.neumatrix.local + +Router unaffected (the endpoint touches only Kea, but verify, never assume): +WAN 172.30.1.2, LAN 10.10.0.1, default route 172.30.1.1, 8 LAN pass rules loaded in pf, +egress to 1.1.1.1 at **0.0% packet loss**. + +**The full chain works: API write -> OPNsense renders -> Kea loads -> daemon serves.** + +## Payload shape (measured -- do not infer this) + +OPNsense GET returns select fields as `{value: {selected: 0|1}}`; SET expects the comma-joined +selected values. A GET response is therefore NOT directly re-POSTable -- it must be flattened: + + {"routers": {"10.10.0.1": {"value": "10.10.0.1", "selected": 1}}} # what GET returns + {"routers": "10.10.0.1"} # what SET expects + +`kea/service/reconfigure` is the apply verb (ServiceController extends +ApiMutableServiceControllerBase; `$internalServiceName = 'kea'`). Without it the config is saved +but the daemon is not reloaded. + +## Consequence: the config.xml push path is now RETIRED IN PRACTICE + +DHCP on this edge is now API-managed. **Pushing a full rendered `config.xml` would clobber it.** +Do not run the old scp/install/reboot path against Office1. The template must be reduced to a +minimal bootstrap (sshd + root key + console) before it is used again -- that is the next step +under D-113(a2), and it is NOT yet done. + +## Revert + +Re-POST the previous values (they are unchanged, so nothing to undo), or from the GUI: +Services > Kea DHCP > DHCPv4 > Subnets. The pre-API `config.xml` backups remain in +`/conf/backup/` on the edge. diff --git a/docs/session-ledger.md b/docs/session-ledger.md index 66e4a1f..f471b95 100644 --- a/docs/session-ledger.md +++ b/docs/session-ledger.md @@ -1996,6 +1996,21 @@ Next: reduce the template to a MINIMAL bootstrap (sshd + key + console) and move DHCP/firewall/interfaces to the API. +- **D-113(a2) WRITE PATH PROVEN 2026-07-13 (live, gated).** `POST kea/dhcpv4/set_subnet/` + -> `{"result":"saved"}`; `POST kea/service/reconfigure` -> `{"status":"ok"}`. GROUND TRUTH + (not the API's self-report): kea-dhcp4 RESTARTED (pid 30027), bound udp4 10.10.0.1:67, and + Kea's OWN generated `/usr/local/etc/kea/kea-dhcp4.conf` carries subnet 10.10.0.0/24, pool + .100-.199, routers/DNS 10.10.0.1. Router unaffected (egress 0.0% loss, 8 LAN pass rules). + **Full chain works: API write -> OPNsense renders -> Kea loads -> daemon serves.** + **PAYLOAD GOTCHA (measured):** a GET response is NOT directly re-POSTable. GET returns select + fields as `{value:{selected:0|1}}`; SET expects comma-joined selected values -- must be + flattened. `kea/service/reconfigure` is the apply verb; without it the config saves but the + daemon never reloads. + **CONSEQUENCE -- the config.xml push path is RETIRED IN PRACTICE for Office1.** DHCP is now + API-managed; a full rendered config.xml push WOULD CLOBBER IT. Do NOT run the old + scp/install/reboot path against this edge. Template reduction to a minimal bootstrap (sshd + + key + console) is the next step and is NOT yet done. + ## State facts to remember - beta cluster left at **node_count=2** (deliberate; bonus resize acceptance coverage).