v0.96.0 — R-50 island NIC: provision attaches the guest island net1
- LocalAPIConfig.island_bridge + island_guest_addr (+ IslandEnabled, Validate all-or-nothing + CIDR guard) - buildBringUpConfig attaches static net1 (island) on provision + DR when set; absent otherwise (pre-R-50 byte-for-byte). Plumbed from cfg.LocalAPI at both RunBringUp sites. Endpoint already follows listen_addr (A0: no template change). - healer stays eth0-only (A3 verify-only) — red-proof test locks the scoping - example config + firewall example rewritten for the island; REUSE updated - 3 non-hollow tests; full green. MinAgent unchanged. Coupling: host-install island config requires agent >= 0.96.0 (vouch first).
This commit is contained in:
@@ -1,53 +1,31 @@
|
||||
# REPORT — v0.95.0: SMART coverage (spike fixes B+A) + device model (2026-07-25)
|
||||
# REPORT — v0.96.0: R-50 island NIC (provisioning half) (2026-07-25)
|
||||
|
||||
**Overwritten** per the standing rule. Part of the SMART-coverage task (agent v0.95.0 + controller
|
||||
v0.171.0); the R-50 island-bridge spike lives in felhom.eu.
|
||||
Implements the agent half of the R-50 island control plane (spike GO,
|
||||
`felhom.eu/documentation/audits/SPIKE-island-bridge-2026-07-25.md`). A fresh install is born immune to
|
||||
F1 (a LAN/DHCP/site move can no longer take the control plane down).
|
||||
|
||||
## Baseline → target
|
||||
felhom-agent `643899c` (v0.94.0) → committed **`ed97232`** (v0.95.0). Deployed to felhom-pve.
|
||||
## What changed
|
||||
- `internal/config/config.go` — `LocalAPIConfig.IslandBridge` + `IslandGuestAddr`; `IslandEnabled()`;
|
||||
`Validate()` all-or-nothing + CIDR guard.
|
||||
- `internal/reconcile/bringup.go` — `BringUpSpec` island fields; `buildBringUpConfig` attaches a static
|
||||
`net1` (island NIC) on provision AND DR when configured; absent otherwise.
|
||||
- `cmd/felhom-agent/main.go` — both `RunBringUp` call sites plumb `cfg.LocalAPI.Island*`.
|
||||
- `configs/agent.example.json` — island shape (island bind + island_bridge/guest_addr + lan_resolver.host_ip).
|
||||
- `configs/felhom-localapi-firewall.example` — rewritten for the island (the portless bind IS the LAN close).
|
||||
- `REUSE.md` — island-NIC provisioning pattern + the "endpoint follows listen_addr" note.
|
||||
|
||||
## What shipped (additive; MinAgent unchanged; hub untouched)
|
||||
Implements `SPIKE-smart-coverage-2026-07-25.md` (both demo disks answer `smartctl -a -j` PASSED, but
|
||||
the agent never asked):
|
||||
- **Fix B — union-path SMART:** `storage.SmartReader.SMARTForBacking` (reuses `smartDeviceFor`) wired
|
||||
into the `/disks` union path via a localapi `Smart` seam (+ a `resolveStorageDevice` seam for
|
||||
testability). Registry/USB drives now get a real read. The watchdog `Known` path stays enrich-free
|
||||
(asserted: zero smartctl calls).
|
||||
- **Fix A — LVM/dm resolution:** `smartDeviceFor` resolves `/dev/dm-N` / `/dev/mapper/X` to the single
|
||||
backing whole disk via `/sys/block/<dm>/slaves` (recursive; **skips** on >1 physical disk). The
|
||||
builtin `local` dir on the LVM root gets a **SMART-only** device from its containing filesystem
|
||||
(`containingMountDevice`), gated to `catDir && backing=="" && reachable` — never touching
|
||||
`backing_device`/`durable_id` (the removable-safety guard stays intact).
|
||||
- **Model:** `SmartSummary.ModelName` captured from smartctl's `model_name`.
|
||||
- Fix C (`-d sat`) stays rejected — no sudoers/manifest change.
|
||||
## A0/A3 determination
|
||||
- **A0 = config-only for the endpoint:** `main.go` sets the bootstrap `Endpoint: cfg.LocalAPI.ListenAddr`;
|
||||
moving the bind to the island moves the guest dial with no template change. The version bump is for the
|
||||
net1-attach (the operator chose agent-bringup over golden-bake to eliminate the golden-coupling risk).
|
||||
- **A3 = healer verify-only:** the guestnet healer is eth0-only (`parseMode` dev-scoped); the static island
|
||||
eth1 is outside its scope. Locked with a red-proof test — no healer change.
|
||||
|
||||
## Files
|
||||
`internal/hub/report.go` (ModelName), `internal/storage/smart.go` (parse model), `internal/storage/smartdev.go`
|
||||
(NEW: dm resolution + SmartReader + containingMountDevice), `internal/storage/observe.go` (smartDeviceFor dm
|
||||
branch, enrich smartHint, build hint), `internal/localapi/{server.go,disks.go}` (Smart seam + union read +
|
||||
resolve seam), `cmd/felhom-agent/main.go` (wire), CHANGELOG/CONTEXT/REUSE. New tests:
|
||||
`smartdev_test.go`, `observe_smart_test.go`, union-path test in `disks_smart_test.go`.
|
||||
## Tests (green, non-hollow)
|
||||
`TestBuildBringUpConfig_IslandNIC`, `TestLocalAPIConfig_IslandValidation`,
|
||||
`TestParseMode_IslandStaticNICDoesNotConfuseEth0`. Full `go build/vet/test ./...` green.
|
||||
|
||||
## Tests + red-proofs (all recorded)
|
||||
`go build/vet/test ./...` — **29 packages pass, 0 fail.** Red-proofs verified then restored:
|
||||
- dm multi-disk guard (`len(disks)!=1`) → mirror-over-two-disks resolves instead of skipping → FAIL.
|
||||
- enrich `smartHint` fallback → system disk stays UNKNOWN → FAIL.
|
||||
- Fix-B union routing removed → union drive carries no SMART → FAIL.
|
||||
- Known-path-never-SMARTs asserted (zero calls; the "route Known through enrich" mutation would break it).
|
||||
|
||||
## Deploy + LIVE acceptance (felhom-pve — REAL N100 hardware, not virtualized)
|
||||
Built `0.95.0` (ldflags), backed up `.bak-0.94.0`, installed, restarted → **active, 68/68 capabilities,
|
||||
listening**. `/disks` payload now carries real SMART + model for BOTH physical disks:
|
||||
- `local` (system SSD): `backing=''` yet **smart=PASSED, model="AirDisk 512GB SSD"** — Fix A resolved
|
||||
`/`→`pve-root`(LVM)→`sda`.
|
||||
- `47a3361a` (USB): `backing=/dev/sdb`, **smart=PASSED, model="TOSHIBA MQ04ABF100"** — Fix B.
|
||||
- `felhom-pbs`/`local-lvm`: UNKNOWN (logical; correctly excluded by the controller).
|
||||
|
||||
The controller v0.171.0 card on 9201 shows both with **real verdicts + human labels**:
|
||||
**"AirDisk 512GB SSD" → Rendben (34°C)** and **"TOSHIBA MQ04ABF100" → Rendben (30°C)** — the operator's
|
||||
"Nincs adat on a raw UUID" complaint is reversed. (A live FAILING/Figyelmeztetés verdict still needs a
|
||||
genuinely degrading disk — unit+red-proof covered.)
|
||||
|
||||
## Observations
|
||||
- The earlier assumption that demo-felhom is "virtualized (no real SMART)" was WRONG — it is a real N100
|
||||
(SATA SSD `sda` + USB HDD `sdb`); the capability-map row is corrected accordingly.
|
||||
## Coupling / deploy order
|
||||
A host-install that writes the island config REQUIRES agent ≥ 0.96.0 (to read `island_guest_addr` and
|
||||
attach net1). **Vouch 0.96.0 before island installs go live.** MinAgent unchanged (no controller coupling).
|
||||
Fleet migration of existing boxes = `felhom.eu/documentation/runbooks/RUNBOOK-island-migration.md` (Phase B).
|
||||
|
||||
Reference in New Issue
Block a user