docs: REPORT — storage lifecycle + acceptance sweep (agent half)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,45 +1,45 @@
|
||||
# REPORT — intermediary-mount re-architecture (agent half) (2026-06-15)
|
||||
# REPORT — storage lifecycle completion + acceptance sweep (agent half) → v0.36.7 (2026-06-15)
|
||||
|
||||
## Type
|
||||
Multi-commit build + live deploy + migration on the demo host (`felhom-pve`, guest 9201). Replaces the
|
||||
per-drive `pct set -mpN` guest bind (reboot-to-activate; bricks when a drive is absent at boot) with a
|
||||
single permanent **parent bind** `/mnt/felhom-drives` plus host-side drive hot-swaps underneath it. Pairs
|
||||
with controller v0.67.5 + the app-catalog repoint. Design: `felhom.eu/documentation/audits/SPIKE-intermediary-mount-2026-06-15.md`.
|
||||
Lifecycle fixes + a full live acceptance sweep (incl. a real HOST REBOOT) on the intermediary-mount
|
||||
foundation. Built + Linux-gated + deployed to felhom-pve per commit. Pairs with controller v0.68.1. Full
|
||||
audit: `felhom.eu/documentation/audits/storage-lifecycle-acceptance-2026-06-15.md`.
|
||||
|
||||
## Shipped (agent), each built + Linux-gated (`go vet`/`go test ./...` green) + deployed to felhom-pve
|
||||
- **v0.33.0 — C1 net (transitional).** Pre-start PVE hookscript (`internal/guesthook`) creates host-root
|
||||
placeholders for absent bind-mount sources so the guest always boots (fail-closed); decommission now
|
||||
`pct set --delete`s the dead mp (`GuestBinder.DetachBind`). **Live-proven**: reproduced the C1 brick
|
||||
(start exit 255) then the hook heal → clean boot.
|
||||
- **v0.34.0 — intermediary mechanism.** `EnsureSharedParent` (self-bind + `--make-shared` + boot unit),
|
||||
`AttachDrive`/`DetachDrive` (host `mount --bind <drive>/felhom-data` under the parent — propagates into
|
||||
the running guest live, confined, fail-closed), `ReassertGuestBinds` rewritten as a host-side reconcile
|
||||
(no pct/reboot). `/disks` adds `GuestPath` + `BoundUnderParent`. **Live-proven**: the startup reconcile
|
||||
bound felhom-flash under the parent, propagating 3-hop into the controller container live.
|
||||
- **v0.35.0 — guest-reboot re-propagation (load-bearing).** A guest's parent bind is NON-RECURSIVE, so a
|
||||
guest reboot leaves enrolled drives bound on the HOST but invisible in the fresh guest ns. `AttachDrive`
|
||||
now takes `vmid`, checks `GuestSeesMount` (`/proc/<init-pid>/mountinfo`), and FORCE re-binds to re-fire
|
||||
propagation; a 20s periodic reconcile self-heals guest reboots; `BoundUnderParent` reflects guest
|
||||
visibility. **Live-proven**: after a guest reboot the drive auto-re-propagated.
|
||||
- **v0.35.1 — host-boot ordering.** The shared-parent oneshot now `WantedBy=pve-guests.service` (pulled
|
||||
in + `Before`-ordered) instead of the unreliable `multi-user.target`; `EnsureSharedParent` reinstalls
|
||||
on content change. Unit verified reinstalled + enabled + runs (the actual host-reboot ordering is not
|
||||
validated — the production demo host can't be rebooted).
|
||||
## Shipped (agent), each green-gated + deployed
|
||||
- **v0.36.0 — guest boot-id on /disks.** `guest_boot_id` = `<host-btime>-<guest-init-starttime>`: changes
|
||||
on every guest/host boot, stable across a controller-only restart. Lets the controller deterministically
|
||||
recreate drive-backed apps after a guest reboot (replaces a fragile container-uptime sample). Pure parser
|
||||
test + companion.
|
||||
- **v0.36.1 — decommission keeps the raw mounted.** Decommission is now a LOGICAL retire (DetachDrive the
|
||||
bind under the parent; LEAVE the raw `/mnt/<name>` mounted), so one-click re-enroll re-binds the real
|
||||
drive. The old raw-unmount orphaned a non-removable drive (re-enroll bound an empty dir). **Caught live
|
||||
in E10.**
|
||||
- **v0.36.2 — eject also keeps the raw mounted** (same fix, for the H1 disconnect→reconnect roundtrip).
|
||||
- **v0.36.3 — DetachDrive loop-umounts** ALL stacked binds (full detach → fail-close intact).
|
||||
- **v0.36.4 — mutex** serializes AttachDrive/DetachDrive (no TOCTOU double-bind race).
|
||||
- **v0.36.5 — AttachDrive normalizes to exactly one bind** (`countHostMounts`).
|
||||
- **v0.36.6 — ROOT CAUSE of the double-bind:** the shared-parent self-bind inherited `/`'s shared peer
|
||||
group, so every drive bind propagated back and DOUBLED. `make-private` (own group) BEFORE `make-shared`.
|
||||
- **v0.36.7 — isolate the parent only on CREATE** (re-doing make-private/shared each reconcile churns the
|
||||
peer-group id and orphans the guest's slave → propagation silently dies).
|
||||
|
||||
Tests are non-hollow, each with a companion that fails the pre-fix/trivial impl (guesthook selector,
|
||||
decommission `--delete`, `GuestAttach` uses host-side AttachDrive not legacy pct, host-side reconcile,
|
||||
GuestPath/BoundUnderParent reporting). Sudoers extended (`FELHOM_GUESTHOOK`, `FELHOM_INTERMEDIARY`).
|
||||
Non-hollow tests + companions updated: decommission/eject keep the raw mounted (`d.unmountCalls==0` +
|
||||
DetachDrive called); the boot-id parser; etc.
|
||||
|
||||
## Live migration (guest 9201) + verification
|
||||
felhom-flash (the drive with all 8 deployed apps) fully migrated to `/mnt/felhom-drives/felhom-flash`;
|
||||
the legacy per-drive `mp2` deleted; **a guest reboot self-converges with no manual intervention** (agent
|
||||
re-propagates the drive, controller startup-recreates the apps onto it). End state: **25 containers
|
||||
healthy** (komga's healthcheck is a pre-existing quirk), `/mnt/felhom-flash` gone from the guest,
|
||||
confinement intact (only `appdata/backups/media/userdata` cross in), data identical. felhom-usb (no
|
||||
deployed apps, stale `decommissioned` intent) left on its legacy bind — out of scope.
|
||||
## Acceptance sweep highlights (live)
|
||||
- **HOST REBOOT live-validated (×2):** `journalctl -b` proves felhom-shared-parent FINISHED before
|
||||
pve-guests STARTED; the guest auto-started (onboot=1); both drives re-propagated; all 8 apps converged
|
||||
via the gate with no manual intervention; data intact.
|
||||
- Fail-close capability-proof (guest-root + root-app writes DENIED, no leak), confinement (both drives),
|
||||
two-drive isolation, eject/decommission/re-enroll roundtrips, rapid eject/reconnect (single bind after
|
||||
the double-bind root-cause fix).
|
||||
|
||||
## Known residuals (documented, not blocking)
|
||||
- Host-reboot ordering: unit fix shipped (v0.35.1) but not validated via an actual host reboot.
|
||||
- Guest-reboot app recreate is state-sampled (controller side): an app cleanly stopped at the exact
|
||||
sample instant may need one manual start (1/8 in one run). The deterministic fix is a guest-boot-id
|
||||
signal (future).
|
||||
## End state
|
||||
Both external drives on the intermediary model, **single bind each**, propagation live, **25 containers
|
||||
healthy**, felhom-flash default. agent v0.36.7 deployed (backups at /usr/local/bin/felhom-agent.bak-*).
|
||||
|
||||
## Known residuals
|
||||
- Pre-start hook vs an agent restart can race the parent-bind churn (exit 255) — resolved by the
|
||||
on-create-only isolation (parent no longer churned); operationally, don't restart the agent and reboot
|
||||
the guest in the same instant.
|
||||
- "Safely removable" fs-flush before a physical pull is the separate "remove from system" action's job.
|
||||
|
||||
Reference in New Issue
Block a user