nodes

package
v1.6.5 Latest Latest
Warning

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

Go to latest
Published: Jul 23, 2026 License: AGPL-3.0 Imports: 15 Imported by: 0

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

Constants

This section is empty.

Variables

View Source
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.

View Source
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

func BuildDirectClient

func BuildDirectClient(srv *models.Server) (docker.Client, error)

BuildDirectClient creates a Docker client for a non-agent remote node (socket or api) from its stored record. Agent nodes are connected by the tunnel manager instead and return an error here.

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

func NewClients(localID uint, local docker.Client) *Clients

NewClients creates the registry seeded with the local node's client.

func (*Clients) Connected

func (c *Clients) Connected(serverID uint) bool

Connected reports whether a node currently has a usable Docker client.

func (*Clients) For

func (c *Clients) For(serverID uint) (docker.Client, error)

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) IsLocal

func (c *Clients) IsLocal(serverID uint) bool

IsLocal reports whether the server id refers to the local node.

func (*Clients) IsSelfContainer

func (c *Clients) IsSelfContainer(serverID uint, containerID string) bool

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) Local

func (c *Clients) Local() docker.Client

Local returns the local node's Docker client.

func (*Clients) LocalID

func (c *Clients) LocalID() uint

LocalID returns the local node's server id.

func (*Clients) RemoteIDs

func (c *Clients) RemoteIDs() []uint

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

func (c *Clients) RemoveRemote(serverID uint)

RemoveRemote drops a remote node's client when its agent disconnects.

func (*Clients) SelfContainerID

func (c *Clients) SelfContainerID(serverID uint) string

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

func (c *Clients) SetLocalSelf(id string)

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

func (c *Clients) SetRemote(serverID uint, cl docker.Client)

SetRemote registers (or replaces) a remote node's client when its agent connects.

func (*Clients) SetRemoteSelf

func (c *Clients) SetRemoteSelf(serverID uint, id string)

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 NewManager

func NewManager(clients *Clients, nodes *node.Service) *Manager

func (*Manager) Clients

func (m *Manager) Clients() *Clients

Clients returns the per-node Docker client registry (for service wiring).

func (*Manager) ConnectDirect

func (m *Manager) ConnectDirect(srv *models.Server) error

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) Connected

func (m *Manager) Connected(nodeID uint) bool

Connected reports whether a node currently has a live agent tunnel.

func (*Manager) Disconnect

func (m *Manager) Disconnect(nodeID uint)

Disconnect tears down a node's tunnel (e.g. when it is deleted).

func (*Manager) DisconnectDirect

func (m *Manager) DisconnectDirect(id uint)

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

func (m *Manager) LoadDirect(ctx context.Context, interval time.Duration)

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

func (m *Manager) ReconcileHealth(ctx context.Context)

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

func (m *Manager) RefreshClient(srv *models.Server)

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

func (m *Manager) SetOnRemove(fn func(ctx context.Context, srv *models.Server, dc docker.Client))

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

func (m *Manager) SetOnStatusChange(fn func(nodeID uint, name string, online bool))

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

func (m *Manager) SetSubscriber(fn func(ctx context.Context, nodeID uint, dc docker.Client))

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

func (m *Manager) Teardown(ctx context.Context, srv *models.Server)

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.

Jump to

Keyboard shortcuts

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