daemon

package
v0.0.5 Latest Latest
Warning

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

Go to latest
Published: Apr 14, 2026 License: MIT Imports: 34 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrAtCapacity = fmt.Errorf("at capacity")

ErrAtCapacity indicates the sandbox limit has been reached.

View Source
var ErrIdentityQuotaExceeded = fmt.Errorf("identity quota exceeded")

ErrIdentityQuotaExceeded indicates the per-identity sandbox limit has been reached.

Functions

func GenerateAuthToken

func GenerateAuthToken() (string, error)

GenerateAuthToken creates a random 32-byte hex token for agent authentication.

func GenerateID

func GenerateID(nodeID string) (string, error)

GenerateID creates a new sandbox ID. If nodeID is non-empty, the format is sbx-{nodeID}-{8 hex}, otherwise sbx-{8 hex}. Embedding the node ID in the sandbox ID lets a routing proxy parse the target node from the ID alone, without a lookup table.

func GenerateTemplateID

func GenerateTemplateID() (string, error)

GenerateTemplateID creates a new template ID in the format tpl-{8 hex chars}.

Types

type BufferedNotification

type BufferedNotification struct {
	Method  string
	Payload []byte // pre-marshaled JSON
}

BufferedNotification stores a notification that arrived while disconnected.

type CreateRequest

type CreateRequest struct {
	Profile  string            `json:"profile"`
	Template string            `json:"template"`
	Memory   string            `json:"memory"`
	CPU      float64           `json:"cpu"`
	Storage  string            `json:"storage"` // tmpfs size for /root (e.g. "500m", "1g"). Overrides profile default.
	TTL      int               `json:"ttl"`
	Labels   map[string]string `json:"labels"`
}

CreateRequest is the request body for POST /sandboxes.

type CreateTemplateRequest

type CreateTemplateRequest struct {
	SandboxID string `json:"sandbox_id"`
	Label     string `json:"label"`
}

CreateTemplateRequest is the request body for POST /templates.

type Daemon

type Daemon struct {
	Config           config.Config
	Runtimes         map[string]runtime.Runtime // keyed by runtime name ("docker", "docker+gvisor", "firecracker")
	Pool             *pool.Manager
	Registry         *Registry
	Templates        *TemplateRegistry
	TemplateBackend  TemplateBackend            // Default template backend (Docker).
	TemplateBackends map[string]TemplateBackend // Per-runtime template backends.
	Server           *Server
	Metrics          *Metrics
	Events           *EventBus
	Tunnels          *TunnelManager

	AuthLimit   *rateLimiter // Rate limiter for failed auth attempts.
	CreateLimit *rateLimiter // Rate limiter for sandbox creation per identity.
	Log         *slog.Logger
	// contains filtered or unexported fields
}

Daemon is the main sandboxd service.

func New

func New(cfg config.Config, log *slog.Logger) (*Daemon, error)

New creates a new Daemon instance.

func (*Daemon) ConnectAgent

func (d *Daemon) ConnectAgent(sbx *Sandbox) (*proxy.AgentConn, error)

ConnectAgent dials the agent for a sandbox.

func (*Daemon) CreateSandbox

func (d *Daemon) CreateSandbox(ctx context.Context, req CreateRequest, id identity.Identity, limits identity.RequestLimits) (*Sandbox, error)

CreateSandbox creates a new sandbox from the given parameters.

func (*Daemon) DestroySandbox

func (d *Daemon) DestroySandbox(ctx context.Context, sbx *Sandbox) error

DestroySandbox removes a sandbox and its container.

func (*Daemon) HandleDisconnect

func (d *Daemon) HandleDisconnect(sbx *Sandbox)

HandleDisconnect handles a WebSocket session ending for a sandbox. If TTL > 0, the sandbox enters disconnected state with a reaper. If TTL == 0, the sandbox is destroyed.

func (*Daemon) Reload

func (d *Daemon) Reload(path string) error

