v0.12.7: mandatory HDD backup, pre-dump, restore for all apps
Fix 1: HDD data backup is now mandatory for all deployed apps. resolveAppBackupPaths() iterates ListDeployedStacks() directly — no longer reads GetAppBackupMap() or checks the Enabled flag. DiscoverAppData() drops backupPrefs parameter; BackupEnabled is set from HasHDDData. Five dead settings methods removed: IsAppBackupEnabled, SetAppBackup, GetAppBackupMap, SetAppBackupBulk, GetAppBackupPrefs. Fix 2: Cross-drive backup now triggers a fresh DB dump (DumpStackDB) before running. DBDumper interface added to crossdrive.go; Manager implements it; SetDBDumper wired in main.go. Non-fatal — proceeds with user data backup even if DB dump fails. Fix 3: Restore dropdown shows ALL deployed apps (not just HDD+enabled). restore.go rewritten: always restores config+DB, adds user data if hasHDD. UI shows restore type banner (full / config+DB / config only) with color-coded styling. Snapshot API clarified for non-HDD apps. Fix 4: "Docker kötetek" → "Konfiguráció" — named volumes are not in the restic backup paths; compose files + app.yaml are what's backed up. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -15,10 +15,16 @@ import (
|
||||
"gitea.dooplex.hu/admin/felhom-controller/internal/system"
|
||||
)
|
||||
|
||||
// DBDumper can run a database dump for a specific stack.
|
||||
type DBDumper interface {
|
||||
DumpStackDB(ctx context.Context, stackName string) error
|
||||
}
|
||||
|
||||
// CrossDriveRunner handles per-app backup to secondary storage.
|
||||
type CrossDriveRunner struct {
|
||||
sett *settings.Settings
|
||||
stackProvider StackDataProvider
|
||||
dbDumper DBDumper
|
||||
logger *log.Logger
|
||||
mu sync.Mutex
|
||||
running map[string]bool // per-app running state
|
||||
@@ -34,6 +40,12 @@ func NewCrossDriveRunner(sett *settings.Settings, provider StackDataProvider, lo
|
||||
}
|
||||
}
|
||||
|
||||
// SetDBDumper sets the DB dumper for pre-backup database dumps.
|
||||
// Called after backup manager is initialized (avoids circular init dependency).
|
||||
func (r *CrossDriveRunner) SetDBDumper(d DBDumper) {
|
||||
r.dbDumper = d
|
||||
}
|
||||
|
||||
// RunAppBackup runs cross-drive backup for a single app.
|
||||
func (r *CrossDriveRunner) RunAppBackup(ctx context.Context, stackName string) error {
|
||||
cfg := r.sett.GetCrossDriveConfig(stackName)
|
||||
@@ -64,6 +76,14 @@ func (r *CrossDriveRunner) RunAppBackup(ctx context.Context, stackName string) e
|
||||
r.logger.Printf("[INFO] Cross-drive backup starting: %s → %s (method: %s)",
|
||||
stackName, cfg.DestinationPath, cfg.Method)
|
||||
|
||||
// Trigger fresh DB dump for this app before cross-drive backup
|
||||
if r.dbDumper != nil {
|
||||
if err := r.dbDumper.DumpStackDB(ctx, stackName); err != nil {
|
||||
r.logger.Printf("[WARN] Pre-backup DB dump failed for %s: %v — proceeding with user data backup", stackName, err)
|
||||
// Non-fatal: user data backup is still valuable without fresh dump
|
||||
}
|
||||
}
|
||||
|
||||
if err := r.ValidateDestination(cfg.DestinationPath); err != nil {
|
||||
r.updateStatus(stackName, "error", err.Error(), time.Since(start), "")
|
||||
return fmt.Errorf("destination validation failed: %w", err)
|
||||
|
||||
Reference in New Issue
Block a user