package catalogue import ( "os" "strings" "testing" ) // The control plane's own addresses follow the node's ports (novox/hq 04-ISSUES/102). func TestASeatPlaceholderAnswersWhereThisMachinePutTheHolder(t *testing.T) { control := map[string]any{ "type": "container", "id": "server", "name": "mesh-controller", "env": map[string]any{ "MESH_STORE_INVENTORY_PORT": "${seat:mesh-store:5432}", "MESH_BROKER_AMQP_PORT": "${seat:mesh-broker:5672}", "MESH_BROKER_ADDRESS_PORT": "${seat:mesh-broker:5671}", "MESH_STORE_INVENTORY_FILE": "/run/secrets/inventory", }, } with := Rendering{Seats: map[string]map[int]int{ "mesh-store": {5432: 6852}, "mesh-broker": {5672: 5679, 5671: 5671}, }} if err := seatInto(control, "mesh-controller", with); err != nil { t.Fatal(err) } env := control["env"].(map[string]any) for key, want := range map[string]string{ "MESH_STORE_INVENTORY_PORT": "6852", "MESH_BROKER_AMQP_PORT": "5679", "MESH_BROKER_ADDRESS_PORT": "5671", "MESH_STORE_INVENTORY_FILE": "/run/secrets/inventory", } { if env[key] != want { t.Errorf("%s = %v, want %q", key, env[key], want) } } } // A seat nothing on this machine holds — or one whose holder the mesh has given no port — answers // with nothing, so the port genesis wrote into the connection string stands. Not the software's // own port: on a node given a port at genesis before the store's module exists, that would // override the right number with the catalogue's. func TestASeatTheMeshCannotPlaceAnswersWithNothing(t *testing.T) { control := map[string]any{ "type": "container", "id": "server", "name": "mesh-controller", "env": map[string]any{"MESH_STORE_INVENTORY_PORT": "${seat:mesh-store:5432}"}, } if err := seatInto(control, "mesh-controller", Rendering{}); err != nil { t.Fatal(err) } if got := control["env"].(map[string]any)["MESH_STORE_INVENTORY_PORT"]; got != "" { t.Fatalf("with nothing known, the seat answered %q", got) } file := map[string]any{"type": "file", "content": "port=${seat:mesh-store:5432}\n"} if err := seatInto(file, "x", Rendering{Seats: map[string]map[int]int{"mesh-store": {5433: 1}}}); err != nil { t.Fatal(err) } if got := file["content"]; got != "port=\n" { t.Fatalf("a port the holder does not publish answered %q", got) } } func TestASeatPlaceholderNamingNoPortIsRefused(t *testing.T) { file := map[string]any{"type": "file", "content": "${seat:mesh-store:99999}"} if err := seatInto(file, "x", Rendering{}); err == nil { t.Fatal("99999 was accepted as a port") } } func TestFillingASeatLeavesTheManifestAlone(t *testing.T) { env := map[string]any{"MESH_STORE_INVENTORY_PORT": "${seat:mesh-store:5432}"} manifest := map[string]any{"type": "container", "id": "server", "env": env} for _, at := range []int{6852, 5432} { copied := map[string]any{} for k, v := range manifest { copied[k] = v } with := Rendering{Seats: map[string]map[int]int{"mesh-store": {5432: at}}} if err := seatInto(copied, "mesh-controller", with); err != nil { t.Fatal(err) } } if env["MESH_STORE_INVENTORY_PORT"] != "${seat:mesh-store:5432}" { t.Fatalf("the module's own manifest was edited: %v", env) } } // **The control plane's own manifest, composed through the whole path.** // // The store was given 6852 and the broker's plain port 5679 (the control-node's migration, novox/hq // 04-ISSUES/102). The control plane's own connections are sealed at genesis with the ports genesis // wrote; what its container is told beside them is where this machine put the store and the // broker now, read from the node's settings exactly as every consumer's binding is. func TestTheControlPlanesOwnAddressesFollowTheNodesPorts(t *testing.T) { raw, err := os.ReadFile("../../module.json") if err != nil { t.Fatal(err) } m, err := ParseManifest(raw) if err != nil { t.Fatalf("the control plane's own manifest does not parse:\n%v", err) } // The manifest itself names them now; withSeatPorts is a no-op on it, and this holds it so. for _, r := range m.Resources { if r["type"] != "container" { continue } env, _ := r["env"].(map[string]any) for key, want := range SeatPorts { if env[key] != want { t.Errorf("module.json says %s=%v, not %q", key, env[key], want) } } } m = withSeatPorts(m) control, err := m.Resolve([]Built{{ Name: "server", Kind: ArtifactImage, Reference: ArtifactStoreScheme + "mesh-controller/server@sha256:" + strings.Repeat("c", 64), }}) if err != nil { t.Fatal(err) } r := Resolution{Node: "anchor", Modules: []Manifest{control}} needed := map[string]map[string]string{"mesh-controller": {}} for name := range m.OwnSecrets { needed["mesh-controller"][name] = "sealed-" + name } out, err := r.Declaration(Rendering{ Needed: needed, ArtifactStore: "anchor.internal:5100", Seats: map[string]map[int]int{ "mesh-store": {5432: 6852}, "mesh-broker": {5671: 5671, 5672: 5679, 15672: 15673}, }, }) if err != nil { t.Fatalf("the control plane does not compose: %v", err) } server := fileNamed(out, "mesh-controller.server") if server == nil { t.Fatalf("the control plane's container is not in the declaration: %v", out) } env, _ := server["env"].(map[string]any) for key, want := range map[string]string{ "MESH_STORE_INVENTORY_PORT": "6852", "MESH_STORE_IDENTITY_PORT": "6852", "MESH_STORE_LICENCES_PORT": "6852", "MESH_BROKER_AMQP_PORT": "5679", "MESH_BROKER_MANAGEMENT_PORT": "15673", "MESH_BROKER_ADDRESS_PORT": "5671", } { if env[key] != want { t.Errorf("the control plane is told %s=%v; the node put it on %s", key, env[key], want) } } if got := server["image"]; got != "anchor.internal:5100/mesh-controller/server@sha256:"+strings.Repeat("c", 64) { t.Errorf("the control plane's own image is %v, not routed through the store", got) } // And on a mesh where the foundation is where genesis raised it, nothing is added. out, err = r.Declaration(Rendering{Needed: needed, ArtifactStore: "anchor.internal:5100"}) if err != nil { t.Fatal(err) } env, _ = fileNamed(out, "mesh-controller.server")["env"].(map[string]any) if env["MESH_STORE_INVENTORY_PORT"] != "" || env["MESH_BROKER_AMQP_PORT"] != "" { t.Errorf("with no settings, the control plane is told %v", env) } } // SeatPorts is what the control plane's manifest says beside each sealed connection: the port // this machine put the seat's holder at (novox/hq 04-ISSUES/102). var SeatPorts = map[string]string{ "MESH_STORE_INVENTORY_PORT": "${seat:mesh-store:5432}", "MESH_STORE_IDENTITY_PORT": "${seat:mesh-store:5432}", "MESH_STORE_LICENCES_PORT": "${seat:mesh-store:5432}", "MESH_BROKER_AMQP_PORT": "${seat:mesh-broker:5672}", "MESH_BROKER_MANAGEMENT_PORT": "${seat:mesh-broker:15672}", "MESH_BROKER_ADDRESS_PORT": "${seat:mesh-broker:5671}", } // withSeatPorts is the control plane's manifest with SeatPorts in its container's environment. // // **The manifest lands one commit after the code that fills it**, deliberately: a control plane // still running the previous build passes `${seat:…}` through unfilled, and the manifest may only // name the placeholder once every control plane that could compose it knows it. So the test does // not depend on module.json carrying these yet, and is a no-op once it does. func withSeatPorts(m Manifest) Manifest { out := m out.Resources = nil for _, r := range m.Resources { if r["type"] != "container" { out.Resources = append(out.Resources, r) continue } copied := map[string]any{} for k, v := range r { copied[k] = v } env := map[string]any{} if had, ok := r["env"].(map[string]any); ok { for k, v := range had { env[k] = v } } for k, v := range SeatPorts { if _, said := env[k]; !said { env[k] = v } } copied["env"] = env out.Resources = append(out.Resources, copied) } return out }