From 1f8295918edc02b58e3648c4647ed44175fafd03 Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Sun, 25 Oct 2026 10:36:20 +0100 Subject: [PATCH] =?UTF-8?q?R-1270=20follow-up=20(found=20live=20on=209202)?= =?UTF-8?q?:=20remove=20with=20=E2=80=9Edelete=20its=20backups=20too?= =?UTF-8?q?=E2=80=9D=20deletes=20the=20app's=20restore-undo=20folder=20too?= =?UTF-8?q?=20=E2=80=94=20a=20not-started=20restore's=20kept=20copy=20outl?= =?UTF-8?q?ived=20the=20remove;=20the=20wiring=20test=20also=20pins=20the?= =?UTF-8?q?=20D47=20set-aside=20removal.=20Red-proved.=20Commit=20only.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 3 +++ controller/internal/api/r474_remove_wiring_test.go | 5 ++++- controller/internal/api/router.go | 3 ++- controller/internal/backup/offbox_restore_undo.go | 3 +++ 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index daa80273..463bcb4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -80,6 +80,9 @@ felhom.eu `07` §6.6. is common). The data stays restored; the restore's undo copy is KEPT, like a failed put-back's copy for support — no new retention rule. A watcher looks 30 more minutes: when the app runs, the record turns to success („…elindult: a visszaállítás kész.") and the copy is removed, as after any successful restore. +- **Found live on 9202, fixed without a row:** the kept undo copy of a not-started restore (and any copy kept for + support) outlived the app's remove with „delete its backups too". The remove now deletes `backups/restore-undo/` + with the app's other backups (`TestR474_RemoveHandlerDeletesUnitMirrorAndPrefs` extended, seen failing). - Tests (each seen failing with the old WARN): `TestR1270_AUnitRestoreWhoseAppDoesNotStartIsNotASuccess`, `…ALateStartTurnsTheRecordIntoASuccess`, `…TheOffsiteRestoreToo`, web `…TheRecordOfANotStartedRestore`; controls `…AHealthyRestoreIsASuccessAsBefore`, `…MarkLateStartTouchesOnlyItsOwnRecord`. diff --git a/controller/internal/api/r474_remove_wiring_test.go b/controller/internal/api/r474_remove_wiring_test.go index b2e00e30..1bd501f4 100644 --- a/controller/internal/api/r474_remove_wiring_test.go +++ b/controller/internal/api/r474_remove_wiring_test.go @@ -33,7 +33,10 @@ func TestR474_RemoveHandlerDeletesUnitMirrorAndPrefs(t *testing.T) { }) } joined := " " + strings.Join(sel, " ") + " " - for _, want := range []string{"RecoveryUnitPath", "Tier2MirrorDirsForApp", "RemoveTier2Mirrors", "DeleteAppBackupPrefs"} { + // 2026-10-25: the set-aside units of earlier installs (D47) and the restore's kept undo copy (found live on 9202: a + // not-started restore's copy outlived the app's remove with its backups) go too. + for _, want := range []string{"RecoveryUnitPath", "Tier2MirrorDirsForApp", "RemoveTier2Mirrors", "DeleteAppBackupPrefs", + "SetAsideDirsForApp", "RemoveSetAsideUnits", "RestoreUndoDir"} { if !strings.Contains(joined, " "+want+" ") { t.Errorf("removeStack must call %s", want) } diff --git a/controller/internal/api/router.go b/controller/internal/api/router.go index 0848c316..72f24d79 100644 --- a/controller/internal/api/router.go +++ b/controller/internal/api/router.go @@ -1054,7 +1054,8 @@ func (r *Router) removeStack(w http.ResponseWriter, req *http.Request, name stri if body.RemoveBackups && r.backupMgr != nil { nsRoot := r.backupMgr.AppNamespaceRoot(name) if nsRoot != "" { - backupPaths = append(backupPaths, backup.RecoveryUnitPath(nsRoot, name), backup.AppDBDumpPath(nsRoot, name)) + backupPaths = append(backupPaths, backup.RecoveryUnitPath(nsRoot, name), backup.AppDBDumpPath(nsRoot, name), + backup.RestoreUndoDir(nsRoot, name)) // a restore's kept undo copy is a backup of the app too (2026-10-25) } mirrorDirs = r.backupMgr.Tier2MirrorDirsForApp(name) // D47: the units of earlier installs set aside for this app are its backups too (the D25 kept-copy rule). diff --git a/controller/internal/backup/offbox_restore_undo.go b/controller/internal/backup/offbox_restore_undo.go index 640864bc..cf89dce1 100644 --- a/controller/internal/backup/offbox_restore_undo.go +++ b/controller/internal/backup/offbox_restore_undo.go @@ -42,6 +42,9 @@ type liveVolumeCopy struct { keep bool // set when a put-back could not be done: the copy is the support path back, never removed } +// RestoreUndoDir is restoreUndoDir for the app's remove with „delete its backups too" (a kept copy goes with it). +func RestoreUndoDir(nsRoot, stack string) string { return restoreUndoDir(nsRoot, stack) } + // restoreUndoDir is where the live-volume copy of one restore lives. Under backups/ on purpose: no capture set // includes it (appbackup.captureset skips backups/), and backups/primary — the recovery unit — is never written. func restoreUndoDir(nsRoot, stack string) string {