From 1e0c6a351600da824c65fac631b7d3ee2d666a3b Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 22 Sep 2026 18:00:03 +0200 Subject: [PATCH] Publish a reconcile report when what is reachable changed, so the controller's converge preview stays fresh (hq ADR 0100) --- cmd/mesh-host/main.go | 12 +++++++++--- cmd/mesh-host/main_test.go | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/cmd/mesh-host/main.go b/cmd/mesh-host/main.go index 12f3e42..cbc7718 100644 --- a/cmd/mesh-host/main.go +++ b/cmd/mesh-host/main.go @@ -669,12 +669,18 @@ type adoptionWatch struct { last string } -// fingerprint is what a report says about adoption: each hold and whether it changed, and the -// firewall. +// fingerprint is what a report says about adoption: each hold and whether it changed, the +// firewall, and what is reachable on the machine — which only an adopted node reports, and which +// is what the controller previews a flip from, so a port that opens or closes between deliveries +// must reach it too (novox/hq ADR 0100). func adoptionFingerprint(r link.Report) string { parts := []string{"firewall=" + r.Firewall} for _, h := range r.Held { - parts = append(parts, h.ID+"="+h.Changed) + parts = append(parts, "held "+h.ID+"="+h.Changed) + } + for _, reach := range r.Reachable { + parts = append(parts, fmt.Sprintf("reach %s %s:%d %s %v %d", reach.Protocol, reach.Address, + reach.Port, reach.By, reach.Published, reach.ContainerPort)) } sort.Strings(parts[1:]) return strings.Join(parts, "\n") diff --git a/cmd/mesh-host/main_test.go b/cmd/mesh-host/main_test.go index cdacdf7..72eb1a1 100644 --- a/cmd/mesh-host/main_test.go +++ b/cmd/mesh-host/main_test.go @@ -169,3 +169,24 @@ func TestWhatTheLinkPublishedCountsAsSaid(t *testing.T) { t.Error("a reconcile repeated what the link had just published") } } + +func TestAReconcileSpeaksWhenWhatIsReachableChanged(t *testing.T) { + // The controller previews a flip from what the node last said is reachable; a port that opened + // since must reach it without waiting for the next delivery (novox/hq ADR 0100). + w := &adoptionWatch{} + before := link.Report{Firewall: "ufw", Reachable: []link.Reach{ + {Protocol: "tcp", Address: "0.0.0.0", Port: 22, By: "sshd"}}} + if !w.changed(before) { + t.Fatal("the first report was not said") + } + reordered := link.Report{Firewall: "ufw", Reachable: []link.Reach{ + {Protocol: "tcp", Address: "0.0.0.0", Port: 22, By: "sshd"}}} + if w.changed(reordered) { + t.Error("the same reachable set was said again") + } + opened := link.Report{Firewall: "ufw", Reachable: append(before.Reachable, + link.Reach{Protocol: "tcp", Address: "0.0.0.0", Port: 8080, By: "hello-web", Published: true, ContainerPort: 80})} + if !w.changed(opened) { + t.Error("a newly published port was not said") + } +}