Name the machines a failing network part points at in the node's health report, so the watchman holds it where the controller does (issue 774)

delivery.NetworkPart.Targets (mesh-sdk 6eae076) is filled where the report is made, by the controller's own rule:
- the hub's node for "hub";
- each resolver's node by its address on the private network;
- none when the part points at nothing, at this machine, or at an address no other mesh machine has.

The names come from the placements the node's own composer holds (Decided.Address, Decided.Hub). A spoke's tunnel names
only the hub, so the tunnel cannot name a resolver on another spoke. A node that does not compose its own names no
target.

Test: rows in TestAHealthStatementIsSaidOnTheLinkOpenNow (hub, two resolvers, a VPN's resolver, its own, a healthy
part).
This commit is contained in:
2026-10-29 23:05:02 +01:00
parent 3ed9abf658
commit c3ff18de4e
7 changed files with 98 additions and 11 deletions
+5 -1
View File
@@ -1488,7 +1488,11 @@ func writeHealthReport(ctx context.Context, queue *link.Session, h link.Health,
peers = append(peers, link.PeerSeen{Key: p.Key, Addresses: p.Addresses, Seen: p.Seen})
}
}
_, err := queue.WriteNodeHealth(ctx, link.NodeHealthOf(queue.Membership.Node, h, peers))
var machines link.Machines
if c := machinesNow.Load(); c != nil {
machines.ByAddress, machines.Hub = c.Machines()
}
_, err := queue.WriteNodeHealth(ctx, link.NodeHealthOf(queue.Membership.Node, h, peers, machines))
switch {
case err != nil && err.Error() != *unwritten:
*unwritten = err.Error()
+5
View File
@@ -626,6 +626,7 @@ func nodeAgent(ctx context.Context, opts options, signer ed25519.PublicKey, trus
continue
}
if composer != nil {
machinesNow.Store(composer) // the machines a failing network part points at, by the placements (issue 774)
composes.set(delivery.ComposesOwn)
env.Composed, env.SelfComposed, env.Trusted, env.Policy = composer, true, nil, composer.Policy
env.HoldsData = composer.HoldsData // what runs from the kept declaration says Data as its manifest does
@@ -768,6 +769,10 @@ func busyModules() []string {
return out
}
// machinesNow is the composer whose placements name the mesh's machines by address, for the health report's targets
// (writeHealthReport); nil on a node that does not compose its own, whose parts then name no target.
var machinesNow atomic.Pointer[selfcompose.Composer]
// keptRetired says the kept declaration is read no more: every module the seat's placement puts on this node has a have of
// its own (placedAllHave), so what runs is the agent's alone (ADR 0550 §2, design 47's L3 s9).
var keptRetired atomic.Bool