Skip to content

Commit 13a3d7d

Browse files
committed
refactor(vm): own gateway registration in driver
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
1 parent 5f41176 commit 13a3d7d

11 files changed

Lines changed: 198 additions & 141 deletions

File tree

‎.github/workflows/branch-checks.yml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,9 +208,9 @@ jobs:
208208
cargo test -p openshell-gateway --all-targets --no-default-features --features compute-driver-docker
209209
cargo test -p openshell-gateway --all-targets --no-default-features --features compute-driver-kubernetes
210210
cargo test -p openshell-gateway --all-targets --no-default-features --features compute-driver-podman
211-
cargo test -p openshell-gateway --all-targets --no-default-features --features compute-driver-vm
211+
cargo test -p openshell-gateway --all-targets --no-default-features --features compute-driver-managed
212212
cargo test -p openshell-gateway --all-targets --no-default-features --features compute-driver-mxc
213-
cargo test -p openshell-gateway --all-targets --no-default-features --features compute-driver-docker,compute-driver-vm
213+
cargo test -p openshell-gateway --all-targets --no-default-features --features compute-driver-docker,compute-driver-managed
214214
215215
- name: Verify the defaults-without-telemetry feature alias tracks the default feature set
216216
run: tasks/scripts/verify-defaults-without-telemetry.sh

‎Cargo.lock‎

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ license = "Apache-2.0"
1313
repository = "https://github.com/NVIDIA/OpenShell"
1414

1515
[workspace.dependencies]
16+
openshell-managed-compute-driver = { package = "openshell-driver-vm", path = "crates/openshell-driver-vm", default-features = false }
17+
1618
# Async runtime
1719
tokio = { version = "1.43", features = ["full"] }
1820

‎README.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -349,20 +349,20 @@ cargo build --release -p openshell-driver-vm --no-default-features --features de
349349

350350
The resulting binaries contain no telemetry endpoint, no telemetry HTTP client, and no emission code. With telemetry compiled out, the gateway emits nothing and reports telemetry disabled to the sandboxes it launches. Cargo has no way to subtract a single default feature, so `defaults-without-telemetry` must be paired with `--no-default-features`; passing it on its own leaves the defaults in place and fails the build rather than producing a binary that still emits.
351351

352-
The gateway also exposes separate Cargo features for its built-in compute drivers: `compute-driver-kubernetes`, `compute-driver-docker`, `compute-driver-podman`, `compute-driver-vm`, and `compute-driver-mxc`. Disable the default feature set, then enable only the drivers and telemetry mode required by the target binary. For example:
352+
The gateway also exposes separate Cargo features for its built-in compute drivers: `compute-driver-kubernetes`, `compute-driver-docker`, `compute-driver-podman`, `compute-driver-managed`, and `compute-driver-mxc`. The driver-owned managed adapter currently registers the standalone VM driver without putting VM-specific code in the gateway crate. Disable the default feature set, then enable only the drivers and telemetry mode required by the target binary. For example:
353353

354354
```shell
355355
# Docker only, with telemetry support.
356356
cargo build --release -p openshell-gateway --no-default-features --features telemetry,compute-driver-docker
357357

358358
# Docker and VM only, with telemetry compiled out.
359-
cargo build --release -p openshell-gateway --no-default-features --features compute-driver-docker,compute-driver-vm
359+
cargo build --release -p openshell-gateway --no-default-features --features compute-driver-docker,compute-driver-managed
360360

361361
# Windows MXC only, with telemetry support and bundled Z3.
362362
cargo build --release -p openshell-gateway --no-default-features --features telemetry,compute-driver-mxc,bundled-z3
363363
```
364364

365-
Regular builds retain their platform driver set through the default `in-tree-compute-drivers` compatibility feature. On Windows, `compute-driver-mxc` selects MXC; the other four features install unsupported-driver stubs. On other platforms, MXC is excluded.
365+
Regular builds retain their platform driver set through the default `in-tree-compute-drivers` compatibility feature. On Windows, `compute-driver-mxc` selects MXC; Docker, Kubernetes, and Podman install unsupported-driver stubs, while the managed standalone adapter is excluded. On other platforms, MXC is excluded.
366366

