controller v0.269.0: whole restore from the second drive; crash loops stopped; exact image digests; steps judged by their own .felhom.yml (decisions 26-28, R-661 R-666 R-667 R-668 R-664 R-665 R-662, 09 6.4 part 6)
gates / gates (push) Successful in 27s
gates / gates (push) Successful in 27s
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:
@@ -170,9 +170,12 @@ type Stack struct {
|
||||
HoldReason string `json:"hold_reason,omitempty"`
|
||||
// HoldNoWholeCopy (v0.268.0, R-659): the hold names NO copy — none on this box brings the app back
|
||||
// whole — so the page offers no restore button beside the sentence (the restore would refuse).
|
||||
HoldNoWholeCopy bool `json:"hold_no_whole_copy,omitempty"`
|
||||
HealthProbe *HealthProbeResult `json:"health_probe,omitempty"` // controller-side probe result
|
||||
LastUpdated time.Time `json:"last_updated"`
|
||||
HoldNoWholeCopy bool `json:"hold_no_whole_copy,omitempty"`
|
||||
// HoldKind (v0.269.0): which hold — "update_failed", "unhealthy_stop" (decision 28: the page offers
|
||||
// Start, not a restore), "restore"; "" when none.
|
||||
HoldKind string `json:"hold_kind,omitempty"`
|
||||
HealthProbe *HealthProbeResult `json:"health_probe,omitempty"` // controller-side probe result
|
||||
LastUpdated time.Time `json:"last_updated"`
|
||||
// RestartingSince (C9-F2) is when this stack was FIRST observed in StateRestarting during the
|
||||
// current restarting run; zero whenever the stack is in any other state. It is what turns a brief
|
||||
// restart (normal: deploy, update, quiesce restart) into a distinguishable crash loop — see
|
||||
@@ -205,10 +208,22 @@ type Stack struct {
|
||||
// pin and the catalog's head; one press climbs one. 0 = unknown or none. The page shows it while
|
||||
// the badge says „Frissítés elérhető".
|
||||
LadderStepsLeft int `json:"ladder_steps_left,omitempty"`
|
||||
|
||||
// CatalogDigests / CatalogTestedAt (v0.269.0, `09` §6.4 part 6): the TESTED digest per service of the
|
||||
// catalog's current refs and when that test ran — the badge's input for a floating tag (never a
|
||||
// registry query). Empty when the ladder has no entry for them.
|
||||
CatalogDigests map[string]string `json:"catalog_digests,omitempty"`
|
||||
CatalogTestedAt time.Time `json:"catalog_tested_at,omitempty"`
|
||||
}
|
||||
|
||||
// Manager handles all docker compose stack operations.
|
||||
type Manager struct {
|
||||
// lastVerifyMeta (v0.269.0) is the .felhom.yml the last update verify judged by — read by a test.
|
||||
lastVerifyMeta string
|
||||
// updateHealthMetaFn (test seam, v0.269.0): the verify with the chosen .felhom.yml; nil → the real wait.
|
||||
updateHealthMetaFn func(ctx context.Context, name string, timeout time.Duration, meta *Metadata) (bool, string)
|
||||
// unhealthy (v0.269.0, decision 28): RestartCount / OOM-kill samples per app for the crash-loop stop.
|
||||
unhealthy unhealthyWatch
|
||||
// selfUpdating (v0.261.0) reports whether the CONTROLLER is swapping itself. Set by
|
||||
// SetSelfUpdatingCheck; nil means no gate. See update.go.
|
||||
selfUpdating func() bool
|
||||
@@ -611,6 +626,8 @@ func (m *Manager) ScanStacks() error {
|
||||
// catalog template by definition, and warning once per app per scan would be noise.
|
||||
var catImages map[string]string
|
||||
stepsLeft := 0
|
||||
var catDigests map[string]string
|
||||
var catTestedAt time.Time
|
||||
if deployed && !m.cfg.IsProtectedStack(name) {
|
||||
catPath := m.CatalogTemplatePath(name, "docker-compose.yml")
|
||||
if appCfg != nil {
|
||||
@@ -618,6 +635,7 @@ func (m *Manager) ScanStacks() error {
|
||||
}
|
||||
if imgs, cerr := ParseComposeImages(catPath); cerr == nil {
|
||||
catImages = imgs
|
||||
catDigests, catTestedAt = catalogTestedDigests(filepath.Dir(catPath), imgs)
|
||||
} else if m.isDebug() {
|
||||
m.logger.Printf("[DEBUG] [stacks] ScanStacks: no readable catalog template for %s (%v) — the update badge will render nothing", name, cerr)
|
||||
}
|
||||
@@ -635,6 +653,7 @@ func (m *Manager) ScanStacks() error {
|
||||
existing.TemplateImages = tplImages
|
||||
existing.CatalogImages = catImages
|
||||
existing.LadderStepsLeft = stepsLeft
|
||||
existing.CatalogDigests, existing.CatalogTestedAt = catDigests, catTestedAt
|
||||
}
|
||||
} else {
|
||||
m.stacks[name] = &Stack{
|
||||
@@ -648,6 +667,8 @@ func (m *Manager) ScanStacks() error {
|
||||
TemplateImages: tplImages,
|
||||
CatalogImages: catImages,
|
||||
LadderStepsLeft: stepsLeft,
|
||||
CatalogDigests: catDigests,
|
||||
CatalogTestedAt: catTestedAt,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user