Adoption mode: a node in use is adopted before it is converged (hq ADR 0100–0103) #44

Merged
jschoubben merged 33 commits from feat/adoption-mode into main 2026-09-22 19:01:51 +00:00
2 changed files with 24 additions and 11 deletions
Showing only changes of commit dd6aad4a2f - Show all commits
+13
View File
@@ -397,3 +397,16 @@ func TestPublishedLeavesOutLoopbackInBothFamilies(t *testing.T) {
t.Fatalf("published is %v, want %v", got, want)
}
}
// novox/hq ADR 0038: only a published port is the mesh's to move. A module that binds the machine
// itself listens where its software was told to, so giving it a machine port is refused.
func TestAGivenPortIsRefusedForAPortNoContainerPublishes(t *testing.T) {
onTheMachine := Manifest{Module: "daemon",
Listens: []Listening{{Port: 9000, From: FromMesh}}, Guards: []int{9000}}
layers := []Layer{{From: "node anchor",
Values: map[string]any{PortsSetting: map[string]any{"9000": float64(9100)}}}}
_, err := GivenPorts(onTheMachine, layers)
if err == nil || !strings.Contains(err.Error(), "does not publish") {
t.Fatalf("a port no container publishes was given: %v", err)
}
}
+11 -11
View File
@@ -475,17 +475,16 @@ const MeshWideLayer = "the mesh"
// GivenPorts reads a module's given machine ports from its settings: software port → machine port.
//
// Refused from a mesh-wide layer — a port is a fact about one machine, and one number for every
// machine is the collision this exists to avoid — and for a port the module neither listens on,
// publishes from a container, nor guards: a given port that reaches nothing is a setting somebody
// believes changed something.
// machine is the collision this exists to avoid — and for a port the module's containers do not
// publish.
//
// **Only a published port is the mesh's to move** (novox/hq ADR 0038). A container's mapping is
// what translates; a module binding the machine's network directly binds the number its software
// was configured with, and moving that number would put it in the filter, in the openings and in
// what consumers are told while the software still listens on the old one — a port that reads as
// moved and is not.
func GivenPorts(m Manifest, layers []Layer) (map[int]int, error) {
known := map[int]bool{}
for _, l := range m.Listens {
known[l.Port] = true
}
for _, p := range m.Guards {
known[p] = true
}
for _, p := range containerPorts(m) {
known[p] = true
}
@@ -510,8 +509,9 @@ func GivenPorts(m Manifest, layers []Layer) (map[int]int, error) {
return nil, fmt.Errorf("%s gives %q a port, which is not a port", m.Module, portText)
}
if !known[port] {
return nil, fmt.Errorf("%s gives port %d a machine port, and it neither listens "+
"on, publishes nor guards %d — the setting reaches nothing", m.Module, port, port)
return nil, fmt.Errorf("%s gives port %d a machine port, and no container of its "+
"publishes %d — the mesh cannot move a port the module does not publish; the "+
"software would go on listening where it was told to", m.Module, port, port)
}
at, ok := asPort(value)
if !ok || at < 1 || at > 65535 {