agent v0.37.0: host-reboot remount re-resolves enrolled drives by fs-UUID
TASK A — close out the reboot story (agent half). Root cause (pinned live on felhom-pve): an enrolled .mount unit left `disabled` by a prior detach never auto-mounts at boot, and kernel re-enumeration can move a drive's node (/dev/sdb->sdc). Fix re-asserts every enrolled mount by filesystem UUID at startup + on the periodic tick. - ResolveStorageDevice: resolve uuid:<fs-uuid> -> current /dev node via /dev/disk/by-uuid (never a cached node); errors if absent. - parseFelhomMountUnit: pure inverse of renderMountUnit (marker-gated). - (*SudoHostOps).ReassertEnrolledMounts: re-run EnsureMount (enable --now) for any enrolled unit not in /proc/mounts; idempotent, skips mounted/absent. - main.go: runs before ReassertGuestBinds at startup + on the 20s tick. - tests (Linux, seam=device resolution): letter-move tolerated (sdb->sdc) + red-proof companion, absent/scheme rejection, render->parse round-trip. TASK A2 verdict: enrolling a NEW drive does NOT need an LXC restart — the path lands on the live AttachDrive (shared parent, named live slots), not RebootGuest. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,37 @@
|
||||
All notable changes to **felhom-agent** are recorded here. Update on every code
|
||||
change that gets pushed.
|
||||
|
||||
## v0.37.0 — host-reboot remount re-resolves enrolled drives by filesystem UUID (2026-06-16)
|
||||
|
||||
**TASK A — close out the reboot story (agent half).** On a host reboot the kernel can re-enumerate block
|
||||
devices and move a drive's node (felhom-usb `/dev/sdb`→`/dev/sdc`), and a `.mount` unit left `disabled`
|
||||
by a prior detach never auto-mounts at boot — so an enrolled drive could stay unmounted (or, with any
|
||||
node-trusting remount, mount the WRONG device). Root cause pinned LIVE: felhom-usb's systemd mount unit
|
||||
was `disabled` (no `multi-user.target.wants` symlink) while felhom-flash's was `enabled`; `What=` was
|
||||
already correct (by-UUID), but nothing re-asserted the unit at startup.
|
||||
|
||||
- `storage.ResolveStorageDevice(durableID)` — resolves the enrolled `uuid:<fs-uuid>` storage scheme to its
|
||||
CURRENT backing `/dev` node by re-scanning `/dev/disk/by-uuid` (never a cached node); errors if the UUID
|
||||
is genuinely absent so a caller skips a gone drive instead of fail-mounting a stale node.
|
||||
- `storage.parseFelhomMountUnit` — pure inverse of `renderMountUnit` (Name/UUID/Where/Type/Options) keyed
|
||||
on a `Managed by felhom-agent` marker; ignores any foreign `.mount` unit.
|
||||
- `(*SudoHostOps).ReassertEnrolledMounts(ctx)` — at startup (BEFORE binding into the guest) and on the
|
||||
periodic 20s tick: for each enrolled `.mount` unit not currently mounted (per `/proc/mounts`), re-resolve
|
||||
by UUID and re-run `EnsureMount` (idempotent `systemctl enable --now`) — re-enables a disabled unit AND
|
||||
mounts the CURRENT device by UUID, so a `/dev/sdX` reshuffle is a no-op. Already-mounted drives are
|
||||
skipped (no daemon-reload churn); an absent UUID is skipped (re-asserts on a later tick).
|
||||
- Wired in `main.go` ahead of `ReassertGuestBinds` so mounts are live before the guest binds re-assert.
|
||||
- Tests (Linux, seam the device-resolution): `TestResolveStorageDevice_ToleratesDeviceLetterMove`
|
||||
(UUID symlink moved sdb→sdc → resolves sdc; companion asserts the cached enroll-time node differs from
|
||||
the freshly-resolved one — a node-based remount would target the wrong device), `..._AbsentAndScheme`
|
||||
(absent UUID errors; only the `uuid:` scheme resolvable), `TestParseFelhomMountUnit` (render→parse
|
||||
round-trip + rejects a foreign unit).
|
||||
|
||||
**TASK A2 — verdict: enrolling a NEW drive does NOT need an LXC restart.** The enroll path lands on the
|
||||
live intermediary-mount `AttachDrive` (`/disks/guest-attach` → `handleDiskGuestAttach` → `AttachDrive`,
|
||||
"no pct, no reboot") under the single shared parent — unbounded named live slots — NOT the legacy
|
||||
`RebootGuest` branch. The operator's pre-created-slot-pool idea is therefore unnecessary.
|
||||
|
||||
## v0.36.7 — isolate the shared parent only on CREATE (no peer-group churn) (2026-06-15)
|
||||
|
||||
Follow-up to v0.36.6: make-private+make-shared must run ONLY when the self-bind is first created, not on
|
||||
|
||||
Reference in New Issue
Block a user