1
0
forked from wrenn/wrenn
Files
wrenn-releases/proto/hostagent/hostagent.proto
pptx704 516890c49a Add background process execution API
Start long-running processes (web servers, daemons) without blocking the
HTTP request. Leverages envd's existing background process support
(context.Background(), List, Connect, SendSignal RPCs) and wires it
through the host agent and control plane layers.

New API surface:
- POST /v1/capsules/{id}/exec with background:true → 202 {pid, tag}
- GET /v1/capsules/{id}/processes → list running processes
- DELETE /v1/capsules/{id}/processes/{selector} → kill by PID or tag
- WS /v1/capsules/{id}/processes/{selector}/stream → reconnect to output

The {selector} param auto-detects: numeric = PID, string = tag.
Tags are auto-generated as "proc-" + 8 hex chars if not provided.
2026-04-14 03:57:01 +06:00

553 lines
15 KiB
Protocol Buffer

syntax = "proto3";
package hostagent.v1;
// HostAgentService manages sandbox VMs on a single physical host.
// The control plane calls these RPCs to orchestrate sandbox lifecycle.
service HostAgentService {
// CreateSandbox boots a new microVM with the given configuration.
rpc CreateSandbox(CreateSandboxRequest) returns (CreateSandboxResponse);
// DestroySandbox stops and cleans up a sandbox (VM, network, rootfs).
rpc DestroySandbox(DestroySandboxRequest) returns (DestroySandboxResponse);
// PauseSandbox pauses a running sandbox's VM.
rpc PauseSandbox(PauseSandboxRequest) returns (PauseSandboxResponse);
// ResumeSandbox resumes a paused sandbox's VM.
rpc ResumeSandbox(ResumeSandboxRequest) returns (ResumeSandboxResponse);
// Exec runs a command inside a sandbox and returns the collected output.
rpc Exec(ExecRequest) returns (ExecResponse);
// ListSandboxes returns all sandboxes managed by this host agent.
rpc ListSandboxes(ListSandboxesRequest) returns (ListSandboxesResponse);
// WriteFile writes content to a file inside a sandbox.
rpc WriteFile(WriteFileRequest) returns (WriteFileResponse);
// ReadFile reads a file from inside a sandbox.
rpc ReadFile(ReadFileRequest) returns (ReadFileResponse);
// ListDir lists directory contents inside a sandbox.
rpc ListDir(ListDirRequest) returns (ListDirResponse);
// MakeDir creates a directory inside a sandbox.
rpc MakeDir(MakeDirRequest) returns (MakeDirResponse);
// RemovePath removes a file or directory inside a sandbox.
rpc RemovePath(RemovePathRequest) returns (RemovePathResponse);
// CreateSnapshot pauses a sandbox, takes a snapshot, stores it as a reusable
// template, and destroys the sandbox.
rpc CreateSnapshot(CreateSnapshotRequest) returns (CreateSnapshotResponse);
// DeleteSnapshot removes a snapshot template from disk.
rpc DeleteSnapshot(DeleteSnapshotRequest) returns (DeleteSnapshotResponse);
// ExecStream runs a command inside a sandbox and streams output events as they arrive.
rpc ExecStream(ExecStreamRequest) returns (stream ExecStreamResponse);
// WriteFileStream writes a file to a sandbox using chunked streaming.
// First message must contain metadata (sandbox_id, path). Subsequent messages contain data chunks.
rpc WriteFileStream(stream WriteFileStreamRequest) returns (WriteFileStreamResponse);
// ReadFileStream reads a file from a sandbox and streams it back in chunks.
rpc ReadFileStream(ReadFileStreamRequest) returns (stream ReadFileStreamResponse);
// PingSandbox resets the inactivity timer for a running sandbox.
rpc PingSandbox(PingSandboxRequest) returns (PingSandboxResponse);
// Terminate instructs the host agent to destroy all sandboxes and exit.
// Called by the control plane immediately when a host is deleted so the
// agent shuts down without waiting for the next heartbeat cycle.
rpc Terminate(TerminateRequest) returns (TerminateResponse);
// GetSandboxMetrics returns ring buffer metrics for a running sandbox.
rpc GetSandboxMetrics(GetSandboxMetricsRequest) returns (GetSandboxMetricsResponse);
// FlushSandboxMetrics returns all ring buffer tiers and clears them.
// Called by the control plane before pause/destroy to persist metrics to DB.
rpc FlushSandboxMetrics(FlushSandboxMetricsRequest) returns (FlushSandboxMetricsResponse);
// FlattenRootfs stops the sandbox VM, flattens the device-mapper CoW
// snapshot into a standalone rootfs.ext4 in the images directory, then
// cleans up all sandbox resources. Used by the template build system to
// produce image-only templates (no memory/CPU state).
rpc FlattenRootfs(FlattenRootfsRequest) returns (FlattenRootfsResponse);
// PtyAttach starts a new PTY process or reconnects to an existing one.
// If cmd is non-empty, starts a new process with the given PTY dimensions.
// If tag is set and cmd is empty, reconnects to the existing process with that tag.
// Returns a stream of output events (started, output data, exit).
rpc PtyAttach(PtyAttachRequest) returns (stream PtyAttachResponse);
// PtySendInput sends raw bytes to a PTY process identified by tag.
rpc PtySendInput(PtySendInputRequest) returns (PtySendInputResponse);
// PtyResize updates the terminal dimensions for a PTY process.
rpc PtyResize(PtyResizeRequest) returns (PtyResizeResponse);
// PtyKill sends a signal to a PTY process.
rpc PtyKill(PtyKillRequest) returns (PtyKillResponse);
// StartBackground starts a process in the background and returns immediately
// with the PID and tag. The process survives RPC disconnection.
rpc StartBackground(StartBackgroundRequest) returns (StartBackgroundResponse);
// ListProcesses returns all running processes inside a sandbox.
rpc ListProcesses(ListProcessesRequest) returns (ListProcessesResponse);
// KillProcess sends a signal to a process identified by PID or tag.
rpc KillProcess(KillProcessRequest) returns (KillProcessResponse);
// ConnectProcess re-attaches to a running process and streams its output.
rpc ConnectProcess(ConnectProcessRequest) returns (stream ConnectProcessResponse);
}
message CreateSandboxRequest {
// Sandbox ID assigned by the control plane. If empty, the host agent generates one.
string sandbox_id = 5;
// Deprecated: use team_id + template_id instead.
string template = 1;
// Number of virtual CPUs (default: 1).
int32 vcpus = 2;
// Memory in MB (default: 512).
int32 memory_mb = 3;
// TTL in seconds. Sandbox is auto-paused after this duration of
// inactivity. 0 means no auto-pause.
int32 timeout_sec = 4;
// Disk size in MB for the rootfs. Base images are expanded to this size
// at host agent startup. Default: 5120 (5 GB).
int32 disk_size_mb = 6;
// Team UUID that owns the template (hex string). All-zeros = platform.
string team_id = 7;
// Template UUID (hex string). Both zeros + team zeros = "minimal" sentinel.
string template_id = 8;
// Default unix user for the sandbox (set in envd via PostInit).
string default_user = 9;
// Default environment variables (set in envd via PostInit).
map<string, string> default_env = 10;
}
message CreateSandboxResponse {
string sandbox_id = 1;
string status = 2;
string host_ip = 3;
}
message DestroySandboxRequest {
string sandbox_id = 1;
}
message DestroySandboxResponse {}
message PauseSandboxRequest {
string sandbox_id = 1;
}
message PauseSandboxResponse {}
message ResumeSandboxRequest {
string sandbox_id = 1;
// TTL in seconds restored from the DB so the reaper can auto-pause
// the sandbox again after inactivity. 0 means no auto-pause.
int32 timeout_sec = 2;
// Default unix user for the sandbox (set in envd via PostInit on resume).
string default_user = 3;
// Default environment variables (set in envd via PostInit on resume).
map<string, string> default_env = 4;
}
message ResumeSandboxResponse {
string sandbox_id = 1;
string status = 2;
string host_ip = 3;
}
message CreateSnapshotRequest {
string sandbox_id = 1;
// Deprecated: use team_id + template_id instead.
string name = 2;
// Team UUID that will own the new template.
string team_id = 3;
// Template UUID for the new snapshot template.
string template_id = 4;
}
message CreateSnapshotResponse {
string name = 1;
int64 size_bytes = 2;
}
message DeleteSnapshotRequest {
// Deprecated: use team_id + template_id instead.
string name = 1;
// Team UUID that owns the template.
string team_id = 2;
// Template UUID to delete.
string template_id = 3;
}
message DeleteSnapshotResponse {}
message ExecRequest {
string sandbox_id = 1;
string cmd = 2;
repeated string args = 3;
// Timeout for the command in seconds (default: 30).
int32 timeout_sec = 4;
}
message ExecResponse {
bytes stdout = 1;
bytes stderr = 2;
int32 exit_code = 3;
}
message ListSandboxesRequest {}
message ListSandboxesResponse {
repeated SandboxInfo sandboxes = 1;
// IDs of sandboxes that were automatically paused by the TTL reaper
// since the last call. Drained on read.
repeated string auto_paused_sandbox_ids = 2;
}
message SandboxInfo {
string sandbox_id = 1;
string status = 2;
// Deprecated: use team_id + template_id instead.
string template = 3;
int32 vcpus = 4;
int32 memory_mb = 5;
string host_ip = 6;
int64 created_at_unix = 7;
int64 last_active_at_unix = 8;
int32 timeout_sec = 9;
string team_id = 10;
string template_id = 11;
}
message WriteFileRequest {
string sandbox_id = 1;
string path = 2;
bytes content = 3;
}
message WriteFileResponse {}
message ReadFileRequest {
string sandbox_id = 1;
string path = 2;
}
message ReadFileResponse {
bytes content = 1;
}
// ── Streaming Exec ──────────────────────────────────────────────────
message ExecStreamRequest {
string sandbox_id = 1;
string cmd = 2;
repeated string args = 3;
int32 timeout_sec = 4;
}
message ExecStreamResponse {
oneof event {
ExecStreamStart start = 1;
ExecStreamData data = 2;
ExecStreamEnd end = 3;
}
}
message ExecStreamStart {
uint32 pid = 1;
}
message ExecStreamData {
oneof output {
bytes stdout = 1;
bytes stderr = 2;
}
}
message ExecStreamEnd {
int32 exit_code = 1;
string error = 2;
}
// ── Streaming File Transfer ─────────────────────────────────────────
message WriteFileStreamRequest {
oneof content {
WriteFileStreamMeta meta = 1;
bytes chunk = 2;
}
}
message WriteFileStreamMeta {
string sandbox_id = 1;
string path = 2;
}
message WriteFileStreamResponse {}
message ReadFileStreamRequest {
string sandbox_id = 1;
string path = 2;
}
message ReadFileStreamResponse {
bytes chunk = 1;
}
// ── Filesystem Operations ──────────────────────────────────────────
message ListDirRequest {
string sandbox_id = 1;
string path = 2;
uint32 depth = 3;
}
message ListDirResponse {
repeated FileEntry entries = 1;
}
message FileEntry {
string name = 1;
string path = 2;
// "file", "directory", or "symlink".
string type = 3;
int64 size = 4;
uint32 mode = 5;
// Human-readable permissions string, e.g. "-rwxr-xr-x".
string permissions = 6;
string owner = 7;
string group = 8;
// Last modification time as Unix timestamp (seconds).
int64 modified_at = 9;
optional string symlink_target = 10;
}
message MakeDirRequest {
string sandbox_id = 1;
string path = 2;
}
message MakeDirResponse {
FileEntry entry = 1;
}
message RemovePathRequest {
string sandbox_id = 1;
string path = 2;
}
message RemovePathResponse {}
// ── Ping ────────────────────────────────────────────────────────────
message PingSandboxRequest {
string sandbox_id = 1;
}
message PingSandboxResponse {}
// ── Terminate ────────────────────────────────────────────────────────
message TerminateRequest {}
message TerminateResponse {}
// ── Metrics ──────────────────────────────────────────────────────────
message MetricPoint {
int64 timestamp_unix = 1;
double cpu_pct = 2;
int64 mem_bytes = 3;
int64 disk_bytes = 4;
}
message GetSandboxMetricsRequest {
string sandbox_id = 1;
// Range tier: "10m", "2h", or "24h".
string range = 2;
}
message GetSandboxMetricsResponse {
repeated MetricPoint points = 1;
}
message FlushSandboxMetricsRequest {
string sandbox_id = 1;
}
message FlushSandboxMetricsResponse {
repeated MetricPoint points_10m = 1;
repeated MetricPoint points_2h = 2;
repeated MetricPoint points_24h = 3;
}
// ── FlattenRootfs ────────────────────────────────────────────────────
message FlattenRootfsRequest {
string sandbox_id = 1;
// Deprecated: use team_id + template_id instead.
string name = 2;
// Team UUID that will own the resulting template.
string team_id = 3;
// Template UUID for the output.
string template_id = 4;
}
message FlattenRootfsResponse {
int64 size_bytes = 1;
}
// ── PTY ─────────────────────────────────────────────────────────────
message PtyAttachRequest {
string sandbox_id = 1;
// Tag is the stable identifier for this PTY session (e.g. "pty-abc123de").
// Chosen by the caller and used to reconnect later.
string tag = 2;
// If cmd is non-empty, a new process is started. If empty, reconnects to
// the existing process identified by tag.
string cmd = 3;
repeated string args = 4;
uint32 cols = 5;
uint32 rows = 6;
// Environment variables for the process.
map<string, string> envs = 7;
// Working directory. Empty means default.
string cwd = 8;
// User to run as. Empty means default (root).
string user = 9;
}
message PtyAttachResponse {
oneof event {
PtyStarted started = 1;
PtyOutput output = 2;
PtyExited exited = 3;
}
}
message PtyStarted {
uint32 pid = 1;
string tag = 2;
}
message PtyOutput {
bytes data = 1;
}
message PtyExited {
int32 exit_code = 1;
string error = 2;
}
message PtySendInputRequest {
string sandbox_id = 1;
string tag = 2;
bytes data = 3;
}
message PtySendInputResponse {}
message PtyResizeRequest {
string sandbox_id = 1;
string tag = 2;
uint32 cols = 3;
uint32 rows = 4;
}
message PtyResizeResponse {}
message PtyKillRequest {
string sandbox_id = 1;
string tag = 2;
}
message PtyKillResponse {}
// ── Background Processes ───────────────────────────────────────────
message StartBackgroundRequest {
string sandbox_id = 1;
string cmd = 2;
repeated string args = 3;
// User-chosen tag for the process. If empty, the host agent generates one.
string tag = 4;
map<string, string> envs = 5;
string cwd = 6;
}
message StartBackgroundResponse {
uint32 pid = 1;
string tag = 2;
}
message ListProcessesRequest {
string sandbox_id = 1;
}
message ProcessEntry {
uint32 pid = 1;
string tag = 2;
string cmd = 3;
repeated string args = 4;
}
message ListProcessesResponse {
repeated ProcessEntry processes = 1;
}
message KillProcessRequest {
string sandbox_id = 1;
oneof selector {
uint32 pid = 2;
string tag = 3;
}
// Signal to send: "SIGTERM" or "SIGKILL" (default: "SIGKILL").
string signal = 4;
}
message KillProcessResponse {}
message ConnectProcessRequest {
string sandbox_id = 1;
oneof selector {
uint32 pid = 2;
string tag = 3;
}
}
// Reuses ExecStream event types for symmetry.
message ConnectProcessResponse {
oneof event {
ExecStreamStart start = 1;
ExecStreamData data = 2;
ExecStreamEnd end = 3;
}
}