Read the foundation's ports from each node's settings, wherever a port is used (hq ADR 0100)

This commit is contained in:
2026-09-22 17:31:07 +02:00
parent 1ea84f8b8f
commit dbf62b5212
9 changed files with 352 additions and 6 deletions
+1 -1
View File
@@ -654,7 +654,7 @@ func (i *Inventory) SettingsFor(ctx context.Context, nodeName, module string) ([
}
from := nodeName
if meshWide {
from = "the mesh"
from = catalogue.MeshWideLayer
}
layers = append(layers, catalogue.Layer{From: from, Values: values})
}
+42
View File
@@ -2,6 +2,7 @@ package inventory
import (
"context"
"encoding/json"
"errors"
"fmt"
@@ -132,6 +133,17 @@ func (i *Inventory) assignPort(
taken[port] = "something this machine already runs"
}
}
// And every port this machine was given for a module (novox/hq ADR 0100): the foundation's
// ports, as genesis chose them, are the node's settings and never the mesh's to hand out.
given, err := i.givenOn(ctx, nodeID)
if err != nil {
return Assigned{}, err
}
for port, by := range given {
if _, mine := taken[port]; !mine {
taken[port] = by
}
}
machine := wanted
if !fixed {
@@ -258,3 +270,33 @@ func (i *Inventory) ReleasePorts(ctx context.Context, node, module string) error
`delete from port_assignment where node = $1 and module = $2`, record.ID, module)
return err
}
// givenOn is every machine port a module was given on this node by its `ports` setting, and which
// module it was given to.
func (i *Inventory) givenOn(ctx context.Context, nodeID any) (map[int]string, error) {
rows, err := i.store.Pool().Query(ctx,
`select module, values->'ports' from settings
where node = $1 and jsonb_typeof(values->'ports') = 'object'`, nodeID)
if err != nil {
return nil, err
}
defer rows.Close()
out := map[int]string{}
for rows.Next() {
var module string
var raw []byte
if err := rows.Scan(&module, &raw); err != nil {
return nil, err
}
var given map[string]any
if err := json.Unmarshal(raw, &given); err != nil {
return nil, err
}
for _, v := range given {
if at, ok := v.(float64); ok {
out[int(at)] = module
}
}
}
return out, rows.Err()
}
+21
View File
@@ -236,3 +236,24 @@ func TestUnassigningReleasesTheModulesPorts(t *testing.T) {
t.Fatalf("port 25 is still held in the name of a module that was unassigned: %v", err)
}
}
// novox/hq ADR 0100: a port a node was given for a module is the node's, and the mesh never hands
// it to another.
func TestAGivenPortIsNeverAssigned(t *testing.T) {
inv, node := aNodeWithModules(t, "postgres", "web")
ctx := t.Context()
if err := inv.SetSettings(ctx, node, "postgres",
map[string]any{catalogue.PortsSetting: map[string]any{"5432": 20000}}); err != nil {
t.Fatal(err)
}
got, err := inv.PortFor(ctx, node, "web", 8080, false)
if err != nil {
t.Fatal(err)
}
if got.Machine == 20000 {
t.Fatal("a port given to postgres was assigned to web")
}
if _, err := inv.PortFor(ctx, node, "web", 20000, true); !errors.Is(err, ErrPortTaken) {
t.Fatalf("a fixed port given to another module was handed over: %v", err)
}
}