diff --git a/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/integration_test.go b/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/integration_test.go index fa805b4b..283a83df 100644 --- a/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/integration_test.go +++ b/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/integration_test.go @@ -42,7 +42,6 @@ import ( "git.novox.be/novox/mesh-sdk/go/announce" "git.novox.be/novox/mesh-sdk/go/buscompose" "git.novox.be/novox/mesh-sdk/go/catalogue" - "git.novox.be/novox/mesh-sdk/go/health" "git.novox.be/novox/mesh-sdk/go/process" "mesh-delivery-assigner/internal/judge" @@ -729,7 +728,7 @@ func (b *bed) conditionsSaid(t *testing.T) map[string]oc.Condition { c := out[e.Key()] c.Key, c.State = e.Key(), occ.StateCleared if e.Operation() == jetstream.KeyValuePut { - f, err := health.DecodeFinding(e.Value()) + f, err := meshconditionsclient.DecodeFinding(e.Value()) if err != nil { t.Fatal(err) } diff --git a/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/main.go b/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/main.go index 5f4f678c..67257b1e 100644 --- a/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/main.go +++ b/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/main.go @@ -23,12 +23,12 @@ import ( "github.com/nats-io/nats.go" "github.com/nats-io/nats.go/jetstream" + mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient" 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" mma "git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner" "git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient" "git.novox.be/novox/mesh-sdk/go/announce" - "git.novox.be/novox/mesh-sdk/go/health" "git.novox.be/novox/mesh-sdk/go/process" "git.novox.be/novox/mesh-delivery/sdk/enginereads" @@ -106,7 +106,7 @@ var keptStates = []announce.State{ {Name: "differences", Readable: true}, {Name: "puts", Readable: true}, {Name: "wants", Readable: true}, - {Name: health.FindingsState, Readable: true}, + {Name: mcc.FindingsState, Readable: true}, {Name: buckets.PoliciesState, Readable: true}, {Name: mma.StateSeatHolders, Readable: true}, {Name: views.MarksState, Readable: true}, // what its views family said each state up to (views.go) diff --git a/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/seat_tools_test.go b/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/seat_tools_test.go index 5b872f5b..ed4dac8a 100644 --- a/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/seat_tools_test.go +++ b/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/seat_tools_test.go @@ -18,12 +18,12 @@ import ( "testing" "time" + mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient" mmac "git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient" mma "git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner" "git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient" stdio "git.novox.be/novox/mesh-sdk/go" "git.novox.be/novox/mesh-sdk/go/catalogue" - "git.novox.be/novox/mesh-sdk/go/health" "github.com/nats-io/nats.go/jetstream" "mesh-delivery-assigner/internal/assign" @@ -458,7 +458,7 @@ func wantsVerbs(t *testing.T) { if n := watches[manifestsState+" by key"]; n == 0 || n > len(st[manifestsState].values) { t.Errorf("the manifests were read by key %d times, want each once", n) } - for _, state := range []string{modulesState, haveState, health.FindingsState} { + for _, state := range []string{modulesState, haveState, mcc.FindingsState} { if watches[state] != 1 { t.Errorf("%s was watched %d times, want once", state, watches[state]) } diff --git a/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/views.go b/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/views.go index 8102e70d..02b4dc2f 100644 --- a/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/views.go +++ b/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/views.go @@ -11,10 +11,10 @@ import ( "github.com/nats-io/nats.go/jetstream" + mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient" "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient" mma "git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner" stdio "git.novox.be/novox/mesh-sdk/go" - "git.novox.be/novox/mesh-sdk/go/health" "git.novox.be/novox/mesh-sdk/go/process" "git.novox.be/novox/mesh-sdk/go/views" @@ -46,7 +46,7 @@ var readTools = []viewedTool{ {"assigner_read_placement", mma.StatePlacement, "where each module is placed, by module."}, {"assigner_read_seat_holders", mma.StateSeatHolders, "who holds which seat on which node."}, {"assigner_read_wants", "wants", "what each node should run: want..."}, - {"assigner_read_findings", health.FindingsState, "the assigner's findings, which the condition keeper raises and clears."}, + {"assigner_read_findings", mcc.FindingsState, "the assigner's findings, which the condition keeper raises and clears."}, {"assigner_read_asks", "asks", "the asks the assigner put to a person, and their answers."}, {"assigner_read_differences", "differences", "every difference between a want and what a node runs."}, } @@ -56,7 +56,7 @@ var viewedStates = map[string]string{ mma.StatePlacement: plc.PlacementBucket, mma.StateSeatHolders: plc.SeatHoldersBucket, "wants": buckets.Wants, - health.FindingsState: assign.FindingsBucket, + mcc.FindingsState: assign.FindingsBucket, "asks": buckets.Asks, "differences": buckets.Differences, } @@ -91,7 +91,7 @@ func startViews(ctx context.Context, js jetstream.JetStream, nc process.Subscrib } process.AwaitBucket(ctx, js, nc, marksBucket, "no change is said on the views family, so every reader waits on its first view", logf).Ready(func(mk jetstream.KeyValue) { em := viewsEmitter(js, account, mk, findings, tooLarge, logf) - for _, state := range []string{"asks", "differences", health.FindingsState, mma.StatePlacement, mma.StateSeatHolders, "wants"} { + for _, state := range []string{"asks", "differences", mcc.FindingsState, mma.StatePlacement, mma.StateSeatHolders, "wants"} { state := state start := func(kv jetstream.KeyValue) { if err := em.Start(ctx, state, kv, errs); err != nil { diff --git a/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/wants_tools.go b/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/wants_tools.go index b18447bf..5b9874e5 100644 --- a/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/wants_tools.go +++ b/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/wants_tools.go @@ -15,10 +15,10 @@ import ( "strconv" "time" + mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient" "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient" stdio "git.novox.be/novox/mesh-sdk/go" "git.novox.be/novox/mesh-sdk/go/catalogue" - "git.novox.be/novox/mesh-sdk/go/health" "mesh-delivery-assigner/internal/assign" ) @@ -171,7 +171,7 @@ func (s *wantsTools) doUpgrade(args map[string]any, by string) (any, error) { out["published"] = published(values) } // The assigner's findings, its said conditions as the condition keeper reads them (§15). - if found, err := s.values(health.FindingsState); err != nil { + if found, err := s.values(mcc.FindingsState); err != nil { out["findings-unread"] = err.Error() } else { keys := []string{} diff --git a/modules/mesh-delivery-assigner/go.mod b/modules/mesh-delivery-assigner/go.mod index b0d6699a..a54f34ef 100644 --- a/modules/mesh-delivery-assigner/go.mod +++ b/modules/mesh-delivery-assigner/go.mod @@ -44,6 +44,7 @@ replace git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds => replace git.novox.be/novox/mesh-delivery/modules/mesh-grants/grantsstate => ../mesh-grants/grantsstate require git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient v0.0.0-00010101000000-000000000000 +require git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions v0.0.0-00010101000000-000000000000 require git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshwatchdogs v0.0.0-00010101000000-000000000000 require git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshwatchdogsclient v0.0.0-00010101000000-000000000000 require git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient v0.0.0-00010101000000-000000000000 diff --git a/modules/mesh-delivery-assigner/internal/assign/asks_test.go b/modules/mesh-delivery-assigner/internal/assign/asks_test.go index 865e4b85..bfe79022 100644 --- a/modules/mesh-delivery-assigner/internal/assign/asks_test.go +++ b/modules/mesh-delivery-assigner/internal/assign/asks_test.go @@ -14,9 +14,10 @@ import ( "testing" "time" + mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient" + mcseat "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" ) // 1297/B9 (the assigner's half): the ask about a held fingerprint is a valid ask of the router and of mesh-sdk's layout at @@ -149,9 +150,9 @@ func saidConditionsAreFindings(t *testing.T) { {SeatWaitsCondition([]string{"placement"}), SeatWaitsCondition(nil), "module.mesh-delivery-assigner.seat-states"}, {BackupCondition("ace", "mail", fNew, "disk full", true), BackupCondition("ace", "mail", fNew, "", false), "module.ace.mail." + strings.TrimPrefix(fNew, meshcatalogclient.SourcePrefix2) + ".backup"}, } { - puts, deletes, said := map[string]health.Finding{}, []string{}, 0 + puts, deletes, said := map[string]mcseat.FindingsByKeyValue{}, []string{}, 0 f := Findings{Put: func(k string, v []byte) error { - got, err := health.DecodeFinding(v) + got, err := mcc.DecodeFinding(v) puts[k] = got return err }, Delete: func(k string) error { deletes = append(deletes, k); return nil }, Now: func() time.Time { return at }} @@ -160,7 +161,7 @@ func saidConditionsAreFindings(t *testing.T) { t.Fatalf("%s: %v", c.key, err) } got, ok := puts[c.key] - if !ok || got.Severity != health.Severity(c.raised.Severity) || got.Headline != c.raised.Headline || got.Observer != mmac.Module || + if !ok || got.Severity != c.raised.Severity || got.Headline != c.raised.Headline || got.Observer != mmac.Module || got.Subject.Machine != c.raised.Subject.Machine || said != 0 { t.Fatalf("%s: finding %+v (written %v), said %d", c.key, got, puts, said) } diff --git a/modules/mesh-delivery-assigner/internal/assign/findings.go b/modules/mesh-delivery-assigner/internal/assign/findings.go index 65b2ec11..10b3c16c 100644 --- a/modules/mesh-delivery-assigner/internal/assign/findings.go +++ b/modules/mesh-delivery-assigner/internal/assign/findings.go @@ -7,9 +7,10 @@ import ( "strings" "time" + mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient" + mcseat "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" ) // The assigner's said conditions become findings (novox/hq ADR 0564 §2, issue 1952 WM6, note 16): every condition it says @@ -20,7 +21,7 @@ import ( // assigner no longer says it straight (never both). // FindingsBucket is the assigner's findings. -var FindingsBucket = health.FindingsBucket(mmac.Module) +var FindingsBucket = mcc.FindingsBucket(mmac.Module) // FindingOf is a said condition as a finding: its key `..`, from the condition's own key // `mesh-delivery-assigner..` (the subject's id when the key names none), its words unchanged. raised is false for @@ -36,9 +37,9 @@ func FindingOf(c oc.Condition, at time.Time) (key string, value []byte, raised b } scope := c.Subject.Scope if scope == "" { - scope = health.ScopeModule + scope = mcc.ScopeModule } - key = health.FindingKey(scope, id, kind) + key = mcc.Key(scope, id, kind) if c.State == occ.StateCleared { return key, nil, false, nil } @@ -49,14 +50,14 @@ func FindingOf(c oc.Condition, at time.Time) (key string, value []byte, raised b if summary == "" { summary = c.Headline } - var actions []health.Action + var actions []mcseat.Action for _, a := range c.Actions { - actions = append(actions, health.Action{Label: a.Label, Verb: a.Verb, Machine: a.Machine, Arguments: a.Arguments, Level: string(a.Level)}) + actions = append(actions, mcseat.Action{Label: a.Label, Verb: a.Verb, Machine: a.Machine, Arguments: a.Arguments, Level: string(a.Level)}) } - value, err = health.EncodeFinding(health.Finding{Key: key, Kind: kind, Subject: health.Subject{Scope: scope, ID: id, Machine: c.Subject.Machine}, - Severity: health.Severity(c.Severity), Summary: summary, Headline: c.Headline, Explanation: c.Explanation, Resolved: c.Resolved, - Needs: c.Needs, Actions: actions, Evidence: []health.Evidence{{At: at.UTC(), Said: summary}}, Source: "assigner." + kind, - Observer: mmac.Module, At: at.UTC()}) + f := mcc.Observation{Scope: scope, ID: id, Kind: kind, Machine: c.Subject.Machine, Severity: string(c.Severity), Summary: summary, + Headline: c.Headline, Explanation: c.Explanation, Resolved: c.Resolved, Needs: c.Needs, Actions: actions, + Source: "assigner." + kind}.Finding(mmac.Module, "", at) + value, err = mcc.EncodeFinding(f) return key, value, true, err } diff --git a/modules/mesh-delivery-assigner/internal/assign/policy.go b/modules/mesh-delivery-assigner/internal/assign/policy.go index 4da019b4..348eff29 100644 --- a/modules/mesh-delivery-assigner/internal/assign/policy.go +++ b/modules/mesh-delivery-assigner/internal/assign/policy.go @@ -9,10 +9,10 @@ import ( "strings" "time" + mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient" occ "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/clients/operatorchannelclient" "git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient" "git.novox.be/novox/mesh-sdk/go/catalogue" - "git.novox.be/novox/mesh-sdk/go/health" ) // A person's upgrade policy is the assigner's (novox/hq ADR 0565 §7, §8, issue 1953 D4, D5): kept in its state `policies`, one @@ -61,19 +61,22 @@ const KindProvisionFailed = "provision-failed" // ProvisionFailedKey is a failed provision's finding's key, `provider...[.].provision-failed`. func ProvisionFailedKey(key string) string { - return health.FindingKey(health.ScopeProvider, key, KindProvisionFailed) + return mcc.Key(mcc.ScopeProvider, key, KindProvisionFailed) } // ProvisionFailedFinding is the finding of a failed provision, naming its consumer, its provider and why. func ProvisionFailedFinding(key string, p meshprovisionerclient.Provision, at time.Time) ([]byte, error) { summary := fmt.Sprintf("%s for %s on %s failed at %s on %s: %s, so %s is not moved there until it is provided", p.Provision, p.Consumer.Module, p.Consumer.Node, p.Provider.Module, p.Provider.Node, p.Why, p.Consumer.Module) - return health.EncodeFinding(health.Finding{Key: ProvisionFailedKey(key), Kind: KindProvisionFailed, - Subject: health.Subject{Scope: health.ScopeProvider, ID: key, Machine: p.Consumer.Node, Also: also(p.Provider.Node, p.Consumer.Node)}, - Severity: health.Warning, Summary: summary, Headline: clipHeadline(p.Consumer.Module + " waits for a provision that failed"), + return encode(mcc.Observation{Scope: mcc.ScopeProvider, ID: key, Kind: KindProvisionFailed, Machine: p.Consumer.Node, Also: also(p.Provider.Node, p.Consumer.Node), + Summary: summary, Said: p.Why, Headline: clipHeadline(p.Consumer.Module + " waits for a provision that failed"), Explanation: occ.NothingToDo + " " + summary + ". It clears once the provider provides it.", - Resolved: p.Provision + " for " + p.Consumer.Module + " is provided", Evidence: []health.Evidence{{At: at.UTC(), Said: p.Why}}, - Source: "assigner." + KindProvisionFailed, Observer: mmac.Module, At: at.UTC()}) + Resolved: p.Provision + " for " + p.Consumer.Module + " is provided", Source: "assigner." + KindProvisionFailed}, at) +} + +// encode is the observation as the assigner's finding at at, in the seat's layout. +func encode(o mcc.Observation, at time.Time) ([]byte, error) { + return mcc.EncodeFinding(o.Finding(mmac.Module, "", at)) } func also(provider, consumer string) []string { @@ -88,7 +91,7 @@ const KindProvisionMissing = "provision-missing" // ProvisionMissingKey is its key, `provider....provision-missing`. func ProvisionMissingKey(key string) string { - return health.FindingKey(health.ScopeProvider, key, KindProvisionMissing) + return mcc.Key(mcc.ScopeProvider, key, KindProvisionMissing) } // ProvisionMissingFinding is the finding of a required provision with no key past bound (key `..`). @@ -100,12 +103,10 @@ func ProvisionMissingFinding(key string, bound time.Duration, at time.Time) ([]b node, module, provision := parts[0], parts[1], parts[2] summary := fmt.Sprintf("%s on %s requires %s and mesh-provisioner has composed no key for it in %s, so %s is not moved there: "+ "no provider of it may be placed", module, node, provision, bound, module) - return health.EncodeFinding(health.Finding{Key: ProvisionMissingKey(key), Kind: KindProvisionMissing, - Subject: health.Subject{Scope: health.ScopeProvider, ID: key, Machine: node}, - Severity: health.Warning, Summary: summary, Headline: clipHeadline(module + " on " + node + " lacks " + provision), + return encode(mcc.Observation{Scope: mcc.ScopeProvider, ID: key, Kind: KindProvisionMissing, Machine: node, + Summary: summary, Headline: clipHeadline(module + " on " + node + " lacks " + provision), Explanation: occ.NothingToDo + " " + summary + ". It clears once the provision has its key.", - Resolved: provision + " for " + module + " on " + node + " has its key", Evidence: []health.Evidence{{At: at.UTC(), Said: summary}}, - Source: "assigner." + KindProvisionMissing, Observer: mmac.Module, At: at.UTC()}) + Resolved: provision + " for " + module + " on " + node + " has its key", Source: "assigner." + KindProvisionMissing}, at) } // KindUnplaced is, from the lease write, a node that runs but no placement names (ADR 0571 §6). @@ -113,19 +114,17 @@ const KindUnplaced = "unplaced" // UnplacedKey is its finding's key, `machine..unplaced`. func UnplacedKey(node string) string { - return health.FindingKey(health.ScopeMachine, node, KindUnplaced) + return mcc.Key(mcc.ScopeMachine, node, KindUnplaced) } // UnplacedFinding is the finding of a node no placement names since the lease write. func UnplacedFinding(node string, at time.Time) ([]byte, error) { summary := fmt.Sprintf("%s runs, but no placement names it: since the controller handed its lease away nothing composes it, "+ "so the assigner writes it no want", node) - return health.EncodeFinding(health.Finding{Key: UnplacedKey(node), Kind: KindUnplaced, - Subject: health.Subject{Scope: health.ScopeMachine, ID: node, Machine: node}, Severity: health.Warning, Summary: summary, + return encode(mcc.Observation{Scope: mcc.ScopeMachine, ID: node, Kind: KindUnplaced, Machine: node, Summary: summary, Headline: clipHeadline(node + " has no placement"), Needs: "place it with mesh-placement.propose.", Explanation: occ.NeedsYou + "place it with mesh-placement.propose. " + summary + ".", - Resolved: node + " is placed", Evidence: []health.Evidence{{At: at.UTC(), Said: summary}}, - Source: "assigner." + KindUnplaced, Observer: mmac.Module, At: at.UTC()}) + Resolved: node + " is placed", Source: "assigner." + KindUnplaced}, at) } func clipHeadline(s string) string {