367367
Telemetry events are limited to anonymous operational categories and counts, such as sandbox lifecycle outcomes, provider profile buckets, policy decision counts, and aggregate network activity denial categories. OpenShell telemetry does not collect sandbox names or IDs, hostnames, file paths, binary paths, prompts, credentials, provider names, model names, or user content.
368368

‎architecture/compute-runtimes.md‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,9 +156,10 @@ on a server-only API.
156156
Driver crates own their configuration defaults and backend-specific startup
157157
contract. The standalone VM driver exposes a lightweight `managed` feature for
158158
its configuration and subprocess arguments; this does not link libkrun or the
159-
VM runtime into the gateway. The gateway composition crate only adapts that
160-
launcher to `ComputeDriverFactory`. The server owns the generic managed-child
161-
readiness probe, UDS connection, supervision, and socket cleanup.
159+
VM runtime into the gateway. Its optional `gateway-integration` feature owns the
160+
`ComputeDriverFactory` adapter and exports an opaque registration; the gateway
161+
only installs that provider. The server owns the generic managed-child readiness
162+
probe, UDS connection, supervision, and socket cleanup.
162163

163164
## Stop and Start Lifecycle
164165

‎crates/openshell-driver-vm/Cargo.toml‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ openshell-otel = { path = "../openshell-otel", optional = true }
3131
openshell-policy = { path = "../openshell-policy", optional = true }
3232
openshell-driver-podman = { path = "../openshell-driver-podman", optional = true }
3333
openshell-vfio = { path = "../openshell-vfio", optional = true }
34+
openshell-server = { path = "../openshell-server", default-features = false, optional = true }
3435

