Live sandbox resource limits

Coppice can resize jail-backed sandboxes while they are running. The gateway exposes PATCH /sandboxes/:id/limits, then reapplies FreeBSD rctl(8) rules for CPU and memory and updates the sandbox dataset’s ZFS quota for disk.

API

The request accepts the same limit names used at create/fork time:

{
  "cpuCount": 150,
  "memoryMB": 768,
  "diskSizeMB": 2048
}

Fields are patch-style: omitted values keep their current setting. Passing 0 clears that cap. The response is the new configured limit set:

{
  "sandboxID": "a1b2c3d4e5f6...",
  "cpuCount": 150,
  "memoryMB": 768,
  "diskSizeMB": 2048
}

The snake_case aliases cpu_count, memory_mb, disk_size_mb, and writable_layer_mb are also accepted for shell scripts and internal rigs.

Host operations

For a jail named e2b-<id>, the backend rebuilds the Coppice-owned rctl rules as a complete set:

rctl -r jail:e2b-<id>
rctl -a jail:e2b-<id>:pcpu:deny=150
rctl -a jail:e2b-<id>:memoryuse:deny=768M
zfs set quota=2048M zroot/jails/e2b-<id>

Rebuilding the whole rule set avoids stale caps when a caller shrinks or clears one dimension. ZFS quota updates are live by design: new writes see the new cap immediately. Clearing disk uses zfs set quota=none.

Caveats

This surface is intentionally jail-only today. bhyve live CPU/RAM hotplug is a different implementation path, and existing bhyve pool templates still express CPU and memory at checkout time.

CPU and memory caps require kern.racct.enable=1 at boot, the same requirement as create-time limits and per-sandbox metrics. Without racct, the rctl -a command fails and the API returns a backend error instead of pretending the cap applied.

Status

This closes the Daytona-style “live resize CPU / RAM / disk” row for jail-backed sandboxes. The latest sampler reading on GET /sandboxes/:id and /metrics catches up on the next metrics tick; the detail response also stores the intended limit values immediately so the UI does not have to wait for the sampler.

Receipt: benchmarks/rigs/live-limits-resize.sh, exposed as mise run limits:live-resize-honor, creates a fresh jail, starts a CPU burner before the patch, applies cpuCount=60, memoryMB=192, and diskSizeMB=128, checks the live rctl(8) rules, checks the ZFS quota, verifies a 256 MiB write fails under the live quota, then clears all three limits with a zero patch.