Files
felhom-agent/REPORT.md
T
admin a621f4c5a0 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>
2026-06-16 17:49:00 +02:00

4.1 KiB
Raw Blame History

REPORT — felhom-agent v0.37.0 (host-reboot remount by durable-id/UUID)

TASK — Close out the reboot story (agent half: Task A + Task A2).

Task A — host-reboot remount resolves by filesystem UUID, never a cached node

Diagnose-first (root cause, pinned LIVE on felhom-pve)

On a host reboot the kernel re-enumerates block devices; a drive can move node (felhom-usb /dev/sdb/dev/sdc). Two things could leave an enrolled drive unmounted after a reboot:

  1. A systemd .mount unit left disabled by a prior detach (Unmount = stop + disable) never gets a multi-user.target.wants symlink, so it does not auto-mount at boot — and nothing in the agent re-asserted it at startup.
  2. Any remount that trusted a remembered /dev/sdX node would target the WRONG device after a letter move.

Confirmed live: felhom-usb's mount unit was disabled (systemctl is-enableddisabled, no wants-symlink) while felhom-flash's was enabled. The What= line was already correct (/dev/disk/by-uuid/<UUID>), so the fix is to re-assert the unit by UUID at startup, not to rewrite the unit.

Fix

  • storage.ResolveStorageDevice(durableID) (durable_device.go) — resolves the enrolled uuid:<fs-uuid> storage scheme to its current backing /dev node by re-scanning /dev/disk/by-uuid (EvalSymlinks); rejects any non-uuid: scheme (anti-node-binding) and errors when the UUID is absent so a caller skips a gone drive instead of fail-mounting.
  • storage.parseFelhomMountUnit (mountunit.go) — pure inverse of renderMountUnit, gated on a Managed by felhom-agent marker; extracts Name/UUID/Where/Type/Options, ignores foreign units.
  • (*SudoHostOps).ReassertEnrolledMounts(ctx) (hostops.go) — for each enrolled .mount unit not in /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; already-mounted drives skipped (no daemon-reload churn), absent UUIDs skipped (retry next tick).
  • main.go — runs ReassertEnrolledMounts at startup before ReassertGuestBinds, and again ahead of the bind re-assert on the periodic 20s tick, so host mounts are live before the guest binds re-establish.

Tests (non-hollow, seam = device resolution; Linux)

  • TestResolveStorageDevice_ToleratesDeviceLetterMove — fake /dev/disk/by-uuid/<uuid> symlink pointed at sdc (moved from the enroll-time sdb); asserts ResolveStorageDevice returns the CURRENT node sdc. Companion (red-proof): asserts the cached enroll-time node (sdb) differs from the freshly-resolved node — a node-trusting remount would mount the wrong device.
  • TestResolveStorageDevice_AbsentAndScheme — absent UUID errors; only uuid: is resolvable (/dev/sdb1, store:, byid:, "" all rejected).
  • TestParseFelhomMountUnitrenderMountUnitparseFelhomMountUnit round-trip + rejects a non-felhom unit.

Task A2 — verdict: enrolling a NEW drive does NOT need an LXC restart

NO. Source-verified the enroll path: /disks/guest-attachhandleDiskGuestAttachGuestBinder.AttachDrive (intermediary-mount model, "no pct, no reboot") — a live bind under the single shared parent /mnt/felhom-drives, which provides unbounded named live slots. It does NOT take the legacy RebootGuest branch. The operator's pre-created-slot-pool idea is unnecessary.

Gate

go build ./..., go vet ./..., go test ./... all green locally (Windows: the symlink tests skip — they assert on Linux, the agent's OS). Linux green gate + companion red-proof run on the build server (192.168.0.180, go1.26.0) — see live-acceptance section.

Live acceptance

Real host reboot ×2 on felhom-pve: before/after lsblk, shared-parent-before-pve-guests ordering, both drives (felhom-usb + felhom-flash) remount by UUID across a /dev/sdX reshuffle, guest 9201 drive-backed apps recover, FileBrowser non-stale. (Captured during the supervised run.)

Secrets (local_api token / leaf fingerprint) handled out-of-band — none committed.