Documentation
¶
Overview ¶
Package isolate is the V8-isolate (Workers-model) runtime driver — the fifth implementation of internal/runtime.Runtime, after pkg/docker (docker + gvisor), internal/runtime/firecracker, and internal/runtime/wasm (plans/isolate-runtime.md).
Like WASM, the isolate runtime is host-mediated: it satisfies only the core Runtime interface, never ContainerRuntime. Isolates get no IP, no TAP/veth, and no per-IP iptables — egress policy is enforced by a host-side proxy the driver owns, and inbound HTTP is proxied to the isolate's fetch handler.
Phase 1 (this file) is the dispatch skeleton: every lifecycle method returns models.ErrRuntimeNotImplemented so the service layer's fifth dispatch branch, daemon wiring, and store schema can land and be proven stable before the engine work (Phase 2: pkg/isolate + pkg/jsbundle).
Index ¶
- Constants
- func SanitizeGroupKey(key string) (string, error)
- func SeccompAllowlist(jitless bool) []string
- func SeccompNeverAllow() []string
- type BundleResolver
- type Config
- type Driver
- func (d *Driver) Create(ctx context.Context, req models.CreateSandboxRequest, ...) (*models.SandboxRuntimeState, error)
- func (d *Driver) CreateSnapshot(ctx context.Context, sandboxID, imageRef string) (string, error)
- func (d *Driver) Destroy(ctx context.Context, sandbox *models.Sandbox) error
- func (d *Driver) DrainNetworkByteCounters() map[string]struct{ ... }
- func (d *Driver) EnsureHTTPListener(ctx context.Context, sandboxID string, guestPort int) (string, error)
- func (d *Driver) Inspect(ctx context.Context, sandboxID string) (*models.SandboxRuntimeState, error)
- func (d *Driver) InvokeHTTP(ctx context.Context, sandboxID string, r *http.Request) (*http.Response, error)
- func (d *Driver) ListManaged(ctx context.Context) (map[string]*models.SandboxRuntimeState, error)
- func (d *Driver) Ping(ctx context.Context) error
- func (d *Driver) ReleaseHTTPListener(sandboxID string, guestPort int)
- func (d *Driver) RemoveImage(ctx context.Context, imageRef string) error
- func (d *Driver) Resize(ctx context.Context, sandboxID string, req models.ResizeSandboxRequest) error
- func (d *Driver) RunIdleReaper(ctx context.Context)
- func (d *Driver) ServeToolbox(ctx context.Context, sandboxID, token string, w http.ResponseWriter, ...)
- func (d *Driver) SetBundleResolver(r BundleResolver)
- func (d *Driver) SetHostSupervisor(s HostSupervisor)
- func (d *Driver) SetNetworkBlocks(sandboxID string, blockIngress, blockEgress bool)
- func (d *Driver) SetWarmPool(p WarmPool)
- func (d *Driver) Start(ctx context.Context, sandboxID string) (*models.SandboxRuntimeState, error)
- func (d *Driver) Stop(ctx context.Context, sandboxID string) error
- func (d *Driver) SyncAllowedPorts(sandboxID string, ports []int)
- type EgressPolicy
- type EgressPolicySetter
- type GroupHost
- type HostSupervisor
- type JailSpec
- type NetworkByteCounter
- type NetworkPolicySink
- type PortGateway
- type ToolboxHost
- type WarmPool
Constants ¶
const ( GroupPerTenant = config.IsolateGroupPerTenant GroupPerSandbox = config.IsolateGroupPerSandbox )
Group granularity values, mirrored from internal/config so the driver does not force every consumer (tests, future pkg/isolate) through daemon config.
const DefaultGroupKey = "default"
DefaultGroupKey is the isolate-group key for the null tenant: creates whose group key fell back to an unscoped (operator/PAT) identity share one default group, which is the single-tenant self-hoster's zero-config path.
Variables ¶
This section is empty.
Functions ¶
func SanitizeGroupKey ¶
SanitizeGroupKey validates a group key for use in host paths and cgroup names. Empty maps to DefaultGroupKey; anything else must match groupKeyPattern exactly — no normalization, because two keys that normalize to the same directory would silently merge two tenants into one process (§2.1's forced-co-residency attack, at the filesystem layer).
func SeccompAllowlist ¶
SeccompAllowlist returns the syscall names a group process may make. jitless=false is the default profile (base + JIT extension); jitless=true is the reduced paranoid-tier profile.
func SeccompNeverAllow ¶
func SeccompNeverAllow() []string
SeccompNeverAllow returns the deny-regardless list (see seccompNeverAllow).
Types ¶
type BundleResolver ¶
type BundleResolver interface {
Resolve(ctx context.Context, tenant, ref string) (*jsbundle.Bundle, error)
}
BundleResolver resolves a bundle reference (path, file://, uploaded name, digest) for a tenant to the concrete bundle code the group host injects. Production implementation: pkg/jsbundle (adapted in bundleresolver.go), the analog of pkg/wasmmod for .wasm modules. tenant scopes uploaded-name lookups.
func NewBundleResolver ¶
func NewBundleResolver(inner *jsbundle.Resolver) BundleResolver
NewBundleResolver wraps a jsbundle.Resolver as a driver BundleResolver.
type Config ¶
type Config struct {
// WorkerdPath is the workerd binary that hosts isolate groups. Ping()
// stats it so /healthz reports a missing binary before the first create.
WorkerdPath string
// RunDir holds per-group runtime state (sockets, capnp configs,
// per-sandbox egress UDS endpoints).
RunDir string
// GroupGranularity is the isolate-group key granularity (§2.1):
// GroupPerTenant (default) or GroupPerSandbox (hostile-code tier).
GroupGranularity string
// UseJail wraps each workerd group process in the isolate jail (jail.go).
UseJail bool
// JailChrootBase is the parent directory for per-group chroots.
JailChrootBase string
// JailUID / JailGID are the unprivileged uid/gid workerd drops to.
JailUID int
JailGID int
// Jitless runs V8 with --jitless so the seccomp allowlist can drop the
// W^X/JIT syscall surface (per-sandbox paranoid tier, §2.1).
Jitless bool
// IdleTTL is how long a group may sit without Create/Invoke before the
// idle reaper tears it down. Zero disables the reaper.
IdleTTL time.Duration
// EgressPoolSize is the per-group egress-slot pool size (§4): the cap on
// concurrently-egressing sandboxes in a group. Zero → pkg/isolate default.
EgressPoolSize int
}
Config holds host-side isolate runtime settings.
func FromDaemonConfig ¶
FromDaemonConfig projects the isolate slice of daemon config into driver config.
type Driver ¶
type Driver struct {
// contains filtered or unexported fields
}
Driver implements runtime.Runtime for isolate sandboxes. Isolate satisfies only the core Runtime interface — not ContainerRuntime (host-mediated networking, same posture as WASM).
func (*Driver) Create ¶
func (d *Driver) Create(ctx context.Context, req models.CreateSandboxRequest, sandboxID, toolboxToken string, hostMounts []mounts.ContainerBind) (*models.SandboxRuntimeState, error)
Create is the cold path (plans/isolate-runtime.md §10): resolve the sandbox's bundle, route it to its isolate group (spawning the group's workerd process under single-flight on the first create — or claiming a warm blank host when the pool is enabled), and load the bundle onto that host. The sandbox is "running" the moment its bundle is pinned — the isolate itself is compiled lazily on first invoke (the §2.2 warm path). No per-IP networking, no container: this is host-mediated like WASM.
Failure rule (LIFO): if load fails after the group was acquired, the sandbox is released from the group, which tears the group's process down when this create had spawned it and no other member joined — so a failed first-create never leaks an empty workerd process (§11 empty-group rule).
func (*Driver) CreateSnapshot ¶
CreateSnapshot is unsupported by design, not just unimplemented: V8 exposes no serialize-a-running-isolate API, so the warm pool is the plan of record and any snapshot phase requires an upstream feasibility spike first (plans/isolate-runtime.md §4, §13 Q6).
func (*Driver) Destroy ¶
Destroy removes the sandbox from its group host and, when it was the group's last member, tears the group process down (§2.1 last-member teardown). Nil, or an unknown sandbox, is a no-op — cleanup paths may run without a record.
func (*Driver) DrainNetworkByteCounters ¶
func (*Driver) EnsureHTTPListener ¶
func (*Driver) InvokeHTTP ¶
func (d *Driver) InvokeHTTP(ctx context.Context, sandboxID string, r *http.Request) (*http.Response, error)
InvokeHTTP calls the sandbox's fetch handler directly (tests + P0 gate).
func (*Driver) ListManaged ¶
ListManaged returns the runtime state of every isolate this daemon owns, so restart reconcile can match live isolates against persisted rows and terminal-ize any strays.
func (*Driver) Ping ¶
Ping verifies the workerd binary exists. Config load deliberately does not stat the path; this is the seam /health surfaces it through, mirroring the Firecracker driver.
func (*Driver) ReleaseHTTPListener ¶
func (*Driver) RemoveImage ¶
RemoveImage GCs a bundle from the content-addressed store (Phase 2; bundles are content-addressed so removal is reference-counted, never destructive to a live sandbox).
func (*Driver) RunIdleReaper ¶
RunIdleReaper tears down isolate-group processes that have been idle longer than cfg.IdleTTL (plans/isolate-runtime.md §11 I22 / Phase 2 leftover). Last-member teardown already stops empty groups; this reaper covers the scale-to-zero case — a group that still has pinned sandboxes but has seen no Create/Invoke traffic for IdleTTL. Members are marked stopped and their bundles stay in the content-addressed store so the next Start/Create path can respawn the group and re-pin.
Nil or non-positive IdleTTL disables the reaper (tests / operators that want groups sticky until last-member teardown). The loop exits when ctx is cancelled.
func (*Driver) ServeToolbox ¶
func (d *Driver) ServeToolbox(ctx context.Context, sandboxID, token string, w http.ResponseWriter, r *http.Request)
ServeToolbox implements ToolboxHost for the isolate driver.
func (*Driver) SetBundleResolver ¶
func (d *Driver) SetBundleResolver(r BundleResolver)
SetBundleResolver injects the JS/TS bundle resolver (pkg/jsbundle in production, Phase 2).
func (*Driver) SetHostSupervisor ¶
func (d *Driver) SetHostSupervisor(s HostSupervisor)
SetHostSupervisor injects the workerd group supervisor (pkg/isolate in production, Phase 2).
func (*Driver) SetNetworkBlocks ¶
func (*Driver) SetWarmPool ¶
SetWarmPool injects the blank-workerd-host pool (internal/pool/isolate, Phase 3). Nil (the default) keeps every first-create on the cold spawn path.
func (*Driver) Start ¶
Start re-affirms a running isolate, and re-pins the bundle after an idle-TTL reap tore the group down. An unknown id is a 404-shaped nil,nil per the Runtime contract.
func (*Driver) Stop ¶
Stop marks a sandbox stopped but keeps its bundle pinned so a later Start is instant. The group process stays up for co-resident sandboxes; true teardown is Destroy. Idle groups are reaped by RunIdleReaper.
func (*Driver) SyncAllowedPorts ¶
type EgressPolicy ¶
type EgressPolicy struct {
BlockAll bool
Allow []string // CIDRs / hosts; empty + !BlockAll = allow-all (self-host default)
Deny []string
}
EgressPolicy is the per-sandbox outbound policy the host-side egress proxy enforces (plans/isolate-runtime.md §4 Phase 3). Mapped from existing CreateSandboxRequest fields (NetworkBlockAll / NetworkAllowOut / NetworkDenyOut) — net-new grant fields wait for the §10.1 checkpoint.
type EgressPolicySetter ¶
type EgressPolicySetter interface {
SetEgressPolicy(sandboxID string, p EgressPolicy)
}
EgressPolicySetter is implemented by GroupHost production adapters so the driver can push per-sandbox policy after Load. Fakes used in unit tests need not implement it (egress is fail-closed until policy is set on a real host).
type GroupHost ¶
type GroupHost interface {
// Load pins a sandbox's bundle so the host can serve it; idempotent.
Load(id string, b *jsbundle.Bundle) error
// Unload drops a sandbox and returns the number still loaded (for
// last-member teardown).
Unload(id string) int
// LoadedCount is the number of sandboxes currently on this host.
LoadedCount() int
// Invoke proxies an HTTP request to the sandbox identified by id.
Invoke(ctx context.Context, id string, r *http.Request) (*http.Response, error)
// Stop kills the group process and releases its resources.
Stop() error
}
GroupHost is a running workerd group process the driver loads sandboxes into and routes requests to. One host backs one isolate-group key (§2.1). Production implementation: *pkg/isolate.Host.
type HostSupervisor ¶
HostSupervisor spawns group hosts, one per isolate-group key (§2.1). SpawnGroup realizes the group's JailSpec (chroot + cgroups + drop-priv + seccomp) and starts the workerd process. Production implementation: pkg/isolate via hostsupervisor.go.
func NewHostSupervisor ¶
func NewHostSupervisor(cfg Config) HostSupervisor
NewHostSupervisor builds the production supervisor over the isolate config.
type JailSpec ¶
type JailSpec struct {
// GroupKey is the sanitized isolate-group key (per-tenant granularity:
// the authorized tenant id; per-sandbox granularity: the sandbox id;
// empty tenant falls back to DefaultGroupKey).
GroupKey string
// ChrootDir is the group's private root: <JailChrootBase>/<GroupKey>.
ChrootDir string
// CgroupName is the per-group cgroup that enforces the GROUP-level
// resource caps (§2.1): OSS workerd has no per-isolate CPU enforcement,
// so the enforced blast radius is the group.
CgroupName string
// UID / GID are the unprivileged identity the process drops to.
UID int
GID int
// CPUQuota / MemoryLimitMB are the group cgroup caps. Zero = unlimited
// on that axis (the cgroup controller is left unset).
CPUQuota float64
MemoryLimitMB int
// Jitless selects the reduced seccomp profile (and --jitless on the V8
// command line when the spawner realizes the spec).
Jitless bool
}
JailSpec describes the OS confinement for one workerd group process. Build one with BuildJailSpec; a hand-rolled spec must pass Validate before use.
func BuildJailSpec ¶
BuildJailSpec computes the jail for one group under the driver config. cpu / memoryMB are the GROUP-level caps (map CreateSandboxRequest.CPU / MemoryMB onto them at create time — Phase 4 owns the exact mapping).
func (JailSpec) SeccompAllowlistFor ¶
SeccompAllowlistFor returns the profile matching the spec's Jitless flag.
type NetworkByteCounter ¶
type NetworkByteCounter interface {
DrainNetworkByteCounters() map[string]struct{ BytesIn, BytesOut int64 }
}
NetworkByteCounter drains ingress/egress byte deltas observed at the mediators.
type NetworkPolicySink ¶
type NetworkPolicySink interface {
SetNetworkBlocks(sandboxID string, blockIngress, blockEgress bool)
}
NetworkPolicySink applies ingress/egress quota blocks at the mediator.
type PortGateway ¶
type PortGateway interface {
EnsureHTTPListener(ctx context.Context, sandboxID string, guestPort int) (dialAddr string, err error)
ReleaseHTTPListener(sandboxID string, guestPort int)
SyncAllowedPorts(sandboxID string, ports []int)
}
PortGateway is the host-mediated HTTP ingress surface for isolate sandboxes (plans/isolate-runtime.md §4 / Phase 3). Same shape as the WASM PortGateway: Caddy dials the loopback address returned by EnsureHTTPListener rather than a guest container IP, so expose_port never walks the TCP host-port pool.
func AsPortGateway ¶
func AsPortGateway(rt any) (PortGateway, bool)
AsPortGateway returns the HTTP ingress surface when rt implements it.
type ToolboxHost ¶
type ToolboxHost interface {
ServeToolbox(ctx context.Context, sandboxID, token string, w http.ResponseWriter, r *http.Request)
}
ToolboxHost is the in-process toolbox surface for isolate sandboxes. Isolates have no POSIX process, so only invoke-handler is supported; everything else is 501 (plans/isolate-runtime.md §3 / Phase 3).
func AsToolboxHost ¶
func AsToolboxHost(rt any) (ToolboxHost, bool)
AsToolboxHost returns the toolbox surface when rt implements it.
type WarmPool ¶
WarmPool hands out blank workerd group hosts. Production implementation: internal/pool/isolate (Phase 3). ok=false means empty or disabled — the caller cold-spawns. The group router runs before the pool: only a tenant's FIRST create claims; subsequent creates join the existing group.