Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FpBYrZCt9sFDqLgbG5GRGD
4.1 KiB
REPORT — FileBrowser no-op recreate fix (F2) + drop restic binary (F1)
Repo: felhom-controller · Version: v0.81.0 → v0.82.0 · Date: 2026-06-24
Baseline: main @ 036a6078b (CHANGELOG top v0.81.0), trunk-based, no branches.
Two findings from TEST-REPORT-stable-path-sysdrive-restart-2026-06-23.md, both validated at source.
F2 — gate the FileBrowser recreate on an actual change
Root cause: syncFileBrowserMounts (internal/web/handlers.go) ran
docker compose up -d --force-recreate --remove-orphans unconditionally. The existing
sourcesChanged flag gated only the restore-mode DB reset (down -v); the force-recreate fired on
every controller restart and every storage sync even when config.yaml/compose were byte-identical —
bouncing the customer's file-access UI, contradicting the "Vezérlő újraindítása → apps keep running"
promise (the 3.4 reproduction in the test report).
Fix:
- Capture
oldConfig/oldComposefrom disk before the writes. - Re-read
finalConfig/finalComposeafter the writes — so the integrations'ReapplyConfigForTarget("filebrowser")edits toconfig.yamlare included in the comparison. - New pure helper
fbNeedsRecreate(oldCfg, newCfg, oldCompose, newCompose) bool(byte-equality on both files) drives the decision.changed→up -d --force-recreate --remove-orphans; otherwise a plainup -d --remove-orphans(ensures running, no bounce). - Preserved: the restore-mode DB reset stays gated on
sourcesChanged && resetDBOnChange; when it runs it setschanged = true(adown -vremoved the container, so it must be recreated). - First-ever run (no old files → empty bytes) differs from generated content →
changed = true→ creates it.
Files: internal/web/handlers.go (helper + gate; added bytes import).
F1 — drop the unused restic binary from the image
controller/Dockerfile: removed the restic \ apt line and its # - restic: … comment. Disk-tier
restic moved to the host agent; no controller code execs the binary. Left untouched (still live in
the dashboard/UI): ResticSchedule config, migrateResticToRsync settings migration, and the
Method/backup-dir-name string references.
Tests
- Added
TestFbNeedsRecreate(internal/web/filebrowser_gate_test.go): unchanged → false (no recreate); config differs → true; compose differs → true; first run (no old files) → true. - Red-proof: hard-wiring
fbNeedsRecreateto always returntrue(the old unconditional behaviour) makes the "unchanged → no recreate" case fail; restoring the byte-equality gate turns it green. - Web package top-level tests: +1 (added
TestFbNeedsRecreate). - Green gate:
go build ./...✓ ·go vet ./...✓ ·go test ./...✓ (all packages ok).
Deploy & verify (guest 9201 / felhom-pve)
Deployed via the golden bootstrap mechanism: docker pull …:0.82.0 into the guest, set
/etc/felhom-controller-image → 0.82.0, systemctl restart felhom-controller-bootstrap.service.
docker ps→gitea.dooplex.hu/admin/felhom-controller:0.82.0 Up … (healthy)✓- F1:
docker exec felhom-controller command -v restic→NO-RESTIC✓ - F2 (no-op): deploying 0.82.0 restarted the controller; its startup sync logged
FileBrowser sync — no config/compose change, ensured running without recreate (3 storage path(s)), and FileBrowserStartedAtstayed2026-06-23T18:15:47(UNCHANGED — not bounced) ✓ - F2 (change path): dirtied the on-disk
config.yaml+ restarted the controller → logFileBrowser mounts synced (recreated) — 3 storage path(s), config updated, FileBrowserStartedAtadvanced to2026-06-24T09:05:53(recreated on a real change) ✓. The sync regeneratedconfig.yamlback to canonical (test line gone), FileBrowser + controller healthy — state restored.
Method: invoked the exact server-side sync (controller restart → syncFileBrowserMounts) on the live
guest; no browser tool needed for this check (it's container-lifecycle, observed via docker inspect).