osupdate: the health baseline is the start of the leg (inventory reading merged with the apply's own) — an app that stops during the run fails it (found live on demo-hp)
gates / gates (push) Successful in 19s
gates / gates (push) Successful in 19s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
@@ -240,6 +240,32 @@ func HealthVerdict(before, after *Health) (bool, string) {
|
|||||||
return true, ""
|
return true, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MergeBaseline is the health baseline from two readings: a container counts as running (and healthy) if EITHER
|
||||||
|
// reading saw it so. nil-safe. Pinned by TestHealth_BaselineIsTheStartOfTheLeg.
|
||||||
|
func MergeBaseline(a, b *Health) *Health {
|
||||||
|
if a == nil {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
if b == nil {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
out := &Health{DockerOK: a.DockerOK && b.DockerOK, NetworkOK: a.NetworkOK && b.NetworkOK, Controller: b.Controller,
|
||||||
|
Containers: map[string]Container{}}
|
||||||
|
for _, h := range []*Health{a, b} {
|
||||||
|
for n, c := range h.Containers {
|
||||||
|
cur, seen := out.Containers[n]
|
||||||
|
if !seen || (cur.State != "running" && c.State == "running") {
|
||||||
|
out.Containers[n] = c
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if c.State == "running" && c.Health == "healthy" {
|
||||||
|
out.Containers[n] = c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// call writes the plan and runs the wrapper once.
|
// call writes the plan and runs the wrapper once.
|
||||||
func (l *Leg) call(ctx context.Context, runID, mode string, vmid int, rel hub.WireOSRelease, pkgs []Package) (WrapperReport, error) {
|
func (l *Leg) call(ctx context.Context, runID, mode string, vmid int, rel hub.WireOSRelease, pkgs []Package) (WrapperReport, error) {
|
||||||
dir := l.PlanDir
|
dir := l.PlanDir
|
||||||
@@ -374,8 +400,12 @@ func (l *Leg) Run(ctx context.Context, vmid int, trigger string) Report {
|
|||||||
}
|
}
|
||||||
deadline := l.now().Add(wait)
|
deadline := l.now().Add(wait)
|
||||||
cur := ap.HealthAfter
|
cur := ap.HealthAfter
|
||||||
|
// The baseline is the guest as it was at the START of the leg (the inventory's reading) merged with the
|
||||||
|
// apply's own "before": an app that stops at any point during the run counts. Found live 2026-10-04: an app
|
||||||
|
// stopped between the inventory and the apply's own reading was taken as "stopped before" and ignored.
|
||||||
|
base := MergeBaseline(inv.HealthAfter, ap.HealthBefore)
|
||||||
for {
|
for {
|
||||||
ok, why := HealthVerdict(ap.HealthBefore, cur)
|
ok, why := HealthVerdict(base, cur)
|
||||||
rep.Healthy, rep.HealthReason = ok, why
|
rep.Healthy, rep.HealthReason = ok, why
|
||||||
if ok || !l.now().Before(deadline) || ctx.Err() != nil {
|
if ok || !l.now().Before(deadline) || ctx.Err() != nil {
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -263,3 +263,19 @@ func TestWrapperSuite(t *testing.T) {
|
|||||||
t.Fatalf("wrapper suite did not report OK:\n%s", out)
|
t.Fatalf("wrapper suite did not report OK:\n%s", out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// An app that stops BETWEEN the start of the leg and the apply's own "before" reading still fails the run.
|
||||||
|
// Measured live 2026-10-04 on demo-hp (privatebin stopped 1 s after the apply plan was written: the old rule
|
||||||
|
// passed). Red-proof: use ap.HealthBefore alone as the baseline and this fails.
|
||||||
|
func TestHealth_BaselineIsTheStartOfTheLeg(t *testing.T) {
|
||||||
|
stoppedEarly := &Health{DockerOK: true, NetworkOK: true, Controller: "healthy", Containers: map[string]Container{
|
||||||
|
"felhom-controller": {State: "running", Health: "healthy"}, "app": {State: "exited"}}}
|
||||||
|
w := &fakeWrapper{t: t, pending: pend, applyRep: WrapperReport{Upgraded: []Package{{Name: "libc6"}},
|
||||||
|
HealthBefore: stoppedEarly, HealthAfter: stoppedEarly},
|
||||||
|
healthSeq: []*Health{stoppedEarly, stoppedEarly, stoppedEarly, stoppedEarly, stoppedEarly, stoppedEarly, stoppedEarly}}
|
||||||
|
l, _ := newLeg(t, w, &hub.WireOSUpdate{Ring: 0, Enabled: true})
|
||||||
|
rep := l.Run(context.Background(), 9201, "night")
|
||||||
|
if rep.Outcome != "health_failed" || !strings.Contains(rep.HealthReason, "app was running") {
|
||||||
|
t.Fatalf("an app that stopped during the run passed: %+v", rep)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user