container

package
v0.4.0 Latest Latest
Warning

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

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

Documentation

Overview

Package container provides container lifecycle management for agents.

Index

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

type AgentRuntimeSpec struct {
	Image        string
	TokenVersion int64
	Status       string
}

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

func NewDockerManager(cfg *config.Config, pool *pgxpool.Pool, logger *zap.Logger) *DockerManager

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

func (m *DockerManager) GetRunning(ctx context.Context, agentID uuid.UUID) (*Container, error)

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

func (m *DockerManager) StartAgent(ctx context.Context, opts AgentOpts) (*Container, error)

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

func (m *DockerManager) StopAgent(ctx context.Context, agentID uuid.UUID) error

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.

Jump to

Keyboard shortcuts

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