arcbox-protocol 0.4.20

Protocol definitions for ArcBox (ttrpc/protobuf)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
// Agent service protocol definitions.
//
// This service runs inside the guest VM and handles requests from the host.

syntax = "proto3";

package arcbox.v1;

import "common.proto";

// AgentService runs inside the guest VM.
service AgentService {
    // Health check.
    rpc Ping(AgentPingRequest) returns (AgentPingResponse);

    // Gets system information.
    rpc GetSystemInfo(Empty) returns (SystemInfo);

    // Ensures guest runtime stack (containerd/dockerd) is ready.
    rpc EnsureRuntime(RuntimeEnsureRequest) returns (RuntimeEnsureResponse);

    // Gets guest runtime stack status.
    rpc GetRuntimeStatus(RuntimeStatusRequest) returns (RuntimeStatusResponse);

    // Starts the native Kubernetes cluster inside the guest.
    rpc StartKubernetes(KubernetesStartRequest) returns (KubernetesStartResponse);

    // Stops the native Kubernetes cluster inside the guest.
    rpc StopKubernetes(KubernetesStopRequest) returns (KubernetesStopResponse);

    // Deletes the native Kubernetes cluster state inside the guest.
    rpc DeleteKubernetes(KubernetesDeleteRequest) returns (KubernetesDeleteResponse);

    // Returns native Kubernetes cluster status from the guest.
    rpc GetKubernetesStatus(KubernetesStatusRequest) returns (KubernetesStatusResponse);

    // Returns kubeconfig content exported from the guest cluster.
    rpc GetKubeconfig(KubernetesKubeconfigRequest) returns (KubernetesKubeconfigResponse);

    // Requests graceful guest shutdown. The agent responds immediately,
    // then performs orderly process teardown and powers off the VM.
    rpc Shutdown(ShutdownRequest) returns (ShutdownResponse);

    // Triggers an immediate fstrim on data mount points to reclaim sparse
    // file space on the host.
    rpc DiskTrim(DiskTrimRequest) returns (DiskTrimResponse);

    // Streams guest readiness events until the requested runtime is ready or failed.
    rpc WatchReadiness(WatchReadinessRequest) returns (stream ReadinessEvent);

    // Streams guest memory pressure events while the balloon is shrunk.
    rpc WatchMemoryPressure(WatchMemoryPressureRequest) returns (stream MemoryPressureEvent);

    // Streams machine-level resource samples (CPU/memory/disk/network).
    rpc WatchStats(WatchStatsRequest) returns (stream MachineStats);
}

// Ping request.
message AgentPingRequest {
    // Optional payload.
    string message = 1;
    // Host wall-clock time in Unix seconds. Agent sets clock when > 0.
    int64 timestamp_secs = 2;
}

// Ping response.
message AgentPingResponse {
    // Response payload.
    string message = 1;
    // Agent version.
    string version = 2;
    // Host↔agent protocol version the agent speaks
    // (`arcbox_constants::wire::AGENT_PROTOCOL_VERSION`). Absent (0) on
    // agents that predate the handshake; the host rejects agents below
    // its minimum supported version at boot.
    uint32 protocol_version = 3;
}

// System information from the guest.
message SystemInfo {
    // Kernel version.
    string kernel_version = 1;
    // OS name.
    string os_name = 2;
    // OS version.
    string os_version = 3;
    // Architecture.
    string arch = 4;
    // Total memory in bytes.
    uint64 total_memory = 5;
    // Available memory in bytes.
    uint64 available_memory = 6;
    // Number of CPUs.
    uint32 cpu_count = 7;
    // Load average (1, 5, 15 minutes).
    repeated double load_average = 8;
    // Hostname.
    string hostname = 9;
    // Uptime in seconds.
    uint64 uptime = 10;
    // Guest IP addresses (excluding loopback).
    repeated string ip_addresses = 11;
}

// Request to ensure runtime services are available.
message RuntimeEnsureRequest {
    // Whether to attempt starting services when not ready.
    bool start_if_needed = 1;
}

