From b4dbda287b8dc0d01b243023f9a26a843f578504 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 5 Nov 2026 14:50:35 +0100 Subject: [PATCH] =?UTF-8?q?Findings=20are=20written=20and=20read=20in=20th?= =?UTF-8?q?e=20seat=20mesh-conditions'=20layout:=20gitea,=20distribution,?= =?UTF-8?q?=20mesh-config,=20artifact-store-tools=20(B5b=20Left=205=20part?= =?UTF-8?q?;=20ADR=200634=20=C2=A74;=20issue=201966)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i --- .../cmd/artifact-store-tools/holder.go | 27 +++++++------- .../cmd/artifact-store-tools/holder_test.go | 7 ++-- .../cmd/artifact-store-tools/sweepseats.go | 16 +++++---- modules/artifact-store-tools/go.mod | 1 + .../cmd/distribution-tools/main.go | 15 ++++---- .../distribution/cmd/distribution/windows.go | 11 +++--- modules/distribution/go.mod | 2 ++ modules/gitea/cmd/package-registry/seats.go | 15 ++++---- modules/gitea/go.mod | 2 ++ .../mesh-config/cmd/mesh-config/findings.go | 35 ++++++++++--------- .../cmd/mesh-config/renames_test.go | 8 ++--- .../cmd/mesh-config/whole_integration_test.go | 4 +-- modules/mesh-config/go.mod | 1 + 13 files changed, 79 insertions(+), 65 deletions(-) diff --git a/modules/artifact-store-tools/cmd/artifact-store-tools/holder.go b/modules/artifact-store-tools/cmd/artifact-store-tools/holder.go index 6a8498829..fda79f764 100644 --- a/modules/artifact-store-tools/cmd/artifact-store-tools/holder.go +++ b/modules/artifact-store-tools/cmd/artifact-store-tools/holder.go @@ -23,11 +23,12 @@ import ( "sync" "time" + "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient" "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient" + meshconditions "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions" stdio "git.novox.be/novox/mesh-sdk/go" "git.novox.be/novox/mesh-sdk/go/catalogue" "git.novox.be/novox/mesh-sdk/go/delivery" - "git.novox.be/novox/mesh-sdk/go/health" "git.novox.be/novox/mesh-sdk/go/views" ) @@ -39,8 +40,8 @@ const ( HavesRead = "node-engine.have" // ManifestsRead is the indexer's manifests: the images a manifest pins by itself. ManifestsRead = delivery.IndexerModule + ".manifests" - // FindingsState is the holder's own findings (health.FindingsState): image-missing. - FindingsState = health.FindingsState + // FindingsState is the holder's own findings (meshconditions.StateFindings): image-missing. + FindingsState = meshconditions.StateFindings // Module is this module, the observer its findings name. Module = "artifact-store-tools" // GoneSubject is where the seat says artifacts-gone. @@ -865,7 +866,7 @@ func (h *Holder) Observe(ctx context.Context) error { for _, b := range j.built { builds[b.Module+" "+b.FP] = b } - now := map[string]health.Finding{} + now := map[string]meshconditions.FindingsByKeyValue{} for _, w := range j.wants { b, ok := builds[w.Module+" "+w.FP] if !ok { @@ -905,7 +906,7 @@ func (h *Holder) Observe(ctx context.Context) error { if _, still := now[k]; !still { // A finding of a first view unanswered is the reader's (views.Reader), cleared by its answer, not by a sweep. if raw, found, err := h.Bus.Get(FindingsState, k); err == nil && found { - if f, err := health.DecodeFinding(raw); err == nil && f.Kind == views.UnansweredKind { + if f, err := meshconditions.DecodeFindingsByKeyValue(raw); err == nil && f.Kind == views.UnansweredKind { continue } } @@ -920,11 +921,11 @@ func (h *Holder) Observe(ctx context.Context) error { return err } if found { - if was, err := health.DecodeFinding(raw); err == nil && was.Summary == f.Summary { + if was, err := meshconditions.DecodeFindingsByKeyValue(raw); err == nil && was.Summary == f.Summary { continue // written only when what it says changes } } - if _, err := health.EncodeFinding(f); err != nil { + if err := meshconditionsclient.CheckFinding(f); err != nil { return err } if err := h.Bus.Put(FindingsState, k, f); err != nil { @@ -935,11 +936,11 @@ func (h *Holder) Observe(ctx context.Context) error { } // imageMissing is S25's finding, in the controller's words (cmd/mesh-controller/image_missing.go watchMissingImages). -func imageMissing(node, module, image string, at time.Time) health.Finding { +func imageMissing(node, module, image string, at time.Time) meshconditions.FindingsByKeyValue { id := module + "." + node - return health.Finding{V: health.FindingVersion, Key: health.FindingKey(health.ScopeModule, id, ImageMissing), Kind: ImageMissing, - Subject: health.Subject{Scope: health.ScopeModule, ID: id, Machine: node}, - Severity: health.Warning, Resolver: health.ResolverOperator, + return meshconditions.FindingsByKeyValue{V: meshconditionsclient.FindingVersion, Key: meshconditionsclient.Key(meshconditionsclient.ScopeModule, id, ImageMissing), Kind: ImageMissing, + Subject: meshconditions.Subject{Scope: meshconditionsclient.ScopeModule, ID: id, Machine: node}, + Severity: meshconditionsclient.Warning, Resolver: meshconditionsclient.ResolverOperator, Summary: fmt.Sprintf("%s is left out of every send to %s: its declaration names an image that the artifact store does "+ "not hold (the evidence names it); the running container is untouched", module, node), Headline: capital(module) + " is not updated on " + node, @@ -947,8 +948,8 @@ func imageMissing(node, module, image string, at time.Time) health.Finding { "was not sent to %s. What runs there is untouched, and the rest of %s is sent as usual.", module, node, node), Needs: fmt.Sprintf("build %s again; the details name the image.", module), Resolved: "Resolved: the store holds the image of " + module + " again", - Evidence: []health.Evidence{{At: at.UTC(), Said: "image " + image + " is not in the store"}}, - Source: "S25", Observer: Module, At: at.UTC()} + Evidence: []meshconditions.Evidence{{At: at.UTC().Format(time.RFC3339Nano), Said: "image " + image + " is not in the store"}}, + Source: "S25", Observer: Module, At: at.UTC().Format(time.RFC3339Nano)} } func capital(s string) string { diff --git a/modules/artifact-store-tools/cmd/artifact-store-tools/holder_test.go b/modules/artifact-store-tools/cmd/artifact-store-tools/holder_test.go index 71bebdf7d..3305ac30f 100644 --- a/modules/artifact-store-tools/cmd/artifact-store-tools/holder_test.go +++ b/modules/artifact-store-tools/cmd/artifact-store-tools/holder_test.go @@ -12,10 +12,11 @@ import ( "testing" "time" + "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient" "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient" + meshconditions "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions" stdio "git.novox.be/novox/mesh-sdk/go" "git.novox.be/novox/mesh-sdk/go/delivery" - "git.novox.be/novox/mesh-sdk/go/health" "git.novox.be/novox/mesh-sdk/go/catalogue" ) @@ -403,9 +404,9 @@ func TestAWantedImageTheStoreLacksIsAFindingAndImagesNamesWantsAndHaves(t *testi if err := h.Observe(context.Background()); err != nil { t.Fatal(err) } - key := health.FindingKey(health.ScopeModule, "letta.ace", ImageMissing) + key := meshconditionsclient.Key(meshconditionsclient.ScopeModule, "letta.ace", ImageMissing) raw, found, _ := b.Get(FindingsState, key) - f, err := health.DecodeFinding(raw) + f, err := meshconditions.DecodeFindingsByKeyValue(raw) if !found || err != nil || f.Subject.Machine != "ace" || f.Source != "S25" || !strings.Contains(f.Evidence[0].Said, imageRef("letta", 1)) { t.Fatalf("the finding is %+v (%v, %v)", f, found, err) } diff --git a/modules/artifact-store-tools/cmd/artifact-store-tools/sweepseats.go b/modules/artifact-store-tools/cmd/artifact-store-tools/sweepseats.go index 0cc5d0b61..ce98ef799 100644 --- a/modules/artifact-store-tools/cmd/artifact-store-tools/sweepseats.go +++ b/modules/artifact-store-tools/cmd/artifact-store-tools/sweepseats.go @@ -13,10 +13,12 @@ import ( "encoding/json" "fmt" "strings" + "time" + "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient" + meshconditions "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions" ociseat "git.novox.be/novox/mesh-delivery/contracts/go/seats/ociartifactregistry" "git.novox.be/novox/mesh-sdk/go/catalogue" - "git.novox.be/novox/mesh-sdk/go/health" reg "git.novox.be/novox/mesh-delivery/contracts/go/seats/containerimageregistry" ) @@ -25,7 +27,7 @@ import ( const SweepRefused = "sweep-refused" // sweepFindingKey is the one key of the sweep's finding in the module's findings. -var sweepFindingKey = health.FindingKey(health.ScopeModule, Module, SweepRefused) +var sweepFindingKey = meshconditionsclient.Key(meshconditionsclient.ScopeModule, Module, SweepRefused) // canonical is a kept reference in the older form, `artifact-store://`, whichever form it came in; another is as // it was. @@ -113,17 +115,17 @@ func (h *Holder) removeOnSeat(reference, why string) error { // sweepFinding writes the sweep's finding: what the seat refused, and why. func (h *Holder) sweepFinding(what string, err error) { at := h.now().UTC() - f := health.Finding{V: health.FindingVersion, Key: sweepFindingKey, Kind: SweepRefused, - Subject: health.Subject{Scope: health.ScopeModule, ID: Module}, - Severity: health.Warning, Resolver: health.ResolverOperator, + f := meshconditions.FindingsByKeyValue{V: meshconditionsclient.FindingVersion, Key: sweepFindingKey, Kind: SweepRefused, + Subject: meshconditions.Subject{Scope: meshconditionsclient.ScopeModule, ID: Module}, + Severity: meshconditionsclient.Warning, Resolver: meshconditionsclient.ResolverOperator, Summary: fmt.Sprintf("the artifact sweep stopped: a registry seat refused %s (the evidence names why)", what), Headline: "The artifact sweep stopped", Explanation: "The sweep keeps what the mesh still needs and removes the rest through the registry seats. A seat " + "refused one of its asks, so it stopped before anything more was removed; what it kept stays kept.", Needs: "read the seat holder's journal for the refusal; the next sweep asks again.", Resolved: "Resolved: the artifact sweep ran through without a refusal", - Evidence: []health.Evidence{{At: at, Said: fmt.Sprintf("%s: %v", what, err)}}, - Source: "CAT-AS1", Observer: Module, At: at} + Evidence: []meshconditions.Evidence{{At: at.UTC().Format(time.RFC3339Nano), Said: fmt.Sprintf("%s: %v", what, err)}}, + Source: "CAT-AS1", Observer: Module, At: at.Format(time.RFC3339Nano)} if werr := h.Bus.Put(FindingsState, sweepFindingKey, f); werr != nil { h.logf("the sweep's finding (%s: %v) could not be written: %v", what, err, werr) } diff --git a/modules/artifact-store-tools/go.mod b/modules/artifact-store-tools/go.mod index 684f336aa..6fd90d5cd 100644 --- a/modules/artifact-store-tools/go.mod +++ b/modules/artifact-store-tools/go.mod @@ -3,6 +3,7 @@ module artifactstoretools go 1.26.0 require ( + git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshhandacts v0.0.0-00010101000000-000000000000 diff --git a/modules/distribution/cmd/distribution-tools/main.go b/modules/distribution/cmd/distribution-tools/main.go index b8a89cf84..19ae96160 100644 --- a/modules/distribution/cmd/distribution-tools/main.go +++ b/modules/distribution/cmd/distribution-tools/main.go @@ -18,12 +18,13 @@ import ( "sync" "time" + "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient" "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient" + meshconditions "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions" reg "git.novox.be/novox/mesh-delivery/contracts/go/seats/containerimageregistry" "git.novox.be/novox/mesh-delivery/sdk/parts" stdio "git.novox.be/novox/mesh-sdk/go" "git.novox.be/novox/mesh-sdk/go/delivery" - "git.novox.be/novox/mesh-sdk/go/health" "distribution/internal/holder" ) @@ -68,16 +69,16 @@ func say(seat, event string, body holder.Event) error { } func finding(kind, subject, words string, raised bool) { - key := health.FindingKey(health.ScopeSeat, "distribution", kind+"."+strings.NewReplacer(".", "_", "@", "_", "/", "_").Replace(subject)) + key := meshconditionsclient.Key(meshconditionsclient.ScopeSeat, "distribution", kind+"."+strings.NewReplacer(".", "_", "@", "_", "/", "_").Replace(subject)) if !raised { - _ = stdio.State(health.FindingsState).Delete(key) + _ = stdio.State(meshconditions.StateFindings).Delete(key) return } - f := health.Finding{V: health.FindingVersion, Key: key, Kind: kind, Ref: key[strings.LastIndex(key, ".")+1:], - Subject: health.Subject{Scope: health.ScopeSeat, ID: "distribution"}, Severity: health.Warning, + f := meshconditions.FindingsByKeyValue{V: meshconditionsclient.FindingVersion, Key: key, Kind: kind, Ref: key[strings.LastIndex(key, ".")+1:], + Subject: meshconditions.Subject{Scope: meshconditionsclient.ScopeSeat, ID: "distribution"}, Severity: meshconditionsclient.Warning, Summary: words, Headline: words, Explanation: words, Resolved: "cleared once it no longer holds", - Source: kind, Observer: "distribution", At: time.Now().UTC()} - if _, err := stdio.State(health.FindingsState).Put(key, f); err != nil { + Source: kind, Observer: "distribution", At: time.Now().UTC().Format(time.RFC3339Nano)} + if _, err := stdio.State(meshconditions.StateFindings).Put(key, f); err != nil { logf("the finding %s could not be written: %v", key, err) } } diff --git a/modules/distribution/cmd/distribution/windows.go b/modules/distribution/cmd/distribution/windows.go index e2356fbde..e180b56bc 100644 --- a/modules/distribution/cmd/distribution/windows.go +++ b/modules/distribution/cmd/distribution/windows.go @@ -18,7 +18,8 @@ import ( "github.com/nats-io/nats.go" "github.com/nats-io/nats.go/jetstream" - "git.novox.be/novox/mesh-sdk/go/health" + "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient" + meshconditions "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions" "git.novox.be/novox/mesh-sdk/go/process" "distribution/internal/holder" @@ -178,17 +179,17 @@ func findingsKV(kv jetstream.KeyValue, logf func(string, ...any)) func(kind, sub if kv == nil { return } - key := health.FindingKey(health.ScopeSeat, holder.Self, kind+"."+strings.NewReplacer(".", "_", "@", "_", "/", "_").Replace(subject)) + key := meshconditionsclient.Key(meshconditionsclient.ScopeSeat, holder.Self, kind+"."+strings.NewReplacer(".", "_", "@", "_", "/", "_").Replace(subject)) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() if !raised { _ = kv.Delete(ctx, key) return } - f := health.Finding{V: health.FindingVersion, Key: key, Kind: kind, Ref: key[strings.LastIndex(key, ".")+1:], - Subject: health.Subject{Scope: health.ScopeSeat, ID: holder.Self}, Severity: health.Warning, + f := meshconditions.FindingsByKeyValue{V: meshconditionsclient.FindingVersion, Key: key, Kind: kind, Ref: key[strings.LastIndex(key, ".")+1:], + Subject: meshconditions.Subject{Scope: meshconditionsclient.ScopeSeat, ID: holder.Self}, Severity: meshconditionsclient.Warning, Summary: words, Headline: words, Explanation: words + "; registry_old_name or registry_direct_writes drops a retired node by hand", - Resolved: "cleared when the window closes", Source: kind, Observer: holder.Self, At: time.Now().UTC()} + Resolved: "cleared when the window closes", Source: kind, Observer: holder.Self, At: time.Now().UTC().Format(time.RFC3339Nano)} b, _ := json.Marshal(f) if _, err := kv.Put(ctx, key, b); err != nil { logf("the finding %s could not be written: %v", key, err) diff --git a/modules/distribution/go.mod b/modules/distribution/go.mod index 4a7a87706..cc5ad086a 100644 --- a/modules/distribution/go.mod +++ b/modules/distribution/go.mod @@ -4,6 +4,8 @@ go 1.26.0 require ( git.novox.be/novox/mesh-delivery/sdk v0.0.0-00010101000000-000000000000 + git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient v0.0.0-00010101000000-000000000000 + git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-delivery/contracts/go/seats/containerimageregistry v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261104174359-05b3e2e1b94f diff --git a/modules/gitea/cmd/package-registry/seats.go b/modules/gitea/cmd/package-registry/seats.go index f924d9d6d..5320e603d 100644 --- a/modules/gitea/cmd/package-registry/seats.go +++ b/modules/gitea/cmd/package-registry/seats.go @@ -27,13 +27,14 @@ import ( "strings" "time" + "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient" "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient" + meshconditions "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions" goreg "git.novox.be/novox/mesh-delivery/contracts/go/seats/gopackageregistry" npmreg "git.novox.be/novox/mesh-delivery/contracts/go/seats/npmpackageregistry" "git.novox.be/novox/mesh-delivery/sdk/parts" stdio "git.novox.be/novox/mesh-sdk/go" "git.novox.be/novox/mesh-sdk/go/delivery" - "git.novox.be/novox/mesh-sdk/go/health" "gitea/internal/packageseats" ) @@ -250,16 +251,16 @@ func sayOn(seat, event string, o packageseats.Outcome) error { } func finding(kind, subject, words string, raised bool) { - key := health.FindingKey(health.ScopeSeat, packageseats.Self, kind+"."+strings.NewReplacer(".", "_", "@", "_", "/", "_").Replace(subject)) + key := meshconditionsclient.Key(meshconditionsclient.ScopeSeat, packageseats.Self, kind+"."+strings.NewReplacer(".", "_", "@", "_", "/", "_").Replace(subject)) if !raised { - _ = stdio.State(health.FindingsState).Delete(key) + _ = stdio.State(meshconditions.StateFindings).Delete(key) return } - f := health.Finding{V: health.FindingVersion, Key: key, Kind: kind, Ref: key[strings.LastIndex(key, ".")+1:], - Subject: health.Subject{Scope: health.ScopeSeat, ID: packageseats.Self}, Severity: health.Warning, + f := meshconditions.FindingsByKeyValue{V: meshconditionsclient.FindingVersion, Key: key, Kind: kind, Ref: key[strings.LastIndex(key, ".")+1:], + Subject: meshconditions.Subject{Scope: meshconditionsclient.ScopeSeat, ID: packageseats.Self}, Severity: meshconditionsclient.Warning, Summary: words, Headline: words, Explanation: words, Resolved: "cleared once it no longer holds", - Source: kind, Observer: packageseats.Self, At: time.Now().UTC()} - if _, err := stdio.State(health.FindingsState).Put(key, f); err != nil { + Source: kind, Observer: packageseats.Self, At: time.Now().UTC().Format(time.RFC3339Nano)} + if _, err := stdio.State(meshconditions.StateFindings).Put(key, f); err != nil { fmt.Fprintf(os.Stderr, "the finding %s could not be written: %v\n", key, err) } } diff --git a/modules/gitea/go.mod b/modules/gitea/go.mod index 831e581b7..33382a81b 100644 --- a/modules/gitea/go.mod +++ b/modules/gitea/go.mod @@ -5,6 +5,8 @@ go 1.26.0 require ( git.novox.be/novox/mesh-delivery/sdk v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient v0.0.0-00010101000000-000000000000 + git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient v0.0.0-00010101000000-000000000000 + git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-delivery/contracts/go/seats/gopackageregistry v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-delivery/contracts/go/seats/npmpackageregistry v0.0.0-00010101000000-000000000000 diff --git a/modules/mesh-config/cmd/mesh-config/findings.go b/modules/mesh-config/cmd/mesh-config/findings.go index fcccb2145..44966c775 100644 --- a/modules/mesh-config/cmd/mesh-config/findings.go +++ b/modules/mesh-config/cmd/mesh-config/findings.go @@ -10,11 +10,12 @@ import ( "strings" "time" - "git.novox.be/novox/mesh-sdk/go/health" + "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient" + meshconditions "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions" ) -// FindingsState is the state, health.FindingsState. -const FindingsState = health.FindingsState +// FindingsState is the state, meshconditions.StateFindings. +const FindingsState = meshconditions.StateFindings // The kinds of finding mesh-config writes. const ( @@ -36,23 +37,23 @@ func findingKey(kind, module, node, ref string) string { if node != "" { id += "." + node } - return health.Key(health.ScopeModule, id, kind+"-"+ref) + return meshconditionsclient.Key(meshconditionsclient.ScopeModule, id, kind+"-"+ref) } -func finding(kind, module, node, ref, summary, headline, explanation, needs, resolved, said string, at time.Time) health.Finding { +func finding(kind, module, node, ref, summary, headline, explanation, needs, resolved, said string, at time.Time) meshconditions.FindingsByKeyValue { id := module if node != "" { id += "." + node } - return health.Finding{V: health.FindingVersion, Key: findingKey(kind, module, node, ref), Kind: kind, Ref: kind + "-" + ref, - Subject: health.Subject{Scope: health.ScopeModule, ID: id, Machine: node}, - Severity: health.Warning, Resolver: health.ResolverOperator, Summary: summary, Headline: headline, + return meshconditions.FindingsByKeyValue{V: meshconditionsclient.FindingVersion, Key: findingKey(kind, module, node, ref), Kind: kind, Ref: kind + "-" + ref, + Subject: meshconditions.Subject{Scope: meshconditionsclient.ScopeModule, ID: id, Machine: node}, + Severity: meshconditionsclient.Warning, Resolver: meshconditionsclient.ResolverOperator, Summary: summary, Headline: headline, Explanation: explanation, Needs: needs, Resolved: resolved, - Evidence: []health.Evidence{{At: at.UTC(), Said: said}}, Source: "config", Observer: Module, At: at.UTC()} + Evidence: []meshconditions.Evidence{{At: at.UTC().Format(time.RFC3339Nano), Said: said}}, Source: "config", Observer: Module, At: at.UTC().Format(time.RFC3339Nano)} } // renameRefused is the finding of a move mesh-config refused. -func renameRefused(module, to, from, why string, at time.Time) health.Finding { +func renameRefused(module, to, from, why string, at time.Time) meshconditions.FindingsByKeyValue { return finding(FindingRenameRefused, module, "", to, fmt.Sprintf("the rename of %s's config value %s to %s is refused: %s", module, from, to, why), fmt.Sprintf("%s's value %s is not moved to %s", module, from, to), @@ -62,7 +63,7 @@ func renameRefused(module, to, from, why string, at time.Time) health.Finding { } // windowHeld is the finding of a rename window held open past HeldFinding by a node. -func windowHeld(r Rename, node string, at time.Time) health.Finding { +func windowHeld(r Rename, node string, at time.Time) meshconditions.FindingsByKeyValue { return finding(FindingWindowHeld, r.Module, node, r.To, fmt.Sprintf("%s on %s has held the old config name %s open for %d days", r.Module, node, r.From, int(HeldFinding.Hours()/24)), fmt.Sprintf("%s on %s still runs the old config name", r.Module, node), @@ -73,13 +74,13 @@ func windowHeld(r Rename, node string, at time.Time) health.Finding { } // setFinding writes a finding when it differs from the one kept. -func (c *Config) setFinding(f health.Finding) { - if _, err := health.EncodeFinding(f); err != nil { +func (c *Config) setFinding(f meshconditions.FindingsByKeyValue) { + if err := meshconditionsclient.CheckFinding(f); err != nil { c.logf("[mesh-config] a finding is not valid: %v", err) return } if e, err := c.Store.Get(FindingsState, f.Key); err == nil && e != nil { - if old, derr := health.DecodeFinding(e.Value); derr == nil && old.Summary == f.Summary { + if old, derr := meshconditions.DecodeFindingsByKeyValue(e.Value); derr == nil && old.Summary == f.Summary { return // what it says has not changed } } @@ -100,7 +101,7 @@ func (c *Config) clearFinding(kind, module, ref string, keep ...string) { if err != nil || e == nil { continue } - f, err := health.DecodeFinding(e.Value) + f, err := meshconditions.DecodeFindingsByKeyValue(e.Value) if err != nil || f.Ref != want || !(f.Subject.ID == module || strings.HasPrefix(f.Subject.ID, module+".")) || (f.Subject.Machine != "" && slices.Contains(keep, f.Subject.Machine)) { continue @@ -112,7 +113,7 @@ func (c *Config) clearFinding(kind, module, ref string, keep ...string) { } // retirementHeld is the finding of a retirement that waits seven days for nodes that still run a build reading the value. -func retirementHeld(e Retiring, at time.Time) health.Finding { +func retirementHeld(e Retiring, at time.Time) meshconditions.FindingsByKeyValue { node := "" if len(e.Nodes) > 0 { node = e.Nodes[0] @@ -127,7 +128,7 @@ func retirementHeld(e Retiring, at time.Time) health.Finding { } // retireUnanswered is the finding of a retirement asked twice and not answered. -func retireUnanswered(e Retiring, at time.Time) health.Finding { +func retireUnanswered(e Retiring, at time.Time) meshconditions.FindingsByKeyValue { return finding(FindingRetireUnanswered, e.Module, "", e.Key, fmt.Sprintf("the operator did not answer the ask to remove %s's %s, asked twice", e.Module, e.Key), fmt.Sprintf("%s's %s waits for an answer", e.Module, e.Key), diff --git a/modules/mesh-config/cmd/mesh-config/renames_test.go b/modules/mesh-config/cmd/mesh-config/renames_test.go index 07e7fc351..e4b5d3a27 100644 --- a/modules/mesh-config/cmd/mesh-config/renames_test.go +++ b/modules/mesh-config/cmd/mesh-config/renames_test.go @@ -9,9 +9,9 @@ import ( "testing" "time" + meshconditions "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions" occ "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/clients/operatorchannelclient" oc "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel" - "git.novox.be/novox/mesh-sdk/go/health" ) // fakeDelivery is the delivery parts as mesh-config asks them: each node's have, whether a node-engine states what it @@ -85,12 +85,12 @@ func aRenamingMesh(t *testing.T) (*Config, *memStore, *fakeDelivery, *time.Time) return c, m, d, &clock } -func findingsOf(t *testing.T, m *memStore, kind string) []health.Finding { +func findingsOf(t *testing.T, m *memStore, kind string) []meshconditions.FindingsByKeyValue { t.Helper() - var out []health.Finding + var out []meshconditions.FindingsByKeyValue for _, k := range m.keysOf(FindingsState) { e, _ := m.Get(FindingsState, k) - f, err := health.DecodeFinding(e.Value) + f, err := meshconditions.DecodeFindingsByKeyValue(e.Value) if err != nil { t.Fatalf("finding %s: %v", k, err) } diff --git a/modules/mesh-config/cmd/mesh-config/whole_integration_test.go b/modules/mesh-config/cmd/mesh-config/whole_integration_test.go index 7c81fdd34..65bc05851 100644 --- a/modules/mesh-config/cmd/mesh-config/whole_integration_test.go +++ b/modules/mesh-config/cmd/mesh-config/whole_integration_test.go @@ -32,10 +32,10 @@ import ( "github.com/nats-io/nats.go/jetstream" "git.novox.be/novox/mesh-contracts/go/seats/meshconfig" + meshconditions "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions" oc "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel" "git.novox.be/novox/mesh-sdk/go/catalogue" "git.novox.be/novox/mesh-sdk/go/delivery" - "git.novox.be/novox/mesh-sdk/go/health" "git.novox.be/novox/mesh-sdk/go/process" "git.novox.be/novox/mesh-sdk/go/testbus" "git.novox.be/novox/mesh-sdk/go/views" @@ -718,7 +718,7 @@ func TestConfigWholeRenamesAndRetiresAgainstTheBus(t *testing.T) { keys, _ := (func() ([]string, error) { kv, _ := p.kv(FindingsState); return kv.Keys(p.ctx) })() for _, k := range keys { raw, _ := p.get(FindingsState, k) - if f, err := health.DecodeFinding(raw); err == nil && f.Kind == FindingRenameRefused && strings.Contains(f.Summary, "dock") { + if f, err := meshconditions.DecodeFindingsByKeyValue(raw); err == nil && f.Kind == FindingRenameRefused && strings.Contains(f.Summary, "dock") { return true } } diff --git a/modules/mesh-config/go.mod b/modules/mesh-config/go.mod index 8693a74c8..f27f531c8 100644 --- a/modules/mesh-config/go.mod +++ b/modules/mesh-config/go.mod @@ -3,6 +3,7 @@ module mesh-config go 1.26.0 require ( + git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-contracts/operator-and-conversation/go/clients/operatorchannelclient v0.0.0-00010101000000-000000000000