fix: scope FileBrowser DB reset to restore-only path
Normal storage add/remove no longer nukes the FileBrowser database volume. A .fb-reset flag file is written during restore and consumed on next startup. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,7 @@
|
|||||||
- **Bind mount write**: `atomicWriteFile()` now falls back to direct write when rename fails (fixes "device or resource busy" on Docker bind-mounted `controller.yaml`)
|
- **Bind mount write**: `atomicWriteFile()` now falls back to direct write when rename fails (fixes "device or resource busy" on Docker bind-mounted `controller.yaml`)
|
||||||
- **Drive mounting after restore**: Restore flow now calls `MountDrivesFromLayout()` to mount drives by UUID and add fstab entries — previously drives referenced in the infra backup were not mounted, causing "Adattároló nem elérhető" warnings
|
- **Drive mounting after restore**: Restore flow now calls `MountDrivesFromLayout()` to mount drives by UUID and add fstab entries — previously drives referenced in the infra backup were not mounted, causing "Adattároló nem elérhető" warnings
|
||||||
- **Post-restore redirect**: UI now polls until the controller is actually up instead of using a fixed 5-second timeout (which was too short for container restart)
|
- **Post-restore redirect**: UI now polls until the controller is actually up instead of using a fixed 5-second timeout (which was too short for container restart)
|
||||||
|
- **FileBrowser DB reset scoped to restore**: `SyncFileBrowserMounts()` no longer resets the FileBrowser database volume on source changes — only the post-restore startup path (`SyncFileBrowserMountsReset`) does, preserving user accounts, permissions, and share links during normal storage operations
|
||||||
|
|
||||||
### v0.31.6 — UI: Brand-consistent button & card styling (2026-02-25)
|
### v0.31.6 — UI: Brand-consistent button & card styling (2026-02-25)
|
||||||
|
|
||||||
|
|||||||
@@ -875,6 +875,11 @@ func (s *Server) restoreFromInfraBackup(ib *report.InfraBackup) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Signal that FileBrowser's database should be reset on next startup.
|
||||||
|
// After restore, the DB has stale source preferences from the initial install.
|
||||||
|
flagPath := filepath.Join(s.dataDir, ".fb-reset")
|
||||||
|
_ = os.WriteFile(flagPath, []byte("restore"), 0644)
|
||||||
}
|
}
|
||||||
|
|
||||||
// mountDrivesFromBackup mounts drives from the infra backup's disk layout.
|
// mountDrivesFromBackup mounts drives from the infra backup's disk layout.
|
||||||
|
|||||||
@@ -1566,6 +1566,17 @@ func (s *Server) settingsStorageLabelHandler(w http.ResponseWriter, r *http.Requ
|
|||||||
// SyncFileBrowserMounts regenerates FileBrowser's docker-compose.yml and config.yaml
|
// SyncFileBrowserMounts regenerates FileBrowser's docker-compose.yml and config.yaml
|
||||||
// with volume mounts and sources for all registered storage paths, then recreates the container.
|
// with volume mounts and sources for all registered storage paths, then recreates the container.
|
||||||
func (s *Server) SyncFileBrowserMounts() {
|
func (s *Server) SyncFileBrowserMounts() {
|
||||||
|
s.syncFileBrowserMounts(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SyncFileBrowserMountsReset is like SyncFileBrowserMounts but resets the FileBrowser
|
||||||
|
// database when sources change. Use only after restore — normal operations should use
|
||||||
|
// SyncFileBrowserMounts to preserve user accounts, permissions, and share links.
|
||||||
|
func (s *Server) SyncFileBrowserMountsReset() {
|
||||||
|
s.syncFileBrowserMounts(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) syncFileBrowserMounts(resetDBOnChange bool) {
|
||||||
// Prevent concurrent syncs — multiple callers can race on the same files (H5 fix).
|
// Prevent concurrent syncs — multiple callers can race on the same files (H5 fix).
|
||||||
s.fileBrowserMu.Lock()
|
s.fileBrowserMu.Lock()
|
||||||
defer s.fileBrowserMu.Unlock()
|
defer s.fileBrowserMu.Unlock()
|
||||||
@@ -1625,13 +1636,13 @@ func (s *Server) SyncFileBrowserMounts() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// If sources changed, reset database so FileBrowser re-reads config.yaml.
|
// If sources changed and caller requested a DB reset (restore flow),
|
||||||
// The database caches user source preferences from the old config.
|
// nuke the data volume so FileBrowser re-reads config.yaml from scratch.
|
||||||
if sourcesChanged {
|
// Normal operations skip this to preserve user accounts, permissions, and share links.
|
||||||
s.logger.Printf("[INFO] FileBrowser sources changed — resetting database")
|
if sourcesChanged && resetDBOnChange {
|
||||||
|
s.logger.Printf("[INFO] FileBrowser sources changed — resetting database (restore mode)")
|
||||||
resetCtx, resetCancel := context.WithTimeout(context.Background(), 30*time.Second)
|
resetCtx, resetCancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
defer resetCancel()
|
defer resetCancel()
|
||||||
// Stop container first, then remove the data volume
|
|
||||||
stop := exec.CommandContext(resetCtx, "docker", "compose", "down", "-v")
|
stop := exec.CommandContext(resetCtx, "docker", "compose", "down", "-v")
|
||||||
stop.Dir = stackDir
|
stop.Dir = stackDir
|
||||||
if out, err := stop.CombinedOutput(); err != nil {
|
if out, err := stop.CombinedOutput(); err != nil {
|
||||||
|
|||||||
@@ -114,8 +114,16 @@ func NewServer(cfg *config.Config, stackMgr *stacks.Manager, cpuCollector *syste
|
|||||||
logger.Printf("[INFO] Auth: no password configured — dashboard is open")
|
logger.Printf("[INFO] Auth: no password configured — dashboard is open")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sync FileBrowser config on startup to ensure mounts and sources are current
|
// Sync FileBrowser config on startup to ensure mounts and sources are current.
|
||||||
go s.SyncFileBrowserMounts()
|
// After a restore, a flag file signals that the database should be reset
|
||||||
|
// (stale source prefs from initial install). Consume the flag and reset.
|
||||||
|
fbResetFlag := filepath.Join(cfg.Paths.DataDir, ".fb-reset")
|
||||||
|
if _, err := os.Stat(fbResetFlag); err == nil {
|
||||||
|
os.Remove(fbResetFlag)
|
||||||
|
go s.SyncFileBrowserMountsReset()
|
||||||
|
} else {
|
||||||
|
go s.SyncFileBrowserMounts()
|
||||||
|
}
|
||||||
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user