36+
async-trait = { version = "0.1", optional = true }
3537
base64 = { workspace = true, optional = true }
3638
bollard = { version = "0.20", features = ["ssh"], optional = true }
3739
tokio = { workspace = true }
@@ -68,6 +70,9 @@ default = ["compute-driver", "telemetry"]
6870
## Expose VM-specific managed launch configuration without linking the VM
6971
## runtime implementation into the gateway process.
7072
managed = ["dep:openshell-policy", "dep:rustix"]
73+
## Adapt the standalone driver to the standard gateway registry. The adapter
74+
## remains driver-owned and does not pull the VM runtime into the gateway.
75+
gateway-integration = ["managed", "dep:async-trait", "dep:openshell-server"]
7176
## Build the standalone compute driver and its host runtime implementation.
7277
compute-driver = [
7378
"managed",

‎crates/openshell-driver-vm/README.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ The driver embeds libkrun, libkrunfw, the guest OCI unpacker, the portable guest
1111
```mermaid
1212
flowchart LR
1313
subgraph host["Host"]
14-
gateway["openshell-gateway<br/>(VM factory adapter)"]
15-
driver["openshell-driver-vm<br/>libkrun"]
14+
gateway["openshell-gateway<br/>(generic registry consumer)"]
15+
driver["openshell-driver-vm<br/>driver-owned registry adapter + libkrun"]
1616
supervisor["openshell-supervisor<br/>host policy supervisor"]
1717
gateway <-->|"gRPC over UDS<br/>compute-driver.sock"| driver
1818
supervisor <-->|"authenticated gRPC<br/>policy + relay"| gateway
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
//! Optional adapter from the standalone VM driver to the gateway registry.
5+
6+
use crate::{VmComputeConfig, spawn_managed_vm_driver};
7+
use openshell_core::telemetry::TelemetryComputeDriver;
8+
use openshell_core::{Error, Result};
9+
use openshell_server::{
10+
ComputeDriverBuildContext, ComputeDriverConfigContext, ComputeDriverFactory,
11+
ComputeDriverInstance, ComputeDriverRegistration, connect_managed_compute_driver,
12+
};
13+
use std::path::{Path, PathBuf};
14+
15+
const DRIVER_NAME: &str = "vm";
16+
17+
/// Build the VM driver's self-contained gateway registration.
18+
pub fn gateway_registration() -> Result<ComputeDriverRegistration> {
19+
ComputeDriverRegistration::new(DRIVER_NAME, u16::MAX, None, VmFactory).map(|registration| {
20+
registration
21+
.with_telemetry_category(TelemetryComputeDriver::anonymous_category(DRIVER_NAME))
22+
.with_local_singleplayer()
23+
})
24+
}
25+
26+
#[derive(Clone, Copy)]
27+
struct VmFactory;
28+
29+
#[async_trait::async_trait]
30+
impl ComputeDriverFactory for VmFactory {
31+
fn supports_config_preflight(&self) -> bool {
32+
true
33+
}
34+
35+
fn validate_config(&self, context: ComputeDriverConfigContext<'_>) -> Result<()> {
36+
let mut config = vm_config(context)?;
37+
apply_default_grpc_endpoint(
38+
&mut config,
39+
context.gateway_tls_enabled(),
40+
context.gateway_port(),
41+
);
42+
config.validate_configuration()
43+
}
44+
45+
async fn build(&self, context: ComputeDriverBuildContext<'_>) -> Result<ComputeDriverInstance> {
46+
let mut config = vm_config(context.config_context())?;
47+
require_guest_tls(&context)?;
48+
if !context.gateway_tls_enabled() || context.guest_tls_paths().is_some() {
49+
apply_default_grpc_endpoint(
50+
&mut config,
51+
context.gateway_tls_enabled(),
52+
context.gateway_port(),
53+
);
54+
}
55+
apply_guest_tls(
56+
&mut config.guest_tls_ca,
57+
&mut config.guest_tls_cert,
58+
&mut config.guest_tls_key,
59+
context.guest_tls_paths(),
60+
);
61+
let launch = spawn_managed_vm_driver(
62+
context.gateway_log_level(),
63+
context.gateway_name(),
64+
&config,
65+
context.otlp_config().map(|config| config.endpoint.as_str()),
66+
)?;
67+
let (child, socket_path) = launch.into_parts();
68+
let endpoint = connect_managed_compute_driver(DRIVER_NAME, socket_path, child)
69+
.await
70+
.map_err(|error| Error::execution(error.to_string()))?;
71+
Ok(ComputeDriverInstance::ManagedRemote(endpoint))
72+
}
73+
}
74+
75+
fn vm_config(context: ComputeDriverConfigContext<'_>) -> Result<VmComputeConfig> {
76+
let mut config: VmComputeConfig = context.driver_config()?;
77+
if config.state_dir.as_os_str().is_empty() {
78+
config.state_dir = VmComputeConfig::default_state_dir();
79+
}
80+
Ok(config)
81+
}
82+
83+
fn apply_default_grpc_endpoint(config: &mut VmComputeConfig, tls_enabled: bool, port: u16) {
84+
if config.grpc_endpoint.trim().is_empty() {
85+
let scheme = if tls_enabled { "https" } else { "http" };
86+
config.grpc_endpoint = format!("{scheme}://127.0.0.1:{port}");
87+
}
88+
}
89+
90+
fn require_guest_tls(context: &ComputeDriverBuildContext<'_>) -> Result<()> {
91+
if context.gateway_tls_enabled() && context.guest_tls_paths().is_none() {
92+
return Err(Error::config(format!(
93+
"gateway TLS requires guest_tls_ca, guest_tls_cert, and guest_tls_key in [openshell.gateway] when using the {DRIVER_NAME} compute driver"
94+
)));
95+
}
96+
Ok(())
97+
}
98+
99+
fn apply_guest_tls(
100+
ca: &mut Option<PathBuf>,
101+
cert: &mut Option<PathBuf>,
102+
key: &mut Option<PathBuf>,
103+
defaults: Option<(&Path, &Path, &Path)>,
104+
) {
105+
if ca.is_none()
106+
&& cert.is_none()
107+
&& key.is_none()
108+
&& let Some((default_ca, default_cert, default_key)) = defaults
109+
{
110+
*ca = Some(default_ca.to_owned());
111+
*cert = Some(default_cert.to_owned());
112+
*key = Some(default_key.to_owned());
113+
}
114+
}
115+
116+
#[cfg(test)]
117+
mod tests {
118+
use super::apply_guest_tls;
119+
use std::path::{Path, PathBuf};
120+
121+
#[test]
122+
fn package_managed_guest_bundle_is_injected_when_driver_paths_are_absent() {
123+
let mut ca = None;
124+
let mut cert = None;
125+
let mut key = None;
126+
apply_guest_tls(
127+
&mut ca,
128+
&mut cert,
129+
&mut key,
130+
Some((
131+
Path::new("ca.pem"),
132+
Path::new("client.pem"),
133+
Path::new("client-key.pem"),
134+
)),
135+
);
136+
137+
assert_eq!(ca, Some(PathBuf::from("ca.pem")));
138+
assert_eq!(cert, Some(PathBuf::from("client.pem")));
139+
assert_eq!(key, Some(PathBuf::from("client-key.pem")));
140+
}
141+
}

‎crates/openshell-driver-vm/src/lib.rs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ pub mod driver;
1717
mod embedded_runtime;
1818
#[cfg(feature = "compute-driver")]
1919
mod ffi;
20+
#[cfg(all(not(target_os = "windows"), feature = "gateway-integration"))]
21+
mod gateway;
2022
#[cfg(feature = "compute-driver")]
2123
pub mod gpu;
2224
#[cfg(feature = "compute-driver")]
@@ -36,6 +38,8 @@ mod runtime;
3638

3739
#[cfg(feature = "compute-driver")]
3840
pub use driver::{VmDriver, VmDriverConfig};
41+
#[cfg(all(not(target_os = "windows"), feature = "gateway-integration"))]
42+
pub use gateway::gateway_registration;
3943
#[cfg(feature = "compute-driver")]
4044
pub use lifecycle::{
4145
BackendFeature, ExtensionCapabilities, ExtensionDescriptor, GuestInitDropin, LaunchAbortReason,

‎crates/openshell-gateway/Cargo.toml‎

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ miette = { workspace = true }
2323
tokio = { workspace = true }
2424

2525
[target.'cfg(not(target_os = "windows"))'.dependencies]
26+
openshell-managed-compute-driver = { workspace = true, features = ["gateway-integration"], optional = true }
2627
openshell-driver-docker = { path = "../openshell-driver-docker", optional = true }
2728
openshell-driver-kubernetes = { path = "../openshell-driver-kubernetes", optional = true }
2829
openshell-driver-podman = { path = "../openshell-driver-podman", optional = true }
29-
openshell-driver-vm = { path = "../openshell-driver-vm", default-features = false, features = ["managed"], optional = true }
3030

3131
[target.'cfg(target_os = "windows")'.dependencies]
3232
openshell-driver-mxc = { path = "../openshell-driver-mxc", optional = true }
@@ -36,18 +36,15 @@ default = ["telemetry", "in-tree-compute-drivers"]
3636
in-tree-compute-drivers = [
3737
"compute-driver-docker",
3838
"compute-driver-kubernetes",
39+
"compute-driver-managed",
3940
"compute-driver-podman",
40-
"compute-driver-vm",
4141
"compute-driver-mxc",
4242
]
4343
compute-driver-mxc = ["dep:openshell-driver-mxc"]
4444
compute-driver-docker = ["dep:openshell-driver-docker", "dep:openshell-otel"]
4545
compute-driver-kubernetes = ["dep:openshell-driver-kubernetes", "dep:openshell-otel"]
46+
compute-driver-managed = ["dep:openshell-managed-compute-driver"]
4647
compute-driver-podman = ["dep:openshell-driver-podman", "dep:openshell-otel"]
47-
compute-driver-vm = [
48-
"dep:openshell-driver-vm",
49-
"dep:openshell-otel",
50-
]
5148
telemetry = ["openshell-core/telemetry", "openshell-server/telemetry"]
5249
## Convenience alias: every default feature except `telemetry`. Build a
5350
## telemetry-free gateway with

0 commit comments

Comments
 (0)