sandboxd

package
v0.1.3 Latest Latest
Warning

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

Go to latest
Published: Aug 31, 2026 License: AGPL-3.0 Imports: 10 Imported by: 0

Documentation

Overview

Package sandboxd is a small HTTP client for the node-local sandboxd warm-pool daemon (the sandbox repo's docs/sandboxd-api.md). It uses only the standard library. The L2 ClaimGateway fronts one of these clients per node: Claim transfers ownership of an already-running microVM in sub-millisecond time, and Release destroys a sandbox's VM on owner-authorized teardown.

Index

Constants

This section is empty.

Variables

View Source
var ErrNodeAtCapacity = errors.New("sandboxd: node at capacity or draining")

ErrNodeAtCapacity is returned by Claim when sandboxd answers 429 (the node is at max_claims, the calling tenant is at its own max_claims, or the node is draining), or when a 200 carries only a peer redirect rather than a delivered sandbox. In every case this node handed over no VM, so the L2 gateway maps this to its ErrNoNodeCapacity sentinel and falls back to the L1 Kubernetes path.

Functions

This section is empty.

Types

type Checkpoint

type Checkpoint struct {
	ID        string    `json:"id"`
	Name      string    `json:"name,omitempty"`
	SandboxID string    `json:"sandbox_id"`
	Key       PoolKey   `json:"key"`
	CreatedAt time.Time `json:"created_at"`
}

Checkpoint is a captured sandbox state that branches can be claimed from.

type CheckpointClaimSpec

type CheckpointClaimSpec struct {
	TTLSeconds int `json:"ttl_seconds,omitempty"`
}

CheckpointClaimSpec is the POST /v1/checkpoints/{id}/claim body.

type CheckpointSpec

type CheckpointSpec struct {
	Token string `json:"token,omitempty"`
	Name  string `json:"name,omitempty"`
}

CheckpointSpec is the POST /v1/sandboxes/{id}/checkpoint body.

type ClaimResult

type ClaimResult struct {
	ID        string    `json:"id"`
	Token     string    `json:"token"`
	Deadline  time.Time `json:"deadline"`
	OwnerAddr string    `json:"owner_addr"`
	// FromCheckpoint is the lineage edge when the claim branched from a checkpoint.
	FromCheckpoint string `json:"from_checkpoint,omitempty"`
	// Redirect, when non-empty on a 200, names warm peers to retry at instead of a
	// delivered sandbox. Claim treats this as a capacity miss (see ErrNodeAtCapacity).
	Redirect []string `json:"redirect,omitempty"`
}

ClaimResult is the POST /v1/claim success body.

type ClaimSpec

type ClaimSpec struct {
	Template   string `json:"template"`
	Net        string `json:"net,omitempty"`
	Size       string `json:"size,omitempty"`
	TTLSeconds int    `json:"ttl_seconds,omitempty"`
	// NoRedirect is set by an SDK retrying at a redirect target; the gateway does
	// not chase redirects (it falls back to L1 instead), so it stays false.
	NoRedirect bool `json:"no_redirect,omitempty"`
	// ClaimRef is the k8s "<namespace>/<name>" of the Sandbox this claim is
	// created for. sandboxd records it on the claim and echoes it in its
	// operator index, so the aggregated read path can map a listed sandbox back
	// to the name it was claimed under. Empty for claims with no k8s identity.
	ClaimRef string `json:"claim_ref,omitempty"`
}

ClaimSpec is the POST /v1/claim body. Net defaults to "none" and Size to "small" server-side; TTLSeconds 0 means the server default.

type Client

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

Client talks to a single sandboxd instance. It is safe for concurrent use.

func New

func New(baseURL, token string, opts ...Option) *Client

New returns a Client for the sandboxd at baseURL, authenticating resource verbs with the node api_token (may be empty when sandboxd runs without auth).

func (*Client) Checkpoint

func (c *Client) Checkpoint(ctx context.Context, id string, spec CheckpointSpec) (Checkpoint, error)

Checkpoint performs POST /v1/sandboxes/{id}/checkpoint, capturing the sandbox's state under a fresh id. The source keeps running.

func (*Client) Checkpoints

func (c *Client) Checkpoints(ctx context.Context) ([]Checkpoint, error)

Checkpoints performs GET /v1/checkpoints, newest first.

func (*Client) Claim

func (c *Client) Claim(ctx context.Context, spec ClaimSpec) (ClaimResult, error)

Claim performs POST /v1/claim, returning the delivered sandbox on success. A 429, or a 200 that carries only a peer redirect, yields ErrNodeAtCapacity.

func (*Client) ClaimCheckpoint

func (c *Client) ClaimCheckpoint(ctx context.Context, checkpointID string, spec CheckpointClaimSpec) (ClaimResult, error)

ClaimCheckpoint performs POST /v1/checkpoints/{id}/claim, delivering a fresh sandbox branched from the checkpoint's exact state.

func (*Client) DeleteCheckpoint

func (c *Client) DeleteCheckpoint(ctx context.Context, checkpointID string) error

DeleteCheckpoint performs DELETE /v1/checkpoints/{id}. A 404 is success.

func (*Client) Fork

func (c *Client) Fork(ctx context.Context, id string, spec ForkSpec) (ForkResult, error)

Fork performs POST /v1/sandboxes/{id}/fork, branching the sandbox into count children. The parent is checkpointed in place and keeps running; each child is a fresh claim with its own id and lease.

func (*Client) Hibernate

func (c *Client) Hibernate(ctx context.Context, id string) error

Hibernate performs POST /v1/sandboxes/{id}/hibernate: it snapshots the sandbox and stops its VM, freeing the node's memory. This is the pause verb; its cost is proportional to guest RAM because the memory is written out.

func (*Client) Info added in v0.1.2

func (c *Client) Info(ctx context.Context) (*NodeInfo, error)

Info performs GET /v1/info: the node's live per-pool warm state and lifecycle counters, read without touching its pool config.

func (*Client) Promote

func (c *Client) Promote(ctx context.Context, id string, spec PromoteSpec) (PoolKey, error)

Promote performs POST /v1/sandboxes/{id}/promote, publishing the sandbox as a node-local template that later claims for that key clone from.

func (*Client) Release

func (c *Client) Release(ctx context.Context, id, token string) error

Release performs POST /v1/sandboxes/{id}/release, which DESTROYS the VM. It authenticates with the sandbox's own token. A 404 (unknown id or already gone) is treated as success, matching the SDK. Callers must only reach this on owner-authorized teardown — see the ClaimGateway.Release contract.

func (*Client) Sandbox

func (c *Client) Sandbox(ctx context.Context, id string) (SandboxSummary, error)

Sandbox performs GET /v1/sandboxes/{id}, the single-sandbox read that avoids scanning the whole-node listing.

func (*Client) Sandboxes

func (c *Client) Sandboxes(ctx context.Context) ([]SandboxSummary, error)

Sandboxes performs GET /v1/sandboxes, this node's live claims.

func (*Client) SetPools

func (c *Client) SetPools(ctx context.Context, pools []PoolSpec) (*NodeInfo, error)

SetPools performs PUT /v1/pools, replacing this node's desired warm targets with the supplied set (an omitted pool is drained). It authenticates with the node api_token. The whole set is sent in one request because sandboxd replaces its pool config wholesale — a partial list silently drains the rest.

func (*Client) Stats

func (c *Client) Stats(ctx context.Context, id string) (SandboxStats, error)

Stats performs GET /v1/sandboxes/{id}/stats.

func (*Client) Wake

func (c *Client) Wake(ctx context.Context, id string) error

Wake performs POST /v1/sandboxes/{id}/wake, restoring a hibernated sandbox through cocoon's mmap fast path (~55 ms) and leaving it running. Idempotent on a sandbox that is already awake.

type ForkResult

type ForkResult struct {
	Children []ClaimResult `json:"children"`
}

ForkResult carries one claim per child; children are fresh sandboxes with their own ids and leases, and the parent keeps running.

type ForkSpec

type ForkSpec struct {
	Token      string `json:"token,omitempty"`
	Count      int    `json:"count"`
	TTLSeconds int    `json:"ttl_seconds,omitempty"`
}

ForkSpec is the POST /v1/sandboxes/{id}/fork body. Token stays empty on the operator path; Count must be within the node's max_fork_count.

type HTTPError

type HTTPError struct {
	StatusCode int
	// Message is the decoded {"error": "..."} body when present.
	Message string
}

HTTPError carries a non-2xx sandboxd status that is not otherwise typed (e.g. 400 bad body, 401 bad api token, 409 egress mismatch, 500 provisioning failed).

func (*HTTPError) Error

func (e *HTTPError) Error() string

type NodeInfo

type NodeInfo struct {
	Pools      []NodePool `json:"pools"`
	Claimed    int        `json:"claimed"`
	Hibernated int        `json:"hibernated"`
	Archived   int        `json:"archived"`
}

NodeInfo is the PUT /v1/pools (and GET /v1/info) response: the node's live per-pool warm state plus its lifecycle counters.

type NodePool

type NodePool struct {
	Key       PoolKey `json:"key"`
	Warm      int     `json:"warm"`
	Refilling int     `json:"refilling"`
	Target    int     `json:"target"`
	Golden    bool    `json:"golden"`
}

NodePool is one pool's live state in a NodeInfo. Only the fields the warm-pool driver reports on are decoded.

type Option

type Option func(*Client)

Option configures a Client.

func WithHTTPClient

func WithHTTPClient(hc *http.Client) Option

WithHTTPClient overrides the default *http.Client (for custom transports or timeouts). The default client has no timeout: sandboxd keeps read/write timeouts at zero because cold claims legitimately block, so callers bound the call with the context instead.

type PoolKey

type PoolKey struct {
	Template string `json:"template"`
	Net      string `json:"net,omitempty"`
	Size     string `json:"size,omitempty"`
	Engine   string `json:"engine,omitempty"`
}

PoolKey is a checkpoint's or template's pool identity.

type PoolSpec

type PoolSpec struct {
	Template string `json:"template"`
	Net      string `json:"net,omitempty"`
	Size     string `json:"size,omitempty"`
	Warm     int    `json:"warm"`
}

PoolSpec is one entry of the PUT /v1/pools body: the desired warm watermark for a single (template, net, size) pool on this node. It mirrors the claim key so a SandboxWarmPool's target lands on the exact pool a Create claims from.

type PromoteResult

type PromoteResult struct {
	Key PoolKey `json:"key"`
}

PromoteResult returns the promoted template's full key.

type PromoteSpec

type PromoteSpec struct {
	Token    string `json:"token,omitempty"`
	Template string `json:"template"`
}

PromoteSpec is the POST /v1/sandboxes/{id}/promote body: it publishes the sandbox's state as a node-local template future claims clone from.

type SandboxStats

type SandboxStats struct {
	ID              string    `json:"id"`
	CPUCount        int       `json:"cpu_count"`
	MemTotalBytes   int64     `json:"mem_total_bytes"`
	MemUsedBytes    int64     `json:"mem_used_bytes"`
	Hibernated      bool      `json:"hibernated"`
	MeasuredAt      time.Time `json:"measured_at"`
	MemUsedMeasured bool      `json:"mem_used_measured"`
}

SandboxStats is one sandbox's resource usage. CPUCount and MemTotalBytes are the tier the VM was booted with (authoritative); MemUsedBytes is the host VMM's resident set and is only meaningful when MemUsedMeasured is true — a hibernated sandbox has no process to measure.

type SandboxSummary

type SandboxSummary struct {
	ID             string    `json:"id"`
	Key            PoolKey   `json:"key"`
	Deadline       time.Time `json:"deadline"`
	Hibernated     bool      `json:"hibernated"`
	Archived       bool      `json:"archived,omitempty"`
	FromCheckpoint string    `json:"from_checkpoint,omitempty"`
	ClaimRef       string    `json:"claim_ref,omitempty"`
}

SandboxSummary is one live claim as the owning node reports it.

Jump to

Keyboard shortcuts

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