Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions architecture/compute-runtimes.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ template resource limits. Docker and Podman apply them as runtime limits.
Kubernetes mirrors each limit into the matching request. VM accepts the fields
but currently ignores them.

The CLI `--runtime-class` flag sets `SandboxTemplate.runtime_class_name`. The
Kubernetes driver maps this onto pod `spec.runtimeClassName` (used to request
sandboxed runtimes such as Kata Containers or gVisor); other drivers ignore it.
When omitted on GPU sandboxes, the Kubernetes driver still falls back to
`nvidia`.

VM runtime state paths are derived only from driver-validated sandbox IDs
matching `[A-Za-z0-9._-]{1,128}`. The gateway-owned VM driver socket uses a
private `run/` directory plus Unix peer UID/PID checks. Standalone
Expand Down
29 changes: 29 additions & 0 deletions crates/openshell-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1148,6 +1148,7 @@ enum DoctorCommands {
}

#[derive(Subcommand, Debug)]
#[allow(clippy::large_enum_variant)]
enum SandboxCommands {
/// Create a sandbox.
#[command(help_template = LEAF_HELP_TEMPLATE, next_help_heading = "FLAGS")]
Expand Down Expand Up @@ -1216,6 +1217,15 @@ enum SandboxCommands {
#[arg(long)]
memory: Option<String>,

/// Request a Kubernetes `RuntimeClass` for the sandbox pod (for example:
/// `kata`, `kata-containers`, `gvisor`).
///
/// Only honored by the Kubernetes driver. On GPU sandboxes the driver
/// defaults to `nvidia` when this flag is omitted; passing this flag
/// overrides that default.
#[arg(long, value_name = "NAME")]
runtime_class: Option<String>,

/// Provider names to attach to this sandbox.
#[arg(long = "provider")]
providers: Vec<String>,
Expand Down Expand Up @@ -2518,6 +2528,7 @@ async fn main() -> Result<()> {
gpu_device,
cpu,
memory,
runtime_class,
providers,
policy,
forward,
Expand Down Expand Up @@ -2586,6 +2597,7 @@ async fn main() -> Result<()> {
gpu_device.as_deref(),
cpu.as_deref(),
memory.as_deref(),
runtime_class.as_deref(),
editor,
&providers,
policy.as_deref(),
Expand Down Expand Up @@ -4168,6 +4180,23 @@ mod tests {
}
}

#[test]
fn sandbox_create_runtime_class_flag_parses() {
let cli =
Cli::try_parse_from(["openshell", "sandbox", "create", "--runtime-class", "kata"])
.expect("sandbox create --runtime-class should parse");

match cli.command {
Some(Commands::Sandbox {
command: Some(SandboxCommands::Create { runtime_class, .. }),
..
}) => {
assert_eq!(runtime_class.as_deref(), Some("kata"));
}
other => panic!("expected SandboxCommands::Create, got: {other:?}"),
}
}

#[test]
fn service_expose_accepts_positional_target_port_and_service() {
let cli = Cli::try_parse_from([
Expand Down
4 changes: 3 additions & 1 deletion crates/openshell-cli/src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1685,6 +1685,7 @@ pub async fn sandbox_create(
gpu_device: Option<&str>,
cpu: Option<&str>,
memory: Option<&str>,
runtime_class: Option<&str>,
editor: Option<Editor>,
providers: &[String],
policy: Option<&str>,
Expand Down Expand Up @@ -1754,10 +1755,11 @@ pub async fn sandbox_create(
let policy = load_sandbox_policy(policy)?;
let resource_limits = build_sandbox_resource_limits(cpu, memory)?;

let template = if image.is_some() || resource_limits.is_some() {
let template = if image.is_some() || resource_limits.is_some() || runtime_class.is_some() {
Some(SandboxTemplate {
image: image.unwrap_or_default(),
resources: resource_limits,
runtime_class_name: runtime_class.unwrap_or_default().to_string(),
..SandboxTemplate::default()
})
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,7 @@ async fn sandbox_create_keeps_command_sessions_by_default() {
None,
None,
None,
None,
&[],
None,
None,
Expand Down Expand Up @@ -830,6 +831,7 @@ async fn sandbox_create_sends_cpu_and_memory_limits_only() {
Some("500m"),
Some("2Gi"),
None,
None,
&[],
None,
None,
Expand Down Expand Up @@ -906,6 +908,7 @@ async fn sandbox_create_does_not_infer_command_providers_when_v2_enabled() {
None,
None,
None,
None,
&[],
None,
None,
Expand Down Expand Up @@ -962,6 +965,7 @@ async fn sandbox_create_returns_vm_error_without_waiting_for_timeout() {
None,
None,
None,
None,
&[],
None,
None,
Expand Down Expand Up @@ -1014,6 +1018,7 @@ async fn sandbox_create_keeps_waiting_while_vm_progress_arrives() {
None,
None,
None,
None,
&[],
None,
None,
Expand Down Expand Up @@ -1058,6 +1063,7 @@ async fn sandbox_create_times_out_when_only_logs_arrive() {
None,
None,
None,
None,
&[],
None,
None,
Expand Down Expand Up @@ -1098,6 +1104,7 @@ async fn sandbox_create_deletes_command_sessions_with_no_keep() {
None,
None,
None,
None,
&[],
None,
None,
Expand Down Expand Up @@ -1142,6 +1149,7 @@ async fn sandbox_create_deletes_shell_sessions_with_no_keep() {
None,
None,
None,
None,
&[],
None,
None,
Expand Down Expand Up @@ -1186,6 +1194,7 @@ async fn sandbox_create_keeps_sandbox_with_hidden_keep_flag() {
None,
None,
None,
None,
&[],
None,
None,
Expand Down Expand Up @@ -1230,6 +1239,7 @@ async fn sandbox_create_keeps_sandbox_with_forwarding() {
None,
None,
None,
None,
&[],
None,
Some(openshell_core::forward::ForwardSpec::new(forward_port)),
Expand Down
13 changes: 13 additions & 0 deletions docs/sandboxes/manage-sandboxes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,19 @@ For Docker-backed sandboxes, GPU injection uses Docker CDI. If you enable Docker
CDI after the gateway starts, restart the gateway so OpenShell can detect the
updated Docker daemon capability.

### Runtime Class

For Kubernetes-backed gateways, use `--runtime-class` to request a sandboxed
container runtime (for example, Kata Containers or gVisor) for the sandbox pod:

```shell
openshell sandbox create --runtime-class kata -- claude
```

The value is passed through to the pod `spec.runtimeClassName`. The cluster
administrator must install and register the named RuntimeClass; OpenShell does
not provision it. Other compute drivers ignore this flag.

### Custom Containers

Use `--from` to create a sandbox from the base image, another pre-built sandbox name, a local directory, or a container image:
Expand Down
Loading