diff --git a/Cargo.lock b/Cargo.lock index 7ac2797b7..0e6e14297 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -925,6 +925,7 @@ dependencies = [ "opentelemetry", "opentelemetry-otlp", "opentelemetry_sdk", + "prost 0.13.5", "protobuf 3.2.0", "rand 0.9.0", "serde", @@ -936,6 +937,7 @@ dependencies = [ "thiserror 2.0.11", "tokio", "tokio-stream", + "toml", "tracing", "tracing-opentelemetry", "tracing-subscriber", diff --git a/crates/containerd-shim-wasm/Cargo.toml b/crates/containerd-shim-wasm/Cargo.toml index 90fb5ad71..792be29a8 100644 --- a/crates/containerd-shim-wasm/Cargo.toml +++ b/crates/containerd-shim-wasm/Cargo.toml @@ -34,6 +34,8 @@ wasmparser = { version = "0.225.0" } tokio-stream = { version = "0.1" } sha256 = { workspace = true } serde_bytes = "0.11" +prost = "0.13" +toml = "0.8" # tracing # note: it's important to keep the version of tracing in sync with tracing-subscriber diff --git a/crates/containerd-shim-wasm/src/sandbox/instance.rs b/crates/containerd-shim-wasm/src/sandbox/instance.rs index 2405e870b..d19de64c7 100644 --- a/crates/containerd-shim-wasm/src/sandbox/instance.rs +++ b/crates/containerd-shim-wasm/src/sandbox/instance.rs @@ -24,6 +24,8 @@ pub struct InstanceConfig { namespace: String, /// GRPC address back to main containerd containerd_address: String, + /// Enables systemd cgroup. + systemd_cgroup: bool, } impl InstanceConfig { @@ -33,6 +35,7 @@ impl InstanceConfig { Self { namespace, containerd_address, + systemd_cgroup: true, stdin: PathBuf::default(), stdout: PathBuf::default(), stderr: PathBuf::default(), @@ -93,6 +96,17 @@ impl InstanceConfig { pub fn get_containerd_address(&self) -> String { self.containerd_address.clone() } + + /// set the systemd cgroup for the instance + pub fn set_systemd_cgroup(&mut self, systemd_cgroup: bool) -> &mut Self { + self.systemd_cgroup = systemd_cgroup; + self + } + + /// get the systemd cgroup for the instance + pub fn get_systemd_cgroup(&self) -> bool { + self.systemd_cgroup + } } /// Represents a WASI module(s). diff --git a/crates/containerd-shim-wasm/src/sandbox/shim/local.rs b/crates/containerd-shim-wasm/src/sandbox/shim/local.rs index e984b726b..a4a53ffec 100644 --- a/crates/containerd-shim-wasm/src/sandbox/shim/local.rs +++ b/crates/containerd-shim-wasm/src/sandbox/shim/local.rs @@ -6,7 +6,7 @@ use std::sync::{Arc, RwLock}; use std::thread; use std::time::Duration; -use anyhow::Context as AnyhowContext; +use anyhow::{ensure, Context as AnyhowContext}; use containerd_shim::api::{ ConnectRequest, ConnectResponse, CreateTaskRequest, CreateTaskResponse, DeleteRequest, Empty, KillRequest, ShutdownRequest, StartRequest, StartResponse, StateRequest, StateResponse, @@ -20,6 +20,9 @@ use containerd_shim::util::IntoOption; use containerd_shim::{DeleteResponse, ExitSignal, TtrpcContext, TtrpcResult}; use log::debug; use oci_spec::runtime::Spec; +use prost::Message; +use protobuf::well_known_types::any::Any; +use serde::Deserialize; #[cfg(feature = "opentelemetry")] use tracing_opentelemetry::OpenTelemetrySpanExt as _; @@ -34,6 +37,43 @@ use crate::sys::metrics::get_metrics; #[cfg(test)] mod tests; +#[derive(Message, Clone, PartialEq)] +struct Options { + #[prost(string)] + type_url: String, + #[prost(string)] + config_path: String, + #[prost(string)] + config_body: String, +} + +#[derive(Deserialize, Default, Clone, PartialEq)] +struct Config { + #[serde(alias = "SystemdCgroup")] + systemd_cgroup: bool, +} + +impl Config { + fn get_from_options(options: Option<&Any>) -> anyhow::Result { + let Some(opts) = options else { + return Ok(Default::default()); + }; + + ensure!( + opts.type_url == "runtimeoptions.v1.Options", + "Invalid options type {}", + opts.type_url + ); + + let opts = Options::decode(opts.value.as_slice())?; + + let config = toml::from_str(opts.config_body.as_str()) + .map_err(|err| Error::InvalidArgument(format!("invalid shim options: {err}")))?; + + Ok(config) + } +} + type LocalInstances = RwLock>>>; /// Local implements the Task service for a containerd shim. @@ -99,6 +139,10 @@ impl Local { impl Local { #[cfg_attr(feature = "tracing", tracing::instrument(skip(self), level = "Debug"))] fn task_create(&self, req: CreateTaskRequest) -> Result { + let config = Config::get_from_options(req.options.as_ref()) + .map_err(|err| Error::InvalidArgument(format!("invalid shim options: {err}")))?; + let systemd_cgroup = config.systemd_cgroup; + if !req.checkpoint().is_empty() || !req.parent_checkpoint().is_empty() { return Err(ShimError::Unimplemented("checkpoint is not supported".to_string()).into()); } @@ -147,7 +191,8 @@ impl Local { cfg.set_bundle(&req.bundle) .set_stdin(&req.stdin) .set_stdout(&req.stdout) - .set_stderr(&req.stderr); + .set_stderr(&req.stderr) + .set_systemd_cgroup(systemd_cgroup); // Check if this is a cri container let instance = InstanceData::new(req.id(), cfg)?; diff --git a/crates/containerd-shim-wasm/src/sys/unix/container/instance.rs b/crates/containerd-shim-wasm/src/sys/unix/container/instance.rs index 383c92dd4..74565e8a3 100644 --- a/crates/containerd-shim-wasm/src/sys/unix/container/instance.rs +++ b/crates/containerd-shim-wasm/src/sys/unix/container/instance.rs @@ -67,11 +67,12 @@ impl SandboxInstance for Instance { if let Ok(f) = open(cfg.get_stderr()) { builder = builder.with_stderr(f); } + let systemd_cgroup = cfg.get_systemd_cgroup(); let container = builder .as_init(&bundle) .as_sibling(true) - .with_systemd(false) + .with_systemd(systemd_cgroup) .build()?; Ok(container)