Reload reloads the configuration file and applies changes.

func (*Daemon) RuntimeFor

func (d *Daemon) RuntimeFor(sbx *Sandbox) runtime.Runtime

RuntimeFor returns the runtime associated with the sandbox, falling back to Docker.

func (*Daemon) Shutdown

func (d *Daemon) Shutdown(ctx context.Context) error

Shutdown gracefully stops the daemon.

func (*Daemon) Start

func (d *Daemon) Start(ctx context.Context) error

Start initializes the daemon: initializes runtimes, starts the warm pool, and begins listening for requests.

func (*Daemon) TemplateBackendFor

func (d *Daemon) TemplateBackendFor(sbx *Sandbox) TemplateBackend

TemplateBackendFor returns the template backend for the sandbox's runtime.

func (*Daemon) Verifier

func (d *Daemon) Verifier() *identity.Verifier

Verifier returns the current multi-tenant verifier, or nil if disabled.

type DockerTemplateBackend

type DockerTemplateBackend struct {
	Docker *client.Client
}

DockerTemplateBackend implements TemplateBackend using Docker commit.

func (*DockerTemplateBackend) Capture

func (b *DockerTemplateBackend) Capture(ctx context.Context, containerID, tag string) (string, int64, error)

Capture commits a running container as a Docker image.

func (*DockerTemplateBackend) Remove

func (b *DockerTemplateBackend) Remove(ctx context.Context, ref string) error

Remove deletes a Docker image.

type Event

type Event struct {
	ID        uint64                 `json:"id"`   // Monotonically increasing sequence number.
	Type      string                 `json:"type"` // "sandbox.created", "sandbox.destroyed", "sandbox.disconnected", "sandbox.reconnected"
	SandboxID string                 `json:"sandbox_id"`
	Identity  string                 `json:"identity,omitempty"`
	Timestamp time.Time              `json:"timestamp"`
	Data      map[string]interface{} `json:"data,omitempty"`
}

Event represents a sandbox lifecycle event.

type EventBus

type EventBus struct {
	// contains filtered or unexported fields
}

EventBus manages pub/sub for sandbox lifecycle events with replay support.

Events are assigned monotonically increasing sequence IDs and stored in a ring buffer. Subscribers that reconnect can replay missed events using Since(), and the SSE endpoint supports the standard Last-Event-ID header.

func NewEventBus

func NewEventBus(capacity int) *EventBus

NewEventBus creates a new EventBus with the given ring buffer capacity. A capacity of 0 defaults to 10 000 events.

func (*EventBus) Publish

func (eb *EventBus) Publish(event Event)

Publish assigns a sequence ID to the event, stores it in the ring buffer, and fans it out to all live subscribers. Non-blocking: drops events for subscribers whose channels are full.

func (*EventBus) Seq

func (eb *EventBus) Seq() uint64

Seq returns the current sequence number (the ID of the last published event).

func (*EventBus) Since

func (eb *EventBus) Since(afterID uint64) ([]Event, bool)

Since returns all buffered events with ID strictly greater than afterID, ordered by ID. If afterID is 0, returns the entire buffer. Returns the events and a boolean indicating whether the requested afterID was still in the buffer (true = complete, false = some events were lost).

func (*EventBus) Subscribe

func (eb *EventBus) Subscribe(bufferSize int) (string, <-chan Event)

Subscribe registers a new subscriber and returns a unique ID and a read-only channel. Returns "", nil if the maximum subscriber count has been reached.

func (*EventBus) Unsubscribe

func (eb *EventBus) Unsubscribe(id string)

Unsubscribe removes a subscriber and closes its channel.

type Metrics

type Metrics struct {
	// contains filtered or unexported fields
}

Metrics holds all Prometheus metrics for the sandboxd daemon.

func NewMetrics

func NewMetrics() *Metrics

NewMetrics creates a new Metrics instance.

func (*Metrics) IncCreateCold

func (m *Metrics) IncCreateCold()

