Merge pull request 'A held module whose backup the node agent interrupted, recorded before #189, is not in the node own composition (issue 1289)' (#190) from fix/held-backup-old-record into main

This commit was merged in pull request #190.
This commit is contained in:
2026-10-31 19:27:48 +00:00
3 changed files with 20 additions and 5 deletions
+10 -4
View File
@@ -618,17 +618,23 @@ func TestADataModuleIsBackedUpFirstAndHeldWhenItFails(t *testing.T) {
detail, backup string
backups, applied int
phase delivery.Phase
namesNothing bool // the have names no fp and no composition
}{
{BackupInterrupted, delivery.BackupAgain, 1, 1, delivery.PhaseRunning},
{BackupInterrupted, "", 1, 1, delivery.PhaseRunning},
{"restic: the repository is locked", delivery.BackupAgain, 0, 0, delivery.PhaseHeld},
{BackupInterrupted, delivery.BackupAgain, 1, 1, delivery.PhaseRunning, false},
// novox's postgres: its held have, written before mesh-host #189, names nothing it runs.
{BackupInterrupted, "", 1, 1, delivery.PhaseRunning, true},
{"restic: the repository is locked", delivery.BackupAgain, 0, 0, delivery.PhaseHeld, false},
} {
r := newBed(t)
r.comps.before(ck1, craw1)
r.comps.before(ck2, craw2)
wk, wraw := wantFor(t, "db", fp2, dig2, row.backup)
r.wants.before(wk, wraw)
r.haves.stored = map[string]Have{"db": {Module: "db", FP: fp1, Composed: dig1, Phase: string(delivery.PhaseHeld), Detail: row.detail}}
held := Have{Module: "db", FP: fp1, Composed: dig1, Phase: string(delivery.PhaseHeld), Detail: row.detail}
if row.namesNothing {
held.FP, held.Composed = "", ""
}
r.haves.stored = map[string]Have{"db": held}
stopR := r.run()
if row.applied > 0 {
eventually(t, row.detail+": not applied after its backup", func() bool { return len(r.appliedList()) == row.applied })
+6 -1
View File
@@ -618,7 +618,12 @@ func (c *Composer) takeModuleHave(u agent.Update) bool {
// A have that names nothing it runs, failed (the node could not compose a module it never ran: NotComposed), is
// no module run inside the node's own composition: taken as one, it was composed from its manifest past its
// build (issue 1126, review round 1 of the builds).
runsNothing := h.Phase == delivery.PhaseFailed && h.FP == "" && h.Composed == ""
// Nor is one held by a backup the node agent's own stop interrupted that names nothing (a have written before
// mesh-host #189, novox's postgres 2026-10-31): taken as one, it was composed from its manifest and refused
// for its secret reader before the start backed it up again. Any other have naming nothing keeps the rule
// (waiting for a yes inside the node's own stays in).
interrupted := h.Phase == delivery.PhaseHeld && h.Detail == agent.BackupInterrupted
runsNothing := (h.Phase == delivery.PhaseFailed || interrupted) && h.FP == "" && h.Composed == ""
in = h.Phase != delivery.PhaseRemoved && !runsNothing && !strings.HasPrefix(h.FP, delivery.SourcePrefix2)
}
}
+4
View File
@@ -1760,6 +1760,10 @@ func TestAHaveSaysWhetherItsModuleRunsInsideTheNodesOwn(t *testing.T) {
{"running with no fingerprint (mesh-wireguard)", delivery.Have{Phase: delivery.PhaseRunning, Health: delivery.HealthOK}, true, false},
{"held today", delivery.Have{FP: "build-0123abcd", Composed: "sha256:" + strings.Repeat("c", 64), Phase: delivery.PhaseHeld,
Health: delivery.HealthWaits, Detail: "held: a required config value is unset"}, true, true},
// novox's postgres (2026-10-31), its have written before mesh-host #189: held by a backup the node agent's stop
// interrupted and naming nothing; counted in, it was composed from its manifest and refused for its secret reader.
{"held by an interrupted backup, naming nothing", delivery.Have{Phase: delivery.PhaseHeld, Health: delivery.HealthWaits,
Detail: agent.BackupInterrupted}, false, true},
} {
t.Run(row.name, func(t *testing.T) {
c := New(Env{Node: "n1"})