discovery

package
v0.0.0-...-b7dec32 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 27, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

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

func CompileHostPattern

func CompileHostPattern(pattern string) (*regexp.Regexp, error)

CompileHostPattern compiles an RE2 host pattern anchored to the whole string. services/warden/config validates operator patterns against the identical anchoring; keep the two in sync.

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.

func NewFile

func NewFile(path string, poll time.Duration) *File

NewFile returns a File discoverer for path, polling every poll (defaulting a non-positive poll to 2s).

func (*File) Discover

func (f *File) Discover(ctx context.Context) (<-chan warden.Roster, error)

Discover polls the roster file and delivers change-only snapshots until ctx ends, then closes the channel.

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.

func NewStatic

func NewStatic(nodes []warden.Node) *Static

NewStatic returns a Static discoverer over a copy of nodes.

func (*Static) Discover

func (s *Static) Discover(ctx context.Context) (<-chan warden.Roster, error)

Discover sends exactly one Roster (a copy of the configured nodes) promptly, keeps the channel open with no further sends, and closes it when ctx ends.

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.

func (*Tailscale) Discover

func (t *Tailscale) Discover(ctx context.Context) (<-chan warden.Roster, error)

Discover polls tailscaled and delivers change-only snapshots until ctx ends, then closes the channel.

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL