mirror of
https://github.com/containers/youki
synced 2024-06-01 20:36:12 +02:00
Merge pull request #1403 from utam0k/exec-manager
libcontainer: Make the workloads injectable
This commit is contained in:
commit
4e029b0d46
|
@ -349,9 +349,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_complete"
|
||||
version = "4.1.2"
|
||||
version = "4.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd125be87bf4c255ebc50de0b7f4d2a6201e8ac3dc86e39c0ad081dc5e7236fe"
|
||||
checksum = "0012995dc3a54314f4710f5631d74767e73c534b8757221708303e48eef7a19b"
|
||||
dependencies = [
|
||||
"clap",
|
||||
]
|
||||
|
@ -1642,11 +1642,6 @@ dependencies = [
|
|||
"serde_json",
|
||||
"serial_test",
|
||||
"syscalls",
|
||||
"wasmedge-sdk",
|
||||
"wasmer",
|
||||
"wasmer-wasi",
|
||||
"wasmtime",
|
||||
"wasmtime-wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4273,6 +4268,11 @@ dependencies = [
|
|||
"serial_test",
|
||||
"tabwriter",
|
||||
"vergen",
|
||||
"wasmedge-sdk",
|
||||
"wasmer",
|
||||
"wasmer-wasi",
|
||||
"wasmtime",
|
||||
"wasmtime-wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -37,7 +37,7 @@ libc = { version = "0.2.140", optional = true }
|
|||
oci-spec = { version = "^0.6.0", features = ["proptests", "runtime"] }
|
||||
quickcheck = "1"
|
||||
mockall = { version = "0.11.3", features = [] }
|
||||
clap = "4.0.32"
|
||||
clap = "4.1.6"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
env_logger = "0.10"
|
||||
|
|
|
@ -13,9 +13,6 @@ keywords = ["youki", "container", "cgroups"]
|
|||
|
||||
[features]
|
||||
default = ["systemd", "v2", "v1"]
|
||||
wasm-wasmer = ["wasmer", "wasmer-wasi"]
|
||||
wasm-wasmedge = ["wasmedge-sdk/standalone"]
|
||||
wasm-wasmtime = ["wasmtime", "wasmtime-wasi"]
|
||||
systemd = ["libcgroups/systemd", "v2"]
|
||||
v2 = ["libcgroups/v2"]
|
||||
v1 = ["libcgroups/v1"]
|
||||
|
@ -43,11 +40,6 @@ serde = { version = "1.0", features = ["derive"] }
|
|||
serde_json = "1.0"
|
||||
syscalls = "0.6.7"
|
||||
rust-criu = "0.4.0"
|
||||
wasmer = { version = "2.2.0", optional = true }
|
||||
wasmer-wasi = { version = "2.3.0", optional = true }
|
||||
wasmedge-sdk = { version = "0.7.1", optional = true }
|
||||
wasmtime = {version = "6.0.1", optional = true }
|
||||
wasmtime-wasi = {version = "6.0.1", optional = true }
|
||||
clone3 = "0.2.3"
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use crate::workload::default::DefaultExecutor;
|
||||
use crate::workload::{Executor, ExecutorManager};
|
||||
use crate::{syscall::Syscall, utils::PathBufExt};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use super::{init_builder::InitContainerBuilder, tenant_builder::TenantContainerBuilder};
|
||||
|
@ -18,6 +20,9 @@ pub struct ContainerBuilder<'a> {
|
|||
pub(super) console_socket: Option<PathBuf>,
|
||||
/// File descriptors to be passed into the container process
|
||||
pub(super) preserve_fds: i32,
|
||||
/// Manage the functions that actually run on the container
|
||||
/// Default executes the specified execution of a generic command
|
||||
pub(super) executor_manager: ExecutorManager,
|
||||
}
|
||||
|
||||
/// Builder that can be used to configure the common properties of
|
||||
|
@ -28,8 +33,12 @@ pub struct ContainerBuilder<'a> {
|
|||
/// ```no_run
|
||||
/// use libcontainer::container::builder::ContainerBuilder;
|
||||
/// use libcontainer::syscall::syscall::create_syscall;
|
||||
/// use libcontainer::workload::default::DefaultExecutor;
|
||||
///
|
||||
/// ContainerBuilder::new("74f1a4cb3801".to_owned(), create_syscall().as_ref())
|
||||
/// ContainerBuilder::new(
|
||||
/// "74f1a4cb3801".to_owned(),
|
||||
/// create_syscall().as_ref(),
|
||||
/// )
|
||||
/// .with_root_path("/run/containers/youki").expect("invalid root path")
|
||||
/// .with_pid_file(Some("/var/run/docker.pid")).expect("invalid pid file")
|
||||
/// .with_console_socket(Some("/var/run/docker/sock.tty"))
|
||||
|
@ -45,8 +54,12 @@ impl<'a> ContainerBuilder<'a> {
|
|||
/// ```no_run
|
||||
/// use libcontainer::container::builder::ContainerBuilder;
|
||||
/// use libcontainer::syscall::syscall::create_syscall;
|
||||
/// use libcontainer::workload::default::DefaultExecutor;
|
||||
///
|
||||
/// let builder = ContainerBuilder::new("74f1a4cb3801".to_owned(), create_syscall().as_ref());
|
||||
/// let builder = ContainerBuilder::new(
|
||||
/// "74f1a4cb3801".to_owned(),
|
||||
/// create_syscall().as_ref(),
|
||||
/// );
|
||||
/// ```
|
||||
pub fn new(container_id: String, syscall: &'a dyn Syscall) -> Self {
|
||||
let root_path = PathBuf::from("/run/youki");
|
||||
|
@ -57,6 +70,9 @@ impl<'a> ContainerBuilder<'a> {
|
|||
pid_file: None,
|
||||
console_socket: None,
|
||||
preserve_fds: 0,
|
||||
executor_manager: ExecutorManager {
|
||||
executors: vec![Box::<DefaultExecutor>::default()],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,8 +116,12 @@ impl<'a> ContainerBuilder<'a> {
|
|||
/// ```no_run
|
||||
/// # use libcontainer::container::builder::ContainerBuilder;
|
||||
/// # use libcontainer::syscall::syscall::create_syscall;
|
||||
/// # use libcontainer::workload::default::DefaultExecutor;
|
||||
///
|
||||
/// ContainerBuilder::new("74f1a4cb3801".to_owned(), create_syscall().as_ref())
|
||||
/// ContainerBuilder::new(
|
||||
/// "74f1a4cb3801".to_owned(),
|
||||
/// create_syscall().as_ref(),
|
||||
/// )
|
||||
/// .as_tenant()
|
||||
/// .with_container_args(vec!["sleep".to_owned(), "9001".to_owned()])
|
||||
/// .build();
|
||||
|
@ -117,8 +137,12 @@ impl<'a> ContainerBuilder<'a> {
|
|||
/// ```no_run
|
||||
/// # use libcontainer::container::builder::ContainerBuilder;
|
||||
/// # use libcontainer::syscall::syscall::create_syscall;
|
||||
/// # use libcontainer::workload::default::DefaultExecutor;
|
||||
///
|
||||
/// ContainerBuilder::new("74f1a4cb3801".to_owned(), create_syscall().as_ref())
|
||||
/// ContainerBuilder::new(
|
||||
/// "74f1a4cb3801".to_owned(),
|
||||
/// create_syscall().as_ref(),
|
||||
/// )
|
||||
/// .as_init("/var/run/docker/bundle")
|
||||
/// .with_systemd(false)
|
||||
/// .build();
|
||||
|
@ -134,8 +158,12 @@ impl<'a> ContainerBuilder<'a> {
|
|||
/// ```no_run
|
||||
/// # use libcontainer::container::builder::ContainerBuilder;
|
||||
/// # use libcontainer::syscall::syscall::create_syscall;
|
||||
/// # use libcontainer::workload::default::DefaultExecutor;
|
||||
///
|
||||
/// ContainerBuilder::new("74f1a4cb3801".to_owned(), create_syscall().as_ref())
|
||||
/// ContainerBuilder::new(
|
||||
/// "74f1a4cb3801".to_owned(),
|
||||
/// create_syscall().as_ref(),
|
||||
/// )
|
||||
/// .with_root_path("/run/containers/youki").expect("invalid root path");
|
||||
/// ```
|
||||
pub fn with_root_path<P: Into<PathBuf>>(mut self, path: P) -> Result<Self> {
|
||||
|
@ -154,8 +182,12 @@ impl<'a> ContainerBuilder<'a> {
|
|||
/// ```no_run
|
||||
/// # use libcontainer::container::builder::ContainerBuilder;
|
||||
/// # use libcontainer::syscall::syscall::create_syscall;
|
||||
/// # use libcontainer::workload::default::DefaultExecutor;
|
||||
///
|
||||
/// ContainerBuilder::new("74f1a4cb3801".to_owned(), create_syscall().as_ref())
|
||||
/// ContainerBuilder::new(
|
||||
/// "74f1a4cb3801".to_owned(),
|
||||
/// create_syscall().as_ref(),
|
||||
/// )
|
||||
/// .with_pid_file(Some("/var/run/docker.pid")).expect("invalid pid file");
|
||||
/// ```
|
||||
pub fn with_pid_file<P: Into<PathBuf>>(mut self, path: Option<P>) -> Result<Self> {
|
||||
|
@ -180,8 +212,12 @@ impl<'a> ContainerBuilder<'a> {
|
|||
/// ```no_run
|
||||
/// # use libcontainer::container::builder::ContainerBuilder;
|
||||
/// # use libcontainer::syscall::syscall::create_syscall;
|
||||
/// # use libcontainer::workload::default::DefaultExecutor;
|
||||
///
|
||||
/// ContainerBuilder::new("74f1a4cb3801".to_owned(), create_syscall().as_ref())
|
||||
/// ContainerBuilder::new(
|
||||
/// "74f1a4cb3801".to_owned(),
|
||||
/// create_syscall().as_ref(),
|
||||
/// )
|
||||
/// .with_console_socket(Some("/var/run/docker/sock.tty"));
|
||||
/// ```
|
||||
pub fn with_console_socket<P: Into<PathBuf>>(mut self, path: Option<P>) -> Self {
|
||||
|
@ -196,14 +232,40 @@ impl<'a> ContainerBuilder<'a> {
|
|||
/// ```no_run
|
||||
/// # use libcontainer::container::builder::ContainerBuilder;
|
||||
/// # use libcontainer::syscall::syscall::create_syscall;
|
||||
/// # use libcontainer::workload::default::DefaultExecutor;
|
||||
///
|
||||
/// ContainerBuilder::new("74f1a4cb3801".to_owned(), create_syscall().as_ref())
|
||||
/// ContainerBuilder::new(
|
||||
/// "74f1a4cb3801".to_owned(),
|
||||
/// create_syscall().as_ref(),
|
||||
/// )
|
||||
/// .with_preserved_fds(5);
|
||||
/// ```
|
||||
pub fn with_preserved_fds(mut self, preserved_fds: i32) -> Self {
|
||||
self.preserve_fds = preserved_fds;
|
||||
self
|
||||
}
|
||||
/// Sets the number of additional file descriptors which will be passed into
|
||||
/// the container process.
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use libcontainer::container::builder::ContainerBuilder;
|
||||
/// # use libcontainer::syscall::syscall::create_syscall;
|
||||
/// # use libcontainer::workload::default::DefaultExecutor;
|
||||
///
|
||||
/// ContainerBuilder::new(
|
||||
/// "74f1a4cb3801".to_owned(),
|
||||
/// create_syscall().as_ref(),
|
||||
/// )
|
||||
/// .with_executor(vec![Box::<DefaultExecutor>::default()]);
|
||||
/// ```
|
||||
pub fn with_executor(mut self, executors: Vec<Box<dyn Executor>>) -> Result<Self> {
|
||||
if executors.is_empty() {
|
||||
bail!("executors must not be empty");
|
||||
};
|
||||
self.executor_manager = ExecutorManager { executors };
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -9,6 +9,7 @@ use crate::{
|
|||
rootless::Rootless,
|
||||
syscall::Syscall,
|
||||
utils,
|
||||
workload::ExecutorManager,
|
||||
};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use nix::unistd::Pid;
|
||||
|
@ -43,6 +44,8 @@ pub(super) struct ContainerBuilderImpl<'a> {
|
|||
pub preserve_fds: i32,
|
||||
/// If the container is to be run in detached mode
|
||||
pub detached: bool,
|
||||
/// Default executes the specified execution of a generic command
|
||||
pub executor_manager: ExecutorManager,
|
||||
}
|
||||
|
||||
impl<'a> ContainerBuilderImpl<'a> {
|
||||
|
@ -126,6 +129,7 @@ impl<'a> ContainerBuilderImpl<'a> {
|
|||
rootless: &self.rootless,
|
||||
cgroup_manager: cmanager,
|
||||
detached: self.detached,
|
||||
executor_manager: &self.executor_manager,
|
||||
};
|
||||
|
||||
let init_pid = process::container_main_process::container_main_process(&container_args)?;
|
||||
|
|
|
@ -14,9 +14,13 @@ impl Container {
|
|||
/// ```no_run
|
||||
/// use libcontainer::container::builder::ContainerBuilder;
|
||||
/// use libcontainer::syscall::syscall::create_syscall;
|
||||
/// use libcontainer::workload::default::DefaultExecutor;
|
||||
///
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// let mut container = ContainerBuilder::new("74f1a4cb3801".to_owned(), create_syscall().as_ref())
|
||||
/// let mut container = ContainerBuilder::new(
|
||||
/// "74f1a4cb3801".to_owned(),
|
||||
/// create_syscall().as_ref(),
|
||||
/// )
|
||||
/// .as_init("/var/run/docker/bundle")
|
||||
/// .build()?;
|
||||
///
|
||||
|
|
|
@ -11,9 +11,13 @@ impl Container {
|
|||
/// ```no_run
|
||||
/// use libcontainer::container::builder::ContainerBuilder;
|
||||
/// use libcontainer::syscall::syscall::create_syscall;
|
||||
/// use libcontainer::workload::default::DefaultExecutor;
|
||||
///
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// let mut container = ContainerBuilder::new("74f1a4cb3801".to_owned(), create_syscall().as_ref())
|
||||
/// let mut container = ContainerBuilder::new(
|
||||
/// "74f1a4cb3801".to_owned(),
|
||||
/// create_syscall().as_ref(),
|
||||
/// )
|
||||
/// .as_init("/var/run/docker/bundle")
|
||||
/// .build()?;
|
||||
///
|
||||
|
|
|
@ -12,10 +12,14 @@ impl Container {
|
|||
/// ```no_run
|
||||
/// use libcontainer::container::builder::ContainerBuilder;
|
||||
/// use libcontainer::syscall::syscall::create_syscall;
|
||||
/// use libcontainer::workload::default::DefaultExecutor;
|
||||
/// use nix::sys::signal::Signal;
|
||||
///
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// let mut container = ContainerBuilder::new("74f1a4cb3801".to_owned(), create_syscall().as_ref())
|
||||
/// let mut container = ContainerBuilder::new(
|
||||
/// "74f1a4cb3801".to_owned(),
|
||||
/// create_syscall().as_ref(),
|
||||
/// )
|
||||
/// .as_init("/var/run/docker/bundle")
|
||||
/// .build()?;
|
||||
///
|
||||
|
|
|
@ -10,9 +10,13 @@ impl Container {
|
|||
/// ```no_run
|
||||
/// use libcontainer::container::builder::ContainerBuilder;
|
||||
/// use libcontainer::syscall::syscall::create_syscall;
|
||||
/// use libcontainer::workload::default::DefaultExecutor;
|
||||
///
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// let mut container = ContainerBuilder::new("74f1a4cb3801".to_owned(), create_syscall().as_ref())
|
||||
/// let mut container = ContainerBuilder::new(
|
||||
/// "74f1a4cb3801".to_owned(),
|
||||
/// create_syscall().as_ref(),
|
||||
/// )
|
||||
/// .as_init("/var/run/docker/bundle")
|
||||
/// .build()?;
|
||||
///
|
||||
|
|
|
@ -11,9 +11,13 @@ impl Container {
|
|||
/// ```no_run
|
||||
/// use libcontainer::container::builder::ContainerBuilder;
|
||||
/// use libcontainer::syscall::syscall::create_syscall;
|
||||
/// use libcontainer::workload::default::DefaultExecutor;
|
||||
///
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// let mut container = ContainerBuilder::new("74f1a4cb3801".to_owned(), create_syscall().as_ref())
|
||||
/// let mut container = ContainerBuilder::new(
|
||||
/// "74f1a4cb3801".to_owned(),
|
||||
/// create_syscall().as_ref(),
|
||||
/// )
|
||||
/// .as_init("/var/run/docker/bundle")
|
||||
/// .build()?;
|
||||
///
|
||||
|
|
|
@ -16,9 +16,13 @@ impl Container {
|
|||
/// ```no_run
|
||||
/// use libcontainer::container::builder::ContainerBuilder;
|
||||
/// use libcontainer::syscall::syscall::create_syscall;
|
||||
/// use libcontainer::workload::default::DefaultExecutor;
|
||||
///
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// let mut container = ContainerBuilder::new("74f1a4cb3801".to_owned(), create_syscall().as_ref())
|
||||
/// let mut container = ContainerBuilder::new(
|
||||
/// "74f1a4cb3801".to_owned(),
|
||||
/// create_syscall().as_ref(),
|
||||
/// )
|
||||
/// .as_init("/var/run/docker/bundle")
|
||||
/// .build()?;
|
||||
///
|
||||
|
|
|
@ -94,6 +94,7 @@ impl<'a> InitContainerBuilder<'a> {
|
|||
// given. For now, set the detached to true because this is what
|
||||
// `youki create` defaults to.
|
||||
detached: true,
|
||||
executor_manager: self.base.executor_manager,
|
||||
};
|
||||
|
||||
// TODO: Fix waiting on this pid (init process) when detached = false.
|
||||
|
|
|
@ -144,6 +144,7 @@ impl<'a> TenantContainerBuilder<'a> {
|
|||
container: None,
|
||||
preserve_fds: self.base.preserve_fds,
|
||||
detached: self.detached,
|
||||
executor_manager: self.base.executor_manager,
|
||||
};
|
||||
|
||||
let pid = builder_impl.create()?;
|
||||
|
|
|
@ -4,6 +4,7 @@ use std::os::unix::prelude::RawFd;
|
|||
use std::path::PathBuf;
|
||||
|
||||
use crate::rootless::Rootless;
|
||||
use crate::workload::ExecutorManager;
|
||||
use crate::{container::Container, notify_socket::NotifyListener, syscall::Syscall};
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
|
@ -35,4 +36,6 @@ pub struct ContainerArgs<'a> {
|
|||
pub cgroup_manager: Box<dyn CgroupManager>,
|
||||
/// If the container is to be run in detached mode
|
||||
pub detached: bool,
|
||||
/// Manage the functions that actually run on the container
|
||||
pub executor_manager: &'a ExecutorManager,
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use super::args::{ContainerArgs, ContainerType};
|
||||
use crate::apparmor;
|
||||
use crate::syscall::Syscall;
|
||||
use crate::workload::ExecutorManager;
|
||||
use crate::{
|
||||
capabilities, hooks, namespaces::Namespaces, process::channel, rootfs::RootFS,
|
||||
rootless::Rootless, seccomp, tty, utils,
|
||||
|
@ -442,7 +441,8 @@ pub fn container_init_process(
|
|||
}
|
||||
|
||||
if proc.args().is_some() {
|
||||
ExecutorManager::exec(spec)
|
||||
args.executor_manager.exec(spec)?;
|
||||
unreachable!("should not be back here");
|
||||
} else {
|
||||
bail!("on non-Windows, at least one process arg entry is required")
|
||||
}
|
||||
|
|
|
@ -8,10 +8,11 @@ use super::{Executor, EMPTY};
|
|||
|
||||
const EXECUTOR_NAME: &str = "default";
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct DefaultExecutor {}
|
||||
|
||||
impl Executor for DefaultExecutor {
|
||||
fn exec(spec: &Spec) -> Result<()> {
|
||||
fn exec(&self, spec: &Spec) -> Result<()> {
|
||||
log::debug!("Executing workload with default handler");
|
||||
let args = spec
|
||||
.process()
|
||||
|
@ -37,11 +38,11 @@ impl Executor for DefaultExecutor {
|
|||
unreachable!();
|
||||
}
|
||||
|
||||
fn can_handle(_: &Spec) -> Result<bool> {
|
||||
fn can_handle(&self, _: &Spec) -> Result<bool> {
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
fn name(&self) -> &'static str {
|
||||
EXECUTOR_NAME
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,51 +1,37 @@
|
|||
use anyhow::{Context, Result};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use oci_spec::runtime::Spec;
|
||||
|
||||
use self::default::DefaultExecutor;
|
||||
#[cfg(feature = "wasm-wasmedge")]
|
||||
use self::wasmedge::WasmEdgeExecutor;
|
||||
#[cfg(feature = "wasm-wasmer")]
|
||||
use self::wasmer::WasmerExecutor;
|
||||
#[cfg(feature = "wasm-wasmtime")]
|
||||
use self::wasmtime::WasmtimeExecutor;
|
||||
|
||||
pub mod default;
|
||||
#[cfg(feature = "wasm-wasmedge")]
|
||||
pub mod wasmedge;
|
||||
#[cfg(feature = "wasm-wasmer")]
|
||||
pub mod wasmer;
|
||||
#[cfg(feature = "wasm-wasmtime")]
|
||||
pub mod wasmtime;
|
||||
|
||||
static EMPTY: Vec<String> = Vec::new();
|
||||
pub static EMPTY: Vec<String> = Vec::new();
|
||||
|
||||
pub trait Executor {
|
||||
/// Executes the workload
|
||||
fn exec(spec: &Spec) -> Result<()>;
|
||||
fn exec(&self, spec: &Spec) -> Result<()>;
|
||||
|
||||
/// Checks if the handler is able to handle the workload
|
||||
fn can_handle(spec: &Spec) -> Result<bool>;
|
||||
fn can_handle(&self, spec: &Spec) -> Result<bool>;
|
||||
|
||||
/// The name of the handler
|
||||
fn name() -> &'static str;
|
||||
fn name(&self) -> &'static str;
|
||||
}
|
||||
|
||||
/// Manage the functions that actually run on the container
|
||||
pub struct ExecutorManager {
|
||||
pub executors: Vec<Box<dyn Executor>>,
|
||||
}
|
||||
pub struct ExecutorManager {}
|
||||
|
||||
impl ExecutorManager {
|
||||
pub fn exec(spec: &Spec) -> Result<()> {
|
||||
#[cfg(feature = "wasm-wasmer")]
|
||||
if WasmerExecutor::can_handle(spec)? {
|
||||
return WasmerExecutor::exec(spec).context("wasmer execution failed");
|
||||
}
|
||||
pub fn exec(&self, spec: &Spec) -> Result<()> {
|
||||
if self.executors.is_empty() {
|
||||
bail!("executors must not be empty");
|
||||
};
|
||||
|
||||
#[cfg(feature = "wasm-wasmedge")]
|
||||
if WasmEdgeExecutor::can_handle(spec)? {
|
||||
return WasmEdgeExecutor::exec(spec).context("wasmedge execution failed");
|
||||
for executor in self.executors.iter() {
|
||||
if executor.can_handle(spec)? {
|
||||
return executor.exec(spec).context("execution failed");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "wasm-wasmtime")]
|
||||
if WasmtimeExecutor::can_handle(spec)? {
|
||||
return WasmtimeExecutor::exec(spec).context("wasmtime execution failed");
|
||||
}
|
||||
|
||||
DefaultExecutor::exec(spec).context("default execution failed")
|
||||
bail!("cannot find an executor that satisfies all requirements")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,6 @@ edition = "2021"
|
|||
keywords = ["youki", "container", "oci"]
|
||||
|
||||
[dependencies.clap]
|
||||
version = "4.0.32"
|
||||
version = "4.1.6"
|
||||
default-features = false
|
||||
features = ["std", "suggestions", "derive", "cargo", "help", "usage", "error-context"]
|
||||
|
|
|
@ -16,12 +16,12 @@ systemd = ["libcgroups/systemd", "libcontainer/systemd", "v2"]
|
|||
v2 = ["libcgroups/v2", "libcontainer/v2"]
|
||||
v1 = ["libcgroups/v1", "libcontainer/v1"]
|
||||
cgroupsv2_devices = ["libcgroups/cgroupsv2_devices", "libcontainer/cgroupsv2_devices"]
|
||||
wasm-wasmer = ["libcontainer/wasm-wasmer"]
|
||||
wasm-wasmedge = ["libcontainer/wasm-wasmedge"]
|
||||
wasm-wasmtime = ["libcontainer/wasm-wasmtime"]
|
||||
wasm-wasmer = ["wasmer", "wasmer-wasi"]
|
||||
wasm-wasmedge = ["wasmedge-sdk/standalone"]
|
||||
wasm-wasmtime = ["wasmtime", "wasmtime-wasi"]
|
||||
|
||||
[dependencies.clap]
|
||||
version = "4.0.32"
|
||||
version = "4.1.6"
|
||||
default-features = false
|
||||
features = ["std", "suggestions", "derive", "cargo", "help", "usage", "error-context"]
|
||||
|
||||
|
@ -40,8 +40,13 @@ procfs = "0.15.1"
|
|||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
tabwriter = "1"
|
||||
clap_complete = "4.0.7"
|
||||
clap_complete = "4.1.3"
|
||||
caps = "0.5.5"
|
||||
wasmer = { version = "2.2.0", optional = true }
|
||||
wasmer-wasi = { version = "2.3.0", optional = true }
|
||||
wasmedge-sdk = { version = "0.7.1", optional = true }
|
||||
wasmtime = {version = "6.0.1", optional = true }
|
||||
wasmtime-wasi = {version = "6.0.1", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
serial_test = "1.0.0"
|
||||
|
|
|
@ -5,6 +5,8 @@ use std::path::PathBuf;
|
|||
use libcontainer::{container::builder::ContainerBuilder, syscall::syscall::create_syscall};
|
||||
use liboci_cli::Create;
|
||||
|
||||
use crate::workload::executor::default_executors;
|
||||
|
||||
// One thing to note is that in the end, container is just another process in Linux
|
||||
// it has specific/different control group, namespace, using which program executing in it
|
||||
// can be given impression that is is running on a complete system, but on the system which
|
||||
|
@ -13,6 +15,7 @@ use liboci_cli::Create;
|
|||
pub fn create(args: Create, root_path: PathBuf, systemd_cgroup: bool) -> Result<()> {
|
||||
let syscall = create_syscall();
|
||||
ContainerBuilder::new(args.container_id.clone(), syscall.as_ref())
|
||||
.with_executor(default_executors())?
|
||||
.with_pid_file(args.pid_file.as_ref())?
|
||||
.with_console_socket(args.console_socket.as_ref())
|
||||
.with_root_path(root_path)?
|
||||
|
|
|
@ -5,9 +5,12 @@ use std::path::PathBuf;
|
|||
use libcontainer::{container::builder::ContainerBuilder, syscall::syscall::create_syscall};
|
||||
use liboci_cli::Exec;
|
||||
|
||||
use crate::workload::executor::default_executors;
|
||||
|
||||
pub fn exec(args: Exec, root_path: PathBuf) -> Result<i32> {
|
||||
let syscall = create_syscall();
|
||||
let pid = ContainerBuilder::new(args.container_id.clone(), syscall.as_ref())
|
||||
.with_executor(default_executors())?
|
||||
.with_root_path(root_path)?
|
||||
.with_console_socket(args.console_socket.as_ref())
|
||||
.with_pid_file(args.pid_file.as_ref())?
|
||||
|
|
|
@ -4,11 +4,14 @@ use anyhow::{Context, Result};
|
|||
use libcontainer::{container::builder::ContainerBuilder, syscall::syscall::create_syscall};
|
||||
use liboci_cli::Run;
|
||||
|
||||
use crate::workload::executor::default_executors;
|
||||
|
||||
pub fn run(args: Run, root_path: PathBuf, systemd_cgroup: bool) -> Result<()> {
|
||||
let syscall = create_syscall();
|
||||
// TODO: `youki run` should support passing in `detached` flags. Defaults to
|
||||
// detached = true right now.
|
||||
let mut container = ContainerBuilder::new(args.container_id.clone(), syscall.as_ref())
|
||||
.with_executor(default_executors())?
|
||||
.with_pid_file(args.pid_file.as_ref())?
|
||||
.with_console_socket(args.console_socket.as_ref())
|
||||
.with_root_path(root_path)?
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
//! This crate provides a container runtime which can be used by a high-level container runtime to run containers.
|
||||
mod commands;
|
||||
mod logger;
|
||||
mod workload;
|
||||
|
||||
use anyhow::bail;
|
||||
use anyhow::Context;
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
use libcontainer::workload::{default::DefaultExecutor, Executor};
|
||||
|
||||
pub fn default_executors() -> Vec<Box<dyn Executor>> {
|
||||
vec![
|
||||
#[cfg(feature = "wasm-wasmer")]
|
||||
Box::<super::wasmer::WasmerExecutor>::default(),
|
||||
#[cfg(feature = "wasm-wasmedge")]
|
||||
Box::<super::wasmedge::WasmEdgeExecutor>::default(),
|
||||
#[cfg(feature = "wasm-wasmtime")]
|
||||
Box::<super::wasmtime::WasmtimeExecutor>::default(),
|
||||
Box::<DefaultExecutor>::default(),
|
||||
]
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
pub mod executor;
|
||||
#[cfg(feature = "wasm-wasmedge")]
|
||||
mod wasmedge;
|
||||
#[cfg(feature = "wasm-wasmer")]
|
||||
mod wasmer;
|
||||
#[cfg(feature = "wasm-wasmtime")]
|
||||
mod wasmtime;
|
|
@ -5,13 +5,15 @@ use wasmedge_sdk::{
|
|||
params, Vm,
|
||||
};
|
||||
|
||||
use super::Executor;
|
||||
use libcontainer::workload::Executor;
|
||||
|
||||
const EXECUTOR_NAME: &str = "wasmedge";
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct WasmEdgeExecutor {}
|
||||
|
||||
impl Executor for WasmEdgeExecutor {
|
||||
fn exec(spec: &Spec) -> Result<()> {
|
||||
fn exec(&self, spec: &Spec) -> Result<()> {
|
||||
// parse wasi parameters
|
||||
let args = get_args(spec);
|
||||
let mut cmd = args[0].clone();
|
||||
|
@ -46,7 +48,7 @@ impl Executor for WasmEdgeExecutor {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn can_handle(spec: &Spec) -> Result<bool> {
|
||||
fn can_handle(&self, spec: &Spec) -> Result<bool> {
|
||||
if let Some(annotations) = spec.annotations() {
|
||||
if let Some(handler) = annotations.get("run.oci.handler") {
|
||||
return Ok(handler == "wasm");
|
||||
|
@ -60,7 +62,7 @@ impl Executor for WasmEdgeExecutor {
|
|||
Ok(false)
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
fn name(&self) -> &'static str {
|
||||
EXECUTOR_NAME
|
||||
}
|
||||
}
|
|
@ -3,14 +3,15 @@ use oci_spec::runtime::Spec;
|
|||
use wasmer::{Instance, Module, Store};
|
||||
use wasmer_wasi::WasiState;
|
||||
|
||||
use super::{Executor, EMPTY};
|
||||
use libcontainer::workload::{Executor, EMPTY};
|
||||
|
||||
const EXECUTOR_NAME: &str = "wasmer";
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct WasmerExecutor {}
|
||||
|
||||
impl Executor for WasmerExecutor {
|
||||
fn exec(spec: &Spec) -> Result<()> {
|
||||
fn exec(&self, spec: &Spec) -> Result<()> {
|
||||
log::debug!("Executing workload with wasmer handler");
|
||||
let process = spec.process().as_ref();
|
||||
|
||||
|
@ -62,7 +63,7 @@ impl Executor for WasmerExecutor {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn can_handle(spec: &Spec) -> Result<bool> {
|
||||
fn can_handle(&self, spec: &Spec) -> Result<bool> {
|
||||
if let Some(annotations) = spec.annotations() {
|
||||
if let Some(handler) = annotations.get("run.oci.handler") {
|
||||
return Ok(handler == "wasm");
|
||||
|
@ -76,7 +77,7 @@ impl Executor for WasmerExecutor {
|
|||
Ok(false)
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
fn name(&self) -> &'static str {
|
||||
EXECUTOR_NAME
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +97,9 @@ mod tests {
|
|||
.build()
|
||||
.context("build spec")?;
|
||||
|
||||
assert!(WasmerExecutor::can_handle(&spec).context("can handle")?);
|
||||
assert!(WasmerExecutor::default()
|
||||
.can_handle(&spec)
|
||||
.context("can handle")?);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -110,7 +113,9 @@ mod tests {
|
|||
.build()
|
||||
.context("build spec")?;
|
||||
|
||||
assert!(WasmerExecutor::can_handle(&spec).context("can handle")?);
|
||||
assert!(WasmerExecutor::default()
|
||||
.can_handle(&spec)
|
||||
.context("can handle")?);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -119,7 +124,9 @@ mod tests {
|
|||
fn test_can_handle_no_execute() -> Result<()> {
|
||||
let spec = SpecBuilder::default().build().context("build spec")?;
|
||||
|
||||
assert!(!WasmerExecutor::can_handle(&spec).context("can handle")?);
|
||||
assert!(!WasmerExecutor::default()
|
||||
.can_handle(&spec)
|
||||
.context("can handle")?);
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -3,14 +3,15 @@ use oci_spec::runtime::Spec;
|
|||
use wasmtime::*;
|
||||
use wasmtime_wasi::WasiCtxBuilder;
|
||||
|
||||
use super::{Executor, EMPTY};
|
||||
use libcontainer::workload::{Executor, EMPTY};
|
||||
|
||||
const EXECUTOR_NAME: &str = "wasmtime";
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct WasmtimeExecutor {}
|
||||
|
||||
impl Executor for WasmtimeExecutor {
|
||||
fn exec(spec: &Spec) -> Result<()> {
|
||||
fn exec(&self, spec: &Spec) -> Result<()> {
|
||||
log::info!("Executing workload with wasmtime handler");
|
||||
let process = spec.process().as_ref();
|
||||
|
||||
|
@ -76,7 +77,7 @@ impl Executor for WasmtimeExecutor {
|
|||
.context("wasm module was not executed successfully")
|
||||
}
|
||||
|
||||
fn can_handle(spec: &Spec) -> Result<bool> {
|
||||
fn can_handle(&self, spec: &Spec) -> Result<bool> {
|
||||
if let Some(annotations) = spec.annotations() {
|
||||
if let Some(handler) = annotations.get("run.oci.handler") {
|
||||
return Ok(handler == "wasm");
|
||||
|
@ -90,7 +91,7 @@ impl Executor for WasmtimeExecutor {
|
|||
Ok(false)
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
fn name(&self) -> &'static str {
|
||||
EXECUTOR_NAME
|
||||
}
|
||||
}
|
|
@ -25,7 +25,7 @@ uuid = "1.3"
|
|||
which = "4.4.0"
|
||||
|
||||
[dependencies.clap]
|
||||
version = "4.0.32"
|
||||
version = "4.1.6"
|
||||
default-features = false
|
||||
features = ["std", "suggestions", "derive", "cargo", "help", "usage", "error-context"]
|
||||
|
||||
|
|
Loading…
Reference in New Issue