Documentation
¶
Overview ¶
Package discovery implements warden.PeerDiscoverer: the sources that report which nodes are candidate members of the cluster. Discovery is advisory. A Discover channel delivers roster snapshots; the election manager verifies each candidate with an identify handshake and only the leader turns stable, verified candidates into one-at-a-time voting-membership changes. Quorum is always computed over the persisted voter set, never over a roster, so a discovery source that goes quiet or unavailable can never shrink the quorum denominator.
Three sources are provided:
- Static — reports one fixed roster (the configured peer seed) once and then stays quiet. This is the explicit "static" mode and the deterministic stand-in used by tests.
- Tailscale — polls the local tailscaled LocalAPI over its unix socket and reports peers selected by ACL tag and/or a hostname pattern.
- File — polls a JSON roster file (warden.Roster's shape). Doubles as a manual dynamic mode: an operator edits the file and warden picks it up.
Contract shared by the polling sources (Tailscale, File):
- The first successful snapshot is always sent; afterwards a snapshot is sent only when the node set actually changes (change-only delivery).
- On any read/parse error the source logs a rate-limited warning (once per distinct error transition) and sends NOTHING. Silence means consumers keep the last roster and the persisted membership — a source never emits an empty or partial roster on error. (A syntactically valid but empty roster, e.g. a file with "nodes": [], is a real empty roster and is sent.)
- Rosters are sorted by node ID.
- The channel is closed when the context ends.
The package is IO-bound by nature and uses the real clock (short poll intervals); it deliberately does not depend on services/warden/testclock.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type File ¶
type File struct {
// contains filtered or unexported fields
}
File is a PeerDiscoverer that polls a JSON roster file whose shape is exactly warden.Roster: {"nodes":[{"id":"...","addr":"host:port"}, ...]}. It doubles as a manual dynamic membership source — an operator edits the file and warden picks up the change on the next poll.
A missing, unreadable, or malformed file is an error: File logs a rate-limited warning and sends nothing, so consumers keep their last roster. A syntactically valid file with an empty node list is a real empty roster and is sent faithfully.
type Static ¶
type Static struct {
// contains filtered or unexported fields
}
Static is a PeerDiscoverer that reports one fixed roster and then stays quiet. It is the explicit "static" discovery mode (the configured peer seed is the roster and never changes) and a deterministic stand-in in tests.
type Tailscale ¶
type Tailscale struct {
// contains filtered or unexported fields
}
Tailscale is a PeerDiscoverer that polls the local tailscaled LocalAPI and reports peers selected by ACL tag and/or hostname pattern. Offline peers are retained in the roster: membership is a persisted, quorum-relevant fact, and liveness is the election manager's job — a rebooting voter must not fall out of the roster and shrink the cluster.
func NewTailscale ¶
func NewTailscale(cfg TailscaleConfig) *Tailscale
NewTailscale constructs a Tailscale discoverer, applying defaults for unset Socket/Port/PollInterval and compiling HostPattern. A malformed HostPattern (which config validation should already have rejected) is logged and ignored so the process still starts; that peer-selection path simply never matches.
type TailscaleConfig ¶
type TailscaleConfig struct {
// Socket is the tailscaled LocalAPI unix socket path
// (default /var/run/tailscale/tailscaled.sock).
Socket string
// Tag selects peers advertising this ACL tag, e.g. "tag:candacenet".
Tag string
// HostPattern is an RE2 pattern matched, anchored to the whole string,
// against a peer's HostName. Tag and HostPattern are OR'd: when both are
// set, either match selects the peer.
HostPattern string
// Port is the warden port used to compose a peer's Addr from its tailscale
// IPv4 (default 7717). cmd/main.go derives it from the node's bind port.
Port int
// PollInterval is how often tailscaled status is polled (default 15s).
PollInterval time.Duration
// IncludeSelf includes the local node (status.Self) in the roster. The
// local node is, by definition, a warden of this cluster, so when set it is
// included unconditionally — the Tag/HostPattern filter governs only remote
// peers. The documented default is true; because a bool cannot distinguish
// "unset" from an explicit false, cmd/main.go always passes true (there is
// no config knob to disable it) and tests set it explicitly.
IncludeSelf bool
}
TailscaleConfig configures a Tailscale discoverer.