Documentation
¶
Overview ¶
Package swarms resolves an application's destination to something that can apply to it.
This is the seam Phase 3 replaces with multi-swarm through swarmcli-rbac-proxy. Per D2 the OSS default resolves exactly one swarm: the one this controller runs in, reached over the docker.sock it is mounted with. It lives in swarms/local and the binary blank-imports it, so that this package — the contract a companion implements — carries no implementation of its own and nothing importing it links the Docker applier.
What a registry may be asked ¶
Registry is the whole of what a companion must implement. Two capabilities beyond it are optional interfaces rather than methods, which is the shape this repository uses everywhere a backend may or may not be able to answer: Lister enumerates swarms, NodeReach reaches the individual nodes of one. A registry that cannot do either simply does not implement them, and the callers degrade to what the OSS build has always done rather than failing.
The alternative — putting them on Registry — would mean every companion, including one that only ever wanted to point at a second swarm, had to write four methods it has no answer for.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Lister ¶
type Lister interface {
// Swarms names every swarm this registry resolves, including the empty
// target if it resolves the local one.
//
// Targets rather than names, so that this survives Target growing a second
// field. Handing back bare names would make a consumer re-wrap them, and
// the day a target is more than a swarm name — a tenant, a context, a
// credential — that re-wrapping would have nothing to put in it and this
// signature would have to break. It has no consumer yet, so it costs
// nothing to get right now and cannot be got right later.
Swarms(ctx context.Context) ([]Target, error)
}
Lister is the optional interface a Registry implements when it can enumerate the swarms it resolves.
It exists for the sweep. prune finds a departed application's releases by asking a swarm what it still holds, so it can only find them on a swarm it can name — and after an application leaves the app set, nothing names its swarm any more. A registry resolving one swarm has no gap to close and does not implement this; a multi-swarm one does, and the sweep can then cover every swarm rather than the one the controller happens to run in.
A consumer must swarm-qualify what it holds before acting on the result. The sweep spares any release the current applications still declare, and it matches those by release name — which is unique within a swarm and not across them. Comparing an unqualified list against several swarms' releases would spare a release on swarm B because a different one shares its name on swarm A, and, worse, delete one on B that nothing on B declares. Nothing consumes this yet for exactly that reason: the qualification is a change to what the app-set loop hands the sweep, not to the sweep.
type Node ¶
type Node struct {
// ID is the node's Swarm id, which is what the daemon's node list keys on.
ID string
// Hostname is what an operator recognises the node by, and is what the
// controller logs. It is not unique and is not a key.
Hostname string
}
Node is one node of a swarm, as a registry can reach it.
A struct for the same reason Target is: it is handed to NodeBackend, so it can grow — an address, a role, a reachability state — without breaking an implementation outside this repository.
type NodeBackend ¶
type NodeBackend interface {
// StackVolumes names the node's volumes labelled as belonging to a stack.
StackVolumes(ctx context.Context, stack string) ([]string, error)
// RemoveVolume deletes one of them by name. A volume that is already gone
// is not an error: a caller retrying a partial sweep must not be failed by
// the part that worked.
RemoveVolume(ctx context.Context, name string) error
}
NodeBackend is what node-local work needs, and deliberately nothing more.
It is not a charts.Backend. A worker node's daemon cannot deploy a stack, remove one or read a service spec — those are manager operations — so handing back something with DeployStack on it would promise what the node cannot do and invite a caller to try. The two methods here are the two questions that are genuinely node-local.
A NodeBackend is only ever asked about a release the caller has already proved it owns and may delete. It is not a second gate, and an implementation should not try to be one: it has none of the evidence — no owner stamp, no app set — that the decision was made from.
type NodeReach ¶
type NodeReach interface {
// Nodes names the nodes of a target's swarm that this registry can reach.
//
// Reachable, not merely present. A node this cannot connect to should be
// left out rather than listed and then failed on: an omission is the
// recoverable answer — the caller covers what it was given and reports the
// rest as uncovered — while a node that is listed and then unreachable
// fails the caller's whole operation, which for a node that is permanently
// gone means an operation that can never complete.
//
// Omitting is safe because no caller may assume this is every node. prune
// checks the count against the swarm's own before it claims to have covered
// the swarm, precisely so that "a node was down" degrades to an honest
// partial rather than to a silent one.
Nodes(ctx context.Context, t Target) ([]Node, error)
// NodeBackend returns a handle to one node's own daemon.
NodeBackend(ctx context.Context, t Target, node Node) (NodeBackend, error)
}
NodeReach is the optional interface a Registry implements when it can reach the individual nodes of a swarm rather than only the swarm's manager API.
It exists because one question the controller has to answer is node-local and nothing else in the design is. The daemon's volume list answers from the node's own store — only CSI cluster volumes come from swarm, and only on a manager — while an ordinary named volume is created by the engine running the task that mounts it. So a stack's volumes live on whichever nodes scheduled its tasks, and the manager API cannot see them, let alone delete them.
**The OSS build does not implement this**, and that is a deployment fact rather than an omission: a Swarm node does not expose its daemon to anything by default, and this controller is given one socket, its own. Reaching the others means operator-provisioned endpoints on every node, a per-node agent, or a privileged global-mode service — each of which is a decision about what the controller is allowed to be, not a function somebody forgot to write.
So prune keeps deleting what its own node can see and saying plainly that that was not all of them, and a companion that has solved the reach properly makes the same sweep complete. See Eldara-Tech/swarmcli-cd#108.
type Registry ¶
type Registry interface {
// Backend returns the backend for a target.
//
// Implementations return the same backend for the same target rather than
// reconnecting per call: the reconcile loop asks on every tick.
Backend(ctx context.Context, t Target) (charts.Backend, error)
}
Registry resolves a destination to a backend.
It hands back a charts.Backend rather than an interface of our own. swarmcli-cd is built on the chart engine — charts.NewEngineWith takes any Backend, which is what makes a controller-supplied applier possible at all — and a fourteen-method pass-through would buy nothing but a second definition to keep in step with CE's.
type Target ¶
type Target struct {
// Swarm is the destination's swarm, as application.Spec.Destination names
// it. Empty means the swarm this controller runs in, which for the OSS
// build is the only one there is.
Swarm string
}
Target names what a backend is wanted for.
It is a struct rather than a parameter list for the reason secrets.Request states: an implementation receives the struct, so a field added later costs it nothing, whereas widening a parameter list is a breaking change to an interface implemented outside this repository. Registry is the only seam method whose parameters this repository can still choose freely — after the companion ships, it cannot.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package local is the OSS swarms.Registry: it resolves exactly one swarm, the one this controller runs in, over the docker.sock it is mounted with (D2).
|
Package local is the OSS swarms.Registry: it resolves exactly one swarm, the one this controller runs in, over the docker.sock it is mounted with (D2). |