assigner, view, watchman: provisions come from meshprovisionerclient, not mesh-sdk go/provisions (ADR 0634 §4; issue 1966)

Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
2026-11-05 16:45:25 +01:00
parent e52d9d7791
commit 738c8ca036
15 changed files with 91 additions and 84 deletions
@@ -37,13 +37,13 @@ import (
oc "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel" oc "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel"
mmac "git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient" mmac "git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient"
mma "git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner" 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" stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/announce" "git.novox.be/novox/mesh-sdk/go/announce"
"git.novox.be/novox/mesh-sdk/go/buscompose" "git.novox.be/novox/mesh-sdk/go/buscompose"
"git.novox.be/novox/mesh-sdk/go/catalogue" "git.novox.be/novox/mesh-sdk/go/catalogue"
"git.novox.be/novox/mesh-sdk/go/health" "git.novox.be/novox/mesh-sdk/go/health"
"git.novox.be/novox/mesh-sdk/go/process" "git.novox.be/novox/mesh-sdk/go/process"
"git.novox.be/novox/mesh-sdk/go/provisions"
"mesh-delivery-assigner/internal/judge" "mesh-delivery-assigner/internal/judge"
"git.novox.be/novox/mesh-contracts/go/seats/nodeengine" "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"]}`) appDigest := b.manifest(t, "app", `{"module":"app","version":"1","requires":["database"]}`)
toolDigest := b.manifest(t, "tool", `{"module":"tool","version":"1"}`) toolDigest := b.manifest(t, "tool", `{"module":"tool","version":"1"}`)
asked := func(state, why string) { asked := func(state, why string) {
raw, err := provisions.Encode(provisions.Provision{V: provisions.Version, Provision: "database", Consumer: provisions.End{Module: "app", Node: "ace"}, raw, err := meshprovisionerclient.Encode(meshprovisionerclient.Provision{V: meshprovisionerclient.Version, Provision: "database", Consumer: meshprovisionerclient.End{Module: "app", Node: "ace"},
Provider: provisions.End{Module: "db", Node: "ace"}, State: state, Why: why, At: time.Now()}) Provider: meshprovisionerclient.End{Module: "db", Node: "ace"}, State: state, Why: why, At: time.Now()})
if err != nil { if err != nil {
t.Fatal(err) 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. // 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) } fpOf := func(c byte) string { return meshcatalogclient.SourcePrefix2 + strings.Repeat(string(c), 64) }
toolOld := fpOf('1') toolOld := fpOf('1')
for module, row := range map[string]struct { 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 { 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()) 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') { 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) t.Errorf("app's want = %+v", w)
} }
@@ -26,10 +26,10 @@ import (
occ "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/clients/operatorchannelclient" 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" oc "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel"
mma "git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner" 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/announce"
"git.novox.be/novox/mesh-sdk/go/health" "git.novox.be/novox/mesh-sdk/go/health"
"git.novox.be/novox/mesh-sdk/go/process" "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-delivery/sdk/enginereads"
"git.novox.be/novox/mesh-sdk/go/views" "git.novox.be/novox/mesh-sdk/go/views"
@@ -64,7 +64,7 @@ var readBuckets = []string{
buckets.Builds, buckets.Builds,
buckets.Presence, buckets.Presence,
buckets.Have, buckets.Have,
provisions.ProvisionsBucket, meshprovisionerclient.ProvisionsBucket,
buckets.Source, buckets.Source,
buckets.Merges, 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) logf("the bucket %s cannot be opened (%v): it is bound once the bus says it was made", name, err)
continue 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; // 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. // 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) 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. // 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 { func startsWithout(name string) bool {
switch name { 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: buckets.Puts, buckets.Source, buckets.Merges, engineReadsBucket:
return true return true
} }
@@ -282,7 +282,7 @@ var watched = []string{
buckets.Differences, buckets.Differences,
buckets.Wants, buckets.Wants,
assign.PoliciesBucket, assign.PoliciesBucket,
provisions.ProvisionsBucket, meshprovisionerclient.ProvisionsBucket,
plc.SeatHoldersBucket, plc.SeatHoldersBucket,
buckets.Source, buckets.Source,
buckets.Merges, 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. // 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 { if kvs[name] == nil && js != nil {
name := name name := name
process.AwaitBucket(ctx, js, nc, name, "until then the bucket is not read", process.AwaitBucket(ctx, js, nc, name, "until then the bucket is not read",
@@ -19,8 +19,8 @@ import (
"time" "time"
oc "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel" 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/catalogue"
"git.novox.be/novox/mesh-sdk/go/provisions"
"git.novox.be/novox/mesh-delivery/sdk/enginereads" "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 // 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.<key>.provision-failed` (a waiting one is the watchman's // provision is also said as the assigner's finding `provider.<key>.provision-failed` (a waiting one is the watchman's
// needs-operator), deleted once it is no longer failed. // needs-operator), deleted once it is no longer failed.
func (p *passer) provisionsOf() func(module string) func(node string) map[string]provisions.Provision { func (p *passer) provisionsOf() func(module string) func(node string) map[string]meshprovisionerclient.Provision {
if p.kvs[provisions.ProvisionsBucket] == nil { if p.kvs[meshprovisionerclient.ProvisionsBucket] == nil {
return func(string) func(string) map[string]provisions.Provision { return nil } return func(string) func(string) map[string]meshprovisionerclient.Provision { return nil }
} }
by := map[string]map[string]map[string]provisions.Provision{} // module, node, key by := map[string]map[string]map[string]meshprovisionerclient.Provision{} // module, node, key
failed := map[string]provisions.Provision{} failed := map[string]meshprovisionerclient.Provision{}
for key, raw := range p.w.read(provisions.ProvisionsBucket) { for key, raw := range p.w.read(meshprovisionerclient.ProvisionsBucket) {
pr, err := provisions.Decode(raw) pr, err := meshprovisionerclient.Decode(raw)
if err != nil { if err != nil {
continue continue
} }
node, module := pr.Consumer.Node, pr.Consumer.Module node, module := pr.Consumer.Node, pr.Consumer.Module
if by[module] == nil { 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 { if by[module][node] == nil {
by[module][node] = map[string]provisions.Provision{} by[module][node] = map[string]meshprovisionerclient.Provision{}
} }
by[module][node][key] = pr by[module][node][key] = pr
if pr.State == provisions.Failed { if pr.State == meshprovisionerclient.Failed {
failed[key] = pr failed[key] = pr
} }
} }
p.provisionFindings(failed) p.provisionFindings(failed)
return func(module string) func(string) map[string]provisions.Provision { return func(module string) func(string) map[string]meshprovisionerclient.Provision {
return func(node string) map[string]provisions.Provision { return by[module][node] } 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. // 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 { if p.findings.Put == nil {
return return
} }
@@ -20,10 +20,10 @@ import (
mmac "git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient" mmac "git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient"
mma "git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner" 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" stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/catalogue" "git.novox.be/novox/mesh-sdk/go/catalogue"
"git.novox.be/novox/mesh-sdk/go/health" "git.novox.be/novox/mesh-sdk/go/health"
"git.novox.be/novox/mesh-sdk/go/provisions"
"github.com/nats-io/nats.go/jetstream" "github.com/nats-io/nats.go/jetstream"
"mesh-delivery-assigner/internal/assign" "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) { t.Run("1954/D1: a failed provision is the assigner's finding until it is provided", func(t *testing.T) {
findings := map[string][]byte{} 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 }, Put: func(k string, v []byte) error { findings[k] = v; return nil },
Delete: func(k string) error { delete(findings, k); 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"}, failed, _ := meshprovisionerclient.Encode(meshprovisionerclient.Provision{Provision: "db", Consumer: meshprovisionerclient.End{Module: "photos", Node: "ace"},
Provider: provisions.End{Module: "postgres", Node: "novox"}, State: provisions.Failed, Why: "the role exists already"}) Provider: meshprovisionerclient.End{Module: "postgres", Node: "novox"}, State: meshprovisionerclient.Failed, Why: "the role exists already"})
p.w.putEntry(provisions.ProvisionsBucket, "ace.photos.db", failed, 1, time.Now()) p.w.putEntry(meshprovisionerclient.ProvisionsBucket, "ace.photos.db", failed, 1, time.Now())
p.kvs[provisions.ProvisionsBucket] = &memKV{} p.kvs[meshprovisionerclient.ProvisionsBucket] = &memKV{}
of := p.provisionsOf() 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) t.Fatalf("provisions = %+v", got)
} }
if _, ok := findings[assign.ProvisionFailedKey("ace.photos.db")]; !ok || len(findings) != 1 { if _, ok := findings[assign.ProvisionFailedKey("ace.photos.db")]; !ok || len(findings) != 1 {
t.Fatalf("findings = %v", findings) t.Fatalf("findings = %v", findings)
} }
provided, _ := provisions.Encode(provisions.Provision{Provision: "db", Consumer: provisions.End{Module: "photos", Node: "ace"}, provided, _ := meshprovisionerclient.Encode(meshprovisionerclient.Provision{Provision: "db", Consumer: meshprovisionerclient.End{Module: "photos", Node: "ace"},
Provider: provisions.End{Module: "postgres", Node: "novox"}, State: provisions.Provided}) Provider: meshprovisionerclient.End{Module: "postgres", Node: "novox"}, State: meshprovisionerclient.Provided})
p.w.putEntry(provisions.ProvisionsBucket, "ace.photos.db", provided, 2, time.Now()) p.w.putEntry(meshprovisionerclient.ProvisionsBucket, "ace.photos.db", provided, 2, time.Now())
p.provisionsOf() p.provisionsOf()
if len(findings) != 0 { if len(findings) != 0 {
t.Errorf("findings after provided = %v", findings) t.Errorf("findings after provided = %v", findings)
+1
View File
@@ -3,6 +3,7 @@ module mesh-delivery-assigner
go 1.26.0 go 1.26.0
require ( 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/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/clients/meshmoduleassignerclient v0.0.0
git.novox.be/novox/mesh-contracts/placement/go/seats/meshwants v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-contracts/placement/go/seats/meshwants v0.0.0-00010101000000-000000000000
@@ -10,9 +10,9 @@ import (
"time" "time"
occ "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/clients/operatorchannelclient" 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/catalogue"
"git.novox.be/novox/mesh-sdk/go/health" "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 // 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. // 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, 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) 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, return health.EncodeFinding(health.Finding{Key: ProvisionFailedKey(key), Kind: KindProvisionFailed,
@@ -14,8 +14,8 @@ import (
"strings" "strings"
"time" "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/catalogue"
"git.novox.be/novox/mesh-sdk/go/provisions"
"git.novox.be/novox/mesh-delivery/sdk/forms" "git.novox.be/novox/mesh-delivery/sdk/forms"
"git.novox.be/novox/mesh-delivery/sdk/graph" "git.novox.be/novox/mesh-delivery/sdk/graph"
@@ -40,7 +40,7 @@ type Module struct {
Manifest catalogue.Manifest Manifest catalogue.Manifest
// Provisions is the seat mesh-provisioner's provisions this module consumes on a node, by key (ADR 0570 §4): the want // 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. // 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 // 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. // 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 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)) { 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) words := fmt.Sprintf("the provision %s of %s on %s is %s, not provided", key, m.Name, node, p.State)
if p.Why != "" { if p.Why != "" {
words += ": " + p.Why words += ": " + p.Why
@@ -14,8 +14,8 @@ import (
"testing" "testing"
"time" "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/catalogue"
"git.novox.be/novox/mesh-sdk/go/provisions"
"git.novox.be/novox/mesh-delivery/sdk/graph" "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. // 1954/D1 (ADR 0570 §4): a provision of the module on that node still asked holds its want.
mwc.RuleProvisions: func(m *Module, _ *Nodes) { mwc.RuleProvisions: func(m *Module, _ *Nodes) {
m.Provisions = func(node string) map[string]provisions.Provision { m.Provisions = func(node string) map[string]meshprovisionerclient.Provision {
return map[string]provisions.Provision{node + ".mail.database": {Provision: "database", State: provisions.Asked}, node + ".mail.oidc": {Provision: "oidc", State: provisions.Provided}} 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. // 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{ for _, all := range []func(string) map[string]meshprovisionerclient.Provision{
func(node string) map[string]provisions.Provision { func(node string) map[string]meshprovisionerclient.Provision {
return map[string]provisions.Provision{node + ".mail.database": {Provision: "database", State: provisions.Provided}} return map[string]meshprovisionerclient.Provision{node + ".mail.database": {Provision: "database", State: meshprovisionerclient.Provided}}
}, nil} { }, nil} {
m, n := ready() m, n := ready()
m.Provisions = all m.Provisions = all
@@ -216,13 +216,13 @@ func TestEachRuleHoldsTheWantBack(t *testing.T) {
name string name string
state, older string state, older string
moves bool moves bool
}{{"the replaced edge provided, the older edge retiring", provisions.Provided, provisions.Retiring, true}, }{{"the replaced edge provided, the older edge retiring", meshprovisionerclient.Provided, meshprovisionerclient.Retiring, true},
{"the replaced edge provided, the older edge asked", provisions.Provided, provisions.Asked, true}, {"the replaced edge provided, the older edge asked", meshprovisionerclient.Provided, meshprovisionerclient.Asked, true},
{"the replaced edge asked, the older edge retiring", provisions.Asked, provisions.Retiring, false}} { {"the replaced edge asked, the older edge retiring", meshprovisionerclient.Asked, meshprovisionerclient.Retiring, false}} {
m, n := ready() m, n := ready()
m.Manifest.Requires = []string{"oidc"} m.Manifest.Requires = []string{"oidc"}
m.Provisions = func(node string) map[string]provisions.Provision { m.Provisions = func(node string) map[string]meshprovisionerclient.Provision {
return map[string]provisions.Provision{node + ".mail.oidc": {Provision: "oidc", State: c.state}, 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"}} node + ".mail.database": {Provision: "database", State: c.older, Why: "the operator's answer"}}
} }
out := Wants(m, n, wantedOld(), nil) out := Wants(m, n, wantedOld(), nil)
@@ -267,7 +267,9 @@ func TestEachRuleHoldsTheWantBack(t *testing.T) {
} { } {
m, n := ready() m, n := ready()
m.Manifest, m.Answering = c.manifest, answering 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) out := Wants(m, n, wantedOld(), nil)
if c.missing == "" { if c.missing == "" {
if out.Wants["g14"].Fp != fNew || len(m.MissingProvisions("g14")) != 0 { 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.Manifest.Requires = []string{c.requires}
m.Answering = func(string) []catalogue.Manifest { return nil } m.Answering = func(string) []catalogue.Manifest { return nil }
m.Offered = func(p string) bool { return c.offered && p == c.requires } 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) out := Wants(m, n, wantedOld(), nil)
if got := out.Wants["g14"].Fp == fNew; got != c.offered || (!c.offered && (out.Rules["g14"].Rule != mwc.RuleProvisions || 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"))) { !strings.Contains(out.Rules["g14"].Words, "no module offers database yet") || !strings.Contains(out.Rules["g14"].Words, "past its bound"))) {
@@ -14,6 +14,7 @@ import (
"git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient" "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/meshhandactsclient"
"git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshwatchdogsclient" "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-builder/builds"
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein"
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-view/viewstate" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-view/viewstate"
@@ -21,7 +22,6 @@ import (
"git.novox.be/novox/mesh-delivery/sdk/enginereads" "git.novox.be/novox/mesh-delivery/sdk/enginereads"
stdio "git.novox.be/novox/mesh-sdk/go" stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/busretry" "git.novox.be/novox/mesh-sdk/go/busretry"
"git.novox.be/novox/mesh-sdk/go/provisions"
"git.novox.be/novox/mesh-sdk/go/views" "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.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.PresenceState, r.StuckState = read(stdio.State(view.StatusPresenceState)), read(stdio.State(view.StatusStuckState))
r.SourceState = read(stdio.State(view.GateModule + ".source")) 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.BuildLog = stdio.Log(builds.BuildLogRead).Since
r.Pending = pendingOf r.Pending = pendingOf
u := view.UsageReader{Haves: r.HavesState, Resolved: read(stdio.State("mesh-config.resolved")), Tries: read(stdio.State("mesh-delivery-checker.tries")), u := view.UsageReader{Haves: r.HavesState, Resolved: read(stdio.State("mesh-config.resolved")), Tries: read(stdio.State("mesh-delivery-checker.tries")),
@@ -14,12 +14,12 @@ import (
"git.novox.be/novox/mesh-contracts/go/seats/nodeengine" "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/health-and-repair/go/clients/meshwatchdogsclient"
"git.novox.be/novox/mesh-contracts/placement/go/clients/meshwantsclient" "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/meshcatalogclient"
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog" "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-builder/builds"
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein"
"git.novox.be/novox/mesh-delivery/sdk/graph" "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. // 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 }.reader().State
r.WantsState.History = func(string) ([]view.Revision, error) { return []view.Revision{{At: since}}, nil } 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 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"}, p, err := meshprovisionerclient.Encode(meshprovisionerclient.Provision{Provision: "database", Consumer: meshprovisionerclient.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}) 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(provisions.Key("ace", "web", "database", "")): encoded(t, p, err)}.reader().State r.ProvisionsState = fake{key(meshprovisionerclient.Key("ace", "web", "database", "")): encoded(t, p, err)}.reader().State
off, err := meshwatchdogsclient.EncodeNodePresence(meshwatchdogsclient.NodePresence{Online: false}) off, err := meshwatchdogsclient.EncodeNodePresence(meshwatchdogsclient.NodePresence{Online: false})
r.PresenceState = fake{key(meshwatchdogsclient.PresenceNodeKey("g14")): encoded(t, off, err)}.reader().State r.PresenceState = fake{key(meshwatchdogsclient.PresenceNodeKey("g14")): encoded(t, off, err)}.reader().State
+1
View File
@@ -3,6 +3,7 @@ module mesh-delivery-view
go 1.26.0 go 1.26.0
require ( 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/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/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 git.novox.be/novox/mesh-contracts/identity-and-access/go/clients/meshvaultclient v0.0.0-00010101000000-000000000000
@@ -12,13 +12,13 @@ import (
"git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient" "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/health-and-repair/go/clients/meshwatchdogsclient"
"git.novox.be/novox/mesh-contracts/placement/go/clients/meshwantsclient" "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/meshcatalogclient"
"git.novox.be/novox/mesh-delivery/contracts/go/clients/meshdeliveryclient" "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/contracts/go/seats/meshcatalog"
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" "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-indexer/takein"
"git.novox.be/novox/mesh-delivery/sdk/graph" "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 // 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 { if perr != nil {
return []TierWait{{Edge: edge, Node: node, Words: "the provisioner's keys cannot be read: " + perr.Error()}} 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 var out []TierWait
found := false found := false
for _, key := range slices.Sorted(maps.Keys(provided)) { for _, key := range slices.Sorted(maps.Keys(provided)) {
@@ -397,12 +397,12 @@ func provisionWaits(node, module, a string, provided map[string]json.RawMessage,
continue continue
} }
found = true found = true
p, err := provisions.Decode(provided[key]) p, err := meshprovisionerclient.Decode(provided[key])
if err != nil { if err != nil {
out = append(out, TierWait{Edge: edge, Node: node, Words: "the provision key " + key + " does not read: " + err.Error()}) out = append(out, TierWait{Edge: edge, Node: node, Words: "the provision key " + key + " does not read: " + err.Error()})
continue continue
} }
if p.State == provisions.Provided { if p.State == meshprovisionerclient.Provided {
continue continue
} }
words := "the provision " + key + " is " + p.State words := "the provision " + key + " is " + p.State
@@ -26,10 +26,10 @@ import (
"github.com/nats-io/nats.go/jetstream" "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/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/contracts/go/clients/meshcatalogclient"
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein"
"git.novox.be/novox/mesh-delivery/sdk/buildstep" "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/socket"
"mesh-delivery-watchman/internal/watch" "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) { 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)) }) pw, err := settle(ctx, kv, func(e jetstream.KeyValueEntry) { w.Provision(e.Key(), e.Value(), opOf(e)) })
if err == nil { if err == nil {
w.ReadWhole(provisions.ProvisionsBucket) w.ReadWhole(meshprovisionerclient.ProvisionsBucket)
} }
return pw, err return pw, err
} }
var provWatch jetstream.KeyWatcher 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 { 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 { } 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) { logger.Printf).Ready(func(kv jetstream.KeyValue) {
pw, err := provisionsWatch(kv) pw, err := provisionsWatch(kv)
if err != nil { 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 return
} }
go func() { go func() {
+1
View File
@@ -3,6 +3,7 @@ module mesh-delivery-watchman
go 1.26.0 go 1.26.0
require ( 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/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/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 git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshwatchdogsclient v0.0.0-00010101000000-000000000000
@@ -17,8 +17,8 @@ import (
"git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-delivery/sdk/buildstep"
"git.novox.be/novox/mesh-sdk/go/health" "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-delivery/sdk/heard"
"git.novox.be/novox/mesh-sdk/go/provisions"
) )
func mustEncode(t *testing.T, f Finding) []byte { 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}}, }, 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) { {"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 { enc := func(state, why string) []byte {
b, err := provisions.Encode(provisions.Provision{Provision: "oidc", Consumer: provisions.End{Module: "photos", Node: "ace"}, b, err := meshprovisionerclient.Encode(meshprovisionerclient.Provision{Provision: "oidc", Consumer: meshprovisionerclient.End{Module: "photos", Node: "ace"},
Provider: provisions.End{Module: "keycloak", Node: "novox"}, State: state, Why: why, At: t0}) Provider: meshprovisionerclient.End{Module: "keycloak", Node: "novox"}, State: state, Why: why, At: t0})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
return b return b
} }
w.Provision("ace.photos.oidc", enc(provisions.Waits, "the operator gives the client's redirect"), Put) w.Provision("ace.photos.oidc", enc(meshprovisionerclient.Waits, "the operator gives the client's redirect"), Put)
w.Provision("ace.photos.db", enc(provisions.Provided, ""), 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" { if f := o.findings["module.photos.ace.needs-operator"]; !strings.Contains(f.Summary, "redirect") || f.Machine != "ace" {
t.Fatalf("findings = %v", o.findings) t.Fatalf("findings = %v", o.findings)
} }
w.Provision("ace.photos.oidc", enc(provisions.Provided, ""), Put) w.Provision("ace.photos.oidc", enc(meshprovisionerclient.Provided, ""), Put)
w.Provision("ace.web.oidc", enc(provisions.Waits, "x"), Put) w.Provision("ace.web.oidc", enc(meshprovisionerclient.Waits, "x"), Put)
w.Provision("ace.web.oidc", nil, Delete) w.Provision("ace.web.oidc", nil, Delete)
}, map[string]string{}}, }, 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) { {"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) 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"}) 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}) released, _ := meshwantsclient.EncodeWant(meshwantsclient.Want{Fp: fpNew, Self: true})
asked, _ := provisions.Encode(provisions.Provision{Provision: "oidc", Consumer: provisions.End{Module: "photos", Node: "ace"}, asked, _ := meshprovisionerclient.Encode(meshprovisionerclient.Provision{Provision: "oidc", Consumer: meshprovisionerclient.End{Module: "photos", Node: "ace"},
Provider: provisions.End{Module: "keycloak", Node: "novox"}, State: provisions.Asked, At: t0}) Provider: meshprovisionerclient.End{Module: "keycloak", Node: "novox"}, State: meshprovisionerclient.Asked, At: t0})
provided, _ := provisions.Encode(provisions.Provision{Provision: "oidc", Consumer: provisions.End{Module: "photos", Node: "ace"}, provided, _ := meshprovisionerclient.Encode(meshprovisionerclient.Provision{Provision: "oidc", Consumer: meshprovisionerclient.End{Module: "photos", Node: "ace"},
Provider: provisions.End{Module: "keycloak", Node: "novox"}, State: provisions.Provided, At: t0}) Provider: meshprovisionerclient.End{Module: "keycloak", Node: "novox"}, State: meshprovisionerclient.Provided, At: t0})
bkey, _ := builds.BuilderBuildKey("web", fpNew) bkey, _ := builds.BuilderBuildKey("web", fpNew)
queued, _ := builds.EncodeBuilderBuild(builds.BuilderBuild{State: builds.BuildQueued, Waits: "mesh-sdk@v0.1.14"}) queued, _ := builds.EncodeBuilderBuild(builds.BuilderBuild{State: builds.BuildQueued, Waits: "mesh-sdk@v0.1.14"})
building, _ := builds.EncodeBuilderBuild(builds.BuilderBuild{State: builds.BuildBuilding, By: "n1"}) 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.Want("want.ace.web", held, Put, t0)
w.Provision("ace.photos.oidc", asked, Put) w.Provision("ace.photos.oidc", asked, Put)
w.Build(bkey, queued, Put, t0) 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 { if len(o.pulses) != 3 || len(o.findings) != 0 {
t.Fatalf("pulses %v findings %v", o.pulses, o.findings) 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. // 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) 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"}) 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"}, asked2, _ := meshprovisionerclient.Encode(meshprovisionerclient.Provision{Provision: "oidc", Consumer: meshprovisionerclient.End{Module: "photos", Node: "ace"},
Provider: provisions.End{Module: "keycloak", Node: "novox"}, State: provisions.Asked, Why: "the provider is applying", At: c.t}) 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.Want("want.ace.web", held2, Put, c.t)
w.Provision("ace.photos.oidc", asked2, Put) w.Provision("ace.photos.oidc", asked2, Put)
w.Build(bkey, queued, Put, c.t) w.Build(bkey, queued, Put, c.t)