diff --git a/internal/catalogue/seat_into_test.go b/internal/catalogue/seat_into_test.go index 96e3a2a..bb7dc6b 100644 --- a/internal/catalogue/seat_into_test.go +++ b/internal/catalogue/seat_into_test.go @@ -101,6 +101,18 @@ func TestTheControlPlanesOwnAddressesFollowTheNodesPorts(t *testing.T) { 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, diff --git a/internal/store/manifest_test.go b/internal/store/manifest_test.go new file mode 100644 index 0000000..1a47e6a --- /dev/null +++ b/internal/store/manifest_test.go @@ -0,0 +1,52 @@ +package store + +import ( + "encoding/json" + "os" + "testing" +) + +// **The manifest's placeholder, unfilled, reaches a store reader and changes nothing.** +// +// The control plane composes its own declaration, so the manifest naming `${seat:…}` can be +// composed by a control plane one build older than it — one that passes the literal through as +// the value. That is the state of the live control-node between this manifest landing and its +// next build being pushed, and a reader that refused the literal would leave it headless +// (novox/hq 04-ISSUES/102, finding F1). So the reader is held to ignoring exactly what +// module.json says, not a placeholder shaped like it. +func TestTheManifestsOwnPlaceholderUnfilledLeavesTheStoreWhereTheFileSays(t *testing.T) { + raw, err := os.ReadFile("../../module.json") + if err != nil { + t.Fatal(err) + } + var m struct { + Resources []struct { + Type string `json:"type"` + Env map[string]string `json:"env"` + } `json:"resources"` + } + if err := json.Unmarshal(raw, &m); err != nil { + t.Fatal(err) + } + var written string + for _, r := range m.Resources { + if r.Type == "container" { + written = r.Env["MESH_STORE_INVENTORY_PORT"] + } + } + if written == "" { + t.Fatal("module.json no longer names MESH_STORE_INVENTORY_PORT") + } + + alone(t) + t.Setenv(Variable(example), dsn) + t.Setenv(PortVariable(example), written) + opened, err := Open(t.Context(), example) + if err != nil { + t.Fatalf("the unfilled placeholder was refused, which is a headless control plane: %v", err) + } + defer opened.Close() + if got := opened.Pool().Config().ConnConfig.Port; got != 5432 { + t.Fatalf("the store is on %d; with the placeholder unfilled, the file's port stands", got) + } +} diff --git a/module.json b/module.json index dbb7f0c..936ca87 100644 --- a/module.json +++ b/module.json @@ -42,7 +42,13 @@ "MESH_STORE_LICENCES_FILE": "/run/secrets/licences", "MESH_BROKER_AMQP_FILE": "/run/secrets/broker", "MESH_BROKER_MANAGEMENT_FILE": "/run/secrets/broker-management", - "MESH_BROKER_ADDRESS_FILE": "/run/secrets/broker-address" + "MESH_BROKER_ADDRESS_FILE": "/run/secrets/broker-address", + "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}" }, "volumes": [ "mesh-broker-tls:/broker-tls:ro",