mesh-self-check reads a node's presence through the watchdogs client: a part's key is no node, a refused version is an error (ADR 0634 section 4; issue 1966)
Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
@@ -10,7 +10,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
watchdogs "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshwatchdogs"
|
||||
watchdogsclient "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshwatchdogsclient"
|
||||
assignerclient "git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient"
|
||||
placing "git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner"
|
||||
"net"
|
||||
@@ -65,16 +65,22 @@ func (c *Checker) heard() (map[string]bool, error) {
|
||||
}
|
||||
out := map[string]bool{}
|
||||
for _, k := range keys {
|
||||
node, ok := watchdogs.ParsePresenceByNodeKey(k)
|
||||
if !ok || node == "" {
|
||||
node, _, _, err := watchdogsclient.ParsePresenceKey(k)
|
||||
if err != nil || node == "" { // a part's key is no node's, and a key of no form is not read
|
||||
continue
|
||||
}
|
||||
raw, ok, err := c.Store.Get(PresenceRead, k)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("the presence of %s cannot be read: %w", node, err)
|
||||
}
|
||||
var p watchdogs.PresenceByNodeValue
|
||||
if ok && json.Unmarshal(raw, &p) == nil && p.Online {
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
p, err := watchdogsclient.DecodeNodePresence(raw)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("the presence of %s is not read: %w", node, err)
|
||||
}
|
||||
if p.Online {
|
||||
out[node] = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"errors"
|
||||
engineclient "git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient"
|
||||
nodeseat "git.novox.be/novox/mesh-contracts/go/seats/nodeengine"
|
||||
watchdogs "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshwatchdogs"
|
||||
watchdogsclient "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshwatchdogsclient"
|
||||
assignerclient "git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient"
|
||||
placing "git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner"
|
||||
catalogclient "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
|
||||
@@ -269,7 +269,7 @@ func machines() *memStore {
|
||||
pl.Modules = []placing.PlacedModule{{Module: "sshd"}} // a module key beside the node key
|
||||
}
|
||||
place(s, pl)
|
||||
_ = s.Put(PresenceRead, p.node, watchdogs.PresenceByNodeValue{V: 1, Online: p.online})
|
||||
_ = s.Put(PresenceRead, p.node, watchdogsclient.NodePresence{V: 1, Online: p.online})
|
||||
key, _ := assignerclient.SeatHoldersKey(BannedSeat, p.node)
|
||||
_ = s.Put(SeatHoldersRead, key, placing.SeatHolders{V: 1, Seat: BannedSeat, Scope: "node", Node: p.node,
|
||||
Holders: []placing.SeatHoldersHoldersItem{{Module: "fail2ban", Node: p.node}}})
|
||||
@@ -438,7 +438,7 @@ func (r *dataRig) holder(node string) {
|
||||
key, _ := assignerclient.SeatHoldersKey("node-backup", node)
|
||||
_ = r.s.Put(SeatHoldersRead, key, placing.SeatHolders{V: 1, Seat: "node-backup", Scope: "node", Node: node,
|
||||
Holders: []placing.SeatHoldersHoldersItem{{Module: "restic", Node: node}}})
|
||||
_ = r.s.Put(PresenceRead, node, watchdogs.PresenceByNodeValue{V: 1, Online: true})
|
||||
_ = r.s.Put(PresenceRead, node, watchdogsclient.NodePresence{V: 1, Online: true})
|
||||
}
|
||||
|
||||
// dataMesh builds the mesh: pg declares data (backed up within 48 h, written all the time within 24 h) and dumps; plex
|
||||
@@ -485,3 +485,24 @@ func dataMesh(change func(*dataRig)) *memStore {
|
||||
}
|
||||
return r.s
|
||||
}
|
||||
|
||||
// TestPresenceIsReadThroughTheWatchdogsClient holds the node's presence to the client's codec (ADR 0634 section 4): a
|
||||
// part's key (`part.<part>.<instance>`) is no node, and a value of a version the client refuses is a refusal, not a
|
||||
// node that is offline.
|
||||
func TestPresenceIsReadThroughTheWatchdogsClient(t *testing.T) {
|
||||
s := newStore()
|
||||
_ = s.Put(PresenceRead, "ace", watchdogsclient.NodePresence{V: 1, Online: true})
|
||||
_ = s.Put(PresenceRead, "part.watchman.1", watchdogsclient.PartPresence{V: 1, Online: true})
|
||||
c := &Checker{Store: s}
|
||||
heard, err := c.heard()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(heard) != 1 || !heard["ace"] {
|
||||
t.Errorf("heard %v, want only ace: a part's presence is no node's", heard)
|
||||
}
|
||||
_ = s.Put(PresenceRead, "g14", watchdogsclient.NodePresence{V: 99, Online: true})
|
||||
if _, err := c.heard(); err == nil {
|
||||
t.Error("a presence of a version the client refuses was read as a node's")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ go 1.26.0
|
||||
require (
|
||||
git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshwatchdogs v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshwatchdogsclient v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-contracts/go/seats/nodeengine v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner v0.0.0-00010101000000-000000000000
|
||||
|
||||
Reference in New Issue
Block a user