Name the machines a failing network part points at, so the watchman holds it there as the controller does without any machine's address (issue 774)

NetworkPart.Targets: the hub's machine for "hub", the machine whose tunnel address is each resolver's; empty where the
part is the machine's own. Filled by the node-engine from its tunnel's peers. Test: a row in
TestTheControlRecordsReadTheirWritersValues, read back byte-equal.
This commit is contained in:
2026-10-29 23:02:54 +01:00
parent 94d0de5c19
commit 6eae0765f4
2 changed files with 15 additions and 4 deletions
+6 -1
View File
@@ -2,6 +2,7 @@ package delivery
import (
"encoding/json"
"strings"
"testing"
"time"
)
@@ -31,6 +32,10 @@ func TestTheControlRecordsReadTheirWritersValues(t *testing.T) {
`"relogin":[{"account":"jochen","module":"brother","resource":"brother.scanner","reason":"relogin needed: the session began before scanner","since":"2026-10-29T20:00:00Z"}],` +
`"found":[{"module":"photos","resource":"photos.library","path":"/srv/photos","reason":"used as found: owned by root","since":"2026-10-29T20:00:00Z"}],` +
`"at":"2026-10-29T20:00:00Z"}`, &NodeHealth{}},
// A part pointing at another machine names it (issue 774): the hub's tunnel, held at the hub's machine.
{"a node's health report, a part pointing at the hub", `{"v":1,"node":"anchor","network":{"state":"unhealthy",` +
`"since":"2026-10-29T20:00:00Z","parts":[{"part":"tunnel","state":"unhealthy","reason":"the tunnel to the hub has not handshaken for over five minutes",` +
`"toward":["hub"],"targets":["novox"],"since":"2026-10-29T20:00:00Z"}]},"at":"2026-10-29T20:00:00Z"}`, &NodeHealth{}},
{"the predefined list", `{"v":1,"commit":"abc","at":"2026-10-29T12:00:00Z","list":{"domain":{"type":"string"}}}`, &PredefinedKept{}},
} {
if err := json.Unmarshal([]byte(c.raw), c.into); err != nil {
@@ -40,7 +45,7 @@ func TestTheControlRecordsReadTheirWritersValues(t *testing.T) {
var want, got any
_ = json.Unmarshal([]byte(c.raw), &want)
_ = json.Unmarshal(again, &got)
if string(jsonOf(want)) != string(jsonOf(got)) || ((c.name == "declared packages" || c.name == "a node's health report") && string(again) != c.raw) {
if string(jsonOf(want)) != string(jsonOf(got)) || ((c.name == "declared packages" || strings.HasPrefix(c.name, "a node's health report")) && string(again) != c.raw) {
t.Errorf("%s reads back as %s", c.name, again)
}
}
+9 -3
View File
@@ -63,9 +63,15 @@ type NetworkPart struct {
Writer string `json:"writer,omitempty"`
Owner string `json:"owner,omitempty"`
// Toward is what the failure points at: "hub", or each resolver's address that failed.
Toward []string `json:"toward,omitempty"`
Since time.Time `json:"since"`
Streak int `json:"streak,omitempty"`
Toward []string `json:"toward,omitempty"`
// Targets are the mesh machines the failure points at, by node name, as the controller holds a part at the machine
// it points at: the hub's machine for "hub", and the machine whose tunnel address is each resolver's. Empty where the
// part is the machine's own: it points at nothing, at this machine, or at an address no other mesh machine has (the
// resolver a VPN client wrote in). Filled by the node-engine from its tunnel's peers, so the watchman needs no
// address of any machine (issue 774).
Targets []string `json:"targets,omitempty"`
Since time.Time `json:"since"`
Streak int `json:"streak,omitempty"`
}
// UnitsHealth is the machine's service managers (issue 315).