IncCreateCold increments the cold sandbox creation counter.

func (*Metrics) IncCreateWarm

func (m *Metrics) IncCreateWarm()

IncCreateWarm increments the warm sandbox creation counter.

func (*Metrics) IncDestroy

func (m *Metrics) IncDestroy()

IncDestroy increments the sandbox destroy counter.

func (*Metrics) IncRequest

func (m *Metrics) IncRequest(method, path string, status int)

IncRequest increments the request counter for the given method, path, and status.

func (*Metrics) ObserveRequestDuration

func (m *Metrics) ObserveRequestDuration(method, path string, duration time.Duration)

ObserveRequestDuration records a request duration observation for the histogram.

type NotificationBuffer

type NotificationBuffer struct {
	// contains filtered or unexported fields
}

NotificationBuffer implements a two-tier buffer for notifications during disconnect. State notifications (process.exit, process.error) are stored in a non-evictable ring. Stream notifications (process.stdout, process.stderr) are stored in an evictable buffer.

func NewNotificationBuffer

func NewNotificationBuffer() *NotificationBuffer

NewNotificationBuffer creates a new notification buffer.

func (*NotificationBuffer) Add

func (b *NotificationBuffer) Add(method string, payload []byte)

Add adds a notification to the buffer. It categorizes based on method.

func (*NotificationBuffer) Count

func (b *NotificationBuffer) Count() int

Count returns the total number of buffered notifications.

func (*NotificationBuffer) Drain

func (b *NotificationBuffer) Drain() (state []BufferedNotification, stream []BufferedNotification, truncated int)

Drain returns all buffered notifications in replay order (state first, then stream) and resets the buffer. Returns the number of truncated stream messages.

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry manages active sandboxes.

func NewRegistry

func NewRegistry() *Registry

NewRegistry creates a new sandbox registry.

func (*Registry) Add

func (r *Registry) Add(sbx *Sandbox) error

Add registers a sandbox. Returns an error if the ID already exists.

func (*Registry) All

func (r *Registry) All() []*Sandbox

All returns every sandbox in the registry.

func (*Registry) AllocCPU

func (r *Registry) AllocCPU() float64

AllocCPU returns the total allocated CPU cores across all sandboxes.

func (*Registry) AllocMemory

func (r *Registry) AllocMemory() int64

AllocMemory returns the total allocated memory across all sandboxes in bytes.

func (*Registry) Count

func (r *Registry) Count() int

Count returns the total number of registered sandboxes.

func (*Registry) CountByIdentity

func (r *Registry) CountByIdentity(identity string) int

CountByIdentity returns the number of sandboxes belonging to the given identity.

func (*Registry) Get

func (r *Registry) Get(id string) (*Sandbox, bool)

Get retrieves a sandbox by ID.

func (*Registry) List

func (r *Registry) List(id identity.Identity) []*Sandbox

List returns all sandboxes matching the given identity. If the identity is empty (single-user mode), all sandboxes are returned.

func (*Registry) Remove

func (r *Registry) Remove(id string) bool

Remove atomically removes a sandbox from the registry. Returns true if the sandbox was found and removed, false if already gone. Only one concurrent caller can get true for a given ID.

type Sandbox

type Sandbox struct {
	ID          string            `json:"id"`
	ContainerID string            `json:"container_id"`
	Image       string            `json:"image"`
	State       SandboxState      `json:"state"`
	Identity    identity.Identity `json:"-"`
	IdentityStr string            `json:"identity,omitempty"`
	AgentAddr   string            `json:"-"`
	AuthToken   string            `json:"-"` // Token for agent authentication.
	Created     time.Time         `json:"created"`
	TTL         int               `json:"ttl"`
	Memory      int64             `json:"-"`
	CPU         float64           `json:"-"`
	Profile     string            `json:"profile,omitempty"`
	Template    string            `json:"template,omitempty"`
	Labels      map[string]string `json:"labels,omitempty"`
	RuntimeName string            `json:"runtime,omitempty"` // "docker" or "firecracker"

	// Session tracking.
	Session *proxy.Session `json:"-"`

	// TTL reconnection fields.
	DisconnectedAt time.Time `json:"-"`

	// Notification buffer for disconnected state.
	Buffer *NotificationBuffer `json:"-"`

	// Agent connection kept alive during disconnect for buffering.
	Agent *proxy.AgentConn `json:"-"`

	// Active port tunnels keyed by container port.
	Tunnels map[int]*Tunnel `json:"-"`
	// contains filtered or unexported fields
}

