v0.55.0: Phase 3 — auto off-drive Tier 2 (rootfs-headroom guard)
Tier 2 rsync-mirrors each HDD app's recovery unit + appdata to a DIFFERENT physical disk (the only off-drive protection bind-mounted userdata can get; PBS can't reach it). Auto-enabled, auto-target: prefer another registered drive (different physical disk via system.SamePhysicalDevice), else the internal SSD for SMALL units only — with a size-aware headroom guard that REFUSES rather than fill the ~8G guest rootfs, recording an honest "needs 2nd HDD" status. Status persisted via the surviving CrossDriveBackup; "2. mentés" UI card now populated. Daily tier2-backup job + POST /api/backup/tier2. - backup/tier2.go (engine+selection+headroom), tier2_test.go (headroom arithmetic) - system.SamePhysicalDevice (linux Stat_t.Dev + stub) - handlers.go Tier2 UI population + tier2DestLabel; backups.html honest no-target reason - fixed stale TestBackupCopiesOnPath (old felhom-data layout -> in-guest layout) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -686,11 +686,48 @@ func (s *Server) buildAppBackupRows(status *backup.FullBackupStatus) []AppBackup
|
||||
row.StatusText = "Adatbázis mentés sikertelen"
|
||||
}
|
||||
|
||||
// Tier 2 (off-drive copy) status, from the config the Tier 2 runner persists.
|
||||
if cd := s.settings.GetCrossDriveConfig(app.StackName); cd != nil {
|
||||
if cd.LastStatus == "no_target" {
|
||||
// Auto Tier 2 found no off-drive target — surface the honest reason (no silent gap).
|
||||
row.Tier2Configured = false
|
||||
row.Tier2StatusBadge = "Nincs 2. meghajtó"
|
||||
row.Tier2LastError = cd.LastError
|
||||
} else if cd.Enabled {
|
||||
row.Tier2Configured = true
|
||||
row.Tier2Dest = tier2DestLabel(cd.DestinationPath, s.cfg.Paths.SystemDataPath)
|
||||
row.Tier2Schedule = "Naponta"
|
||||
row.Tier2LastRun = cd.LastRun
|
||||
row.Tier2LastStatus = cd.LastStatus
|
||||
row.Tier2LastError = cd.LastError
|
||||
row.Tier2SizeHuman = cd.LastSizeHuman
|
||||
switch cd.LastStatus {
|
||||
case "ok":
|
||||
row.Tier2StatusBadge = "Sikeres"
|
||||
case "error":
|
||||
row.Tier2StatusBadge = "Hiba"
|
||||
case "running":
|
||||
row.Tier2StatusBadge = "Fut..."
|
||||
default:
|
||||
row.Tier2StatusBadge = "—"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rows = append(rows, row)
|
||||
}
|
||||
return rows
|
||||
}
|
||||
|
||||
// tier2DestLabel renders a friendly destination label for the "2. mentés" card. A destination under
|
||||
// the system-data path is the internal SSD (DB/config only); otherwise it's an external drive.
|
||||
func tier2DestLabel(destPath, systemDataPath string) string {
|
||||
if systemDataPath != "" && strings.HasPrefix(destPath, systemDataPath) {
|
||||
return "belső SSD (csak DB/konfiguráció)"
|
||||
}
|
||||
return filepath.Base(strings.TrimSuffix(destPath, "/"+backup.FelhomDataDir))
|
||||
}
|
||||
|
||||
func (s *Server) backupRestoreHandler(w http.ResponseWriter, r *http.Request) {
|
||||
_ = r.ParseForm()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user