// Response from runtime ensure operation.
message RuntimeEnsureResponse {
    // Whether runtime is ready for Docker API requests.
    bool ready = 1;
    // Runtime endpoint exposed to host proxy.
    string endpoint = 2;
    // Additional status detail.
    string message = 3;
    // Outcome of this ensure call: "started", "reused", or "failed".
    string status = 4;
}

// Request for runtime status.
message RuntimeStatusRequest {}

// Request for guest-driven readiness events.
message WatchReadinessRequest {
    // Whether the agent should start the runtime if it is not ready.
    bool start_runtime_if_needed = 1;
    // Maximum time to wait for runtime readiness before reporting failure.
    uint32 timeout_ms = 2;
}

// Guest readiness event.
message ReadinessEvent {
    enum Kind {
        KIND_UNSPECIFIED = 0;
        AGENT_READY = 1;
        RUNTIME_STARTING = 2;
        RUNTIME_READY = 3;
        RUNTIME_FAILED = 4;
    }

    // Event kind.
    Kind kind = 1;
    // Runtime endpoint exposed to host proxy when known.
    string endpoint = 2;
    // Human-readable detail for diagnostics.
    string detail = 3;
    // Per-service status entries for fine-grained observability.
    repeated ServiceStatus services = 4;
}

// Request for a guest-driven memory pressure event stream.
//
// The agent samples in-guest memory signals (`MemAvailable`, workingset
// refault rate) and emits an event when a threshold trips, plus periodic
// keepalives so the host can distinguish "no pressure" from "guest too
// starved to answer". The watch returns after `timeout_ms`; the host
// re-issues the request to keep watching.
message WatchMemoryPressureRequest {
    // Watch window in milliseconds; the agent ends the stream with a
    // WINDOW_ELAPSED frame when it passes.
    uint32 timeout_ms = 1;
    // Trip when MemAvailable falls below this many bytes. 0 disables.
    uint64 min_available_bytes = 2;
    // Trip when the page refault rate (pages/second) stays at or above this
    // for consecutive samples. 0 disables.
    uint64 max_refault_rate = 3;
    // Keepalive cadence in milliseconds (0 = agent default).
    uint32 keepalive_ms = 4;
    // PSI trigger threshold: microseconds of full (all non-idle tasks)
    // memory stall within the agent's 1s window before pressure fires.
    // 0 = agent default. Used only on kernels with CONFIG_PSI; older
    // kernels fall back to MemAvailable/refault sampling.
    uint64 psi_full_stall_us = 5;
}

// One frame on the memory pressure stream.
message MemoryPressureEvent {
    enum Reason {
        // Watch established (first frame) or periodic keepalive.
        KEEPALIVE = 0;
        // MemAvailable fell below the requested floor. PSI stall trips
        // are also reported under this reason: a new enum value would be
        // decoded as KEEPALIVE by older hosts (proto3 open enums), which
        // must never happen to a pressure frame. The agent log records
        // the true trigger.
        LOW_AVAILABLE = 1;
        // Page refault rate exceeded the requested threshold.
        REFAULT_SPIKE = 2;
        // The watch window elapsed without pressure.
        WINDOW_ELAPSED = 3;
        // The detector armed: the guest settled at the current balloon
        // target. The host uses this to continue a staged shrink.
        SETTLED = 4;
    }

    // Why this frame was emitted.
    Reason reason = 1;
    // MemAvailable at sample time, in bytes.
    uint64 available_bytes = 2;
    // Observed refault rate, pages/second.
    uint64 refault_rate = 3;
}

// Request for a guest-driven machine resource stats stream.
//
// The agent reads /proc once per interval and emits one MachineStats frame
// per tick; every frame doubles as a keepalive. The stream ends after
// `timeout_ms`; the host re-issues the request to keep watching.
message WatchStatsRequest {
    // Watch window in milliseconds (0 = agent default).
    uint32 timeout_ms = 1;
    // Sample interval in milliseconds (0 = agent default, 1000).
    uint32 interval_ms = 2;
}