Sandbox represents a running sandbox container.

func (*Sandbox) CancelReaper

func (s *Sandbox) CancelReaper()

CancelReaper cancels the TTL reaper if one is running.

func (*Sandbox) ContainerIP

func (s *Sandbox) ContainerIP() string

ContainerIP extracts the container IP from AgentAddr (strips the :port suffix).

func (*Sandbox) GetSession

func (s *Sandbox) GetSession() *proxy.Session

GetSession atomically gets the active session.

func (*Sandbox) GetState

func (s *Sandbox) GetState() SandboxState

GetState atomically gets the sandbox state.

func (*Sandbox) Info

func (s *Sandbox) Info() SandboxInfo

Info returns the public API representation of the sandbox.

func (*Sandbox) MatchLabels

func (s *Sandbox) MatchLabels(filters map[string]string) bool

MatchLabels returns true if the sandbox's labels match all the given filters. Thread-safe: acquires the sandbox mutex.

func (*Sandbox) SetSession

func (s *Sandbox) SetSession(session *proxy.Session) *proxy.Session

SetSession atomically sets the active session, returning the old one.

func (*Sandbox) SetState

func (s *Sandbox) SetState(state SandboxState)

SetState atomically sets the sandbox state.

func (*Sandbox) StartReaper

func (s *Sandbox) StartReaper(ttl time.Duration, destroyFn func())

StartReaper starts a goroutine that will call destroyFn after TTL expires. Returns immediately. Can be cancelled by calling CancelReaper.

type SandboxInfo

type SandboxInfo struct {
	ID       string            `json:"id"`
	Image    string            `json:"image"`
	State    SandboxState      `json:"state"`
	Created  time.Time         `json:"created"`
	TTL      int               `json:"ttl"`
	Profile  string            `json:"profile,omitempty"`
	Template string            `json:"template,omitempty"`
	Labels   map[string]string `json:"labels,omitempty"`
}

SandboxInfo is the JSON-serializable sandbox information returned by the API.

type SandboxState

type SandboxState string

SandboxState represents the lifecycle state of a sandbox.

const (
	StateCreating     SandboxState = "creating"
	StateRunning      SandboxState = "running"
	StateDisconnected SandboxState = "disconnected"
	StateStopping     SandboxState = "stopping"
	StateStopped      SandboxState = "stopped"
)

type SandboxStats

type SandboxStats struct {
	CPUPercent       float64 `json:"cpu_percent"`
	MemoryUsageBytes uint64  `json:"memory_usage_bytes"`
	MemoryLimitBytes uint64  `json:"memory_limit_bytes"`
	MemoryPercent    float64 `json:"memory_percent"`
	NetworkRxBytes   uint64  `json:"network_rx_bytes"`
	NetworkTxBytes   uint64  `json:"network_tx_bytes"`
	PIDs             uint64  `json:"pids"`
	UptimeSeconds    float64 `json:"uptime_seconds"`
}

SandboxStats is the JSON response for GET /sandboxes/{id}/stats.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server manages the HTTP listeners for the daemon.

func NewServer

func NewServer(d *Daemon) *Server

NewServer creates a new HTTP server for the daemon.

func (*Server) Shutdown

func (s *Server) Shutdown(ctx context.Context) error

Shutdown gracefully stops the server.

func (*Server) Start

