Merge pull request 'A converged machine can speak unasked' (#48) from fix/a-converged-machine-can-speak-unasked into main
This commit was merged in pull request #48.
This commit is contained in:
+28
-1
@@ -1198,7 +1198,17 @@ func holdTheMachine(ctx context.Context, opts options, mine identity.Identity, s
|
||||
// A reconcile is otherwise silent. On an adopted node it speaks when what it holds or
|
||||
// its firewall changed, because that is how a predecessor still writing is caught
|
||||
// (novox/hq ADR 0100); publish decides whether anything did.
|
||||
if publish != nil && report.Refused == "" && (len(report.Held) > 0 || report.Firewall != "") {
|
||||
//
|
||||
// **And on any node, when it can say which links face outside** (novox/hq ADR 0140). A
|
||||
// converged node holds nothing and found no firewall, so this gate closed on it and the
|
||||
// node could speak only in reply to a declaration — while the mesh composes no declaration
|
||||
// for a node that has not said which links face outside. A machine waiting for a push that
|
||||
// was waiting for the machine, and measured: three converged machines sat silent while the
|
||||
// control plane refused to send them a filter.
|
||||
//
|
||||
// Offered, not published: whether it is news is still the watch's to decide, so an
|
||||
// unchanged answer costs one comparison every reconcile and nothing on the bus.
|
||||
if publish != nil && worthSaying(report) {
|
||||
publish(report)
|
||||
}
|
||||
switch {
|
||||
@@ -1210,6 +1220,23 @@ func holdTheMachine(ctx context.Context, opts options, mine identity.Identity, s
|
||||
}
|
||||
}
|
||||
|
||||
// worthSaying is whether a reconcile's report carries anything the mesh needs to hear unasked.
|
||||
//
|
||||
// **Named rather than written into the loop**, so the rule can be tested. It was a condition inline
|
||||
// and it was wrong in a way nothing could catch: it asked only what an adopted node reports, so a
|
||||
// converged node — which holds nothing and found no firewall — could speak only in reply to a
|
||||
// declaration, while the mesh composes no declaration for a node that has not said which links face
|
||||
// outside (novox/hq ADR 0140). Three machines sat silent waiting for a push that was waiting for them.
|
||||
//
|
||||
// A refused report says nothing about the machine, so it is not news; the refusal is said on the
|
||||
// console where a person reads it.
|
||||
func worthSaying(report link.Report) bool {
|
||||
if report.Refused != "" {
|
||||
return false
|
||||
}
|
||||
return len(report.Held) > 0 || report.Firewall != "" || len(report.Outward) > 0
|
||||
}
|
||||
|
||||
// applyDeclared applies a declaration that has already been proved to come from the mesh.
|
||||
//
|
||||
// Signature checking happens before this is called, in the link. By the time anything here runs,
|
||||
|
||||
@@ -533,3 +533,38 @@ func TestANewOutwardLinkIsSaidUnasked(t *testing.T) {
|
||||
t.Fatal("a changed outward link is not said, so the filter stays written around the old one")
|
||||
}
|
||||
}
|
||||
|
||||
// **A converged machine can say which links face outside, unasked.**
|
||||
//
|
||||
// A reconcile is otherwise silent, and the condition deciding when it speaks asked only what an
|
||||
// adopted node reports — what it holds, and the firewall it found. A converged node has neither, so
|
||||
// it could speak only in reply to a declaration, and the mesh composes no declaration for a node
|
||||
// that has not said which links face outside (novox/hq ADR 0140). Measured: three converged machines
|
||||
// sat silent while the control plane refused to send them a filter.
|
||||
func TestAConvergedMachineSaysItsOutwardLinksUnasked(t *testing.T) {
|
||||
// A converged node's reconcile: nothing held, no found firewall, and the links it can see.
|
||||
converged := link.Report{Outward: []string{"eth0"}}
|
||||
if !worthSaying(converged) {
|
||||
t.Fatal("a converged machine cannot say which links face outside, so it can never be " +
|
||||
"sent a filter — a machine waiting for a push that is waiting for the machine")
|
||||
}
|
||||
|
||||
// An adopted node's reasons still hold, because that is how a predecessor still writing is caught.
|
||||
if !worthSaying(link.Report{Firewall: "ufw"}) {
|
||||
t.Fatal("an adopted machine no longer says which firewall it found")
|
||||
}
|
||||
if !worthSaying(link.Report{Held: []link.Held{{ID: "a-file"}}}) {
|
||||
t.Fatal("an adopted machine no longer says what it holds")
|
||||
}
|
||||
|
||||
// And a reconcile with nothing to say stays silent, or every machine speaks every five minutes
|
||||
// about nothing.
|
||||
if worthSaying(link.Report{}) {
|
||||
t.Fatal("a reconcile with nothing to say speaks anyway")
|
||||
}
|
||||
|
||||
// A refused report says nothing about the machine; the refusal is for the console.
|
||||
if worthSaying(link.Report{Outward: []string{"eth0"}, Refused: "not for this node"}) {
|
||||
t.Fatal("a refused report is offered as news about the machine")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user