Data-loss hunt: R-1180 proven against production code (the nightly rsync --delete mirror runs while a restore holds the backup flag and deletes the files being restored)
gates / gates (push) Successful in 13m20s
gates / gates (push) Successful in 13m20s
This commit is contained in:
1 parent
a57a8363df
commit
20a77d367b
4 files changed
+49
-2
No files matched your search
@@ -33,7 +33,7 @@ Register: none of the candidates below is in OPEN-ITEMS or CLOSED-ITEMS (searche
|
||||
| D6 kept-data page can list a running app's folder | PLAUSIBLE | defect | needs an unreadable app.yaml |
|
||||
| D7 unit restore can point the app at an old drive | PLAUSIBLE (low) | defect | |
|
||||
| D8 local whole-guest keep=1 | design (07 §6.1 R-684 chose it) | design | **NOT-A-FINDING: the operator chose keep=1 for demo-hp; recorded in 07** |
|
||||
| T1 the nightly mirror (`rsync --delete`) can run during a restore from that mirror | CONFIRMED-CODE | defect | `RunAllTier2` (`tier2.go:479-520`) takes no backup flag; the whole restore holds only `acquireRunning` (`tier2_whole.go:301`) |
|
||||
| T1 the nightly mirror (`rsync --delete`) can run during a restore from that mirror | **CONFIRMED** (unit test, production rsync mirror: `C3-T1-mirror-during-restore/`) → R-1180 | defect | `RunAllTier2` (`tier2.go:479-520`) takes no backup flag; the whole restore holds only `acquireRunning` (`tier2_whole.go:301`) |
|
||||
| T2 controller image without tzdata → UTC schedules | **NOT-A-FINDING:** measured on 9202 (controller 0.331.0, Debian 13 base): `/usr/share/zoneinfo/Europe/Budapest` present, scheduler logs „scheduled for … CEST" | — | |
|
||||
| T3 whole-guest start creeps ~5 min/night | PLAUSIBLE | defect | needs the agent journal over weeks |
|
||||
| T4 whole-guest quiesce stops apps mid-restore | PLAUSIBLE | defect | `quiesce.go:213-275` |
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
# go test at controller 7ca59e2 (v0.336.0), scratch clone; the PRODUCTION rsyncMirror (rsync -a --delete) on local temp dirs; 2026-10-20T11:02:49Z
|
||||
=== RUN TestRehearsalT1_NightlyMirrorRunsDuringARestore
|
||||
zz_rehearsal_t1_test.go:26: POSITIVE CONTROL: mirror after the night = [a.jpg b.jpg c.jpg d.jpg]
|
||||
zz_rehearsal_t1_test.go:34: restore in progress: backup flag held = true
|
||||
zz_rehearsal_t1_test.go:37: FAULT: mirror DURING the restore = [a.jpg b.jpg] (c.jpg, d.jpg — the files the restore is bringing back — are gone from the only copy)
|
||||
--- PASS: TestRehearsalT1_NightlyMirrorRunsDuringARestore (0.22s)
|
||||
PASS
|
||||
ok gitea.dooplex.hu/admin/felhom-controller/internal/backup 0.230s
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package backup
|
||||
|
||||
// THROWAWAY proof for the 2026-10-20 data-loss hunt (candidate T1 / R-1180). Never committed.
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type t1Provider struct{ *t2v2Provider }
|
||||
|
||||
func (p t1Provider) ListDeployedStacks() []StackSummary { return []StackSummary{{Name: "app"}} }
|
||||
|
||||
func TestRehearsalT1_NightlyMirrorRunsDuringARestore(t *testing.T) {
|
||||
m, src, target, prov := newTier2V2(t, "app")
|
||||
prov.has["app"] = true
|
||||
prov.binds["app"] = []ClassifiedBind{mHDD("appdata/app/photos")}
|
||||
m.stackProvider = t1Provider{prov}
|
||||
m.tier2Mirror = rsyncMirror // the PRODUCTION mirror (rsync -a --delete), local temp dirs only
|
||||
for _, n := range []string{"a.jpg", "b.jpg", "c.jpg", "d.jpg"} {
|
||||
mustWrite(t, filepath.Join(src, "appdata", "app", "photos", n), n)
|
||||
}
|
||||
m.RunAllTier2()
|
||||
mir := filepath.Join(target, "backups", "secondary", "app", "hdd", "appdata", "app", "photos")
|
||||
ls := func(d string) []string { e, _ := os.ReadDir(d); var o []string; for _, x := range e { o = append(o, x.Name()) }; return o }
|
||||
t.Logf("POSITIVE CONTROL: mirror after the night = %v", ls(mir))
|
||||
|
||||
// The household deleted half the photos and starts the second drive's restore; the restore holds the backup flag.
|
||||
os.Remove(filepath.Join(src, "appdata", "app", "photos", "c.jpg"))
|
||||
os.Remove(filepath.Join(src, "appdata", "app", "photos", "d.jpg"))
|
||||
if err := m.acquireRunning(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("restore in progress: backup flag held = %v", m.acquireRunning() != nil)
|
||||
// 03:30 — the nightly second-drive leg fires while the restore is still copying.
|
||||
m.RunAllTier2()
|
||||
t.Logf("FAULT: mirror DURING the restore = %v (c.jpg, d.jpg — the files the restore is bringing back — are gone from the only copy)", ls(mir))
|
||||
m.releaseRunning()
|
||||
}
|
||||
Reference in new issue
Block a user