From df351458aadb0d06383679722a670df6beb9fcc0 Mon Sep 17 00:00:00 2001 From: mesh-tools Date: Tue, 20 Oct 2026 11:10:35 +0000 Subject: [PATCH] stage 2 of 8 for issue 1389 --- cmd/mesh-controller/compose_sdk_test.go | 34 ++++++----------- cmd/mesh-controller/config_moved_test.go | 8 +--- cmd/mesh-controller/core_box.go | 24 ++++-------- .../core_box_integration_test.go | 2 +- cmd/mesh-controller/core_box_test.go | 12 +++--- .../credential_on_assign_test.go | 2 +- cmd/mesh-controller/epoch_send_test.go | 12 +----- cmd/mesh-controller/facts.go | 37 ------------------- cmd/mesh-controller/facts_test.go | 6 +-- cmd/mesh-controller/generation.go | 13 ------- .../grant_follows_binding_integration_test.go | 18 ++++----- cmd/mesh-controller/grants_step_store_test.go | 8 +--- cmd/mesh-controller/held_back.go | 7 +--- .../held_back_integration_test.go | 12 +----- cmd/mesh-controller/held_back_test.go | 17 --------- cmd/mesh-controller/holdings_test.go | 2 +- .../identity_bound_integration_test.go | 6 +-- .../issue201_integration_test.go | 2 +- 18 files changed, 51 insertions(+), 171 deletions(-) diff --git a/cmd/mesh-controller/compose_sdk_test.go b/cmd/mesh-controller/compose_sdk_test.go index dddfd8a7..8d6a3cb8 100644 --- a/cmd/mesh-controller/compose_sdk_test.go +++ b/cmd/mesh-controller/compose_sdk_test.go @@ -8,7 +8,6 @@ import ( "git.novox.be/novox/mesh-sdk/go/catalogue" "git.novox.be/novox/mesh-sdk/go/compose" - "github.com/novox/mesh-controller/internal/inventory" ) // A declaration as the SDK composes it is the one the controller sends, byte for byte, whatever it carries: the body is the @@ -38,39 +37,28 @@ func TestASendableIsTheComposedDeclarationByteForByte(t *testing.T) { } } -// 1386: what a send records as carried is what the controller's own carriedOn recorded. +// 1386: what a send records as carried: the current build of each module it carries, the build a module left out of it was last +// sent (when that is known), and a module kept at the build the machine runs at that one. (The controller's carriedOn recorded +// the same; mesh-sdk's node_test TestAModuleLeftOutKeepsTheBuildItWasLastSent holds the left-out case.) func TestWhatASendRecordsAsCarriedIsWhatTheControllerRecorded(t *testing.T) { plan := catalogue.Resolution{Modules: []catalogue.Manifest{{Module: "postgres"}, {Module: "files"}, {Module: "cache"}}} - current := map[string]inventory.CurrentBuild{"postgres": {Commit: "p2"}, "files": {Commit: "f2"}, "cache": {Commit: "c2"}} leftOut := map[string]string{"cache": "a setting cannot compose"} for name, c := range map[string]struct { sent map[string]string known bool kept map[string]string + want map[string]string }{ - "nothing sent": {}, - "sent and kept": {sent: map[string]string{"postgres": "p1", "cache": "c1", "files": "f1"}, known: true, kept: map[string]string{"postgres": "p1"}}, - "sent but not known": {sent: map[string]string{"cache": "c1"}}, - "kept a module not in": {known: true, kept: map[string]string{"mail": "m1"}}, + "nothing sent": {want: map[string]string{"postgres": "p2", "files": "f2"}}, + "sent and kept": {sent: map[string]string{"postgres": "p1", "cache": "c1", "files": "f1"}, known: true, + kept: map[string]string{"postgres": "p1"}, want: map[string]string{"postgres": "p1", "files": "f2", "cache": "c1"}}, + "sent but not known": {sent: map[string]string{"cache": "c1"}, want: map[string]string{"postgres": "p2", "files": "f2"}}, + "kept a module not in": {known: true, kept: map[string]string{"mail": "m1"}, want: map[string]string{"postgres": "p2", "files": "f2"}}, } { - var names []string - for _, m := range plan.Modules { - names = append(names, m.Module) - } - before := c.sent - if !c.known { - before = nil - } - want := carriedBuilds(names, leftOut, current, before) - for m, was := range c.kept { - if _, carried := want[m]; carried { - want[m] = was - } - } in := compose.Input{CurrentBuilds: map[string]string{"postgres": "p2", "files": "f2", "cache": "c2"}} node := compose.Node{SentBuilds: c.sent, SentKnown: c.known, KeptBuilds: c.kept} - if got := buildsOf(in, node, plan, leftOut); !reflect.DeepEqual(got, want) { - t.Errorf("%s: a send records %v, the controller recorded %v", name, got, want) + if got := buildsOf(in, node, plan, leftOut); !reflect.DeepEqual(got, c.want) { + t.Errorf("%s: a send records %v, want %v", name, got, c.want) } } } diff --git a/cmd/mesh-controller/config_moved_test.go b/cmd/mesh-controller/config_moved_test.go index 2692a44e..7aa2aa8c 100644 --- a/cmd/mesh-controller/config_moved_test.go +++ b/cmd/mesh-controller/config_moved_test.go @@ -127,21 +127,17 @@ type snapshotFacts = snapshot.Facts func toldEveryMachine(t *testing.T, open *stores, served map[string]map[string]any, on map[string][]string) map[string]string { t.Helper() ctx := t.Context() - gens, err := generators(ctx, open) - if err != nil { - t.Fatal(err) - } shelf, err := open.inventory.Catalogue(ctx) if err != nil { t.Fatal(err) } told := map[string]string{} for _, node := range fourMachines { - plan, settings, err := planFor(ctx, open, node) + plan, _, err := resolveNode(ctx, open, node) if err != nil { t.Fatalf("%s: %v", node, err) } - with, _, err := renderingFor(ctx, open, node, plan, settings, gens, Allocating) + with, err := madeAndRendered(ctx, open, node) if err != nil { t.Fatalf("%s: %v", node, err) } diff --git a/cmd/mesh-controller/core_box.go b/cmd/mesh-controller/core_box.go index 83166b26..33c99192 100644 --- a/cmd/mesh-controller/core_box.go +++ b/cmd/mesh-controller/core_box.go @@ -16,7 +16,6 @@ import ( "git.novox.be/novox/mesh-sdk/go/catalogue" "github.com/novox/mesh-controller/internal/conditions" "github.com/novox/mesh-controller/internal/inventory" - "github.com/novox/mesh-controller/internal/link" ) // The core's own credentials, sealed by the vault (novox/hq ADR 0349 §16, issue 755; the lead's decision on issue 755, @@ -40,15 +39,6 @@ import ( // the vault and the machine, cleared by the first send the vault answers whole. Only a machine with no sealing key, or // one whose key cannot be read, leaves its module out. -// engineOpensVaultBox says whether a machine's node-engine opens the vault's box, by its own newest statement. -func engineOpensVaultBox(ctx context.Context, inv *inventory.Inventory, node string) (bool, error) { - stated, had, err := inv.HealthOf(ctx, node) - if err != nil { - return false, err - } - return had && stated.Contract >= link.VaultBoxContract, nil -} - // coreAnswer is the vault's `get` answer as the controller reads it: the name, the generation and the box, never // opened. type coreAnswer struct { @@ -121,7 +111,7 @@ func sealingKeyPEM(raw string) (string, error) { // own seal where nothing was kept; on any other question, the kept box, or a stand-in the next send asks for. Pure: what to keep and what to // say is answered, not done. func coreBoxesOf(node, sealingKey string, core map[string][]string, kept map[string]map[string]inventory.CoreBox, - choosing Choosing, ask coreAsk) coreBoxes { + allocating bool, ask coreAsk) coreBoxes { out := coreBoxes{sealed: map[string]map[string]json.RawMessage{}, notPlaced: map[string]string{}} modules := make([]string, 0, len(core)) for m := range core { @@ -143,7 +133,7 @@ func coreBoxesOf(node, sealingKey string, core map[string][]string, kept map[str for _, name := range core[module] { k, has := kept[module][name] valid := has && k.SealedTo == sealingKey && len(k.Box) > 0 - if choosing != Allocating { + if !allocating { if valid { boxes[name] = k.Box } else { @@ -218,10 +208,10 @@ var coreVault = func(ctx context.Context) coreAsk { // coreBoxesFor is coreBoxesOf for one machine, read from and kept in the store, and said on a send. func coreBoxesFor(ctx context.Context, inv *inventory.Inventory, node string, modules []catalogue.Manifest, - handed func(catalogue.Manifest) bool, choosing Choosing) (coreBoxes, error) { + handed func(catalogue.Manifest) bool, allocating bool) (coreBoxes, error) { core := coreModulesOf(modules, handed) if len(core) == 0 { - if choosing == Allocating { + if allocating { settleVaultSilent(ctx, node) } return coreBoxes{}, nil @@ -235,16 +225,16 @@ func coreBoxesFor(ctx context.Context, inv *inventory.Inventory, node string, mo return coreBoxes{}, err } var ask coreAsk - if choosing == Allocating { + if allocating { ask = coreVault(ctx) } - out := coreBoxesOf(node, key, core, kept, choosing, ask) + out := coreBoxesOf(node, key, core, kept, allocating, ask) for _, b := range out.keep { if err := inv.KeepCoreBox(ctx, node, b); err != nil { return coreBoxes{}, err } } - if choosing == Allocating { + if allocating { sayVaultSilent(ctx, node, out) } return out, nil diff --git a/cmd/mesh-controller/core_box_integration_test.go b/cmd/mesh-controller/core_box_integration_test.go index de2f210d..d26e0e56 100644 --- a/cmd/mesh-controller/core_box_integration_test.go +++ b/cmd/mesh-controller/core_box_integration_test.go @@ -96,7 +96,7 @@ func TestASilentVaultHoldsTheKeptBoxAndSaysSo(t *testing.T) { func TestACoreModuleFirstPlacedWhileTheVaultIsSilentIsSealedByTheController(t *testing.T) { open, vault := aCoreMesh(t, link.VaultBoxContract) vault.silent = errors.New("no responders") - plan, settings, err := planFor(t.Context(), open, "laptop") + plan, settings, err := resolveNode(t.Context(), open, "laptop") if err != nil { t.Fatal(err) } diff --git a/cmd/mesh-controller/core_box_test.go b/cmd/mesh-controller/core_box_test.go index 56d8782e..1148d0a1 100644 --- a/cmd/mesh-controller/core_box_test.go +++ b/cmd/mesh-controller/core_box_test.go @@ -68,7 +68,7 @@ func TestReplay908(t *testing.T) { key := "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=" core := map[string][]string{"nats": {"password"}} ask := func(name, publicKey string) (coreAnswer, error) { return coreAnswer{}, errors.New("no responders") } - got := coreBoxesOf("novox", key, core, nil, Allocating, ask) + got := coreBoxesOf("novox", key, core, nil, true, ask) if _, sealed := got.sealed["nats"]; sealed || len(got.notPlaced) != 0 { t.Fatalf("nats is vault-sealed %v or not placed %v", got.sealed, got.notPlaced) } @@ -81,7 +81,7 @@ func TestReplay908(t *testing.T) { } // A kept box is still carried while the vault is silent. kept := map[string]map[string]inventory.CoreBox{"nats": {"password": {SealedTo: key, Box: json.RawMessage(`{"v":1}`)}}} - got = coreBoxesOf("novox", key, core, kept, Allocating, ask) + got = coreBoxesOf("novox", key, core, kept, true, ask) if string(got.sealed["nats"]["password"]) != `{"v":1}` || len(got.byController) != 0 { t.Fatalf("the kept box was not held: %+v", got) } @@ -99,17 +99,17 @@ func TestOnlyASendAsksTheVault(t *testing.T) { t.Fatal("the vault was asked by a question that is not a send") return coreAnswer{}, nil } - for _, choosing := range []Choosing{Reading, Foreseeing} { - if got := coreBoxesOf("anchor", key, core, kept, choosing, never); string(got.sealed["nats"]["broker"]) != `{"v":1}` { + for _, allocating := range []bool{false} { + if got := coreBoxesOf("anchor", key, core, kept, allocating, never); string(got.sealed["nats"]["broker"]) != `{"v":1}` { t.Errorf("read %s", got.sealed["nats"]["broker"]) } - if got := coreBoxesOf("anchor", key, core, nil, choosing, never); string(got.sealed["nats"]["broker"]) != + if got := coreBoxesOf("anchor", key, core, nil, allocating, never); string(got.sealed["nats"]["broker"]) != string(catalogue.ForeseenVaultBox) { t.Errorf("with none kept, read %s", got.sealed["nats"]["broker"]) } } // A box kept for another key of the machine is never carried. - other := coreBoxesOf("anchor", aPublicKey(t), core, kept, Allocating, + other := coreBoxesOf("anchor", aPublicKey(t), core, kept, true, func(string, string) (coreAnswer, error) { return coreAnswer{}, errors.New("silent") }) if _, vaultSealed := other.sealed["nats"]; vaultSealed || !reflect.DeepEqual(other.byController, []string{"nats"}) { t.Fatalf("a box sealed to the machine's old key was carried: %+v", other) diff --git a/cmd/mesh-controller/credential_on_assign_test.go b/cmd/mesh-controller/credential_on_assign_test.go index b6f557c4..0cbc1262 100644 --- a/cmd/mesh-controller/credential_on_assign_test.go +++ b/cmd/mesh-controller/credential_on_assign_test.go @@ -40,7 +40,7 @@ func TestAssigningAModuleThatSpeaksOnTheBusNamesItsCredential(t *testing.T) { } // And the push refuses to send it, naming the same verb, rather than sealing a placeholder. - plan, settings, err := planFor(ctx, open, "laptop") + plan, settings, err := resolveNode(ctx, open, "laptop") if err != nil { t.Fatal(err) } diff --git a/cmd/mesh-controller/epoch_send_test.go b/cmd/mesh-controller/epoch_send_test.go index 9e138c3c..4fc2e5e4 100644 --- a/cmd/mesh-controller/epoch_send_test.go +++ b/cmd/mesh-controller/epoch_send_test.go @@ -42,12 +42,8 @@ func TestAMachineIsSentTheEpochOnlyOnceItSaysItReadsOne(t *testing.T) { if err := inv.RecordReadsEpoch(ctx, anchor.ID, true); err != nil { t.Fatal(err) } - gens, err := generators(ctx, open) - if err != nil { - t.Fatal(err) - } d := &bodiesDelivery{recordedDelivery: recordedDelivery{inv: inv}, bodies: map[string][]byte{}} - if _, err := sendRound(ctx, open, []string{"anchor", "laptop"}, composeForPush(open, gens), d, "", nil); err != nil { + if _, err := sendRound(ctx, open, []string{"anchor", "laptop"}, composeForPush(open), d, "", nil); err != nil { t.Fatal(err) } carried := func(node string) (epoch float64, has bool) { @@ -89,12 +85,8 @@ func TestNothingIsComposedOrSentWithoutTheLease(t *testing.T) { was := epochForActs epochForActs = func(context.Context) (uint64, error) { return 0, errors.New("this controller lost the lease") } t.Cleanup(func() { epochForActs = was }) - gens, err := generators(ctx, open) - if err != nil { - t.Fatal(err) - } d := &bodiesDelivery{recordedDelivery: recordedDelivery{inv: open.inventory}, bodies: map[string][]byte{}} - refused, err := sendRound(ctx, open, []string{"anchor"}, composeForPush(open, gens), d, "", nil) + refused, err := sendRound(ctx, open, []string{"anchor"}, composeForPush(open), d, "", nil) if err != nil { t.Fatal(err) } diff --git a/cmd/mesh-controller/facts.go b/cmd/mesh-controller/facts.go index f0e5c41c..67bd4c07 100644 --- a/cmd/mesh-controller/facts.go +++ b/cmd/mesh-controller/facts.go @@ -14,8 +14,6 @@ import ( "sync" "time" - "git.novox.be/novox/mesh-sdk/go/validate" - "git.novox.be/novox/mesh-sdk/go/catalogue" "git.novox.be/novox/mesh-sdk/go/compose" snapshot "git.novox.be/novox/mesh-sdk/go/facts" @@ -504,41 +502,6 @@ func declarationFacts(ctx context.Context, open *stores, node string, gensErr er return d } -// composedAndValidated composes one machine's declaration — as a push would (Allocating) or as the next -// push will without making anything (Foreseeing) — with the order it was last sent, and runs the -// node-engine's own validator over the body. An error is that it did not compose; problems are what the -// validator refuses. -func composedAndValidated(ctx context.Context, open *stores, node string, gens map[string]catalogue.Generator, - choosing Choosing) (sendable, []string, error) { - plan, settings, err := planFor(ctx, open, node) - if err != nil { - return sendable{}, nil, err - } - declared, err := declarationWith(ctx, open, node, plan, settings, gens, choosing) - if err != nil { - return sendable{}, nil, err - } - record, err := open.inventory.NodeByName(ctx, node) - if err != nil { - return sendable{}, nil, err - } - if declared.Sequence, err = open.inventory.Sequence(ctx, record.ID); err != nil { - return sendable{}, nil, err - } - if declared.Epoch, err = open.inventory.SentEpoch(ctx, record.ID); err != nil { - return sendable{}, nil, err - } - // And the generation it was last sent, as the would-send is (novox/hq issue 234). - if declared.Generation, err = open.inventory.SentGeneration(ctx, record.ID); err != nil { - return sendable{}, nil, err - } - body, err := declared.Body() - if err != nil { - return sendable{}, nil, err - } - return declared, validate.Declaration(body), nil -} - // resourceNames are a declaration's resources as `type:id`, sorted. func resourceNames(resources []map[string]any) []string { out := make([]string, 0, len(resources)) diff --git a/cmd/mesh-controller/facts_test.go b/cmd/mesh-controller/facts_test.go index c3ce5e34..5edc0095 100644 --- a/cmd/mesh-controller/facts_test.go +++ b/cmd/mesh-controller/facts_test.go @@ -42,12 +42,8 @@ func aMeshWithSecrets(t *testing.T) (*stores, []string) { t.Fatal(err) } // A push's worth of composition, which makes the pair credential the consumer is sent. - gens, err := generators(ctx, open) - if err != nil { - t.Fatal(err) - } for _, node := range []string{"laptop", "anchor"} { - if _, _, err := composedAndValidated(ctx, open, node, gens, Allocating); err != nil { + if _, err := composeSend(ctx, open, node); err != nil { t.Fatalf("%s does not compose: %v", node, err) } } diff --git a/cmd/mesh-controller/generation.go b/cmd/mesh-controller/generation.go index a354d289..ce649ce0 100644 --- a/cmd/mesh-controller/generation.go +++ b/cmd/mesh-controller/generation.go @@ -6,7 +6,6 @@ import ( "fmt" "io" "os" - "sort" "strings" "time" @@ -103,18 +102,6 @@ func senderOf(caller string) string { return fmt.Sprintf("%s (pid %d on %s, build %s)", caller, os.Getpid(), host, version) } -// namedModules are the modules a declaration names: its machine's set, less what was left out of it. -func namedModules(plan catalogue.Resolution, leftOut map[string]string) []string { - out := make([]string, 0, len(plan.Modules)) - for _, m := range plan.Modules { - if _, left := leftOut[m.Module]; !left { - out = append(out, m.Module) - } - } - sort.Strings(out) - return out -} - // heardGenerationRefusal keeps a machine's refusal of a send for its generation, so S20 names its sender // and says it (novox/hq issue 234): on the send it refused or — when the mesh has no record of sending that // sequence — as a refusal of its own, naming the sender as unknown. Either way S20 is raised: a refusal the diff --git a/cmd/mesh-controller/grant_follows_binding_integration_test.go b/cmd/mesh-controller/grant_follows_binding_integration_test.go index 96362c4b..100d3bb4 100644 --- a/cmd/mesh-controller/grant_follows_binding_integration_test.go +++ b/cmd/mesh-controller/grant_follows_binding_integration_test.go @@ -35,7 +35,7 @@ func TestAConsumerPinnedBackIsNoLongerGrantedByTheProviderItLeft(t *testing.T) { if err := inv.PinProvision(ctx, "laptop", "postgres-database", "anchor", "store"); err != nil { t.Fatal(err) } - plan, _, err := planFor(ctx, open, "laptop") + plan, _, err := resolveNode(ctx, open, "laptop") if err != nil { t.Fatal(err) } @@ -45,7 +45,7 @@ func TestAConsumerPinnedBackIsNoLongerGrantedByTheProviderItLeft(t *testing.T) { if err := inv.RecordBindings(ctx, "laptop", boundToData(plan, nil)); err != nil { t.Fatal(err) } - grants, _, unbound, err := grantsFor(ctx, open, "anchor") + grants, _, unbound, err := grantsOf(ctx, open, "anchor") if err != nil { t.Fatal(err) } @@ -57,7 +57,7 @@ func TestAConsumerPinnedBackIsNoLongerGrantedByTheProviderItLeft(t *testing.T) { if err := inv.PinProvision(ctx, "laptop", "postgres-database", "laptop", "store"); err != nil { t.Fatal(err) } - plan, _, err = planFor(ctx, open, "laptop") + plan, _, err = resolveNode(ctx, open, "laptop") if err != nil { t.Fatal(err) } @@ -76,7 +76,7 @@ func TestAConsumerPinnedBackIsNoLongerGrantedByTheProviderItLeft(t *testing.T) { } // The store it left: no longer granted, and said. - grants, _, unbound, err = grantsFor(ctx, open, "anchor") + grants, _, unbound, err = grantsOf(ctx, open, "anchor") if err != nil { t.Fatal(err) } @@ -87,7 +87,7 @@ func TestAConsumerPinnedBackIsNoLongerGrantedByTheProviderItLeft(t *testing.T) { strings.Join(unbound[0].BoundTo, ",") != "laptop" { t.Fatalf("the consumer that moved is not the one said: %+v", unbound) } - planned, settings, err := planFor(ctx, open, "anchor") + planned, settings, err := resolveNode(ctx, open, "anchor") if err != nil { t.Fatal(err) } @@ -105,7 +105,7 @@ func TestAConsumerPinnedBackIsNoLongerGrantedByTheProviderItLeft(t *testing.T) { } // The store it is bound to: granted. - grants, _, unbound, err = grantsFor(ctx, open, "laptop") + grants, _, unbound, err = grantsOf(ctx, open, "laptop") if err != nil { t.Fatal(err) } @@ -131,7 +131,7 @@ func TestAConsumerWhoseResolutionCannotBeReadIsNotWithdrawn(t *testing.T) { t.Fatalf("assign %s %s: %v", a[0], a[1], err) } } - if _, _, err := planFor(ctx, open, "laptop"); err != nil { + if _, _, err := resolveNode(ctx, open, "laptop"); err != nil { t.Fatal(err) } @@ -144,10 +144,10 @@ func TestAConsumerWhoseResolutionCannotBeReadIsNotWithdrawn(t *testing.T) { if err := inv.RecordSealingKey(ctx, laptop.ID, "not a key"); err != nil { t.Fatal(err) } - if _, _, err := planFor(ctx, open, "laptop"); err == nil || unresolvable(err) { + if _, _, err := resolveNode(ctx, open, "laptop"); err == nil || unresolvable(err) { t.Fatalf("the seam this test relies on moved: %v", err) } - grants, _, unbound, err := grantsFor(ctx, open, "anchor") + grants, _, unbound, err := grantsOf(ctx, open, "anchor") if err == nil { t.Fatalf("an unreadable consumer was answered: grants %+v, unbound %+v", grants, unbound) } diff --git a/cmd/mesh-controller/grants_step_store_test.go b/cmd/mesh-controller/grants_step_store_test.go index 206303ab..8432483d 100644 --- a/cmd/mesh-controller/grants_step_store_test.go +++ b/cmd/mesh-controller/grants_step_store_test.go @@ -66,15 +66,11 @@ func TestTheGrantsStepSendsTheUserListAndNothingElse(t *testing.T) { if err != nil { t.Fatal(err) } - plan, settings, err := planFor(under, open, "anchor") + plan, _, err := resolveNode(under, open, "anchor") if err != nil { t.Fatal(err) } - gens, err := generators(under, open) - if err != nil { - t.Fatal(err) - } - declared, err := declarationWith(under, open, "anchor", plan, settings, gens, Allocating) + declared, err := composeSend(under, open, "anchor") if err != nil { t.Fatal(err) } diff --git a/cmd/mesh-controller/held_back.go b/cmd/mesh-controller/held_back.go index e02c8d34..16ffc4d5 100644 --- a/cmd/mesh-controller/held_back.go +++ b/cmd/mesh-controller/held_back.go @@ -7,7 +7,6 @@ import ( "sort" "strings" - "git.novox.be/novox/mesh-sdk/go/catalogue" "github.com/novox/mesh-controller/internal/inventory" ) @@ -265,11 +264,9 @@ func flushBehind(ctx context.Context, open *stores, nodes []inventory.Node, hand // composeForPush is how a push composes one machine: its set resolved, what it cannot host and what // is left out of it said, and its declaration allocated. -func composeForPush(open *stores, gens map[string]catalogue.Generator) func(held context.Context, node string) (sendable, error) { +func composeForPush(open *stores) func(held context.Context, node string) (sendable, error) { return func(held context.Context, node string) (sendable, error) { - // Read afresh for each machine: the send before it made and recorded things. gens is the private network the - // controller's own composition took; the SDK's is computed from the same Input. - _ = gens + // Read afresh for each machine: the send before it made and recorded things. held = freshInput(held) plan, _, err := resolveNode(held, open, node) if err != nil { diff --git a/cmd/mesh-controller/held_back_integration_test.go b/cmd/mesh-controller/held_back_integration_test.go index e8e2eb5d..dc0b3d7d 100644 --- a/cmd/mesh-controller/held_back_integration_test.go +++ b/cmd/mesh-controller/held_back_integration_test.go @@ -28,11 +28,7 @@ func TestANamedPushLeavesAMachineAPolicyHoldsBack(t *testing.T) { if err := inv.SetUpgradeOf(ctx, "resolver", inventory.Upgrade{Why: "each machine checked by hand"}); err != nil { t.Fatal(err) } - gens, err := generators(ctx, open) - if err != nil { - t.Fatal(err) - } - compose := composeForPush(open, gens) + compose := composeForPush(open) d := &recordedDelivery{inv: inv} if _, err := sendRound(ctx, open, []string{"anchor", "laptop"}, compose, d, "", nil); err != nil { t.Fatal(err) @@ -134,11 +130,7 @@ func TestANamedPushStillSendsAConsequenceNothingHolds(t *testing.T) { if _, err := inv.Assign(ctx, "laptop", "resolver"); err != nil { t.Fatal(err) } - gens, err := generators(ctx, open) - if err != nil { - t.Fatal(err) - } - compose := composeForPush(open, gens) + compose := composeForPush(open) d := &recordedDelivery{inv: inv} if _, err := sendRound(ctx, open, []string{"anchor", "laptop"}, compose, d, "", nil); err != nil { t.Fatal(err) diff --git a/cmd/mesh-controller/held_back_test.go b/cmd/mesh-controller/held_back_test.go index 66b66e6d..05e7c65a 100644 --- a/cmd/mesh-controller/held_back_test.go +++ b/cmd/mesh-controller/held_back_test.go @@ -3,7 +3,6 @@ package main import ( "context" "encoding/json" - "reflect" "strings" "testing" "time" @@ -99,22 +98,6 @@ func TestAPlanWaitingOnItsFirstMachineHoldsTheRest(t *testing.T) { } } -// A send records the build of each module it carried; a module left out of it keeps the build it -// was last sent, since the machine keeps that one. -func TestASendCarriesTheCurrentBuildsAndALeftOutModuleKeepsItsOwn(t *testing.T) { - current := map[string]inventory.CurrentBuild{"a": {Commit: "a2"}, "b": {Commit: "b2"}, "c": {}} - got := carriedBuilds([]string{"a", "b", "c"}, map[string]string{"b": "a setting does not compose"}, - current, map[string]string{"a": "a1", "b": "b1"}) - if want := map[string]string{"a": "a2", "b": "b1", "c": ""}; !reflect.DeepEqual(got, want) { - t.Fatalf("carried %v, wanted %v", got, want) - } - // Not known before: the left-out module is not recorded at all, so it reads as never sent. - got = carriedBuilds([]string{"a", "b"}, map[string]string{"b": "x"}, current, nil) - if want := map[string]string{"a": "a2"}; !reflect.DeepEqual(got, want) { - t.Fatalf("carried %v, wanted %v", got, want) - } -} - // recordedDelivery sends nothing and records each send as the mesh does, so the next comparison // reads the machine as current — and writes down which machines it declared. type recordedDelivery struct { diff --git a/cmd/mesh-controller/holdings_test.go b/cmd/mesh-controller/holdings_test.go index 8b3a0054..420360c4 100644 --- a/cmd/mesh-controller/holdings_test.go +++ b/cmd/mesh-controller/holdings_test.go @@ -63,7 +63,7 @@ func TestASecondEligibleHolderStandsBesideTheOneHeldByBeingAlone(t *testing.T) { // And the record decides from here: the anchor's plan holds the seat, the laptop's does not. for node, holds := range map[string]bool{"anchor": true, "laptop": false} { - plan, _, err := planFor(ctx, open, node) + plan, _, err := resolveNode(ctx, open, node) if err != nil { t.Fatalf("%s no longer resolves: %v", node, err) } diff --git a/cmd/mesh-controller/identity_bound_integration_test.go b/cmd/mesh-controller/identity_bound_integration_test.go index 97d5a7a8..01774c33 100644 --- a/cmd/mesh-controller/identity_bound_integration_test.go +++ b/cmd/mesh-controller/identity_bound_integration_test.go @@ -31,7 +31,7 @@ func TestAnOverflowingConsumerNeverRefusesItsProvidersMachine(t *testing.T) { } // The consumer's machine resolves, and says which of its modules no provider will grant. - consumer, _, err := planFor(ctx, open, "laptop") + consumer, _, err := resolveNode(ctx, open, "laptop") if err != nil { t.Fatal(err) } @@ -42,7 +42,7 @@ func TestAnOverflowingConsumerNeverRefusesItsProvidersMachine(t *testing.T) { // The provider's machine composes. Under ADR 0049's one bound this was a refusal naming // networkmanager, and no push to the provider could go through. - plan, settings, err := planFor(ctx, open, "anchor") + plan, settings, err := resolveNode(ctx, open, "anchor") if err != nil { t.Fatal(err) } @@ -53,7 +53,7 @@ func TestAnOverflowingConsumerNeverRefusesItsProvidersMachine(t *testing.T) { if len(declared.withheld) != 1 || declared.withheld[0].Identity != "mesh_laptop_photoalbum" { t.Fatalf("the overflowing consumer is not the one withheld: %+v", declared.withheld) } - grants, _, _, err := grantsFor(ctx, open, "anchor") + grants, _, _, err := grantsOf(ctx, open, "anchor") if err != nil { t.Fatal(err) } diff --git a/cmd/mesh-controller/issue201_integration_test.go b/cmd/mesh-controller/issue201_integration_test.go index 1ee6d8eb..a138642c 100644 --- a/cmd/mesh-controller/issue201_integration_test.go +++ b/cmd/mesh-controller/issue201_integration_test.go @@ -79,7 +79,7 @@ func TestReplay201(t *testing.T) { t.Fatalf("the send keeps the newer controller there: %v %v", keeps, err) } shelf := map[string]catalogue.Manifest{"mesh-controller": {Module: "mesh-controller", Version: "old"}} - if _, err := keepRecorded(keepingRecorded(judged), open, "anchor", shelf); err != nil || shelf["mesh-controller"].Version != "1" { + if err := applyKept(keepingRecorded(judged), open, "anchor", keeps, shelf); err != nil || shelf["mesh-controller"].Version != "1" { t.Fatalf("the send composes the kept build's manifest: %+v %v", shelf, err) } key := coreDowngradeObservation(lease.ComponentController, "anchor", "").Key()