Fix FileBrowser integration config lost after SyncFileBrowserMounts
SyncFileBrowserMounts regenerates config.yaml from scratch, overwriting any integration config. The old approach used an async OnStackStart hook after container restart, which failed due to timing issues (stack state not yet refreshed). New approach: ReapplyConfigForTarget() writes integration config synchronously after config generation but before container restart, with a no-op RestartStack since the caller handles restart. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -184,6 +184,53 @@ func (m *Manager) buildApplyContext(provider, target string) (*ApplyContext, err
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ReapplyConfigForTarget applies all active integrations targeting the given stack,
|
||||
// writing config changes only (no container restart). Use this when the caller
|
||||
// handles container restart separately (e.g. SyncFileBrowserMounts).
|
||||
func (m *Manager) ReapplyConfigForTarget(targetName string) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
all := m.sett.GetIntegrationsForTarget(targetName)
|
||||
for key, state := range all {
|
||||
if !state.Enabled || state.Status == "disabled" {
|
||||
continue
|
||||
}
|
||||
|
||||
provider, target, ok := ParseIntegrationKey(key)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
handler, hOk := m.handlers[key]
|
||||
if !hOk {
|
||||
continue
|
||||
}
|
||||
|
||||
ac, err := m.buildApplyContext(provider, target)
|
||||
if err != nil {
|
||||
m.logger.Printf("[WARN] Cannot build context for integration %s reapply: %v", key, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Override RestartStack to no-op — caller handles restart
|
||||
ac.RestartStack = func(string) error { return nil }
|
||||
|
||||
if err := handler.Apply(ac); err != nil {
|
||||
m.logger.Printf("[WARN] Integration config reapply failed for %s: %v", key, err)
|
||||
state.Status = "error"
|
||||
state.LastError = err.Error()
|
||||
_ = m.sett.SetIntegrationState(key, state)
|
||||
continue
|
||||
}
|
||||
|
||||
state.Status = "active"
|
||||
state.LastError = ""
|
||||
_ = m.sett.SetIntegrationState(key, state)
|
||||
m.logger.Printf("[INFO] Integration %s config reapplied for %s", key, targetName)
|
||||
}
|
||||
}
|
||||
|
||||
// loadDecryptedEnv reads app.yaml for a stack and decrypts sensitive values.
|
||||
func (m *Manager) loadDecryptedEnv(s *stacks.Stack) map[string]string {
|
||||
stackDir := filepath.Dir(s.ComposePath)
|
||||
|
||||
@@ -1605,6 +1605,11 @@ func (s *Server) SyncFileBrowserMounts() {
|
||||
return
|
||||
}
|
||||
|
||||
// Re-apply active integrations into config.yaml (before container restart)
|
||||
if s.integrationMgr != nil {
|
||||
s.integrationMgr.ReapplyConfigForTarget("filebrowser")
|
||||
}
|
||||
|
||||
// Generate and write compose (includes config.yaml mount)
|
||||
compose := generateFileBrowserCompose(domain, storageMounts)
|
||||
if err := os.WriteFile(composePath, []byte(compose), 0644); err != nil {
|
||||
@@ -1621,10 +1626,6 @@ func (s *Server) SyncFileBrowserMounts() {
|
||||
s.logger.Printf("[ERROR] Failed to recreate FileBrowser: %s — %v", string(out), err)
|
||||
} else {
|
||||
s.logger.Printf("[INFO] FileBrowser mounts synced — %d storage path(s), config updated", len(paths))
|
||||
// Re-apply active integrations (config regeneration overwrites config.yaml)
|
||||
if s.integrationMgr != nil {
|
||||
go s.integrationMgr.OnStackStart(context.Background(), "filebrowser")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user