Documentation
¶
Overview ¶
Package nodes manages the control plane's view of cluster nodes: the per-node Docker client registry and the agent connection manager.
Index ¶
- Variables
- func BuildDirectClient(srv *models.Server) (docker.Client, error)
- type Clients
- func (c *Clients) Connected(serverID uint) bool
- func (c *Clients) For(serverID uint) (docker.Client, error)
- func (c *Clients) ForServiceTask(ctx context.Context, serviceName string) (docker.Client, string, error)
- func (c *Clients) IsLocal(serverID uint) bool
- func (c *Clients) IsSelfContainer(serverID uint, containerID string) bool
- func (c *Clients) Local() docker.Client
- func (c *Clients) LocalID() uint
- func (c *Clients) RemoteIDs() []uint
- func (c *Clients) RemoveRemote(serverID uint)
- func (c *Clients) SelfContainerID(serverID uint) string
- func (c *Clients) SetLocalSelf(id string)
- func (c *Clients) SetRemote(serverID uint, cl docker.Client)
- func (c *Clients) SetRemoteSelf(serverID uint, id string)
- type Manager
- func (m *Manager) Clients() *Clients
- func (m *Manager) ConnectDirect(srv *models.Server) error
- func (m *Manager) Connected(nodeID uint) bool
- func (m *Manager) Disconnect(nodeID uint)
- func (m *Manager) DisconnectDirect(id uint)
- func (m *Manager) Handle(srv *models.Server, token, agentVersion, agentContainerID string, ...)
- func (m *Manager) LoadDirect(ctx context.Context, interval time.Duration)
- func (m *Manager) ReconcileHealth(ctx context.Context)
- func (m *Manager) RefreshClient(srv *models.Server)
- func (m *Manager) SetOnConnect(...)
- func (m *Manager) SetOnRemove(fn func(ctx context.Context, srv *models.Server, dc docker.Client))
- func (m *Manager) SetOnStatusChange(fn func(nodeID uint, name string, online bool))
- func (m *Manager) SetSubscriber(fn func(ctx context.Context, nodeID uint, dc docker.Client))
- func (m *Manager) Teardown(ctx context.Context, srv *models.Server)
Constants ¶
This section is empty.
Variables ¶
var ErrNodeOffline = errors.New("node is offline (no connected agent)")
ErrNodeOffline is returned when a Docker client is requested for a node whose agent is not currently connected.
var ErrTaskUnreachable = errors.New("the service's task runs on a swarm node with no Miabi agent")
ErrTaskUnreachable is returned when a swarm service HAS a running task, but no engine we hold a client for can see its container — Swarm placed it on a node with no Miabi agent (an "unmanaged" swarm member).
Such a node runs the workload perfectly well: Swarm ships the task to it over the swarm control plane and never involves Miabi. But anything that must read the container itself (stats, exec, top) has no engine to read it through. Logs are the exception — the manager aggregates them (docker.StreamServiceLogs).
It is deliberately distinct from docker.ErrNotFound ("nothing is running"): reporting "no active container" for a service Swarm reports as 1/1 is simply false, and sends the user looking for the wrong problem.
Functions ¶
Types ¶
type Clients ¶
type Clients struct {
// contains filtered or unexported fields
}
Clients resolves a Docker client for a given server/node id. The local node uses the direct engine client; remote nodes use a tunneled client registered by the connection manager when their agent connects.
A server id of 0 (unset) resolves to the local node, so code paths that don't yet carry placement keep working on single-node installs.
func NewClients ¶
NewClients creates the registry seeded with the local node's client.
func (*Clients) For ¶
For returns the Docker client for a node, or ErrNodeOffline if a remote node has no connected agent.
func (*Clients) ForServiceTask ¶ added in v1.3.0
func (c *Clients) ForServiceTask(ctx context.Context, serviceName string) (docker.Client, string, error)
ForServiceTask resolves the engine and container id of a task of the named swarm service, wherever the scheduler placed it.
A service app has no fixed node: Swarm places its task on whichever node it likes, and ONLY that node's engine can see the resulting container. The manager can enumerate a service's tasks but cannot read their containers.
Correlating the task's swarm node id back to a Miabi node is not reliable — Server.SwarmNodeID is only persisted when Miabi itself joined the node to the swarm, and is empty for a node that joined any other way. So ask the engines directly: the local one first (free, and the common case), then each connected node. Exactly one node runs a given task, so the first hit is it.
Returns ErrTaskUnreachable when the service is running but on a node we cannot see, and docker.ErrNotFound when nothing is running at all.
func (*Clients) IsSelfContainer ¶
IsSelfContainer reports whether containerID is Miabi's own runtime container on the given node (the control plane locally, or that node's agent).
func (*Clients) RemoteIDs ¶
RemoteIDs returns the ids of remote nodes that currently have a live client (the local node is excluded). Used by the health sweep to probe each tunnel.
func (*Clients) RemoveRemote ¶
RemoveRemote drops a remote node's client when its agent disconnects.
func (*Clients) SelfContainerID ¶
SelfContainerID returns Miabi's own runtime container ID on the node — the control plane locally, or the node's agent — or "" when unknown (e.g. an offline agent or detection that found nothing).
func (*Clients) SetLocalSelf ¶
SetLocalSelf records the control-plane's own container ID (detected at startup) so it is protected from removal on the local node.
func (*Clients) SetRemote ¶
SetRemote registers (or replaces) a remote node's client when its agent connects.
func (*Clients) SetRemoteSelf ¶
SetRemoteSelf records a connected node's agent container ID (reported by the agent) so it is protected from removal on that node.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager accepts agent tunnels and maintains the live remote Docker clients in the registry, plus each node's online/offline status.
func (*Manager) ConnectDirect ¶
ConnectDirect builds and registers a direct node's Docker client, replacing any existing one. No-op for agent or local nodes. Best-effort: a build error is returned so callers can surface it, but the node stays registered as offline until the next attempt.
func (*Manager) Disconnect ¶
Disconnect tears down a node's tunnel (e.g. when it is deleted).
func (*Manager) DisconnectDirect ¶
DisconnectDirect drops a direct node's client (on delete or mode change).
func (*Manager) Handle ¶
func (m *Manager) Handle(srv *models.Server, token, agentVersion, agentContainerID string, ws *websocket.Conn)
Handle owns an authenticated agent WebSocket: it builds the tunnel, registers the node's remote Docker client, marks it online, and blocks until the tunnel closes (so the HTTP handler keeps the connection open). The caller has already validated the join token; the plaintext token is passed through so the connect hook can configure node-side infrastructure (e.g. the gateway).
func (*Manager) LoadDirect ¶
LoadDirect registers clients for all direct-access nodes at startup and runs a health poller that pings them on interval to keep their status current. It blocks until ctx is cancelled.
func (*Manager) ReconcileHealth ¶
ReconcileHealth actively verifies every connected node by pinging its Docker daemon over the tunnel. A node that fails to answer has a dead or half-open tunnel that yamux keepalive hasn't caught yet, so its session is closed — which triggers the normal disconnect cleanup (registry removal + MarkDisconnected), correcting a stale "online" status. Run periodically by the node-health cron task as a global backstop to the per-connection heartbeat; safe to call concurrently with real Docker traffic (ping opens its own short-lived stream).
func (*Manager) RefreshClient ¶
RefreshClient rebuilds a node's Docker client after its connectivity settings change. A live agent tunnel owns its own client registration, so this leaves a connected agent untouched — rebuilding here would evict (and close) the live client and flip the node offline even though the agent is still connected. For direct-access (socket/api) nodes it drops and rebuilds the client to pick up endpoint/credential changes.
func (*Manager) SetOnConnect ¶
func (m *Manager) SetOnConnect(fn func(ctx context.Context, srv *models.Server, token string, dc docker.Client))
SetOnConnect registers a hook run (in a goroutine) once a node's agent has connected and its remote Docker client is live — e.g. to deploy an edge-gateway node's gateway. The hook receives the node's plaintext join token, which is only available at connect time.
func (*Manager) SetOnRemove ¶
SetOnRemove registers a hook run when a node is being removed while still connected — e.g. to tear down an edge-gateway node's gateway. It runs with the node's live Docker client before the tunnel is closed. See Teardown.
func (*Manager) SetOnStatusChange ¶ added in v1.6.0
SetOnStatusChange registers a hook fired when a node comes online (agent connected) or goes offline (tunnel dropped). Used by alerting to raise/resolve a "node offline" alert. Best-effort: run in a goroutine, must not block.
func (*Manager) SetSubscriber ¶
SetSubscriber registers a per-node worker run (in a goroutine) for the node's whole connection lifetime: started once its Docker client is live, its context cancelled when the tunnel drops. Used for the per-node app event subscriber.
func (*Manager) Teardown ¶
Teardown runs the onRemove hook with the node's live Docker client, if the node is currently connected. Call it before Disconnect/DeleteNode so node-side infrastructure can be cleaned up over the still-open tunnel. Best-effort: a no-op when the node is offline or no hook is set.