mirror of
https://github.com/NVIDIA/OpenShell.git
synced 2026-10-21 06:11:31 +08:00
fix(server): fall through compiled-out auto-detected drivers
Signed-off-by: Evan Lezar <elezar@nvidia.com>
This commit is contained in:
@@ -252,7 +252,7 @@ OpenShell collects anonymous telemetry to help improve the project for developer
|
||||
|
||||
Disable telemetry at runtime by setting `OPENSHELL_TELEMETRY_ENABLED=false` on the gateway deployment. OpenShell propagates this deployment setting into sandbox supervisor environments so sandbox-side telemetry collection is disabled as well.
|
||||
|
||||
You can also compile telemetry out entirely. Telemetry support is a default-on `telemetry` Cargo feature; building `openshell-server` with `--no-default-features` and selecting only the driver features you need produces a gateway that contains no telemetry endpoint, no telemetry HTTP client, and no emission code. The gateway requires at least one compute driver to link; for example, `cargo build --release -p openshell-server --bin openshell-gateway --no-default-features --features driver-kubernetes,driver-docker,driver-podman,driver-vm` builds a telemetry-free gateway with every driver. Build telemetry-free `openshell-sandbox` and `openshell-driver-vm` binaries with a plain `--no-default-features`. With telemetry compiled out, the gateway emits nothing and reports telemetry disabled to the sandboxes it launches.
|
||||
You can also compile telemetry out entirely. Telemetry support is a default-on `telemetry` Cargo feature; building `openshell-server` with `--no-default-features` produces a gateway that contains no telemetry endpoint, no telemetry HTTP client, and no emission code. Enable the built-in driver features you need, or enable none for an extension-only gateway; for example, `cargo build --release -p openshell-server --bin openshell-gateway --no-default-features --features driver-kubernetes,driver-docker,driver-podman,driver-vm` builds a telemetry-free gateway with every built-in driver. Build telemetry-free `openshell-sandbox` and `openshell-driver-vm` binaries with a plain `--no-default-features`. With telemetry compiled out, the gateway emits nothing and reports telemetry disabled to the sandboxes it launches.
|
||||
|
||||
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.
|
||||
|
||||
@@ -269,7 +269,7 @@ cargo build --release -p openshell-server --bin openshell-gateway \
|
||||
--no-default-features --features driver-kubernetes,telemetry
|
||||
```
|
||||
|
||||
Any non-empty driver subset is a valid build, including zero built-in drivers (an extension-only gateway that reaches an out-of-tree driver over `[openshell.drivers.<name>].socket_path`). What the gateway needs at *runtime* is a `compute_drivers` entry it can serve: either a built-in this binary was built with, or an extension driver name with a matching socket_path entry. Naming a built-in that this gateway was not built with fails at startup with a message naming both the driver and the Cargo flag that re-enables it. Extension drivers reached via `--compute-driver-socket` work regardless of the feature set. See the [gateway configuration reference](docs/reference/gateway-config.mdx) for details.
|
||||
Any built-in driver subset is a valid build, including zero built-in drivers (an extension-only gateway that reaches an out-of-tree driver over `[openshell.drivers.<name>].socket_path`). What the gateway needs at *runtime* is a `compute_drivers` entry it can serve: either a built-in this binary was built with, or an extension driver name with a matching socket path entry. Naming a built-in that this gateway was not built with fails at startup with a message naming the unsupported driver. Extension drivers reached via `--compute-driver-socket` work regardless of the feature set. See the [gateway configuration reference](docs/reference/gateway-config.mdx) for details.
|
||||
|
||||
## Notice and Disclaimer
|
||||
|
||||
|
||||
@@ -208,10 +208,10 @@ carries no in-tree driver code and speaks `compute_driver.proto` only to
|
||||
out-of-tree drivers named in `compute_drivers` with a matching
|
||||
`[openshell.drivers.<name>].socket_path`. A driver named in
|
||||
`gateway.toml` that this binary was not built with fails at startup with
|
||||
a message naming both the driver and the Cargo flag that re-enables it;
|
||||
auto-detection skips drivers that were compiled out and falls through to
|
||||
a "no suitable driver" error rather than silently picking a
|
||||
different backend. Extension drivers reached via
|
||||
a message naming the unsupported driver. Auto-detection skips detected
|
||||
drivers that were compiled out and falls through to the next detected
|
||||
compiled-in backend; if none remain, startup fails with the standard "no
|
||||
suitable driver" error. Extension drivers reached via
|
||||
`--compute-driver-socket` are always available regardless of driver
|
||||
features — they run out-of-process and the gateway only needs to speak
|
||||
`compute_driver.proto`.
|
||||
|
||||
@@ -149,25 +149,32 @@ impl FromStr for ComputeDriverKind {
|
||||
/// Priority order: Kubernetes → Podman → Docker.
|
||||
/// VM is never auto-detected (requires explicit `--drivers vm`).
|
||||
///
|
||||
/// Returns the first driver where the environment check passes.
|
||||
/// Returns `None` if no compatible driver is found.
|
||||
pub fn detect_driver() -> Option<ComputeDriverKind> {
|
||||
/// Returns every driver where the environment check passes, in priority order.
|
||||
pub fn detect_drivers() -> Vec<ComputeDriverKind> {
|
||||
let mut drivers = Vec::new();
|
||||
|
||||
// Kubernetes: check for KUBERNETES_SERVICE_HOST env var (set inside pods)
|
||||
if std::env::var_os("KUBERNETES_SERVICE_HOST").is_some() {
|
||||
return Some(ComputeDriverKind::Kubernetes);
|
||||
drivers.push(ComputeDriverKind::Kubernetes);
|
||||
}
|
||||
|
||||
// Podman: check for a reachable local API socket.
|
||||
if is_podman_available() {
|
||||
return Some(ComputeDriverKind::Podman);
|
||||
drivers.push(ComputeDriverKind::Podman);
|
||||
}
|
||||
|
||||
// Docker: check for a reachable local API socket.
|
||||
if is_docker_available() {
|
||||
return Some(ComputeDriverKind::Docker);
|
||||
drivers.push(ComputeDriverKind::Docker);
|
||||
}
|
||||
|
||||
None
|
||||
drivers
|
||||
}
|
||||
|
||||
/// Returns the first driver where the environment check passes.
|
||||
/// Returns `None` if no compatible driver is found.
|
||||
pub fn detect_driver() -> Option<ComputeDriverKind> {
|
||||
detect_drivers().into_iter().next()
|
||||
}
|
||||
|
||||
fn is_podman_available() -> bool {
|
||||
@@ -982,9 +989,9 @@ mod tests {
|
||||
ComputeDriverKind, Config, DEFAULT_SERVICE_ROUTING_DOMAIN, GatewayInterceptorBindingPolicy,
|
||||
GatewayInterceptorConfig, GatewayInterceptorFailurePolicy, GatewayJwtConfig,
|
||||
GatewayProviderProfileSourceConfig, detect_docker_socket_from_candidates, detect_driver,
|
||||
detect_podman_socket_from_candidates, docker_host_unix_socket_path, docker_socket_responds,
|
||||
is_unix_socket, normalize_compute_driver_name, podman_socket_candidates_from_env,
|
||||
podman_socket_responds,
|
||||
detect_drivers, detect_podman_socket_from_candidates, docker_host_unix_socket_path,
|
||||
docker_socket_responds, is_unix_socket, normalize_compute_driver_name,
|
||||
podman_socket_candidates_from_env, podman_socket_responds,
|
||||
};
|
||||
#[cfg(unix)]
|
||||
use std::io::{Read as _, Write as _};
|
||||
@@ -1401,6 +1408,8 @@ mod tests {
|
||||
|
||||
let result = detect_driver();
|
||||
assert_eq!(result, Some(ComputeDriverKind::Kubernetes));
|
||||
let detected = detect_drivers();
|
||||
assert_eq!(detected.first(), Some(&ComputeDriverKind::Kubernetes));
|
||||
|
||||
// Restore the original env var
|
||||
unsafe {
|
||||
|
||||
@@ -757,7 +757,7 @@ fn normalize_compute_driver_socket_args(args: &mut RunArgs, matches: &ArgMatches
|
||||
|
||||
fn effective_single_driver(args: &RunArgs) -> Option<ComputeDriverKind> {
|
||||
match args.drivers.as_slice() {
|
||||
[] => openshell_core::config::detect_driver(),
|
||||
[] => crate::first_compiled_driver(openshell_core::config::detect_drivers()),
|
||||
[driver] => driver.parse().ok(),
|
||||
_ => None,
|
||||
}
|
||||
|
||||
@@ -983,7 +983,7 @@ fn resolve_configured_compute_driver(
|
||||
///
|
||||
/// Third-party drivers reached via `--compute-driver-socket` are handled
|
||||
/// through the remote path and are always available regardless of features.
|
||||
const fn driver_compiled_in(kind: ComputeDriverKind) -> bool {
|
||||
pub(crate) const fn driver_compiled_in(kind: ComputeDriverKind) -> bool {
|
||||
match kind {
|
||||
ComputeDriverKind::Kubernetes => cfg!(feature = "driver-kubernetes"),
|
||||
ComputeDriverKind::Docker => cfg!(feature = "driver-docker"),
|
||||
@@ -992,15 +992,19 @@ const fn driver_compiled_in(kind: ComputeDriverKind) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn first_compiled_driver(
|
||||
detected: impl IntoIterator<Item = ComputeDriverKind>,
|
||||
) -> Option<ComputeDriverKind> {
|
||||
detected.into_iter().find(|kind| driver_compiled_in(*kind))
|
||||
}
|
||||
|
||||
/// Auto-detect a driver, ignoring any that were compiled out.
|
||||
///
|
||||
/// Wraps [`openshell_core::config::detect_driver`]; if the environment's
|
||||
/// preferred driver is not compiled in, the caller falls back to the
|
||||
/// standard "no driver configured" error rather than silently starting a
|
||||
/// different backend.
|
||||
/// Walks [`openshell_core::config::detect_drivers`] in priority order so
|
||||
/// a compiled-out driver detected first does not hide a later compiled-in
|
||||
/// backend from automatic startup.
|
||||
fn filtered_detect_driver() -> Option<ComputeDriverKind> {
|
||||
let kind = openshell_core::config::detect_driver()?;
|
||||
driver_compiled_in(kind).then_some(kind)
|
||||
first_compiled_driver(openshell_core::config::detect_drivers())
|
||||
}
|
||||
|
||||
fn builtin_compute_driver(name: &str) -> Option<ComputeDriverKind> {
|
||||
@@ -1090,7 +1094,8 @@ mod tests {
|
||||
use super::{
|
||||
ConfiguredComputeDriver, ConnectionProtocol, MultiplexService, ServerState, TlsAcceptor,
|
||||
allow_plaintext_service_http, classify_initial_bytes, configured_compute_driver,
|
||||
gateway_listener_addresses, is_benign_tls_handshake_failure, serve_gateway_listener,
|
||||
first_compiled_driver, gateway_listener_addresses, is_benign_tls_handshake_failure,
|
||||
serve_gateway_listener,
|
||||
};
|
||||
use openshell_core::{
|
||||
ComputeDriverKind, Config,
|
||||
@@ -1661,4 +1666,18 @@ mod tests {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn first_compiled_driver_skips_detected_drivers_not_in_this_build() {
|
||||
let detected = [
|
||||
ComputeDriverKind::Kubernetes,
|
||||
ComputeDriverKind::Podman,
|
||||
ComputeDriverKind::Docker,
|
||||
];
|
||||
let expected = detected
|
||||
.into_iter()
|
||||
.find(|kind| super::driver_compiled_in(*kind));
|
||||
|
||||
assert_eq!(first_compiled_driver(detected), expected);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -488,6 +488,6 @@ cargo build --release -p openshell-server --bin openshell-gateway --no-default-f
|
||||
This build carries no built-in driver code. `compute_drivers` must name an
|
||||
extension driver with a matching `[openshell.drivers.<name>].socket_path`.
|
||||
Configuring a driver in `gateway.toml` that this gateway was not built with fails at startup with a
|
||||
message naming both the driver and the Cargo flag that re-enables it.
|
||||
message naming the unsupported driver.
|
||||
Extension drivers reached via `--compute-driver-socket` do not depend on any
|
||||
driver feature and work regardless.
|
||||
|
||||
Reference in New Issue
Block a user