// One machine-level resource sample.
//
// Counter fields are cumulative since guest boot; consumers derive rates
// from deltas between samples, which stays correct across missed samples
// and stream restarts.
message MachineStats {
    // Guest monotonic clock at sample time (from /proc/uptime), in
    // milliseconds. Rate denominators come from deltas of this field, not
    // from host receive times (delivery jitter would distort rates).
    uint64 monotonic_ms = 1;
    // Aggregate CPU ticks since boot across all CPUs (/proc/stat "cpu"):
    // busy = everything except idle + iowait.
    uint64 cpu_busy_ticks = 2;
    uint64 cpu_total_ticks = 3;
    // Online CPU count.
    uint32 online_cpus = 4;
    // 1-minute load average.
    double loadavg1 = 5;
    // Bytes, from /proc/meminfo.
    uint64 memory_total_bytes = 6;
    uint64 memory_available_bytes = 7;
    // PSI memory "full avg10" percentage (0-100), from
    // /proc/pressure/memory. Negative when the kernel lacks CONFIG_PSI.
    double memory_psi_full_avg10 = 8;
    // Cumulative bytes across whole physical disks (/proc/diskstats,
    // partitions excluded so traffic is not double-counted).
    uint64 disk_read_bytes = 9;
    uint64 disk_written_bytes = 10;
    // Cumulative bytes across the VM's physical/uplink interfaces
    // (/proc/net/dev; container bridges and veths are excluded so their
    // traffic is not counted once per internal hop).
    uint64 net_rx_bytes = 11;
    uint64 net_tx_bytes = 12;
    // Per-container samples, one per running Docker container (cgroup v2
    // tree under /sys/fs/cgroup/docker). Empty when no containers run or
    // the subscriber did not request them.
    repeated ContainerStats containers = 13;
}

// One container's cgroup v2 resource sample.
//
// CPU, disk, and network fields are cumulative; memory and pids are
// gauges. CPU/memory/disk/pids come from the container's cgroup
// (cpu.stat, memory.current, memory.max, io.stat, pids.current). Network
// is not a cgroup counter — it lives in the container's network
// namespace, read via /proc/<pid>/net/dev for a process in the container.
message ContainerStats {
    // Full container ID (the cgroup directory name).
    string id = 1;
    // Human-readable name, filled by the daemon from its container
    // registry. Empty on the guest→host hop and when the daemon has no
    // name for the ID (the consumer falls back to the short ID).
    string name = 2;
    // Cumulative CPU time in microseconds (cpu.stat usage_usec).
    uint64 cpu_usage_usec = 3;
    // Current memory charge in bytes (memory.current).
    uint64 memory_current_bytes = 4;
    // Memory limit in bytes (memory.max); 0 means unlimited ("max").
    uint64 memory_limit_bytes = 5;
    // Cumulative block I/O bytes summed across devices (io.stat
    // rbytes/wbytes).
    uint64 disk_read_bytes = 6;
    uint64 disk_written_bytes = 7;
    // Current process/thread count (pids.current).
    uint32 pids = 8;
    // Cumulative bytes across the container's non-loopback interfaces,
    // from /proc/<pid>/net/dev in its network namespace. Zero for a
    // host-networked container (its traffic is the machine's, already
    // counted in MachineStats) or when no process is readable.
    uint64 net_rx_bytes = 9;
    uint64 net_tx_bytes = 10;
}

// Runtime status report.
message RuntimeStatusResponse {
    // Whether containerd socket is reachable.
    bool containerd_ready = 1;
    // Whether Docker socket is reachable.
    bool docker_ready = 2;
    // Runtime endpoint exposed to host proxy.
    string endpoint = 3;
    // Human-readable detail for diagnostics.
    string detail = 4;
    // Per-service status entries for fine-grained observability.
    repeated ServiceStatus services = 5;
}

// Request to trigger an immediate fstrim on data mount points.
message DiskTrimRequest {}

