Files
rvbox/docs/control-plane.md
T

139 lines
8.0 KiB
Markdown

# RVBox v1 control plane
[`../protos/rvbox/v1/control.proto`](../protos/rvbox/v1/control.proto) defines
the canonical control API. `rvc` uses the `Control` gRPC service over the local
Unix-domain socket. The server also exposes the same unary operations through
an optional JSON-RPC 2.0 HTTP adapter for local debugging and batch automation.
## Endpoints
- Unix socket: enabled by default, mode `0600`, owned by the server account.
- HTTP JSON-RPC: disabled unless enabled; default bind `127.0.0.1:6900`.
It has no authentication by design. Binding it beyond loopback is an explicit
deployment choice and requires external protection.
gRPC streams command history and live events through `FollowCommand`. JSON-RPC
remains simple: callers issue work, query command state, poll event/output pages
after an event sequence, append stdin, close stdin, or signal a command. It does
not invent a separate event-stream protocol.
The JSON-RPC method names are the lower-camel protobuf operation names:
`listClients`, `getClient`, `listCommands`, `getCommand`, `runCommand`,
`appendStdin`, `closeStdin`, `signalCommand`, `getOutput`, and the three storage
incident methods documented below. Parameters and results use protobuf JSON
mapping (including base64 strings for `bytes` and UTC RFC 3339 strings for
timestamps). Control response messages contain successful results only. gRPC
failures use canonical non-OK status codes with structured RVBox details where
needed; the JSON-RPC adapter maps the same domain errors to standard JSON-RPC
error objects. `getOutput` and `getCommand` are the polling path for what gRPC
exposes as follow streams.
`rvc stat CLIENT` also shows the active durable client-instance ID and the most
recent different instance rejected while that client is live. An operator may
run `rvc client takeover CLIENT INSTANCE-ID`; this creates a one-shot 5-minute
authorization for that exact pending claim. Its matching reconnect consumes the
authorization and fences the old session. If the old session is no longer live,
the replacement connects normally without this command. The JSON-RPC method is
`authorizeClientTakeover`.
Both transports enforce the same decoded field limits. A control gRPC request
may be at most 16 MiB; a JSON-RPC HTTP body may be at most 24 MiB to accommodate
base64 expansion of the 10 MiB script maximum. `ExecutionSpec` itself may be at
most 768 KiB, which also keeps its agent dispatch below the 1 MiB envelope cap.
## CLI semantics
`rvc stat` maps to `ListClients`, `GetClient`, `ListCommands`, and `GetCommand`.
History pages default to 20 commands and may request at most 100. Historical
output uses opaque, byte-bounded cursors and may resume within an output event;
it is not numbered or paginated by lines. The server returns uncompressed output
slices with event sequence, byte offset, stream, observed timestamp, and server
receipt timestamp. `rvc` may render line-oriented human output, but line
boundaries are not storage or pagination boundaries.
`rvc run` always creates a durable command through unary `RunCommand`, which
returns the UUID. Foreground mode then calls `FollowCommand` with that UUID,
`after_event_seq=0`, and `include_existing=true`, streaming output until a
terminal event. `--background` returns immediately after `RunCommand`.
Interrupting the CLI, timing out its local wait, or losing the local control
connection never cancels remote work. The explicit `rvc kill` operation is the
only termination path. A foreground caller can resume `FollowCommand` after its
last received event sequence without missing durable history.
`FollowCommandResponse` wraps either a client-sequenced `CommandEvent` or a
server-created retention marker and exposes server receipt/recording time
separately from client observation time. A retention marker does not advance the
resume cursor. When retained history is incomplete, the server emits the relevant
marker before any terminal event on that stream, so a follower never stops on
terminal while believing truncated history was complete.
Mutating requests accept an optional `request_id`. `rvc` generates one per
mutation and reuses it for transport retries; `--request-id` lets automation
reuse it across CLI invocations. The CLI accepts that option globally and drops
it for reads. For `RunCommand`, the supplied request ID is the command's
`issue_uuid`. For stdin, close, signal, repair, and acknowledgement operations
it deduplicates that action while `issue_uuid` or `incident_id` continues to
identify the target. The server generates a request ID when omitted, preserving
simple JSON-RPC use.
The server stores the mutation kind, target, immutable request hash, and result
under that ID. An identical retry returns the original result; reuse with any
different method, target, or content returns `CONFLICT`. The record is owned by
the affected command or incident for quota and retention. A retry after that
owner has been reclaimed cannot repeat the action: it returns retained
tombstone information where available or `NOT_FOUND`.
`rvc run --queue-ttl` controls how long work may wait for server-confirmed
acceptance and defaults to 15 minutes; zero means indefinite. `rvc stat`
distinguishes terminal `Expired`, `Expired (awaiting reconciliation)`, and
actual lifecycle with a late-after-expiry warning. It renders terminal
`Rejected` with the client's structured validation/platform reason; `Failed`
means the requested code actually launched.
`rvc run --elevated` maps directly to `ExecutionSpec.elevated`; omission is
false. Non-Windows clients reject true as unsupported in v1. Windows chooses
the effective context from that bit and launch-time login state: normal commands
use `active-user` when possible and otherwise `local-service`; elevated commands
with an active user try `active-user-elevated`, `active-system`, then
`local-system`, while logged-out machines use `local-system` directly. These
fallbacks finish before `launch_prepared` and never retry a process.
Detailed `rvc stat CLIENT ISSUE_UUID` output shows requested elevation, every
attempted Windows context, selection/fallback detail, effective context and
process-token SID, and target session ID/owner SID when applicable.
`active-system` is rendered conspicuously as SYSTEM in another user's session,
never as that user. A pre-launch rejection shows the structured final context-
selection error rather than implying requested code ran.
`rvc append` turns a string into `StdinWrite` with `append_newline=true` unless
the caller selects raw mode; `--file` supplies raw bytes; `--attach` streams
local standard input. `CloseStdin` is available separately. All stdin actions
are acknowledged and idempotent.
## Query behavior
Command details expose persisted request fields, effective execution metadata,
lifecycle, terminal result, output availability/truncation, current resource
snapshot, and `suspected_hung` diagnostics. The latter is informational and
must not be shown as a terminal state. Pagination response cursors are stable
within their declared ordering (newest issue time for command lists; increasing
`event_seq` for events/output).
Control failures are never embedded in otherwise-successful response messages.
They use canonical gRPC status codes with structured RVBox details; JSON-RPC
returns the corresponding JSON-RPC error object, and `rvc` maps the same domain
error to a stable exit code rather than parsing text.
## Storage incidents
`rvc storage incidents` lists unresolved storage incidents by default and can
include resolved history. `rvc storage repair INCIDENT` attempts only a known
safe repair. `rvc storage acknowledge INCIDENT --note ...` accepts documented
irrecoverable loss and clears that incident from dirty health. Both mutations
use the same optional `--request-id` behavior as other mutations. An
acknowledgement note is required and bounded to 4 KiB. Repair or acknowledgement
changes incident state; it does not delete history as part of that action;
resolved history later follows the independent audit/incident quota. The
JSON-RPC equivalents are `listStorageIncidents`,
`repairStorageIncident`, and `acknowledgeStorageIncident`.