feat: Docker volume backup, Tier 2 restore, restore dropdown fixes (v0.33.0)
- Add Docker named volume backup to Tier 1 (dump to tar, include in restic) and Tier 2 (copy tars to rsync mirror _volumes/ dir) - Fix volume name resolution: use project-prefixed names (mealie_mealie_data) - Fix double Tier 1 in restore dropdown: filter snapshots by app's home drive - Add Tier 2 restore: RestoreAppFromTier2() restores from rsync mirror - Show Tier 2 entry in restore dropdown when cross-drive backup succeeded - Add .fab import link in restore section - Volume-aware restore type banners and backup content labels Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -795,7 +795,18 @@ func (r *Router) backupSnapshots(w http.ResponseWriter, req *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
snapshots, err := r.backupMgr.ListAllSnapshots(50)
|
||||
stackName := req.URL.Query().Get("stack")
|
||||
|
||||
var snapshots []backup.SnapshotInfo
|
||||
var err error
|
||||
|
||||
if stackName != "" {
|
||||
// Per-app: only snapshots from the app's home drive
|
||||
snapshots, err = r.backupMgr.ListSnapshotsForApp(stackName, 20)
|
||||
} else {
|
||||
// Fallback: all snapshots (general use)
|
||||
snapshots, err = r.backupMgr.ListAllSnapshots(50)
|
||||
}
|
||||
if err != nil {
|
||||
r.logger.Printf("[ERROR] [api] Failed to list backup snapshots: %v", err)
|
||||
writeJSON(w, http.StatusInternalServerError, apiResponse{OK: false, Error: err.Error()})
|
||||
@@ -814,6 +825,32 @@ func (r *Router) backupSnapshots(w http.ResponseWriter, req *http.Request) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Append Tier 2 (cross-drive rsync) entry if available for this app
|
||||
if stackName != "" {
|
||||
cdCfg := r.sett.GetCrossDriveConfig(stackName)
|
||||
if cdCfg != nil && cdCfg.Enabled && cdCfg.LastStatus == "ok" && cdCfg.LastRun != "" {
|
||||
lastRun, _ := time.Parse(time.RFC3339, cdCfg.LastRun)
|
||||
if !lastRun.IsZero() {
|
||||
// Resolve drive label for destination
|
||||
var destLabel string
|
||||
for _, sp := range storagePaths {
|
||||
if sp.Path == cdCfg.DestinationPath {
|
||||
destLabel = sp.Label
|
||||
break
|
||||
}
|
||||
}
|
||||
tier2 := backup.SnapshotInfo{
|
||||
ID: "tier2-rsync",
|
||||
Time: lastRun,
|
||||
Tier: 2,
|
||||
Source: "rsync",
|
||||
DriveLabel: destLabel,
|
||||
}
|
||||
snapshots = append(snapshots, tier2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if snapshots == nil {
|
||||
|
||||
Reference in New Issue
Block a user