Documentation
¶
Overview ¶
Package container provides container lifecycle management for agents.
Index ¶
- type AgentOpts
- type AgentRuntimeSpec
- type Container
- type ContainerManager
- type DockerManager
- func (m *DockerManager) CaptureToolserverDiagnostics(ctx context.Context, name, reason string) error
- func (m *DockerManager) Close()
- func (m *DockerManager) GetRunning(ctx context.Context, agentID uuid.UUID) (*Container, error)
- func (m *DockerManager) KillToolserver(ctx context.Context, name string) error
- func (m *DockerManager) LockSwap(agentID uuid.UUID) func()
- func (m *DockerManager) MarkBusy(agentID uuid.UUID)
- func (m *DockerManager) MarkIdle(agentID uuid.UUID)
- func (m *DockerManager) PruneAgentResources(ctx context.Context, validAgents map[string]AgentRuntimeSpec) []uuid.UUID
- func (m *DockerManager) RemoveImage(ctx context.Context, imageRef string) error
- func (m *DockerManager) RunningAgents(ctx context.Context, agentIDs []uuid.UUID) (map[uuid.UUID]bool, error)
- func (m *DockerManager) StartAgent(ctx context.Context, opts AgentOpts) (*Container, error)
- func (m *DockerManager) StartToolserver(ctx context.Context, opts ToolserverOpts) (*Container, error)
- func (m *DockerManager) StopAgent(ctx context.Context, agentID uuid.UUID) error
- func (m *DockerManager) StopToolserver(ctx context.Context, name string) error
- type ToolserverOpts
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AgentOpts ¶
type AgentOpts struct {
AgentID uuid.UUID
Image string // Docker image to run (e.g., "my-agent:abc123")
Token string // Versioned agent JWT issued from the live agent row
Env map[string]string // Additional environment variables
}
AgentOpts configures an agent container.
type AgentRuntimeSpec ¶ added in v0.4.0
PruneAgentResources removes Docker containers and images for agents that no longer exist in the database, and removes stale image tags for active agents (keeping only the current image_ref).
AgentRuntimeSpec is the persisted identity a reusable agent container must match.
type Container ¶
type Container struct {
ID string // Docker container ID
Name string // Human-readable name
Endpoint string // HTTP endpoint (e.g., "http://172.17.0.2:8080")
Token string // Bearer token for authenticating requests to this container
AgentID uuid.UUID
// Image is the tag the container was started with, copied from
// Docker's Config.Image at inspect time. StartAgent compares this
// against opts.Image to detect a stale running container after a
// build/rollback swap — adopting one with the wrong image would
// silently keep the agent on the old code.
Image string
// Network is the Docker network selected when the runtime was created.
// Managed isolation uses it to reject containers left on a shared network.
Network string
}
Container represents a running container.
type ContainerManager ¶
type ContainerManager interface {
// StartAgent ensures an agent container is running.
// Returns the existing container if already running and healthy.
StartAgent(ctx context.Context, opts AgentOpts) (*Container, error)
// GetRunning returns the running container for an agent without starting
// one if absent. Returns (nil, nil) when no container is up. Used by
// out-of-band signals (e.g. /refresh push) where booting a container
// just to notify it would defeat the purpose.
GetRunning(ctx context.Context, agentID uuid.UUID) (*Container, error)
// RunningAgents reports, per requested agent ID, whether a running
// container currently exists for it. One Docker query regardless of
// how many agents are asked about — for list/grid views that would
// otherwise fan out into one inspect per agent.
RunningAgents(ctx context.Context, agentIDs []uuid.UUID) (map[uuid.UUID]bool, error)
// StopAgent stops a specific agent's container (resolved from the agent
// ID via the instance-scoped name scheme).
StopAgent(ctx context.Context, agentID uuid.UUID) error
// MarkBusy / MarkIdle bracket an in-flight request to an agent
// container. While the in-flight count is above zero the idle
// reaper leaves the container alone, even past the idle timeout —
// so a run that runs longer than the timeout is not killed
// mid-execution. MarkIdle also refreshes the idle clock, so the
// timeout is measured from the end of the last request. Pair every
// MarkBusy with exactly one MarkIdle.
MarkBusy(agentID uuid.UUID)
MarkIdle(agentID uuid.UUID)
// StartToolserver starts an ephemeral toolserver container for build operations.
// Returns the container with a WebSocket endpoint for tool execution.
StartToolserver(ctx context.Context, opts ToolserverOpts) (*Container, error)
// StopToolserver stops and removes an ephemeral toolserver container.
StopToolserver(ctx context.Context, name string) error
// KillToolserver force-kills (SIGKILL) and removes an ephemeral
// toolserver container without waiting for graceful shutdown. Used
// on the build-cancel path so an in-flight tool stops emitting logs
// the moment cancel hits, instead of after the 5s graceful timeout.
KillToolserver(ctx context.Context, name string) error
// CaptureToolserverDiagnostics snapshots abnormal runtime state/logs
// before the ephemeral toolserver container is removed.
CaptureToolserverDiagnostics(ctx context.Context, name, reason string) error
// RemoveImage removes a Docker image by reference (e.g., "agentID:hash").
RemoveImage(ctx context.Context, imageRef string) error
// LockSwap serializes the agent's container-swap window. Held by the
// builder around Phase F (StopAgent → StartAgent → UpdateAgentRefs)
// and by EnsureRunning around its GetAgent → StartAgent critical
// section, so a concurrent trigger can't start the old image while a
// build is mid-swap (and vice versa). Returns a release function
// callers must defer. Scope is just the swap — codegen, image build,
// and migration validation all run outside the lock.
LockSwap(agentID uuid.UUID) func()
}
ContainerManager manages the lifecycle of agent containers.
type DockerManager ¶
type DockerManager struct {
// contains filtered or unexported fields
}
DockerManager implements ContainerManager using the Docker API.
func NewDockerManager ¶
NewDockerManager creates a Docker-based ContainerManager.
func (*DockerManager) CaptureToolserverDiagnostics ¶ added in v0.4.0
func (m *DockerManager) CaptureToolserverDiagnostics(ctx context.Context, name, reason string) error
CaptureToolserverDiagnostics snapshots abnormal tool runtime state/logs.
func (*DockerManager) Close ¶
func (m *DockerManager) Close()
Close stops the idle reaper and closes the Docker client.
func (*DockerManager) GetRunning ¶
GetRunning implements ContainerManager. Returns (nil, nil) when no container exists for the agent — caller is expected to treat that as "nothing to do" rather than an error. Repopulates the in-memory cache when it finds a running container Airlock didn't previously know about (typical after an Airlock restart).
func (*DockerManager) KillToolserver ¶
func (m *DockerManager) KillToolserver(ctx context.Context, name string) error
KillToolserver force-removes an ephemeral toolserver container without waiting for graceful shutdown. RemoveOptions{Force: true} sends SIGKILL and removes in one call, so any in-flight tool execution dies immediately. Used by the build-cancellation path: graceful shutdown is 5+ seconds of dead air during which the toolserver keeps running its in-flight tool (e.g. a long `bash go build`) and emitting log lines — which makes the cancel feel like it didn't take. Idempotent: returns nil/NotFound if the container is already gone.
func (*DockerManager) LockSwap ¶ added in v0.4.0
func (m *DockerManager) LockSwap(agentID uuid.UUID) func()
LockSwap acquires the per-agent container-swap mutex. See the ContainerManager interface comment for the design rationale.
func (*DockerManager) MarkBusy ¶ added in v0.4.0
func (m *DockerManager) MarkBusy(agentID uuid.UUID)
MarkBusy records the start of an in-flight request to an agent container. While the in-flight count is above zero the idle reaper skips the container, so a run that outlasts idleTimeout is not stopped mid-execution. Pair every MarkBusy with exactly one MarkIdle.
func (*DockerManager) MarkIdle ¶ added in v0.4.0
func (m *DockerManager) MarkIdle(agentID uuid.UUID)
MarkIdle records the end of an in-flight request. It also refreshes the idle clock so the timeout is measured from the end of the last request rather than its start.
func (*DockerManager) PruneAgentResources ¶
func (m *DockerManager) PruneAgentResources(ctx context.Context, validAgents map[string]AgentRuntimeSpec) []uuid.UUID
validAgents maps agent UUID string to its current runtime identity. Any container or UUID-tagged image owned by this instance (run.airlock.instance label) not matching this set is removed. Other instances' resources carry a different label value and are never listed here.
func (*DockerManager) RemoveImage ¶
func (m *DockerManager) RemoveImage(ctx context.Context, imageRef string) error
RemoveImage removes a Docker image by reference.
func (*DockerManager) RunningAgents ¶ added in v0.4.0
func (m *DockerManager) RunningAgents(ctx context.Context, agentIDs []uuid.UUID) (map[uuid.UUID]bool, error)
RunningAgents implements ContainerManager. One ContainerList call, scoped to this instance via the ownership label, then matched back to the requested IDs via agentName. Builder/toolserver containers ("<instance>-agent-builder-*") also carry the label but never equal an agentName(id), so they fall out of the lookup harmlessly.
func (*DockerManager) StartAgent ¶
StartAgent implements ContainerManager.
func (*DockerManager) StartToolserver ¶
func (m *DockerManager) StartToolserver(ctx context.Context, opts ToolserverOpts) (*Container, error)
StartToolserver starts an ephemeral toolserver container for build operations. The container runs the toolserver binary with the workspace mounted. Returns the container with a WebSocket endpoint for remote tool execution.
func (*DockerManager) StopAgent ¶
StopAgent implements ContainerManager. Idempotent: if Docker stopped or removed the container out-of-band (crash, OOM, daemon restart, the idle reaper), the desired post-condition — container not running — is already met, so a not-found error is success. Without this a dead-but-status='active' agent could never be stopped and so never restarted (the UI only offers Stop while active).
func (*DockerManager) StopToolserver ¶
func (m *DockerManager) StopToolserver(ctx context.Context, name string) error
StopToolserver stops and removes an ephemeral toolserver container.
type ToolserverOpts ¶
type ToolserverOpts struct {
Image string // toolserver image (e.g., "agent-builder:v1.0.0")
Mounts []mount.Mount // workspace bind mounts
WorkDir string // -space-dir value inside the container
Env []string // additional environment variables
LogCallback func(line string)
}
ToolserverOpts configures an ephemeral toolserver container for build operations.