No client names the holder of the seat mesh-provisioner: each reader keeps its own constant, held to its manifest (ADR 0625 section 4, issue 1966)
Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
@@ -100,7 +100,7 @@ func main() {
|
||||
}
|
||||
cfg.Log = say
|
||||
svc := NewService(cfg)
|
||||
p := svc.Provider(provider.StateBus(Module))
|
||||
p := svc.Provider(provider.StateBus(Module, provisionerModule))
|
||||
ctx := context.Background()
|
||||
// A pass answers every consumer; one at a time, and one per change of a machine's key.
|
||||
var passing sync.Mutex
|
||||
@@ -132,3 +132,7 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// provisionerModule is the holder of the seat mesh-provisioner, named from this module's manifest (its `reads` of plans and
|
||||
// provisions; TestTheProvisionerIsTheManifests).
|
||||
const provisionerModule = "mesh-provisioner"
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"slices"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// The module holding the seat mesh-provisioner, which this provider reads the plans and provisions of, is the one its manifest's
|
||||
// `reads` name: no client names a holder (novox/hq ADR 0625 §4).
|
||||
func TestTheProvisionerIsTheManifests(t *testing.T) {
|
||||
raw, err := os.ReadFile("../../module.json")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var m struct {
|
||||
Reads []string `json:"reads"`
|
||||
}
|
||||
if err := json.Unmarshal(raw, &m); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, state := range []string{"plans", "provisions"} {
|
||||
if !slices.Contains(m.Reads, provisionerModule+"."+state) {
|
||||
t.Errorf("the provider reads %s.%s, its manifest's reads are %v", provisionerModule, state, m.Reads)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -125,7 +125,7 @@ func (s *Service) Provider(bus provider.Bus) *provider.Provider {
|
||||
vb := &valuesBus{Bus: bus, s: s, written: map[string][]byte{}}
|
||||
s.bound = vb
|
||||
return provider.New(provider.Options{
|
||||
Node: s.cfg.Node, Module: Module,
|
||||
Node: s.cfg.Node, Module: Module, Provisioner: provisionerModule,
|
||||
Offers: map[string]provider.Offer{ProvisionName: {Credential: provider.NoCredential}},
|
||||
Bus: vb,
|
||||
Make: s.Make, Gone: s.Gone,
|
||||
|
||||
@@ -110,19 +110,19 @@ func (b *fakeBus) bindClient(node string) {
|
||||
// bindPlan makes module on node bind gitea's forge-account as the seat mesh-provisioner keeps it: its plan, and the
|
||||
// provision key asked of gitea on novox (novox/hq ADR 0570 clauses 1 to 3).
|
||||
func (b *fakeBus) bindPlan(node, module, as string) {
|
||||
b.set(meshprovisionerclient.PlansBucket, node+"."+module, []byte(fmt.Sprintf(
|
||||
b.set(meshprovisionerclient.PlansBucketOf(provisionerModule), node+"."+module, []byte(fmt.Sprintf(
|
||||
`{"v":1,"node":%q,"module":%q,"plan":{"provisions":[{"provision":"forge-account","provider":"novox","provider-module":"gitea","as":%q}]}}`,
|
||||
node, module, as)))
|
||||
b.set(meshprovisionerclient.ProvisionsBucket, node+"."+module+".forge-account", provisionKey(node, module, meshprovisionerclient.Asked, nil))
|
||||
b.set(meshprovisionerclient.ProvisionsBucketOf(provisionerModule), node+"."+module+".forge-account", provisionKey(node, module, meshprovisionerclient.Asked, nil))
|
||||
}
|
||||
|
||||
// retire is the operator's yes to the retiring of module's forge-account on node: its plan gone, its key retiring
|
||||
// with the warrant (ADR 0570 clause 5), the only way the provider lets an entry go.
|
||||
func (b *fakeBus) retire(node, module string) {
|
||||
b.mu.Lock()
|
||||
delete(b.buckets[meshprovisionerclient.PlansBucket], node+"."+module)
|
||||
delete(b.buckets[meshprovisionerclient.PlansBucketOf(provisionerModule)], node+"."+module)
|
||||
b.mu.Unlock()
|
||||
b.set(meshprovisionerclient.ProvisionsBucket, node+"."+module+".forge-account", provisionKey(node, module, meshprovisionerclient.Retiring,
|
||||
b.set(meshprovisionerclient.ProvisionsBucketOf(provisionerModule), node+"."+module+".forge-account", provisionKey(node, module, meshprovisionerclient.Retiring,
|
||||
&meshprovisionerclient.Warrant{Ask: "ask-1", Option: "yes", By: "operator", At: time.Date(2026, 10, 29, 12, 0, 0, 0, time.UTC)}))
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ func noOpPlan(bus *bucketBus, node, module string) {
|
||||
// keycloak on novox the key the seat composes, asked (novox/hq ADR 0570 clauses 1 to 3).
|
||||
func seatPlan(bus *bucketBus, node, module string, plan map[string]any) {
|
||||
raw, _ := json.Marshal(map[string]any{"v": 1, "node": node, "module": module, "plan": plan})
|
||||
_ = bus.Put(ctx, meshprovisionerclient.PlansBucket, node+"."+module, raw)
|
||||
_ = bus.Put(ctx, meshprovisionerclient.PlansBucketOf(provisionerModule), node+"."+module, raw)
|
||||
list, _ := plan["provisions"].([]any)
|
||||
for _, e := range list {
|
||||
entry := e.(map[string]any)
|
||||
@@ -64,7 +64,7 @@ func seatPlan(bus *bucketBus, node, module string, plan map[string]any) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_ = bus.Put(ctx, meshprovisionerclient.ProvisionsBucket, key, asked)
|
||||
_ = bus.Put(ctx, meshprovisionerclient.ProvisionsBucketOf(provisionerModule), key, asked)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ func movedWorld(t *testing.T, h *harness.Harness) (f *fakeKeycloak, start func()
|
||||
}
|
||||
bus := &bucketBus{buckets: map[string]map[string][]byte{}}
|
||||
noOpPlan(bus, "elsewhere", "unrelated")
|
||||
p := provider.New(provider.Options{Node: h.Node, Module: "keycloak", Bus: bus,
|
||||
p := provider.New(provider.Options{Provisioner: provisionerModule, Node: h.Node, Module: "keycloak", Bus: bus,
|
||||
Vault: provider.ConsumersFile{Paths: []string{consumersFile}},
|
||||
Offers: map[string]provider.Offer{ProvisionName: {Credential: provider.PerConsumer, Serves: servedValues(testIssuer)}},
|
||||
Make: run.Make, Gone: run.Gone, Every: h.Every, Logf: func(string, ...any) {}})
|
||||
|
||||
@@ -50,9 +50,13 @@ func valuesOf(e provider.Entry) map[string]any {
|
||||
// them. Each client it gives is made and checked by the harness's grant pass exactly as on the grant path; a client
|
||||
// a plan names is the helper's alone.
|
||||
func moved(consumersFile string, h *harness.Harness, issuer string) (*harness.Moved, *provider.Provider, provider.Bus, error) {
|
||||
return harness.NewMoved(consumersFile, h, harness.MovedSpec{Module: "keycloak", Provision: ProvisionName,
|
||||
return harness.NewMoved(consumersFile, h, harness.MovedSpec{Module: "keycloak", Provisioner: provisionerModule, Provision: ProvisionName,
|
||||
Offer: provider.Offer{Credential: provider.PerConsumer, Serves: servedValues(issuer)},
|
||||
Login: func(e provider.Entry) string { return e.As },
|
||||
Values: valuesOf,
|
||||
Noun: "client id", Made: "client", Backend: "Keycloak", WithGrants: true})
|
||||
}
|
||||
|
||||
// provisionerModule is the holder of the seat mesh-provisioner, named from this module's manifest (its `reads` of plans and
|
||||
// provisions; TestTheProvisionerIsTheManifests).
|
||||
const provisionerModule = "mesh-provisioner"
|
||||
|
||||
@@ -158,7 +158,7 @@ func TestBothPathsLeaveTheSameClientInKeycloak(t *testing.T) {
|
||||
seatPlan(bus, "home", "grafana", map[string]any{
|
||||
"provisions": []any{map[string]any{"provision": ProvisionName, "provider": "novox",
|
||||
"provider-module": "keycloak", "contributes": grafanaContributes, "names": grafanaNames}}})
|
||||
pr := provider.New(provider.Options{Node: "novox", Module: "keycloak", Bus: bus,
|
||||
pr := provider.New(provider.Options{Provisioner: provisionerModule, Node: "novox", Module: "keycloak", Bus: bus,
|
||||
Vault: provider.ConsumersFile{Paths: []string{file}},
|
||||
Offers: map[string]provider.Offer{ProvisionName: {Credential: provider.PerConsumer,
|
||||
Serves: servedValues(testIssuer)}},
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"slices"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// The module holding the seat mesh-provisioner, which this provider reads the plans and provisions of, is the one its manifest's
|
||||
// `reads` name: no client names a holder (novox/hq ADR 0625 §4).
|
||||
func TestTheProvisionerIsTheManifests(t *testing.T) {
|
||||
raw, err := os.ReadFile("../../module.json")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var m struct {
|
||||
Reads []string `json:"reads"`
|
||||
}
|
||||
if err := json.Unmarshal(raw, &m); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, state := range []string{"plans", "provisions"} {
|
||||
if !slices.Contains(m.Reads, provisionerModule+"."+state) {
|
||||
t.Errorf("the provider reads %s.%s, its manifest's reads are %v", provisionerModule, state, m.Reads)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,11 +49,14 @@ const (
|
||||
haveBucket = engineHolder + "_" + nodeengine.StateHave
|
||||
)
|
||||
|
||||
// provisionerModule is the module holding the seat mesh-provisioner, whose plans the client reads.
|
||||
const provisionerModule = "mesh-provisioner"
|
||||
|
||||
// The buckets the client reads and writes, and the subject it reports on.
|
||||
const (
|
||||
// PlansBucket is where each module's provisioning plan on each node is read: the seat mesh-provisioner's
|
||||
// `plans` (novox/hq ADR 0570 clause 2), read as an assignment's value carried it (asAssignment).
|
||||
PlansBucket = meshprovisionerclient.PlansBucket
|
||||
PlansBucket = provisionerModule + "_" + meshprovisionerclient.PlansState
|
||||
// PlacementBucket is the seat mesh-module-assigner's placement (novox/hq ADR 0567): a module it names on this node stays
|
||||
// here while the seat mesh-provisioner holds no plan of it (nats on novox runs without a want), filled from its
|
||||
// last plan, and leaves only when neither names it (issue 1126 B12; the controller's assignments mirror, read for
|
||||
|
||||
@@ -55,9 +55,9 @@ func (m *memBus) Delete(_ context.Context, bucket, key string) error {
|
||||
// as the seat mesh-provisioner keeps it (ADR 0570 clause 2).
|
||||
func routeEntryFor(t *testing.T, module, planEntry string) string {
|
||||
t.Helper()
|
||||
bus := &memBus{buckets: map[string]map[string][]byte{meshprovisionerclient.PlansBucket: {
|
||||
bus := &memBus{buckets: map[string]map[string][]byte{meshprovisionerclient.PlansBucketOf(provisionerModule): {
|
||||
node + "." + module: []byte(`{"v":1,"node":"` + node + `","module":"` + module + `","plan":{"provisions":[` +
|
||||
planEntry + `]}}`)}, meshprovisionerclient.ProvisionsBucket: {}}}
|
||||
planEntry + `]}}`)}, meshprovisionerclient.ProvisionsBucketOf(provisionerModule): {}}}
|
||||
// The key the seat composed for that entry, provided-for: asked of route-proxy (ADR 0570 clause 3).
|
||||
var b struct {
|
||||
Provision string `json:"provision"`
|
||||
@@ -76,8 +76,8 @@ func routeEntryFor(t *testing.T, module, planEntry string) string {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
bus.buckets[meshprovisionerclient.ProvisionsBucket][key] = raw
|
||||
p := provider.New(provider.Options{Node: "novox", Module: "route-proxy", Bus: bus, Logf: t.Logf,
|
||||
bus.buckets[meshprovisionerclient.ProvisionsBucketOf(provisionerModule)][key] = raw
|
||||
p := provider.New(provider.Options{Provisioner: provisionerModule, Node: "novox", Module: "route-proxy", Bus: bus, Logf: t.Logf,
|
||||
Offers: map[string]provider.Offer{"route": {Credential: provider.NoCredential, Serves: map[string]any{}}}})
|
||||
out, err := p.Pass(context.Background())
|
||||
if err != nil {
|
||||
@@ -157,3 +157,11 @@ func TestNatsAModuleThatFailedOnAMissingNameIsFilledWhenTheNameArrives(t *testin
|
||||
return e.read(t, "/etc/gitea/origins") == "https://git.example.org\n"
|
||||
})
|
||||
}
|
||||
|
||||
// The module holding the seat mesh-provisioner is this client's own word (the grants part grants the bucket whole; no client
|
||||
// names a holder, novox/hq ADR 0625 §4), and the plans bucket is its state plans.
|
||||
func TestThePlansBucketIsTheSeatsStatePlans(t *testing.T) {
|
||||
if PlansBucket != "mesh-provisioner_plans" || provisionerModule != "mesh-provisioner" {
|
||||
t.Errorf("the plans bucket is %q of %q", PlansBucket, provisionerModule)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,6 +92,9 @@ var BoundReads = []string{"gitea", "keycloak", "postgres", "route-adapter", "rou
|
||||
// (novox/hq ADR 0625 §4).
|
||||
const vaultModule = "mesh-vault"
|
||||
|
||||
// plansRead is the address a provider's manifest's `reads` names this seat's state plans by: the holder is this module.
|
||||
const plansRead = Module + "." + meshprovisionerclient.PlansState
|
||||
|
||||
// boundRead is a provider's entries as this module reads them.
|
||||
func boundRead(module string) string { return module + ".bound" }
|
||||
|
||||
@@ -783,10 +786,10 @@ func (h *Holder) unread(module string) string {
|
||||
var decl struct {
|
||||
Reads []string `json:"reads"`
|
||||
}
|
||||
if json.Unmarshal([]byte(manifest), &decl) != nil || slices.Contains(decl.Reads, meshprovisionerclient.PlansRead) {
|
||||
if json.Unmarshal([]byte(manifest), &decl) != nil || slices.Contains(decl.Reads, plansRead) {
|
||||
return ""
|
||||
}
|
||||
return module + " reads no plans of the seat (its manifest's reads do not name " + meshprovisionerclient.PlansRead +
|
||||
return module + " reads no plans of the seat (its manifest's reads do not name " + plansRead +
|
||||
"), so its helper never answers this key"
|
||||
}
|
||||
|
||||
|
||||
@@ -78,7 +78,14 @@ const ProvisionerPrefix = "provisioner."
|
||||
// seat mesh-provisioner's state `plans`, `<node>.<module>` (novox/hq ADR 0570 clause 2), no longer the controller's
|
||||
// assignments. A plan is read as the assignment's value carried it (asAssignment), so the rules that read a plan are
|
||||
// unchanged.
|
||||
const AssignmentsRead = meshprovisionerclient.PlansRead
|
||||
const AssignmentsRead = provisionerModule + "." + meshprovisionerclient.PlansState
|
||||
|
||||
// ProvisionsRead is the seat's state provisions as the manifest's `reads` names it; provisionerModule the module holding the seat
|
||||
// mesh-provisioner (TestThePlacementNamesAreTheManifests).
|
||||
const (
|
||||
ProvisionsRead = provisionerModule + "." + meshprovisionerclient.ProvisionsState
|
||||
provisionerModule = "mesh-provisioner"
|
||||
)
|
||||
|
||||
// asAssignment is a plan's key in the form the vault's rules read: `{node, module, provisioning: plan}`, nil for none.
|
||||
func asAssignment(key string, raw []byte, err error) ([]byte, error) {
|
||||
|
||||
@@ -9,7 +9,6 @@ package main
|
||||
|
||||
import (
|
||||
"git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient"
|
||||
"git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient"
|
||||
|
||||
"encoding/json"
|
||||
|
||||
@@ -80,7 +79,7 @@ func build() *Env {
|
||||
Delete: func(key string) error { return stdio.State(BoundState).Delete(key) },
|
||||
Keys: func() ([]string, error) { return stdio.State(BoundState).Keys() },
|
||||
Provision: func(key string) ([]byte, error) {
|
||||
e, err := stdio.State(meshprovisionerclient.ProvisionsRead).Get(key)
|
||||
e, err := stdio.State(ProvisionsRead).Get(key)
|
||||
if err != nil || e == nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -220,7 +219,7 @@ func watchCredentialAsks(env *Env, kick chan<- struct{}) bool {
|
||||
if env.Vault == nil {
|
||||
return true
|
||||
}
|
||||
err := stdio.State(meshprovisionerclient.ProvisionsRead).Watch("", func(c stdio.StateChange) error {
|
||||
err := stdio.State(ProvisionsRead).Watch("", func(c stdio.StateChange) error {
|
||||
if !c.Current && credentialAsked(c.Value) {
|
||||
select {
|
||||
case kick <- struct{}{}:
|
||||
|
||||
@@ -86,6 +86,15 @@ func TestThePlacementNamesAreTheManifests(t *testing.T) {
|
||||
if err := json.Unmarshal(raw, &m); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var reads struct {
|
||||
Reads []string `json:"reads"`
|
||||
}
|
||||
_ = json.Unmarshal(raw, &reads)
|
||||
for _, r := range []string{AssignmentsRead, ProvisionsRead} {
|
||||
if !slices.Contains(reads.Reads, r) {
|
||||
t.Errorf("the vault reads %s, its manifest's reads are %v", r, reads.Reads)
|
||||
}
|
||||
}
|
||||
if !slices.Contains(m.Invokes, PlacementTool) || !slices.Contains(m.Consumes, PlacementViewsEvent) {
|
||||
t.Errorf("the vault asks %s and follows %s, its manifest invokes %v and consumes %v", PlacementTool, PlacementViewsEvent, m.Invokes, m.Consumes)
|
||||
}
|
||||
|
||||
@@ -204,9 +204,9 @@ func TestNoBucketHoldsASecret(t *testing.T) {
|
||||
for _, call := range []string{"Get(", "Put(", "Delete(", "Keys("} {
|
||||
code = []byte(strings.Replace(string(code), "stdio.State(BoundState)."+call, "", 1))
|
||||
}
|
||||
code = []byte(strings.Replace(string(code), "stdio.State(meshprovisionerclient.ProvisionsRead).Get(", "", 1))
|
||||
code = []byte(strings.Replace(string(code), "stdio.State(ProvisionsRead).Get(", "", 1))
|
||||
// And one watch of them, for a credential asked of the vault (issue 1126).
|
||||
code = []byte(strings.Replace(string(code), "stdio.State(meshprovisionerclient.ProvisionsRead).Watch(", "", 1))
|
||||
code = []byte(strings.Replace(string(code), "stdio.State(ProvisionsRead).Watch(", "", 1))
|
||||
}
|
||||
if m := bucket.Find(code); m != nil {
|
||||
t.Errorf("%s opens a bucket (%s): the vault keeps every secret in its own store only", f, m)
|
||||
|
||||
@@ -30,8 +30,12 @@ const ProvisionName = "postgres-database"
|
||||
// It serves its consumers the port its server is published on, on its machine (servedPort), never the container's
|
||||
// own 5432: on a machine that publishes it elsewhere (6852:5432 on novox) nothing answers 5432 (issue 957).
|
||||
func moved(consumersFile string, h *harness.Harness, servedPort int) (*harness.Moved, *provider.Provider, provider.Bus, error) {
|
||||
return harness.NewMoved(consumersFile, h, harness.MovedSpec{Module: "postgres", Provision: ProvisionName,
|
||||
return harness.NewMoved(consumersFile, h, harness.MovedSpec{Module: "postgres", Provisioner: provisionerModule, Provision: ProvisionName,
|
||||
Offer: provider.Offer{Credential: provider.PerConsumer, Serves: map[string]any{"port": servedPort}},
|
||||
Login: func(e provider.Entry) string { return e.User },
|
||||
Noun: "login", Made: "login", Backend: "the backend", WithGrants: true})
|
||||
}
|
||||
|
||||
// provisionerModule is the holder of the seat mesh-provisioner, named from this module's manifest (its `reads` of plans and
|
||||
// provisions; TestTheProvisionerIsTheManifests).
|
||||
const provisionerModule = "mesh-provisioner"
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"slices"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// The module holding the seat mesh-provisioner, which this provider reads the plans and provisions of, is the one its manifest's
|
||||
// `reads` name: no client names a holder (novox/hq ADR 0625 §4).
|
||||
func TestTheProvisionerIsTheManifests(t *testing.T) {
|
||||
raw, err := os.ReadFile("../../module.json")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var m struct {
|
||||
Reads []string `json:"reads"`
|
||||
}
|
||||
if err := json.Unmarshal(raw, &m); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, state := range []string{"plans", "provisions"} {
|
||||
if !slices.Contains(m.Reads, provisionerModule+"."+state) {
|
||||
t.Errorf("the provider reads %s.%s, its manifest's reads are %v", provisionerModule, state, m.Reads)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ func main() {
|
||||
if node == "" {
|
||||
say("MESH_NODE is not set; answering no consumers")
|
||||
} else {
|
||||
p := newProvider(node, provider.StateBus(ModuleName), say)
|
||||
p := newProvider(node, provider.StateBus(ModuleName, provisionerModule), say)
|
||||
go func() {
|
||||
if err := p.Run(context.Background()); err != nil {
|
||||
say("the provider helper stopped: %v", err)
|
||||
@@ -35,3 +35,7 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// provisionerModule is the holder of the seat mesh-provisioner, named from this module's manifest (its `reads` of plans and
|
||||
// provisions; TestTheProvisionerIsTheManifests).
|
||||
const provisionerModule = "mesh-provisioner"
|
||||
|
||||
@@ -25,7 +25,7 @@ const ModuleName = "route-adapter"
|
||||
func newProvider(node string, bus provider.Bus, logf func(string, ...any)) *provider.Provider {
|
||||
return provider.New(provider.Options{
|
||||
Node: node,
|
||||
Module: ModuleName,
|
||||
Module: ModuleName, Provisioner: provisionerModule,
|
||||
Offers: map[string]provider.Offer{ProvisionName: {
|
||||
Credential: provider.NoCredential,
|
||||
Serves: map[string]any{},
|
||||
|
||||
@@ -51,7 +51,7 @@ func TestAConsumerOfARouteIsToldItsNamesFromItsPlanEntry(t *testing.T) {
|
||||
"provider-module": ModuleName, "at": "10.7.0.1", "from": "novox", "as": "mesh_g14_gitea",
|
||||
"names": map[string]any{"name": "git.example.org", "internal-name": "git.novox.internal",
|
||||
"name-web": "git.example.org"}}}}})
|
||||
if err := bus.Put(context.Background(), meshprovisionerclient.PlansBucket, "g14.gitea", plan); err != nil {
|
||||
if err := bus.Put(context.Background(), meshprovisionerclient.PlansBucketOf(provisionerModule), "g14.gitea", plan); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// The key the seat composed for the entry, asked of route-adapter (novox/hq ADR 0570 clauses 1, 3).
|
||||
@@ -61,7 +61,7 @@ func TestAConsumerOfARouteIsToldItsNamesFromItsPlanEntry(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := bus.Put(context.Background(), meshprovisionerclient.ProvisionsBucket, key, asked); err != nil {
|
||||
if err := bus.Put(context.Background(), meshprovisionerclient.ProvisionsBucketOf(provisionerModule), key, asked); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
p := newProvider("novox", bus, t.Logf)
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"slices"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// The module holding the seat mesh-provisioner, which this provider reads the plans and provisions of, is the one its manifest's
|
||||
// `reads` name: no client names a holder (novox/hq ADR 0625 §4).
|
||||
func TestTheProvisionerIsTheManifests(t *testing.T) {
|
||||
raw, err := os.ReadFile("../../module.json")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var m struct {
|
||||
Reads []string `json:"reads"`
|
||||
}
|
||||
if err := json.Unmarshal(raw, &m); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, state := range []string{"plans", "provisions"} {
|
||||
if !slices.Contains(m.Reads, provisionerModule+"."+state) {
|
||||
t.Errorf("the provider reads %s.%s, its manifest's reads are %v", provisionerModule, state, m.Reads)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user