v0.270.0: no update for a current app (R-679); an interrupted install is reported (R-681); a restore brings back the pinned version's health check (R-669); R-674
gates / gates (push) Successful in 24s
gates / gates (push) Successful in 24s
Five red-proofs. MinAgent 0.131.0 unchanged. 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:
@@ -0,0 +1,57 @@
|
||||
package backup
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gitea.dooplex.hu/admin/felhom-controller/internal/stacks"
|
||||
)
|
||||
|
||||
// R-669 (v0.270.0): the recovery unit captures the PINNED version's .felhom.yml (the applied record),
|
||||
// not the stack dir's — which the sync may already have replaced with a newer, even failing, step's file.
|
||||
// MEASURED 2026-09-24 (A2): the unit held port 8999 (the failing step's probe), a restore wrote it back,
|
||||
// and the next undo judged the correct version with it and held the app.
|
||||
//
|
||||
// COMPANION RED-PROOF (REPORT.md): capture the stack dir's .felhom.yml again → "the unit carries the
|
||||
// failing step's probe".
|
||||
func TestR669_UnitCapturesThePinnedVersionsMeta(t *testing.T) {
|
||||
tmp := t.TempDir()
|
||||
stackDir := filepath.Join(tmp, "stack")
|
||||
drive := filepath.Join(tmp, "drive")
|
||||
mustWrite(t, filepath.Join(stackDir, "docker-compose.yml"), "services:\n app:\n image: example/app:1.2.3\n")
|
||||
mustWrite(t, filepath.Join(stackDir, ".felhom.yml"), "display_name: Example\nhealthcheck:\n checks:\n - type: api\n port: 8999\n") // flowed by the sync
|
||||
mustWrite(t, stacks.AppliedMetaFile(stackDir), "display_name: Example\nhealthcheck:\n checks:\n - type: api\n port: 80\n") // the pinned version's
|
||||
mustWrite(t, filepath.Join(stackDir, "app.yaml"), "deployed: true\nenv: {}\n")
|
||||
m := &Manager{
|
||||
logger: log.New(io.Discard, "", 0),
|
||||
systemDataPath: filepath.Join(tmp, "system"),
|
||||
stackProvider: &fakeRecoveryProvider{info: RecoveryInfo{StackDir: stackDir, DisplayName: "Example", ImagePins: []string{"example/app:1.2.3"}}, hdd: drive},
|
||||
version: "vtest",
|
||||
}
|
||||
if err := m.CaptureRecoveryUnit("example"); err != nil {
|
||||
t.Fatalf("capture: %v", err)
|
||||
}
|
||||
b, err := os.ReadFile(filepath.Join(RecoveryUnitComposePath(drive, "example"), ".felhom.yml"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if strings.Contains(string(b), "8999") || !strings.Contains(string(b), "port: 80") {
|
||||
t.Fatalf("the unit carries the failing step's probe, not the pinned version's:\n%s", b)
|
||||
}
|
||||
// Control: no applied record (an app pinned before v0.263.2) → the stack dir's file, as before.
|
||||
if err := os.RemoveAll(filepath.Dir(stacks.AppliedMetaFile(stackDir))); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mustWrite(t, filepath.Join(stackDir, ".felhom.yml"), "display_name: Example changed\n") // force a recapture
|
||||
if err := m.CaptureRecoveryUnit("example"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
b, _ = os.ReadFile(filepath.Join(RecoveryUnitComposePath(drive, "example"), ".felhom.yml"))
|
||||
if !strings.Contains(string(b), "Example changed") {
|
||||
t.Fatalf("without an applied record the stack dir's file must be captured: %s", b)
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gitea.dooplex.hu/admin/felhom-controller/internal/stacks"
|
||||
"gitea.dooplex.hu/admin/felhom-controller/internal/system"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
@@ -115,7 +116,17 @@ func (m *Manager) CaptureRecoveryUnit(stackName string) error {
|
||||
checksums := make(map[string]string)
|
||||
var configFiles []string
|
||||
for _, fname := range []string{"docker-compose.yml", ".felhom.yml"} {
|
||||
data, err := os.ReadFile(filepath.Join(info.StackDir, fname))
|
||||
src := filepath.Join(info.StackDir, fname)
|
||||
// R-669 (v0.270.0): the .felhom.yml that belongs to the PINNED version — the one the compose above
|
||||
// runs — is the applied record. The stack dir's own file flows from the catalog on every sync and
|
||||
// can already be a NEWER (even a failing) version's; restored with the unit, it became the pinned
|
||||
// version's probe and an undo judged the correct version unhealthy (measured 2026-09-24, A2).
|
||||
if fname == ".felhom.yml" {
|
||||
if _, err := os.Stat(stacks.AppliedMetaFile(info.StackDir)); err == nil {
|
||||
src = stacks.AppliedMetaFile(info.StackDir)
|
||||
}
|
||||
}
|
||||
data, err := os.ReadFile(src)
|
||||
if err != nil {
|
||||
continue // optional — capture whichever exist
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user