`rollout mint` gives every principal the new bus will have a credential it does not yet have and puts each where its owner reads it: a machine's as a membership — bus address, fingerprint, password, transport — sealed into its declaration (migration 0041, the `bus-membership` resource the host reads after applying); a module's as its broker secret, through the same delivery `module issue` uses; the control plane's own as its `bus` secret. Idempotent, and worked out from where the bus's module is assigned rather than from this process's environment, because this process is still on the old bus when it runs and must be. This is the half of design 28 task 5.2 the first live attempt found missing: a credential was minted only at enrolment, at `module issue` and for a person, so no machine already enrolled could ever be moved. `rollout check` was right to refuse; now there is something to run first.
100 lines
3.3 KiB
Go
100 lines
3.3 KiB
Go
package inventory
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/novox/mesh-controller/internal/catalogue"
|
|
)
|
|
|
|
// A seat's holder is a row, changed as one act (novox/hq ADR 0131). What these pin is the shape of
|
|
// that row's life: it needs an assignment to point at, it is replaced rather than added to, and it
|
|
// goes when the assignment does — so a seat never points at something that is not running anywhere.
|
|
|
|
func twoBrokersOnTwoNodes(t *testing.T) (*Inventory, context.Context) {
|
|
t.Helper()
|
|
old := catalogue.Manifest{Module: "old-broker", Version: "1",
|
|
Provides: []catalogue.Offer{{Name: "mesh-bus", Scope: catalogue.ScopeMesh}},
|
|
Claims: []catalogue.Claim{{Name: "mesh-broker", Scope: catalogue.ScopeMesh}}}
|
|
new := catalogue.Manifest{Module: "new-broker", Version: "1",
|
|
Provides: []catalogue.Offer{{Name: "mesh-bus", Scope: catalogue.ScopeMesh}},
|
|
Claims: []catalogue.Claim{{Name: "mesh-broker", Scope: catalogue.ScopeMesh}}}
|
|
inv, ctx := aMeshWith(t, old, new)
|
|
// The holding references the seat's row, which `migrate` seeds on a real mesh.
|
|
if _, err := inv.SeedSeats(ctx, catalogue.DefaultSeats()); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, n := range []string{"anchor", "laptop"} {
|
|
if _, err := inv.AddNode(ctx, n); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
if _, err := inv.Assign(ctx, "anchor", "old-broker"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := inv.Assign(ctx, "laptop", "new-broker"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return inv, ctx
|
|
}
|
|
|
|
func TestAHandoverIsOneRowReplacedNotOneAdded(t *testing.T) {
|
|
inv, ctx := twoBrokersOnTwoNodes(t)
|
|
|
|
if err := inv.HoldSeat(ctx, "mesh-broker", catalogue.ScopeMesh, "anchor", "old-broker"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := inv.HoldSeat(ctx, "mesh-broker", catalogue.ScopeMesh, "laptop", "new-broker"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
held, err := inv.Holdings(ctx)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(held) != 1 || held[0].Node != "laptop" || held[0].Module != "new-broker" || held[0].Scope != catalogue.ScopeMesh {
|
|
t.Fatalf("after a handover the seat is not held by exactly the new holder: %+v", held)
|
|
}
|
|
}
|
|
|
|
func TestASeatCannotBeHandedToSomethingNotAssigned(t *testing.T) {
|
|
inv, ctx := twoBrokersOnTwoNodes(t)
|
|
// new-broker is assigned to laptop, not anchor.
|
|
if err := inv.HoldSeat(ctx, "mesh-broker", catalogue.ScopeMesh, "anchor", "new-broker"); err == nil {
|
|
t.Fatal("a seat was handed to a module not assigned where it was named")
|
|
}
|
|
}
|
|
|
|
func TestUnassigningTheHolderTakesTheHoldingWithIt(t *testing.T) {
|
|
inv, ctx := twoBrokersOnTwoNodes(t)
|
|
if err := inv.HoldSeat(ctx, "mesh-broker", catalogue.ScopeMesh, "laptop", "new-broker"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := inv.Unassign(ctx, "laptop", "new-broker"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
held, err := inv.Holdings(ctx)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(held) != 0 {
|
|
t.Fatalf("the holding outlived the assignment it pointed at: %+v", held)
|
|
}
|
|
}
|
|
|
|
func TestAMachinesMembershipIsOneRowReplacedAndGoesWithTheMachine(t *testing.T) {
|
|
inv, ctx := twoBrokersOnTwoNodes(t)
|
|
if err := inv.PutBusMembership(ctx, "anchor", "first"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := inv.PutBusMembership(ctx, "anchor", "second"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, err := inv.BusMemberships(ctx)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got["anchor"] != "second" || len(got) != 1 {
|
|
t.Fatalf("a re-told membership did not replace the first: %v", got)
|
|
}
|
|
}
|