// Response from a disk trim operation.
message DiskTrimResponse {
    // Human-readable result summary (e.g. bytes trimmed per mount).
    string result = 1;
}

// Notification that a container's published port bindings changed.
message PortBindingsChanged {
    // Container ID.
    string container_id = 1;
    // Current published bindings from dockerd inspect output.
    repeated PortBinding bindings = 2;
}

// Notification that a container no longer has active published ports.
message PortBindingsRemoved {
    // Container ID.
    string container_id = 1;
}

// Individual service status within the guest runtime stack.
message ServiceStatus {
    // Service name (e.g. "containerd", "dockerd", "runc").
    string name = 1;
    // Service status: "ready", "not_ready", or "error".
    string status = 2;
    // Human-readable detail for diagnostics (error message, socket path, etc.).
    string detail = 3;
}

// Request to start the native Kubernetes cluster.
message KubernetesStartRequest {}

// Response from starting the native Kubernetes cluster.
message KubernetesStartResponse {
    // Whether the cluster process is running.
    bool running = 1;
    // Whether the Kubernetes API endpoint is reachable.
    bool api_ready = 2;
    // API endpoint exposed to the host.
    string endpoint = 3;
    // Human-readable detail for diagnostics.
    string detail = 4;
}

// Request to stop the native Kubernetes cluster.
message KubernetesStopRequest {}

// Response from stopping the native Kubernetes cluster.
message KubernetesStopResponse {
    // Whether the cluster is fully stopped.
    bool stopped = 1;
    // Human-readable detail for diagnostics.
    string detail = 2;
}

// Request to delete the native Kubernetes cluster state.
message KubernetesDeleteRequest {}

// Response from deleting the native Kubernetes cluster state.
message KubernetesDeleteResponse {
    // Human-readable detail for diagnostics.
    string detail = 1;
}

// Request for Kubernetes cluster status.
message KubernetesStatusRequest {}

// Runtime status report for the native Kubernetes cluster.
message KubernetesStatusResponse {
    // Whether the cluster process is running.
    bool running = 1;
    // Whether the Kubernetes API endpoint is reachable.
    bool api_ready = 2;
    // API endpoint exposed to the host.
    string endpoint = 3;
    // Human-readable detail for diagnostics.
    string detail = 4;
    // Per-service status entries for fine-grained observability.
    repeated ServiceStatus services = 5;
}

// Request for managed kubeconfig content.
message KubernetesKubeconfigRequest {}

// Managed kubeconfig payload exported from the guest cluster.
message KubernetesKubeconfigResponse {
    // Raw kubeconfig YAML.
    string kubeconfig = 1;
    // ArcBox-managed context name.
    string context_name = 2;
    // API endpoint embedded in the exported kubeconfig.
    string endpoint = 3;
}

// Graceful shutdown request from host.
message ShutdownRequest {
    // Grace period in seconds for processes to exit after SIGTERM.
    // 0 means use the agent's default (currently 25 seconds).
    uint32 timeout_seconds = 1;
}

// Shutdown acknowledgement. Sent before the agent begins teardown.
message ShutdownResponse {
    // Always true when the agent accepts the request.
    bool accepted = 1;
}

// Test-only: read a file through `mmap(MAP_SHARED)` to force the guest
// kernel to issue `FUSE_SETUPMAPPING` and exercise the VirtioFS DAX path.
// Used by the ABX-362 E2E harness. Not intended for production callers.
message MmapReadFileRequest {
    // Absolute guest path (typically a file inside a VirtioFS mount).
    string path = 1;
    // Byte offset within the file.
    uint64 offset = 2;
    // Number of bytes to read. Rounded up to a page boundary internally;
    // the response trims back to the requested length.
    uint64 length = 3;
}

// Response to `MmapReadFileRequest`.
message MmapReadFileResponse {
    // Bytes read, trimmed to the originally requested length.
    bytes data = 1;
    // Number of bytes actually read (<= length). Short if file smaller
    // than offset+length.
    uint64 bytes_read = 2;
}