Fleet P2b: run agent sandboxes on connected nodes (RemoteDriver + placement)
Agents can now provision their sandbox on a connected fleet node instead of the gateway host. Local stays the strict default, so existing agents are byte-for- byte unaffected until explicitly placed elsewhere. Security parity: the daemon links the REAL cm-sandbox DockerDriver and runs the typed container ops (sb_provision/sb_exec/sb_destroy/sb_health/sb_list) through it — identical hardening (cap-drop ALL, seccomp, no-net, read-only, non-root) to local sandboxes. cm-sandbox spec types are now Serialize/Deserialize so the spec crosses the channel. - cm-api: RemoteDriver (impl SandboxDriver over the node channel) + HubDriverProvider (impl cm_runtime::NodeDriverProvider, hands out a driver only for connected nodes via a sync online set) + NodeHub.call/is_connected. AppState.with_node_hub so the hub is shared with the placement provider. - cm-runtime SandboxManager: driver_for(node_id) routes by the recorded agent_containers.node_id (local default = existing driver, identical path); placement_node() reads the workspace setting and falls back to local if the node is offline; exec/release route accordingly. NodeDriverProvider trait. - DB: 0020_workspace_placement + repo (for_agent/get/set/clear). - main.rs: build the NodeHub first; inject HubDriverProvider into the agent manager + share the hub with AppState. - API+UI: GET/PUT /api/fleet/placement + a "Run agents on: Local / <node>" selector in the Fleet overview. Note: a node must be able to pull the agent image (the daemon docker-pulls it); interactive PTY for agent containers on remote nodes is not wired (Terminal app stays local) — the in-dashboard node shell already covers host access. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
33aa9c0693
commit
fb59378aa2
@@ -1,8 +1,10 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Hardening parameters for one agent sandbox. The non-negotiable controls
|
||||
/// (uid 10001, cap-drop ALL, no-new-privileges, seccomp profile, read-only
|
||||
/// rootfs, no network) are enforced by the driver and are not configurable
|
||||
/// here by design — only resource limits vary per deployment.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SandboxSpec {
|
||||
/// Unique container name, e.g. `clawmates-sbx-{agent_id}`.
|
||||
pub name: String,
|
||||
@@ -24,7 +26,7 @@ pub struct SandboxSpec {
|
||||
|
||||
/// A read-write mount of a per-agent subpath of a named Docker volume into the
|
||||
/// container — used to expose the Files drives inside the Terminal.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DriveMount {
|
||||
/// The engine's named volume (e.g. `clawmates_filedata`).
|
||||
pub volume: String,
|
||||
@@ -37,7 +39,7 @@ pub struct DriveMount {
|
||||
|
||||
/// The flavour of a sandbox container. Agent + Browser are hardened tool
|
||||
/// sandboxes; Terminal is the interactive themed dev shell.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum SandboxKind {
|
||||
/// Hardened, no-egress agent tool sandbox (read-only rootfs, tmpfs home).
|
||||
Agent,
|
||||
@@ -84,14 +86,14 @@ pub struct PtySession {
|
||||
pub input: std::pin::Pin<Box<dyn tokio::io::AsyncWrite + Send>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SandboxHandle {
|
||||
/// Container id assigned by the engine.
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ExecResult {
|
||||
pub exit_code: i64,
|
||||
pub stdout: String,
|
||||
@@ -100,7 +102,7 @@ pub struct ExecResult {
|
||||
|
||||
/// A sandbox the driver currently knows about (label-filtered), used by the
|
||||
/// reaper to find orphans — containers that outlived the process that made them.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ManagedSandbox {
|
||||
/// Engine container/pod id.
|
||||
pub id: String,
|
||||
|
||||
Reference in New Issue
Block a user