func (s *Server) Start() error

Start begins listening on the configured socket and optionally TCP.

type Template

type Template struct {
	ID         string    `json:"id"`
	Label      string    `json:"label"`
	Image      string    `json:"image"`   // Docker image tag or snapshot path.
	Backend    string    `json:"backend"` // "docker" or "firecracker".
	Identity   string    `json:"identity,omitempty"`
	Size       int64     `json:"size"`
	CreatedAt  time.Time `json:"created_at"`
	LastUsedAt time.Time `json:"last_used,omitempty"`
}

Template represents a saved sandbox template.

type TemplateBackend

type TemplateBackend interface {
	// Capture creates a template from a running sandbox, returning the
	// image/snapshot reference and its size in bytes.
	Capture(ctx context.Context, containerID, tag string) (ref string, size int64, err error)

	// Remove deletes the underlying image or snapshot files.
	Remove(ctx context.Context, ref string) error
}

TemplateBackend abstracts how templates are captured and cleaned up. The default implementation uses Docker commit; a Firecracker implementation would snapshot memory + disk state instead.

type TemplateRegistry

type TemplateRegistry struct {
	// contains filtered or unexported fields
}

TemplateRegistry manages template metadata in a thread-safe manner.

func NewTemplateRegistry

func NewTemplateRegistry() *TemplateRegistry

NewTemplateRegistry creates a new template registry.

func (*TemplateRegistry) Add

func (r *TemplateRegistry) Add(tpl *Template) error

Add registers a template. Returns an error if the ID already exists.

func (*TemplateRegistry) All

func (r *TemplateRegistry) All() []*Template

All returns a snapshot of all templates in the registry.

func (*TemplateRegistry) Count

func (r *TemplateRegistry) Count() int

Count returns the total number of registered templates.

func (*TemplateRegistry) CountByIdentity

func (r *TemplateRegistry) CountByIdentity(ident string) int

CountByIdentity returns the number of templates belonging to the given identity.

func (*TemplateRegistry) Get

func (r *TemplateRegistry) Get(id string) (*Template, bool)

Get retrieves a template by ID.

func (*TemplateRegistry) List

func (r *TemplateRegistry) List(id identity.Identity) []*Template

List returns all templates matching the given identity. If the identity is empty (single-user mode), all templates are returned.

func (*TemplateRegistry) MarkUsed

func (r *TemplateRegistry) MarkUsed(id string)

MarkUsed updates the LastUsedAt timestamp for a template.

func (*TemplateRegistry) Remove

func (r *TemplateRegistry) Remove(id string) (*Template, bool)

Remove removes a template from the registry. Returns the template if found.

type Tunnel

type Tunnel struct {
	SandboxID   string
	Port        int // container port
	HostPort    int // allocated host port
	ContainerIP string
	// contains filtered or unexported fields
}

Tunnel represents an active host-port → container-port mapping.

type TunnelInfo

type TunnelInfo struct {
	Port     int    `json:"port"`
	HostPort int    `json:"host_port"`
	URL      string `json:"url"`
}

TunnelInfo is the JSON-serializable tunnel information returned by the API.

type TunnelManager

type TunnelManager struct {
	// contains filtered or unexported fields
}

TunnelManager manages host-port tunnels for sandboxes.

func NewTunnelManager

func NewTunnelManager(portMin, portMax, maxConns int, log *slog.Logger) *TunnelManager

NewTunnelManager creates a tunnel manager.

func (*TunnelManager) Close

func (tm *TunnelManager) Close(t *Tunnel)

Close shuts down a tunnel, draining active connections.

func (*TunnelManager) Expose

func (tm *TunnelManager) Expose(ctx context.Context, sbx *Sandbox, containerPort int, timeout time.Duration) (*Tunnel, error)

Expose creates a tunnel from a host port to container_ip:port. It probes the container port for readiness with exponential backoff up to timeout.

Jump to

Keyboard shortcuts

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