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 74678cc6..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 @@ -37,13 +37,12 @@ import ( oc "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel" 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/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" - "git.novox.be/novox/mesh-sdk/go/provisions" "mesh-delivery-assigner/internal/judge" "git.novox.be/novox/mesh-contracts/go/seats/nodeengine" @@ -526,15 +525,15 @@ func TestWantsAreWrittenAndNoDifferenceIs(t *testing.T) { appDigest := b.manifest(t, "app", `{"module":"app","version":"1","requires":["database"]}`) toolDigest := b.manifest(t, "tool", `{"module":"tool","version":"1"}`) asked := func(state, why string) { - raw, err := provisions.Encode(provisions.Provision{V: provisions.Version, Provision: "database", Consumer: provisions.End{Module: "app", Node: "ace"}, - Provider: provisions.End{Module: "db", Node: "ace"}, State: state, Why: why, At: time.Now()}) + raw, err := meshprovisionerclient.Encode(meshprovisionerclient.Provision{V: meshprovisionerclient.Version, Provision: "database", Consumer: meshprovisionerclient.End{Module: "app", Node: "ace"}, + Provider: meshprovisionerclient.End{Module: "db", Node: "ace"}, State: state, Why: why, At: time.Now()}) if err != nil { t.Fatal(err) } - b.putJSON(t, provisions.ProvisionsBucket, "ace.app.database", raw) + b.putJSON(t, meshprovisionerclient.ProvisionsBucket, "ace.app.database", raw) } // The provisioner keys it from the manifests, as soon as they are known and whether the provider is placed yet or not. - asked(provisions.Asked, "the provider's build is not done") + asked(meshprovisionerclient.Asked, "the provider's build is not done") fpOf := func(c byte) string { return meshcatalogclient.SourcePrefix2 + strings.Repeat(string(c), 64) } toolOld := fpOf('1') for module, row := range map[string]struct { @@ -565,7 +564,7 @@ func TestWantsAreWrittenAndNoDifferenceIs(t *testing.T) { if e, err := b.buckets[buckets.Wants].Get(b.ctx, "want.ace.app"); err == nil { t.Errorf("app was wanted while its provision was asked: %s", e.Value()) } - asked(provisions.Provided, "") + asked(meshprovisionerclient.Provided, "") if w := b.wantNow(t, "ace", "app", "the consumer's want once its provision is provided", func(w mwc.Want) bool { return w.Fp == fpOf('3') }); w.Fp != fpOf('3') { t.Errorf("app's want = %+v", w) } @@ -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 c1f7d5f3..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,13 +23,13 @@ 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-sdk/go/provisions" "git.novox.be/novox/mesh-delivery/sdk/enginereads" "git.novox.be/novox/mesh-sdk/go/views" @@ -64,7 +64,7 @@ var readBuckets = []string{ buckets.Builds, buckets.Presence, buckets.Have, - provisions.ProvisionsBucket, + meshprovisionerclient.ProvisionsBucket, buckets.Source, buckets.Merges, } @@ -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) @@ -140,7 +140,7 @@ func open(ctx context.Context, js process.BucketOpener, logf func(string, ...any logf("the bucket %s cannot be opened (%v): it is bound once the bus says it was made", name, err) continue } - if name == provisions.ProvisionsBucket && err != nil { + if name == meshprovisionerclient.ProvisionsBucket && err != nil { // The seat mesh-provisioner's state, with its own delivery (ADR 0570 §4): bound once the bus says it was made; // until then no want waits for a provision, as before. logf("the bucket %s cannot be opened (%v): it is bound once the bus says it was made", name, err) @@ -187,7 +187,7 @@ func open(ctx context.Context, js process.BucketOpener, logf func(string, ...any // states and those new with a delivery of their own, bound once made, and the two that choose the grants' source. func startsWithout(name string) bool { switch name { - case plc.SeatHoldersBucket, provisions.ProvisionsBucket, assign.PoliciesBucket, assign.FindingsBucket, + case plc.SeatHoldersBucket, meshprovisionerclient.ProvisionsBucket, assign.PoliciesBucket, assign.FindingsBucket, buckets.Puts, buckets.Source, buckets.Merges, engineReadsBucket: return true } @@ -282,7 +282,7 @@ var watched = []string{ buckets.Differences, buckets.Wants, assign.PoliciesBucket, - provisions.ProvisionsBucket, + meshprovisionerclient.ProvisionsBucket, plc.SeatHoldersBucket, buckets.Source, buckets.Merges, @@ -428,7 +428,7 @@ func follow(ctx context.Context, js jetstream.JetStream, nc process.Subscriber, } } // And the two that choose where grants are read from, with the same delivery as the grants part that writes one. - for _, name := range []string{buckets.Grants, assign.PoliciesBucket, provisions.ProvisionsBucket, plc.SeatHoldersBucket} { + for _, name := range []string{buckets.Grants, assign.PoliciesBucket, meshprovisionerclient.ProvisionsBucket, plc.SeatHoldersBucket} { if kvs[name] == nil && js != nil { name := name process.AwaitBucket(ctx, js, nc, name, "until then the bucket is not read", diff --git a/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/pass.go b/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/pass.go index 00840a56..e3e0ece1 100644 --- a/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/pass.go +++ b/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/pass.go @@ -19,8 +19,8 @@ import ( "time" oc "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel" + "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/provisions" "git.novox.be/novox/mesh-delivery/sdk/enginereads" @@ -940,37 +940,37 @@ func chosenOf(chosen map[string]catalogue.PersonPolicy, module string) *catalogu // mesh-provisioner's state; nil while the state is not read (the seat not delivered yet), so no want waits on it. A failed // provision is also said as the assigner's finding `provider..provision-failed` (a waiting one is the watchman's // needs-operator), deleted once it is no longer failed. -func (p *passer) provisionsOf() func(module string) func(node string) map[string]provisions.Provision { - if p.kvs[provisions.ProvisionsBucket] == nil { - return func(string) func(string) map[string]provisions.Provision { return nil } +func (p *passer) provisionsOf() func(module string) func(node string) map[string]meshprovisionerclient.Provision { + if p.kvs[meshprovisionerclient.ProvisionsBucket] == nil { + return func(string) func(string) map[string]meshprovisionerclient.Provision { return nil } } - by := map[string]map[string]map[string]provisions.Provision{} // module, node, key - failed := map[string]provisions.Provision{} - for key, raw := range p.w.read(provisions.ProvisionsBucket) { - pr, err := provisions.Decode(raw) + by := map[string]map[string]map[string]meshprovisionerclient.Provision{} // module, node, key + failed := map[string]meshprovisionerclient.Provision{} + for key, raw := range p.w.read(meshprovisionerclient.ProvisionsBucket) { + pr, err := meshprovisionerclient.Decode(raw) if err != nil { continue } node, module := pr.Consumer.Node, pr.Consumer.Module if by[module] == nil { - by[module] = map[string]map[string]provisions.Provision{} + by[module] = map[string]map[string]meshprovisionerclient.Provision{} } if by[module][node] == nil { - by[module][node] = map[string]provisions.Provision{} + by[module][node] = map[string]meshprovisionerclient.Provision{} } by[module][node][key] = pr - if pr.State == provisions.Failed { + if pr.State == meshprovisionerclient.Failed { failed[key] = pr } } p.provisionFindings(failed) - return func(module string) func(string) map[string]provisions.Provision { - return func(node string) map[string]provisions.Provision { return by[module][node] } + return func(module string) func(string) map[string]meshprovisionerclient.Provision { + return func(node string) map[string]meshprovisionerclient.Provision { return by[module][node] } } } // provisionFindings writes the finding of each failed provision and deletes the ones no longer failed. -func (p *passer) provisionFindings(failed map[string]provisions.Provision) { +func (p *passer) provisionFindings(failed map[string]meshprovisionerclient.Provision) { if p.findings.Put == nil { return } 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 355f372a..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" - "git.novox.be/novox/mesh-sdk/go/provisions" "github.com/nats-io/nats.go/jetstream" "mesh-delivery-assigner/internal/assign" @@ -325,23 +325,23 @@ func TestTheSeatsVerbs(t *testing.T) { }) t.Run("1954/D1: a failed provision is the assigner's finding until it is provided", func(t *testing.T) { findings := map[string][]byte{} - p := &passer{w: newWorld(), logf: func(string, ...any) {}, kvs: kvSet{provisions.ProvisionsBucket: nil}, findings: assign.Findings{ + p := &passer{w: newWorld(), logf: func(string, ...any) {}, kvs: kvSet{meshprovisionerclient.ProvisionsBucket: nil}, findings: assign.Findings{ Put: func(k string, v []byte) error { findings[k] = v; return nil }, Delete: func(k string) error { delete(findings, k); return nil }}} - failed, _ := provisions.Encode(provisions.Provision{Provision: "db", Consumer: provisions.End{Module: "photos", Node: "ace"}, - Provider: provisions.End{Module: "postgres", Node: "novox"}, State: provisions.Failed, Why: "the role exists already"}) - p.w.putEntry(provisions.ProvisionsBucket, "ace.photos.db", failed, 1, time.Now()) - p.kvs[provisions.ProvisionsBucket] = &memKV{} + failed, _ := meshprovisionerclient.Encode(meshprovisionerclient.Provision{Provision: "db", Consumer: meshprovisionerclient.End{Module: "photos", Node: "ace"}, + Provider: meshprovisionerclient.End{Module: "postgres", Node: "novox"}, State: meshprovisionerclient.Failed, Why: "the role exists already"}) + p.w.putEntry(meshprovisionerclient.ProvisionsBucket, "ace.photos.db", failed, 1, time.Now()) + p.kvs[meshprovisionerclient.ProvisionsBucket] = &memKV{} of := p.provisionsOf() - if got := of("photos")("ace"); got["ace.photos.db"].State != provisions.Failed { + if got := of("photos")("ace"); got["ace.photos.db"].State != meshprovisionerclient.Failed { t.Fatalf("provisions = %+v", got) } if _, ok := findings[assign.ProvisionFailedKey("ace.photos.db")]; !ok || len(findings) != 1 { t.Fatalf("findings = %v", findings) } - provided, _ := provisions.Encode(provisions.Provision{Provision: "db", Consumer: provisions.End{Module: "photos", Node: "ace"}, - Provider: provisions.End{Module: "postgres", Node: "novox"}, State: provisions.Provided}) - p.w.putEntry(provisions.ProvisionsBucket, "ace.photos.db", provided, 2, time.Now()) + provided, _ := meshprovisionerclient.Encode(meshprovisionerclient.Provision{Provision: "db", Consumer: meshprovisionerclient.End{Module: "photos", Node: "ace"}, + Provider: meshprovisionerclient.End{Module: "postgres", Node: "novox"}, State: meshprovisionerclient.Provided}) + p.w.putEntry(meshprovisionerclient.ProvisionsBucket, "ace.photos.db", provided, 2, time.Now()) p.provisionsOf() if len(findings) != 0 { t.Errorf("findings after provided = %v", findings) @@ -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 15478b61..a54f34ef 100644 --- a/modules/mesh-delivery-assigner/go.mod +++ b/modules/mesh-delivery-assigner/go.mod @@ -3,6 +3,7 @@ module mesh-delivery-assigner go 1.26.0 require ( + git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient v0.0.0 git.novox.be/novox/mesh-contracts/placement/go/seats/meshwants v0.0.0-00010101000000-000000000000 @@ -43,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 f4a5921c..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" - "git.novox.be/novox/mesh-sdk/go/provisions" ) // 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 provisions.Provision, at time.Time) ([]byte, error) { +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 { diff --git a/modules/mesh-delivery-assigner/internal/assign/wants.go b/modules/mesh-delivery-assigner/internal/assign/wants.go index a4aadc29..c9df972d 100644 --- a/modules/mesh-delivery-assigner/internal/assign/wants.go +++ b/modules/mesh-delivery-assigner/internal/assign/wants.go @@ -14,8 +14,8 @@ import ( "strings" "time" + "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/provisions" "git.novox.be/novox/mesh-delivery/sdk/forms" "git.novox.be/novox/mesh-delivery/sdk/graph" @@ -40,7 +40,7 @@ type Module struct { Manifest catalogue.Manifest // Provisions is the seat mesh-provisioner's provisions this module consumes on a node, by key (ADR 0570 §4): the want // waits until each is provided. Nil: the seat's state is not read (not delivered yet), and nothing waits on it. - Provisions func(node string) map[string]provisions.Provision + Provisions func(node string) map[string]meshprovisionerclient.Provision // Answering is the manifests of the modules placed somewhere that provide a provision: what catalogue.Awaited // judges a want's provisions by (issue 774). Nil: none known, and no key is waited for that is not there. Answering func(provision string) []catalogue.Manifest @@ -242,7 +242,7 @@ func (m Module) provisionWaiting(node string) (string, bool) { } } for _, key := range slices.Sorted(maps.Keys(keyed)) { - if p := keyed[key]; p.State != provisions.Provided && slices.Contains(needed, p.Provision) { + if p := keyed[key]; p.State != meshprovisionerclient.Provided && slices.Contains(needed, p.Provision) { words := fmt.Sprintf("the provision %s of %s on %s is %s, not provided", key, m.Name, node, p.State) if p.Why != "" { words += ": " + p.Why diff --git a/modules/mesh-delivery-assigner/internal/assign/wants_test.go b/modules/mesh-delivery-assigner/internal/assign/wants_test.go index 4bae5fbe..d0208d41 100644 --- a/modules/mesh-delivery-assigner/internal/assign/wants_test.go +++ b/modules/mesh-delivery-assigner/internal/assign/wants_test.go @@ -14,8 +14,8 @@ import ( "testing" "time" + "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/provisions" "git.novox.be/novox/mesh-delivery/sdk/graph" ) @@ -81,8 +81,8 @@ func TestEachRuleHoldsTheWantBack(t *testing.T) { }, // 1954/D1 (ADR 0570 §4): a provision of the module on that node still asked holds its want. mwc.RuleProvisions: func(m *Module, _ *Nodes) { - m.Provisions = func(node string) map[string]provisions.Provision { - return map[string]provisions.Provision{node + ".mail.database": {Provision: "database", State: provisions.Asked}, node + ".mail.oidc": {Provision: "oidc", State: provisions.Provided}} + m.Provisions = func(node string) map[string]meshprovisionerclient.Provision { + return map[string]meshprovisionerclient.Provision{node + ".mail.database": {Provision: "database", State: meshprovisionerclient.Asked}, node + ".mail.oidc": {Provision: "oidc", State: meshprovisionerclient.Provided}} } }, } { @@ -103,9 +103,9 @@ func TestEachRuleHoldsTheWantBack(t *testing.T) { } } // 1954/D1: every provision provided, the want moves; with the seat's state not read, nothing waits on it. - for _, all := range []func(string) map[string]provisions.Provision{ - func(node string) map[string]provisions.Provision { - return map[string]provisions.Provision{node + ".mail.database": {Provision: "database", State: provisions.Provided}} + for _, all := range []func(string) map[string]meshprovisionerclient.Provision{ + func(node string) map[string]meshprovisionerclient.Provision { + return map[string]meshprovisionerclient.Provision{node + ".mail.database": {Provision: "database", State: meshprovisionerclient.Provided}} }, nil} { m, n := ready() m.Provisions = all @@ -216,13 +216,13 @@ func TestEachRuleHoldsTheWantBack(t *testing.T) { name string state, older string moves bool - }{{"the replaced edge provided, the older edge retiring", provisions.Provided, provisions.Retiring, true}, - {"the replaced edge provided, the older edge asked", provisions.Provided, provisions.Asked, true}, - {"the replaced edge asked, the older edge retiring", provisions.Asked, provisions.Retiring, false}} { + }{{"the replaced edge provided, the older edge retiring", meshprovisionerclient.Provided, meshprovisionerclient.Retiring, true}, + {"the replaced edge provided, the older edge asked", meshprovisionerclient.Provided, meshprovisionerclient.Asked, true}, + {"the replaced edge asked, the older edge retiring", meshprovisionerclient.Asked, meshprovisionerclient.Retiring, false}} { m, n := ready() m.Manifest.Requires = []string{"oidc"} - m.Provisions = func(node string) map[string]provisions.Provision { - return map[string]provisions.Provision{node + ".mail.oidc": {Provision: "oidc", State: c.state}, + m.Provisions = func(node string) map[string]meshprovisionerclient.Provision { + return map[string]meshprovisionerclient.Provision{node + ".mail.oidc": {Provision: "oidc", State: c.state}, node + ".mail.database": {Provision: "database", State: c.older, Why: "the operator's answer"}} } out := Wants(m, n, wantedOld(), nil) @@ -267,7 +267,9 @@ func TestEachRuleHoldsTheWantBack(t *testing.T) { } { m, n := ready() m.Manifest, m.Answering = c.manifest, answering - m.Provisions = func(string) map[string]provisions.Provision { return map[string]provisions.Provision{} } + m.Provisions = func(string) map[string]meshprovisionerclient.Provision { + return map[string]meshprovisionerclient.Provision{} + } out := Wants(m, n, wantedOld(), nil) if c.missing == "" { if out.Wants["g14"].Fp != fNew || len(m.MissingProvisions("g14")) != 0 { @@ -292,7 +294,9 @@ func TestEachRuleHoldsTheWantBack(t *testing.T) { m.Manifest.Requires = []string{c.requires} m.Answering = func(string) []catalogue.Manifest { return nil } m.Offered = func(p string) bool { return c.offered && p == c.requires } - m.Provisions = func(string) map[string]provisions.Provision { return map[string]provisions.Provision{} } + m.Provisions = func(string) map[string]meshprovisionerclient.Provision { + return map[string]meshprovisionerclient.Provision{} + } out := Wants(m, n, wantedOld(), nil) if got := out.Wants["g14"].Fp == fNew; got != c.offered || (!c.offered && (out.Rules["g14"].Rule != mwc.RuleProvisions || !strings.Contains(out.Rules["g14"].Words, "no module offers database yet") || !strings.Contains(out.Rules["g14"].Words, "past its bound"))) { diff --git a/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer-tools/views.go b/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer-tools/views.go index 342ab1d3..00fe26e6 100644 --- a/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer-tools/views.go +++ b/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer-tools/views.go @@ -5,11 +5,11 @@ import ( "fmt" "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" "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient" "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog" stdio "git.novox.be/novox/mesh-sdk/go" - "git.novox.be/novox/mesh-sdk/go/health" "git.novox.be/novox/mesh-sdk/go/views" @@ -177,7 +177,7 @@ func outOfStepTool(state func(string) views.Source) stdio.Tool { "build of the same module), then each open pull request whose check's verdict named out-of-step files.", Input: map[string]any{"type": "object", "properties": map[string]any{}}, Run: func(map[string]any) (any, error) { - rows, err := index.OutOfStepOf(state(index.SeatDefinitionsState), state(health.FindingsState)) + rows, err := index.OutOfStepOf(state(index.SeatDefinitionsState), state(mcc.FindingsState)) if err != nil { return nil, err } diff --git a/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/seatlist.go b/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/seatlist.go index e8341b9b..f04c7ec4 100644 --- a/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/seatlist.go +++ b/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/seatlist.go @@ -131,7 +131,9 @@ func followSeatList(bus *seatBus, say func(context.Context, index.SeatDefinition } // bucket is a state bound when it appears (process.AwaitedBucket). -type bucket interface{ Ready(func(jetstream.KeyValue)) } +type bucket interface { + Ready(func(jetstream.KeyValue)) +} // readWhenBound has the reader read the list again as each of the states it is answered from is bound. The reader starts before // they are, its first read finds them missing and leaves it unread, and the indexer's own events (said) are the only other thing diff --git a/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/views.go b/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/views.go index 55abd58b..ae03d7df 100644 --- a/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/views.go +++ b/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/views.go @@ -8,8 +8,8 @@ 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-delivery/modules/mesh-delivery-builder/buildrun" - "git.novox.be/novox/mesh-sdk/go/health" "git.novox.be/novox/mesh-sdk/go/process" sdkfindings "git.novox.be/novox/mesh-delivery/sdk/findings" @@ -22,7 +22,7 @@ import ( // findingsBucket is the indexer's own findings, which the condition keeper raises and clears (ADR 0564 §2): a value too // large for its views event, and its first view of the assigner's placement unanswered past its bound. -var findingsBucket = health.FindingsBucket(index.Module) +var findingsBucket = mcc.FindingsBucket(index.Module) // readyOf binds a state's bucket: now for one bound at the start, once it appears for one awaited. type readyOf func(func(jetstream.KeyValue)) diff --git a/modules/mesh-delivery-indexer/go.mod b/modules/mesh-delivery-indexer/go.mod index 80e0949d..7350b9fe 100644 --- a/modules/mesh-delivery-indexer/go.mod +++ b/modules/mesh-delivery-indexer/go.mod @@ -57,3 +57,7 @@ replace git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein => replace git.novox.be/novox/mesh-delivery/modules/mesh-delivery-forge-bridge/forgemsg => ../mesh-delivery-forge-bridge/forgemsg replace git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds => ../mesh-delivery-builder/builds + +require git.novox.be/novox/mesh-networking/modules/mesh-wireguard/go v0.0.0-20261105000000-000000000000 +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 diff --git a/modules/mesh-delivery-indexer/internal/index/accepted.go b/modules/mesh-delivery-indexer/internal/index/accepted.go index e9ab39c3..586ab4f6 100644 --- a/modules/mesh-delivery-indexer/internal/index/accepted.go +++ b/modules/mesh-delivery-indexer/internal/index/accepted.go @@ -8,9 +8,9 @@ import ( "strings" "time" + mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient" "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient" "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog" - "git.novox.be/novox/mesh-sdk/go/health" "git.novox.be/novox/mesh-sdk/go/keys" "mesh-delivery-indexer/judge" @@ -62,7 +62,7 @@ func (ix *Indexer) sayAccepted(ctx context.Context, a meshcatalog.ManifestAccept // unsaidKey is the key of module's unsaid finding. func unsaidKey(module string) string { - return health.FindingKey(health.ScopeModule, Module+".accepted."+module, UnsaidKind) + return mcc.Key(mcc.ScopeModule, Module+".accepted."+module, UnsaidKind) } // unsaid writes module's finding for err, or deletes it with none. @@ -77,14 +77,12 @@ func (ix *Indexer) unsaid(ctx context.Context, module string, err error) { } at := ix.now().UTC() summary := fmt.Sprintf("%s of %s was not published: %v", meshcatalog.EventManifestAccepted, module, err) - data, ferr := health.EncodeFinding(health.Finding{Key: key, Kind: UnsaidKind, - Subject: health.Subject{Scope: health.ScopeModule, ID: Module + ".accepted." + module}, Severity: health.Warning, + data, ferr := mcc.EncodeFinding(mcc.Observation{Scope: mcc.ScopeModule, ID: Module + ".accepted." + module, Kind: UnsaidKind, Summary: summary, Headline: "The indexer could not tell the bus module that " + module + "'s manifest was accepted", Explanation: "The bus module creates and removes a module's bus state from this event. The indexer says it again at its " + "next judging pass and clears this once it is said; indexer_say_accepted says it now.", - Resolved: "manifest-accepted of " + module + " was said.", - Evidence: []health.Evidence{{At: at, Said: summary}}, Source: UnsaidKind, Observer: Module, At: at}) + Resolved: "manifest-accepted of " + module + " was said.", Source: UnsaidKind}.Finding(Module, "", at)) return data, false, ferr }) if werr != nil { @@ -168,7 +166,7 @@ func (ix *Indexer) SayUnsaid(ctx context.Context) { if err != nil || !found { continue } - f, err := health.DecodeFinding(value) + f, err := mcc.DecodeFinding(value) if err != nil || f.Kind != UnsaidKind { continue } diff --git a/modules/mesh-delivery-indexer/internal/index/control_records_test.go b/modules/mesh-delivery-indexer/internal/index/control_records_test.go index cbc7db65..b1abd21f 100644 --- a/modules/mesh-delivery-indexer/internal/index/control_records_test.go +++ b/modules/mesh-delivery-indexer/internal/index/control_records_test.go @@ -9,12 +9,12 @@ import ( "testing" "time" + mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient" "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient" "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-forge-bridge/forgemsg" sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" - "git.novox.be/novox/mesh-sdk/go/health" "git.novox.be/novox/mesh-sdk/go/keys" "git.novox.be/novox/mesh-sdk/go/process" "git.novox.be/novox/mesh-sdk/go/seatdef" @@ -173,7 +173,7 @@ func TestTheControlRecords(t *testing.T) { } return e, ok } - unparsed := health.FindingKey(health.ScopeModule, findingID("seat-definitions", "mesh-contracts"), SeatDefinitionUnparsedKind) + unparsed := mcc.Key(mcc.ScopeModule, findingID("seat-definitions", "mesh-contracts"), SeatDefinitionUnparsedKind) merged(m1) merged(m1) // the same digests again say nothing g1, ok := entry("git.trunk") @@ -221,7 +221,7 @@ func TestTheControlRecords(t *testing.T) { t.Fatal(err) } } - twice := health.FindingKey(health.ScopeModule, findingID("seat-defined-twice", "other-contracts"), SeatDefinedTwiceKind) + twice := mcc.Key(mcc.ScopeModule, findingID("seat-defined-twice", "other-contracts"), SeatDefinedTwiceKind) before := len(said) mergedOther("o1") if g, _ := entry("git.trunk"); g.Repository != repo || g.Commit != m3 || len(said) != before { @@ -348,7 +348,7 @@ func TestTheControlRecords(t *testing.T) { t.Fatal(err) } } - outside := health.FindingKey(health.ScopeModule, findingID("seat-outside-its-domain", "mesh-contracts"), SeatOutsideItsDomainKind) + outside := mcc.Key(mcc.ScopeModule, findingID("seat-outside-its-domain", "mesh-contracts"), SeatOutsideItsDomainKind) before = len(said) // mesh-contracts defines wants and vault, seats of other domains: refused with a finding naming both modules, the // held entries stand, and lone (Core) is taken. diff --git a/modules/mesh-delivery-indexer/internal/index/holds_test.go b/modules/mesh-delivery-indexer/internal/index/holds_test.go index 10fcb0a0..6c5bdc13 100644 --- a/modules/mesh-delivery-indexer/internal/index/holds_test.go +++ b/modules/mesh-delivery-indexer/internal/index/holds_test.go @@ -7,9 +7,9 @@ import ( "testing" "time" + mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient" "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient" "git.novox.be/novox/mesh-sdk/go/catalogue" - "git.novox.be/novox/mesh-sdk/go/health" ) // fakeBounds is the state hold-bounds: the end each key was armed with, a standing key keeping its end. @@ -50,7 +50,7 @@ func storeHoldersNewManifestWaitsForEveryCountedEngine(t *testing.T) { ix.Holds, ix.Findings, ix.HoldBounds, ix.Now = holds, findings, bounds, func() time.Time { return clock } ix.Counted = func() (map[string][]string, bool) { return stated, true } ix.AskEngines = func(nodes []string, _ string) { asked = append(asked, nodes...) } - heldKey := health.FindingKey(health.ScopeModule, findingID("hold", "distribution"), HoldStandingKind) + heldKey := mcc.Key(mcc.ScopeModule, findingID("hold", "distribution"), HoldStandingKind) first := withManifests(mergedMsg(catalogueRepo, map[string]string{dir: "tree1", dockerDir: "d1"}), map[string]string{dir: old, dockerDir: docker}, nil) if err := ix.Apply(ctx, first); err != nil { @@ -95,7 +95,7 @@ func storeHoldersNewManifestWaitsForEveryCountedEngine(t *testing.T) { t.Fatal(err) } stays("past its bound,") - f, err := health.DecodeFinding(findings.vals[heldKey]) + f, err := mcc.DecodeFinding(findings.vals[heldKey]) if err != nil || f.Kind != HoldStandingKind || !strings.Contains(f.Summary, "n2 lacks form:seat-reach") { t.Fatalf("past its bound the finding %s = %+v (%v), want manifest-held naming n2", heldKey, f, err) } diff --git a/modules/mesh-delivery-indexer/internal/index/seatdefs.go b/modules/mesh-delivery-indexer/internal/index/seatdefs.go index da670903..fb96c29b 100644 --- a/modules/mesh-delivery-indexer/internal/index/seatdefs.go +++ b/modules/mesh-delivery-indexer/internal/index/seatdefs.go @@ -25,11 +25,11 @@ import ( "strings" "time" + mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient" "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-forge-bridge/forgemsg" "git.novox.be/novox/mesh-sdk/go/catalogue" - "git.novox.be/novox/mesh-sdk/go/health" "git.novox.be/novox/mesh-sdk/go/keys" "git.novox.be/novox/mesh-sdk/go/seatdef" "git.novox.be/novox/mesh-sdk/go/views" @@ -599,20 +599,19 @@ func (ix *Indexer) finding(ctx context.Context, id, kind string, raise bool, sum if ix.Findings == nil { return } - key := health.FindingKey(health.ScopeModule, id, kind) + key := mcc.Key(mcc.ScopeModule, id, kind) err := write(ctx, ix.Findings, key, func(value []byte, found bool) ([]byte, bool, error) { if !raise { return nil, found, nil } if found { - if f, err := health.DecodeFinding(value); err == nil && f.Summary == summary { + if f, err := mcc.DecodeFinding(value); err == nil && f.Summary == summary { return nil, false, nil } } at := ix.now().UTC() - data, err := health.EncodeFinding(health.Finding{Key: key, Kind: kind, Subject: health.Subject{Scope: health.ScopeModule, ID: id}, - Severity: health.Warning, Summary: summary, Headline: headline, Explanation: explanation, Resolved: resolved, - Evidence: []health.Evidence{{At: at, Said: summary}}, Source: kind, Observer: Module, At: at}) + data, err := mcc.EncodeFinding(mcc.Observation{Scope: mcc.ScopeModule, ID: id, Kind: kind, Summary: summary, + Headline: headline, Explanation: explanation, Resolved: resolved, Source: kind}.Finding(Module, "", at)) return data, false, err }) if err != nil { @@ -762,7 +761,7 @@ func OutOfStepOf(defs, findings views.Source) ([]OutOfStepRow, error) { if err != nil || !ok || v == nil { continue } - f, err := health.DecodeFinding(v.Value) + f, err := mcc.DecodeFinding(v.Value) if err != nil || f.Kind != OutOfStepKind { continue } diff --git a/modules/mesh-delivery-indexer/internal/index/views.go b/modules/mesh-delivery-indexer/internal/index/views.go index 67a8a468..ab2ca0ab 100644 --- a/modules/mesh-delivery-indexer/internal/index/views.go +++ b/modules/mesh-delivery-indexer/internal/index/views.go @@ -1,7 +1,7 @@ package index import ( - "git.novox.be/novox/mesh-sdk/go/health" + mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient" "git.novox.be/novox/mesh-delivery/sdk/graph" "git.novox.be/novox/mesh-sdk/go/views" @@ -30,7 +30,7 @@ var ReadTools = []ViewedTool{ {Tool: "indexer_read_graph", State: graph.State, Words: "the module graph: each module's build and provision edges."}, {Tool: "indexer_read_heard", State: HeardState, Words: "the forge messages the indexer heard and what it did with each."}, {Tool: "indexer_read_taken", State: "taken", Words: "each repository's merge the indexer took in last."}, - {Tool: "indexer_read_findings", State: health.FindingsState, Words: "the indexer's findings, which the condition keeper raises and clears."}, + {Tool: "indexer_read_findings", State: mcc.FindingsState, Words: "the indexer's findings, which the condition keeper raises and clears."}, {Tool: "indexer_read_seat_definitions", State: SeatDefinitionsState, Words: "the seat definitions the trunk's and each open pull request's contracts modules hold, resolved, or why one does not parse."}, } @@ -51,6 +51,6 @@ var ViewedStates = map[string]string{ graph.State: graph.Bucket, HeardState: HeardBucket, "taken": TakenBucket, - health.FindingsState: health.FindingsBucket(Module), + mcc.FindingsState: mcc.FindingsBucket(Module), SeatDefinitionsState: SeatDefinitionsBucket, } diff --git a/modules/mesh-delivery-indexer/judge/judge_test.go b/modules/mesh-delivery-indexer/judge/judge_test.go index 3e743737..0eaf20e8 100644 --- a/modules/mesh-delivery-indexer/judge/judge_test.go +++ b/modules/mesh-delivery-indexer/judge/judge_test.go @@ -7,8 +7,8 @@ import ( "testing" "git.novox.be/novox/mesh-delivery/sdk/composer" + "git.novox.be/novox/mesh-networking/modules/mesh-wireguard/go/overlay" "git.novox.be/novox/mesh-sdk/go/catalogue" - "git.novox.be/novox/mesh-sdk/go/overlay" ) // The judge (novox/hq ADR 0578 §1): a manifest alone is accepted, or refused with each problem; an unknown field is diff --git a/modules/mesh-delivery-indexer/manifest_test.go b/modules/mesh-delivery-indexer/manifest_test.go index 48574a86..706f75c1 100644 --- a/modules/mesh-delivery-indexer/manifest_test.go +++ b/modules/mesh-delivery-indexer/manifest_test.go @@ -15,8 +15,8 @@ import ( "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein" "git.novox.be/novox/mesh-sdk/go/catalogue" + mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient" "git.novox.be/novox/mesh-delivery/sdk/graph" - "git.novox.be/novox/mesh-sdk/go/health" "git.novox.be/novox/mesh-sdk/go/views" "mesh-delivery-indexer/internal/index" @@ -114,7 +114,7 @@ func TestManifestDeclarations(t *testing.T) { // 1238/AC1, 1444 (reads the build } // 1126 note 76: heard keeps the last 64 FORGE messages the indexer handled, for indexer_heard. if want := []state{{Name: "candidates", History: 10}, {Name: "heard", History: 64}, {Name: "manifests", History: 1}, {Name: "modules", History: 20}, {Name: "predefined", History: 5}, {Name: "config-candidates", History: 5}, {Name: "taken", History: 1}, {Name: "takeins", History: 1}, {Name: "verdicts", History: 5}, {Name: "oldsections", History: 1}, {Name: index.PackagesState, History: index.PackagesHistory}, - {Name: graph.State, History: graph.History}, {Name: views.MarksState, History: 1}, {Name: health.FindingsState, History: 5}, {Name: views.StatusState, History: 1}, + {Name: graph.State, History: graph.History}, {Name: views.MarksState, History: 1}, {Name: mcc.FindingsState, History: 5}, {Name: views.StatusState, History: 1}, {Name: index.RequirementsState, History: 5}, {Name: index.SeatDefinitionsState, History: 5}, {Name: index.HoldsState, History: 5}, {Name: index.EngineReadsState, History: 1}, {Name: index.HoldBoundsState, History: 1, KeyTTL: true}, {Name: index.PendingState, History: 1}}; !reflect.DeepEqual(m.State, want) { // DLV-I7, DLV-I17, ADR 0632 §2 t.Errorf("state = %+v, want %+v", m.State, want) diff --git a/modules/mesh-delivery-view/cmd/mesh-delivery-view-tools/main.go b/modules/mesh-delivery-view/cmd/mesh-delivery-view-tools/main.go index 8a28f8b6..132a563e 100644 --- a/modules/mesh-delivery-view/cmd/mesh-delivery-view-tools/main.go +++ b/modules/mesh-delivery-view/cmd/mesh-delivery-view-tools/main.go @@ -14,6 +14,7 @@ import ( "git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient" "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient" "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshwatchdogsclient" + "git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-view/viewstate" @@ -21,7 +22,6 @@ import ( "git.novox.be/novox/mesh-delivery/sdk/enginereads" stdio "git.novox.be/novox/mesh-sdk/go" "git.novox.be/novox/mesh-sdk/go/busretry" - "git.novox.be/novox/mesh-sdk/go/provisions" "git.novox.be/novox/mesh-sdk/go/views" ) @@ -414,7 +414,7 @@ func main() { r.ConditionsState, r.AttemptsState = read(stdio.State(view.StatusConditionsState)), read(stdio.State(view.StatusAttemptsState)) r.PresenceState, r.StuckState = read(stdio.State(view.StatusPresenceState)), read(stdio.State(view.StatusStuckState)) r.SourceState = read(stdio.State(view.GateModule + ".source")) - r.ProvisionsState = read(stdio.State(provisions.ProvisionsRead)) + r.ProvisionsState = read(stdio.State(meshprovisionerclient.ProvisionsRead)) r.BuildLog = stdio.Log(builds.BuildLogRead).Since r.Pending = pendingOf u := view.UsageReader{Haves: r.HavesState, Resolved: read(stdio.State("mesh-config.resolved")), Tries: read(stdio.State("mesh-delivery-checker.tries")), diff --git a/modules/mesh-delivery-view/cmd/mesh-delivery-view-tools/tiers_rows_test.go b/modules/mesh-delivery-view/cmd/mesh-delivery-view-tools/tiers_rows_test.go index 45f0f905..b43db756 100644 --- a/modules/mesh-delivery-view/cmd/mesh-delivery-view-tools/tiers_rows_test.go +++ b/modules/mesh-delivery-view/cmd/mesh-delivery-view-tools/tiers_rows_test.go @@ -14,12 +14,12 @@ import ( "git.novox.be/novox/mesh-contracts/go/seats/nodeengine" "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshwatchdogsclient" "git.novox.be/novox/mesh-contracts/placement/go/clients/meshwantsclient" + "git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient" "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient" "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein" "git.novox.be/novox/mesh-delivery/sdk/graph" - "git.novox.be/novox/mesh-sdk/go/provisions" ) // encoded is v as its contract's encoder writes it, failing the test when it refuses. @@ -85,9 +85,9 @@ func tiersToolSaysEachModulesWait(t *testing.T) { }.reader().State r.WantsState.History = func(string) ([]view.Revision, error) { return []view.Revision{{At: since}}, nil } r.HavesState = fake{key(nodeengineclient.HaveKey("ace", "db")): have(nodeengine.HaveByNodeModuleValue{Fp: fp("a"), Phase: nodeengineclient.PhaseRunning, Health: nodeengineclient.HealthOK})}.reader().State - p, err := provisions.Encode(provisions.Provision{Provision: "database", Consumer: provisions.End{Module: "web", Node: "ace"}, - Provider: provisions.End{Module: "db", Node: "ace"}, State: provisions.Asked, Why: "the build db runs does not offer it", At: since}) - r.ProvisionsState = fake{key(provisions.Key("ace", "web", "database", "")): encoded(t, p, err)}.reader().State + p, err := meshprovisionerclient.Encode(meshprovisionerclient.Provision{Provision: "database", Consumer: meshprovisionerclient.End{Module: "web", Node: "ace"}, + Provider: meshprovisionerclient.End{Module: "db", Node: "ace"}, State: meshprovisionerclient.Asked, Why: "the build db runs does not offer it", At: since}) + r.ProvisionsState = fake{key(meshprovisionerclient.Key("ace", "web", "database", "")): encoded(t, p, err)}.reader().State off, err := meshwatchdogsclient.EncodeNodePresence(meshwatchdogsclient.NodePresence{Online: false}) r.PresenceState = fake{key(meshwatchdogsclient.PresenceNodeKey("g14")): encoded(t, off, err)}.reader().State diff --git a/modules/mesh-delivery-view/go.mod b/modules/mesh-delivery-view/go.mod index 14731581..786f7410 100644 --- a/modules/mesh-delivery-view/go.mod +++ b/modules/mesh-delivery-view/go.mod @@ -3,6 +3,7 @@ module mesh-delivery-view go 1.26.0 require ( + git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshwatchdogsclient v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-contracts/identity-and-access/go/clients/meshvaultclient v0.0.0-00010101000000-000000000000 @@ -50,3 +51,6 @@ require ( replace git.novox.be/novox/mesh-delivery/sdk => ../../sdk replace git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein => ../mesh-delivery-indexer/takein +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/meshhealers v0.0.0-00010101000000-000000000000 diff --git a/modules/mesh-delivery-view/internal/view/status.go b/modules/mesh-delivery-view/internal/view/status.go index ef2ba554..bb5c5e41 100644 --- a/modules/mesh-delivery-view/internal/view/status.go +++ b/modules/mesh-delivery-view/internal/view/status.go @@ -8,9 +8,11 @@ import ( "git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient" "git.novox.be/novox/mesh-contracts/go/seats/nodeengine" + mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient" "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshwatchdogsclient" + mcseat "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions" + healers "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshhealers" "git.novox.be/novox/mesh-contracts/placement/go/clients/meshwantsclient" - "git.novox.be/novox/mesh-sdk/go/health" "git.novox.be/novox/mesh-sdk/go/motion" ) @@ -28,8 +30,8 @@ const StatusTool = "view_status" // The states status reads, as the view's manifest names them. const ( - StatusConditionsState = health.KeeperModule + "." + health.ConditionsState - StatusAttemptsState = health.HealersModule + "." + health.AttemptsState + StatusConditionsState = mcseat.Seat + "." + mcseat.StateConditions + StatusAttemptsState = healers.Seat + "." + healers.StateAttempts StatusPresenceState = WatchmanModule + ".presence" StatusStuckState = WatchmanModule + ".stuck" ) @@ -115,17 +117,17 @@ func DeriveStatus(r StatusRead, now time.Time) Status { if raw, err := values(r.Conditions); err != nil { st.ConditionsUnread = "the condition keeper's conditions cannot be read: " + err.Error() } else { - var open []health.Condition + var open []mcseat.ConditionsByKeyValue for _, v := range raw { - var c health.Condition + var c mcseat.ConditionsByKeyValue if json.Unmarshal(v, &c) == nil && c.Key != "" { open = append(open, c) } } - health.Order(open) + mcc.Order(open) for _, c := range open { - st.Conditions = append(st.Conditions, StatusCondition{Key: c.Key, Severity: string(c.Severity), Machine: c.Subject.Machine, - Summary: c.Summary, Raised: c.Raised, Silenced: c.SilencedAt(now)}) + st.Conditions = append(st.Conditions, StatusCondition{Key: c.Key, Severity: c.Severity, Machine: c.Subject.Machine, + Summary: c.Summary, Raised: c.Raised, Silenced: mcc.SilencedAt(c, now)}) } } @@ -203,13 +205,13 @@ func DeriveStatus(r StatusRead, now time.Time) Status { st.HealsUnread = "mesh-healers' attempts cannot be read: " + err.Error() } else { for _, v := range raw { - var a health.Attempt + var a healers.AttemptsByAttemptValue if json.Unmarshal(v, &a) != nil || now.Sub(a.Begun) > HealsWithin { continue } outcome := a.Outcome if outcome == "" { - outcome = health.OutcomeActing + outcome = healers.AttemptsByAttemptValueOutcomeActing } st.Heals[outcome]++ } diff --git a/modules/mesh-delivery-view/internal/view/tiers.go b/modules/mesh-delivery-view/internal/view/tiers.go index 34e71b05..dab12820 100644 --- a/modules/mesh-delivery-view/internal/view/tiers.go +++ b/modules/mesh-delivery-view/internal/view/tiers.go @@ -12,13 +12,13 @@ import ( "git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient" "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshwatchdogsclient" "git.novox.be/novox/mesh-contracts/placement/go/clients/meshwantsclient" + "git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient" "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient" "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshdeliveryclient" "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein" "git.novox.be/novox/mesh-delivery/sdk/graph" - "git.novox.be/novox/mesh-sdk/go/provisions" ) // The tiers of a source revision are a view, worked out at each call and never stored (novox/hq ADR 0603 §1, §6): the @@ -389,7 +389,7 @@ func provisionWaits(node, module, a string, provided map[string]json.RawMessage, if perr != nil { return []TierWait{{Edge: edge, Node: node, Words: "the provisioner's keys cannot be read: " + perr.Error()}} } - prefix, _ := provisions.Key(node, module, a, "") + prefix, _ := meshprovisionerclient.Key(node, module, a, "") var out []TierWait found := false for _, key := range slices.Sorted(maps.Keys(provided)) { @@ -397,12 +397,12 @@ func provisionWaits(node, module, a string, provided map[string]json.RawMessage, continue } found = true - p, err := provisions.Decode(provided[key]) + p, err := meshprovisionerclient.Decode(provided[key]) if err != nil { out = append(out, TierWait{Edge: edge, Node: node, Words: "the provision key " + key + " does not read: " + err.Error()}) continue } - if p.State == provisions.Provided { + if p.State == meshprovisionerclient.Provided { continue } words := "the provision " + key + " is " + p.State diff --git a/modules/mesh-delivery-view/internal/view/view_test.go b/modules/mesh-delivery-view/internal/view/view_test.go index 32c2182a..8d849fb3 100644 --- a/modules/mesh-delivery-view/internal/view/view_test.go +++ b/modules/mesh-delivery-view/internal/view/view_test.go @@ -10,12 +10,14 @@ import ( "git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient" "git.novox.be/novox/mesh-contracts/go/seats/nodeengine" + mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient" "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshwatchdogsclient" + mcseat "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions" + healers "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshhealers" "git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient" "git.novox.be/novox/mesh-contracts/placement/go/clients/meshwantsclient" "git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner" "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient" - "git.novox.be/novox/mesh-sdk/go/health" "git.novox.be/novox/mesh-sdk/go/keys" "git.novox.be/novox/mesh-sdk/go/motion" ) @@ -301,8 +303,8 @@ func statusDerivesEachPartFromItsBucket(t *testing.T) { fin := t0.Add(time.Minute) r := StatusRead{ Conditions: states(map[string]string{ - "machine.b.silent": enc(health.Condition{Key: "machine.b.silent", Severity: health.Warning, Summary: "b silent", Raised: t0}), - "core.doctor.self-check": enc(health.Condition{Key: "core.doctor.self-check", Severity: health.Urgent, Summary: "no run", Raised: t0.Add(time.Minute)}), + "machine.b.silent": enc(mcseat.ConditionsByKeyValue{Key: "machine.b.silent", Severity: mcc.Warning, Summary: "b silent", Raised: t0}), + "core.doctor.self-check": enc(mcseat.ConditionsByKeyValue{Key: "core.doctor.self-check", Severity: mcc.Urgent, Summary: "no run", Raised: t0.Add(time.Minute)}), }), Presence: states(map[string]string{"a": presence(true), "b": presence(false)}), Stuck: states(map[string]string{stuckWant: stuckOf(AssignerWantsBucket, "want.b.web", "b to run web", false), @@ -310,8 +312,8 @@ func statusDerivesEachPartFromItsBucket(t *testing.T) { Wants: states(map[string]string{"want.a.web": want(fp2), "want.a.mail": want(fp1), "want.b.web": want(fp2), "want.a.db": want(fp3)}), Haves: states(map[string]string{"a.web": have(fp1, nodeengineclient.PhaseRunning, nodeengineclient.HealthOK, ""), "a.mail": have(fp1, nodeengineclient.PhaseRunning, nodeengineclient.HealthOK, ""), "b.web": have(fp1, nodeengineclient.PhaseRunning, nodeengineclient.HealthOK, ""), "a.db": have(fp3, nodeengineclient.PhaseRunning, nodeengineclient.HealthFailed, "the unit failed")}), - Attempts: states(map[string]string{"1": enc(health.Attempt{Outcome: health.OutcomeActed, Begun: t0, Finished: &fin}), - "2": enc(health.Attempt{Outcome: health.OutcomeEscalated, Begun: t0}), "old": enc(health.Attempt{Outcome: health.OutcomeActed, Begun: now.Add(-8 * 24 * time.Hour)})}), + Attempts: states(map[string]string{"1": enc(healers.AttemptsByAttemptValue{Outcome: healers.AttemptsByAttemptValueOutcomeActed, Begun: t0, Finished: &fin}), + "2": enc(healers.AttemptsByAttemptValue{Outcome: healers.AttemptsByAttemptValueOutcomeEscalated, Begun: t0}), "old": enc(healers.AttemptsByAttemptValue{Outcome: healers.AttemptsByAttemptValueOutcomeActed, Begun: now.Add(-8 * 24 * time.Hour)})}), } st := DeriveStatus(r, now) if len(st.Conditions) != 2 || st.Conditions[0].Key != "core.doctor.self-check" || st.Conditions[1].Key != "machine.b.silent" { @@ -328,7 +330,7 @@ func statusDerivesEachPartFromItsBucket(t *testing.T) { if !reflect.DeepEqual(st.Moving, wantMoving) { t.Errorf("moving = %+v\nwant %+v", st.Moving, wantMoving) } - if !reflect.DeepEqual(st.Heals, map[string]int{health.OutcomeActed: 1, health.OutcomeEscalated: 1}) || st.Well { + if !reflect.DeepEqual(st.Heals, map[string]int{healers.AttemptsByAttemptValueOutcomeActed: 1, healers.AttemptsByAttemptValueOutcomeEscalated: 1}) || st.Well { t.Errorf("heals = %v, well %v", st.Heals, st.Well) } // A part it cannot read is said, and the mesh is not well; with nothing wrong and every part read it is. diff --git a/modules/mesh-delivery-watchman/go.mod b/modules/mesh-delivery-watchman/go.mod index 3ad71562..db23d545 100644 --- a/modules/mesh-delivery-watchman/go.mod +++ b/modules/mesh-delivery-watchman/go.mod @@ -41,3 +41,4 @@ replace git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/buildrun require git.novox.be/novox/mesh-delivery/sdk v0.0.0-00010101000000-000000000000 replace git.novox.be/novox/mesh-delivery/sdk => ../../sdk +require git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient v0.0.0-00010101000000-000000000000 diff --git a/modules/mesh-delivery-watchman/internal/watch/finding.go b/modules/mesh-delivery-watchman/internal/watch/finding.go index abf0af0c..fbc5114f 100644 --- a/modules/mesh-delivery-watchman/internal/watch/finding.go +++ b/modules/mesh-delivery-watchman/internal/watch/finding.go @@ -3,40 +3,40 @@ package watch import ( "time" - "git.novox.be/novox/mesh-sdk/go/health" + mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient" "git.novox.be/novox/mesh-delivery/sdk/heard" ) // The watchman is an observer of the seat mesh-watchdogs (novox/hq ADR 0564 §2, §4): what it observes wrong it writes as a -// finding, one key `..` of its own bucket `findings` in mesh-sdk's layout (health.Finding), only when what +// finding, one key `..` of its own bucket `findings` in the seat mesh-conditions' layout (meshconditionsclient), only when what // it says changes, and it deletes the key when it no longer observes it. The condition keeper (mesh-conditions) raises and // clears the conditions from them; the watchman writes no condition and reads none (Limits 11). // FindingsBucket is the watchman's findings. -var FindingsBucket = health.FindingsBucket(health.WatchmanModule) +var FindingsBucket = mcc.FindingsBucket(Observer) // Observer is the name a finding of the watchman carries. -const Observer = health.WatchmanModule +const Observer = "mesh-delivery-watchman" // The scopes and severities a finding of the watchman names, as the controller's conditions name them, so the keeper's // `compare` meets the same keys. const ( - ScopeMachine = health.ScopeMachine - ScopeDelivery = health.ScopeDelivery - ScopeModule = health.ScopeModule - ScopeProvider = health.ScopeProvider - ScopeBus = health.ScopeBus - ScopeCore = health.ScopeCore + ScopeMachine = mcc.ScopeMachine + ScopeDelivery = mcc.ScopeDelivery + ScopeModule = mcc.ScopeModule + ScopeProvider = mcc.ScopeProvider + ScopeBus = mcc.ScopeBus + ScopeCore = mcc.ScopeCore - Urgent = string(health.Urgent) - Warning = string(health.Warning) + Urgent = mcc.Urgent + Warning = mcc.Warning ) // Finding is what the watchman builds of one thing it observes wrong: its subject (scope, id, the machine and the others // it concerns), kind and severity, its evidence (Summary, and Said with Since, its one observation), the words the // operator reads (ADR 0253; empty leaves the keeper's wording of the kind), and the row or fact it comes from (Source). -// It is written as health.Finding. +// It is written as the seat's finding. type Finding struct { Scope, ID, Token, Kind, Machine string Also []string @@ -51,8 +51,8 @@ type Finding struct { Since time.Time } -// FindingKey composes a finding's key as the controller composes a condition's (health.Key). -func FindingKey(scope, id, token string) string { return health.FindingKey(scope, id, token) } +// FindingKey composes a finding's key as the controller composes a condition's (mcc.Key). +func FindingKey(scope, id, token string) string { return mcc.Key(scope, id, token) } // Key is the finding's key: its token, or its kind when it has none. func (f Finding) Key() string { @@ -63,27 +63,21 @@ func (f Finding) Key() string { return FindingKey(f.Scope, f.ID, token) } -// EncodeFinding is f in mesh-sdk's layout, refusing one the keeper could not make a condition of. +// EncodeFinding is f in the seat's layout, refusing one the keeper could not make a condition of. func EncodeFinding(f Finding) ([]byte, error) { - said := f.Said - if said == "" { - said = f.Summary - } - return health.EncodeFinding(health.Finding{Key: f.Key(), Kind: f.Kind, Ref: f.Token, - Subject: health.Subject{Scope: f.Scope, ID: f.ID, Machine: f.Machine, Also: f.Also}, - Severity: health.Severity(f.Severity), Summary: f.Summary, Headline: f.Headline, Explanation: f.Explanation, - Resolved: f.Resolved, Needs: f.Needs, Evidence: []health.Evidence{{At: f.Since.UTC(), Said: said}}, - Source: f.Source, Observer: Observer, At: f.Since.UTC()}) + return mcc.EncodeFinding(mcc.Observation{Scope: f.Scope, ID: f.ID, Kind: f.Kind, Ref: f.Token, Machine: f.Machine, Also: f.Also, + Severity: f.Severity, Summary: f.Summary, Said: f.Said, Headline: f.Headline, Explanation: f.Explanation, + Resolved: f.Resolved, Needs: f.Needs, Source: f.Source}.Finding(Observer, "", f.Since)) } // DecodeFinding reads a finding the watchman wrote. func DecodeFinding(data []byte) (Finding, error) { - h, err := health.DecodeFinding(data) + h, err := mcc.DecodeFinding(data) if err != nil { return Finding{}, err } f := Finding{Scope: h.Subject.Scope, ID: h.Subject.ID, Token: h.Ref, Kind: h.Kind, Machine: h.Subject.Machine, - Also: h.Subject.Also, Severity: string(h.Severity), Summary: h.Summary, Headline: h.Headline, Explanation: h.Explanation, + Also: h.Subject.Also, Severity: h.Severity, Summary: h.Summary, Headline: h.Headline, Explanation: h.Explanation, Needs: h.Needs, Resolved: h.Resolved, Source: h.Source, Observer: h.Observer, Since: h.At} if len(h.Evidence) > 0 { f.Said = h.Evidence[0].Said diff --git a/modules/mesh-delivery-watchman/internal/watch/findings_test.go b/modules/mesh-delivery-watchman/internal/watch/findings_test.go index ff12c769..f5b6a5bc 100644 --- a/modules/mesh-delivery-watchman/internal/watch/findings_test.go +++ b/modules/mesh-delivery-watchman/internal/watch/findings_test.go @@ -9,13 +9,13 @@ import ( "git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient" "git.novox.be/novox/mesh-contracts/go/seats/nodeengine" + mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient" "git.novox.be/novox/mesh-contracts/placement/go/clients/meshwantsclient" "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient" "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein" "git.novox.be/novox/mesh-delivery/sdk/buildstep" - "git.novox.be/novox/mesh-sdk/go/health" "git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient" "git.novox.be/novox/mesh-delivery/sdk/heard" @@ -277,7 +277,7 @@ func TestTheWatchmansFindings(t *testing.T) { case !row.noState && row.want == "" && stands: t.Errorf("%s: the finding stands once bound", row.name) case row.want != "": - f, err := health.DecodeFinding(raw) + f, err := mcc.DecodeFinding(raw) // Review round 2: it says it clears at the part's next start, since Bind runs at the start. if err != nil || f.Kind != heard.Kind || f.Summary != row.want || f.Observer != "mesh-delivery-indexer" || !strings.Contains(f.Explanation, "next start") { t.Errorf("%s: the finding %+v (%v), want summary %q", row.name, f, err, row.want)