From 738c8ca036381bda5b810bb3daa0bef4a970a482 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 5 Nov 2026 16:45:25 +0100 Subject: [PATCH] =?UTF-8?q?assigner,=20view,=20watchman:=20provisions=20co?= =?UTF-8?q?me=20from=20meshprovisionerclient,=20not=20mesh-sdk=20go/provis?= =?UTF-8?q?ions=20(ADR=200634=20=C2=A74;=20issue=201966)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i --- .../integration_test.go | 12 ++++---- .../cmd/mesh-delivery-assigner/main.go | 12 ++++---- .../cmd/mesh-delivery-assigner/pass.go | 28 ++++++++--------- .../mesh-delivery-assigner/seat_tools_test.go | 20 ++++++------- modules/mesh-delivery-assigner/go.mod | 1 + .../internal/assign/policy.go | 4 +-- .../internal/assign/wants.go | 6 ++-- .../internal/assign/wants_test.go | 30 +++++++++++-------- .../cmd/mesh-delivery-view-tools/main.go | 4 +-- .../tiers_rows_test.go | 8 ++--- modules/mesh-delivery-view/go.mod | 1 + .../mesh-delivery-view/internal/view/tiers.go | 8 ++--- .../cmd/mesh-delivery-watchman/main.go | 12 ++++---- modules/mesh-delivery-watchman/go.mod | 1 + .../internal/watch/findings_test.go | 28 ++++++++--------- 15 files changed, 91 insertions(+), 84 deletions(-) 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..fa805b4b 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,13 @@ 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 +526,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 +565,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) } 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..5f4f678c 100644 --- a/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/main.go +++ b/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/main.go @@ -26,10 +26,10 @@ import ( 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, } @@ -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..5b872f5b 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 @@ -20,10 +20,10 @@ import ( 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) diff --git a/modules/mesh-delivery-assigner/go.mod b/modules/mesh-delivery-assigner/go.mod index 15478b61..b0d6699a 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 diff --git a/modules/mesh-delivery-assigner/internal/assign/policy.go b/modules/mesh-delivery-assigner/internal/assign/policy.go index f4a5921c..4da019b4 100644 --- a/modules/mesh-delivery-assigner/internal/assign/policy.go +++ b/modules/mesh-delivery-assigner/internal/assign/policy.go @@ -10,9 +10,9 @@ import ( "time" 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 @@ -65,7 +65,7 @@ func ProvisionFailedKey(key string) string { } // 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, 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-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..3cb4b11a 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 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-watchman/cmd/mesh-delivery-watchman/main.go b/modules/mesh-delivery-watchman/cmd/mesh-delivery-watchman/main.go index b00534cb..0a62fdf9 100644 --- a/modules/mesh-delivery-watchman/cmd/mesh-delivery-watchman/main.go +++ b/modules/mesh-delivery-watchman/cmd/mesh-delivery-watchman/main.go @@ -26,10 +26,10 @@ import ( "github.com/nats-io/nats.go/jetstream" "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/contracts/go/clients/meshcatalogclient" "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/provisions" "mesh-delivery-watchman/internal/socket" "mesh-delivery-watchman/internal/watch" @@ -382,21 +382,21 @@ func run(ctx context.Context, getenv func(string) string, logOut io.Writer) erro provisionsWatch := func(kv jetstream.KeyValue) (jetstream.KeyWatcher, error) { pw, err := settle(ctx, kv, func(e jetstream.KeyValueEntry) { w.Provision(e.Key(), e.Value(), opOf(e)) }) if err == nil { - w.ReadWhole(provisions.ProvisionsBucket) + w.ReadWhole(meshprovisionerclient.ProvisionsBucket) } return pw, err } var provWatch jetstream.KeyWatcher - if kv, err := js.KeyValue(ctx, provisions.ProvisionsBucket); err == nil { + if kv, err := js.KeyValue(ctx, meshprovisionerclient.ProvisionsBucket); err == nil { if provWatch, err = provisionsWatch(kv); err != nil { - process.NotWatched(logger.Printf, provisions.ProvisionsBucket, err, "no provision waiting for the operator is said until the watchman starts again") + process.NotWatched(logger.Printf, meshprovisionerclient.ProvisionsBucket, err, "no provision waiting for the operator is said until the watchman starts again") } } else { - process.AwaitBucket(ctx, js, conn, provisions.ProvisionsBucket, "no provision waiting for the operator is said", + process.AwaitBucket(ctx, js, conn, meshprovisionerclient.ProvisionsBucket, "no provision waiting for the operator is said", logger.Printf).Ready(func(kv jetstream.KeyValue) { pw, err := provisionsWatch(kv) if err != nil { - process.NotWatched(logger.Printf, provisions.ProvisionsBucket, err, "no provision waiting for the operator is said until the watchman starts again") + process.NotWatched(logger.Printf, meshprovisionerclient.ProvisionsBucket, err, "no provision waiting for the operator is said until the watchman starts again") return } go func() { diff --git a/modules/mesh-delivery-watchman/go.mod b/modules/mesh-delivery-watchman/go.mod index 2899b58e..44bef1e5 100644 --- a/modules/mesh-delivery-watchman/go.mod +++ b/modules/mesh-delivery-watchman/go.mod @@ -3,6 +3,7 @@ module mesh-delivery-watchman 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/go/seats/nodeengine v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshwatchdogsclient v0.0.0-00010101000000-000000000000 diff --git a/modules/mesh-delivery-watchman/internal/watch/findings_test.go b/modules/mesh-delivery-watchman/internal/watch/findings_test.go index 789ca57a..ff12c769 100644 --- a/modules/mesh-delivery-watchman/internal/watch/findings_test.go +++ b/modules/mesh-delivery-watchman/internal/watch/findings_test.go @@ -17,8 +17,8 @@ import ( "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" - "git.novox.be/novox/mesh-sdk/go/provisions" ) func mustEncode(t *testing.T, f Finding) []byte { @@ -474,20 +474,20 @@ func TestTheWatchmansFindings(t *testing.T) { }, map[string]string{"module.fail2ban.novox.unhealthy": Warning}}, {"1954/D2: a provision in waits is its consumer's needs-operator; provided, it ends", func(t *testing.T, w *Watchman, o *fakeOut, c *clock) { enc := func(state, why string) []byte { - b, err := provisions.Encode(provisions.Provision{Provision: "oidc", Consumer: provisions.End{Module: "photos", Node: "ace"}, - Provider: provisions.End{Module: "keycloak", Node: "novox"}, State: state, Why: why, At: t0}) + b, err := meshprovisionerclient.Encode(meshprovisionerclient.Provision{Provision: "oidc", Consumer: meshprovisionerclient.End{Module: "photos", Node: "ace"}, + Provider: meshprovisionerclient.End{Module: "keycloak", Node: "novox"}, State: state, Why: why, At: t0}) if err != nil { t.Fatal(err) } return b } - w.Provision("ace.photos.oidc", enc(provisions.Waits, "the operator gives the client's redirect"), Put) - w.Provision("ace.photos.db", enc(provisions.Provided, ""), Put) + w.Provision("ace.photos.oidc", enc(meshprovisionerclient.Waits, "the operator gives the client's redirect"), Put) + w.Provision("ace.photos.db", enc(meshprovisionerclient.Provided, ""), Put) if f := o.findings["module.photos.ace.needs-operator"]; !strings.Contains(f.Summary, "redirect") || f.Machine != "ace" { t.Fatalf("findings = %v", o.findings) } - w.Provision("ace.photos.oidc", enc(provisions.Provided, ""), Put) - w.Provision("ace.web.oidc", enc(provisions.Waits, "x"), Put) + w.Provision("ace.photos.oidc", enc(meshprovisionerclient.Provided, ""), Put) + w.Provision("ace.web.oidc", enc(meshprovisionerclient.Waits, "x"), Put) w.Provision("ace.web.oidc", nil, Delete) }, map[string]string{}}, {"774: a node's own report: its network, the resolver file rewritten, failed units, a relogin, a directory used as found, a login fallen back", func(t *testing.T, w *Watchman, o *fakeOut, c *clock) { @@ -674,10 +674,10 @@ func TestTheWatchmansFindings(t *testing.T) { w.SetStepBound(30 * time.Minute) held, _ := meshwantsclient.EncodeWant(meshwantsclient.Want{Fp: fpOld, Self: true, Newest: fpNew, Rule: meshwantsclient.RuleCanary, Words: "the canary ace does not run it yet"}) released, _ := meshwantsclient.EncodeWant(meshwantsclient.Want{Fp: fpNew, Self: true}) - asked, _ := provisions.Encode(provisions.Provision{Provision: "oidc", Consumer: provisions.End{Module: "photos", Node: "ace"}, - Provider: provisions.End{Module: "keycloak", Node: "novox"}, State: provisions.Asked, At: t0}) - provided, _ := provisions.Encode(provisions.Provision{Provision: "oidc", Consumer: provisions.End{Module: "photos", Node: "ace"}, - Provider: provisions.End{Module: "keycloak", Node: "novox"}, State: provisions.Provided, At: t0}) + asked, _ := meshprovisionerclient.Encode(meshprovisionerclient.Provision{Provision: "oidc", Consumer: meshprovisionerclient.End{Module: "photos", Node: "ace"}, + Provider: meshprovisionerclient.End{Module: "keycloak", Node: "novox"}, State: meshprovisionerclient.Asked, At: t0}) + provided, _ := meshprovisionerclient.Encode(meshprovisionerclient.Provision{Provision: "oidc", Consumer: meshprovisionerclient.End{Module: "photos", Node: "ace"}, + Provider: meshprovisionerclient.End{Module: "keycloak", Node: "novox"}, State: meshprovisionerclient.Provided, At: t0}) bkey, _ := builds.BuilderBuildKey("web", fpNew) queued, _ := builds.EncodeBuilderBuild(builds.BuilderBuild{State: builds.BuildQueued, Waits: "mesh-sdk@v0.1.14"}) building, _ := builds.EncodeBuilderBuild(builds.BuilderBuild{State: builds.BuildBuilding, By: "n1"}) @@ -685,15 +685,15 @@ func TestTheWatchmansFindings(t *testing.T) { w.Want("want.ace.web", held, Put, t0) w.Provision("ace.photos.oidc", asked, Put) w.Build(bkey, queued, Put, t0) - waits := map[string]string{AssignerWantsBucket: "want.ace.web", provisions.ProvisionsBucket: "ace.photos.oidc", BuilderBuildsBucket: bkey} + waits := map[string]string{AssignerWantsBucket: "want.ace.web", meshprovisionerclient.ProvisionsBucket: "ace.photos.oidc", BuilderBuildsBucket: bkey} if len(o.pulses) != 3 || len(o.findings) != 0 { t.Fatalf("pulses %v findings %v", o.pulses, o.findings) } // The keys are written again as their parts move on, with new words and a new time: the wait still began at t0. c.t = c.t.Add(20 * time.Minute) held2, _ := meshwantsclient.EncodeWant(meshwantsclient.Want{Fp: fpOld, Self: true, Newest: fpNew, Rule: meshwantsclient.RuleCanary, Words: "the canary ace runs it, not healthy yet"}) - asked2, _ := provisions.Encode(provisions.Provision{Provision: "oidc", Consumer: provisions.End{Module: "photos", Node: "ace"}, - Provider: provisions.End{Module: "keycloak", Node: "novox"}, State: provisions.Asked, Why: "the provider is applying", At: c.t}) + asked2, _ := meshprovisionerclient.Encode(meshprovisionerclient.Provision{Provision: "oidc", Consumer: meshprovisionerclient.End{Module: "photos", Node: "ace"}, + Provider: meshprovisionerclient.End{Module: "keycloak", Node: "novox"}, State: meshprovisionerclient.Asked, Why: "the provider is applying", At: c.t}) w.Want("want.ace.web", held2, Put, c.t) w.Provision("ace.photos.oidc", asked2, Put) w.Build(bkey, queued, Put, c.t)