From cdd3638312136305219b88a518f8a160113c7db4 Mon Sep 17 00:00:00 2001 From: jochen Date: Wed, 23 Sep 2026 23:49:55 +0200 Subject: [PATCH] The control plane's own manifest says where the node put the store and the broker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Beside each sealed connection genesis wrote, the port this machine put the seat's holder at: `${seat:mesh-store:5432}` for the three stores, `${seat:mesh-broker:…}` for the bus, the plain AMQP port and the management API. Filled from the node's settings when the control plane composes its own declaration; empty — the sealed value stands — when the mesh has nothing to add. On its own, after the commit before it is built and running: a control plane that does not know the placeholder passes it through as the value, and this manifest is composed by whatever control plane is running when it is pushed. The reader ignores an unfilled placeholder either way, and a test holds it to ignoring exactly what this manifest says. novox/hq 04-ISSUES/102 --- internal/catalogue/seat_into_test.go | 12 +++++++ internal/store/manifest_test.go | 52 ++++++++++++++++++++++++++++ module.json | 8 ++++- 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 internal/store/manifest_test.go 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",