diff --git a/crates/youki/src/workload/wasmedge.rs b/crates/youki/src/workload/wasmedge.rs index 67191a26b..574965370 100644 --- a/crates/youki/src/workload/wasmedge.rs +++ b/crates/youki/src/workload/wasmedge.rs @@ -11,8 +11,8 @@ const EXECUTOR_NAME: &str = "wasmedge"; #[derive(Default)] pub struct WasmEdgeExecutor {} -impl WasmEdgeExecutor { - fn exec_inner(spec: &Spec) -> anyhow::Result<()> { +impl Executor for WasmEdgeExecutor { + fn exec(&self, spec: &Spec) -> Result<(), ExecutorError> { // parse wasi parameters let args = get_args(spec); let mut cmd = args[0].clone(); @@ -24,14 +24,23 @@ impl WasmEdgeExecutor { // create configuration with `wasi` option enabled let config = ConfigBuilder::new(CommonConfigOptions::default()) .with_host_registration_config(HostRegistrationConfigOptions::default().wasi(true)) - .build()?; + .build() + .map_err(|err| { + ExecutorError::Other(format!("failed to create wasmedge config: {}", err)) + })?; // create a vm with the config settings let mut vm = VmBuilder::new() .with_config(config) - .build()? - .register_module_from_file("main", cmd)?; - + .build() + .map_err(|err| ExecutorError::Other(format!("failed to create wasmedge vm: {}", err)))? + .register_module_from_file("main", cmd) + .map_err(|err| { + ExecutorError::Other(format!( + "failed to register wasmedge module from the file: {}", + err + )) + })?; // initialize the wasi module with the parsed parameters let wasi_instance = vm .wasi_module_mut() @@ -42,19 +51,11 @@ impl WasmEdgeExecutor { None, ); - vm.run_func(Some("main"), "_start", params!())?; + vm.run_func(Some("main"), "_start", params!()) + .map_err(|err| ExecutorError::Execution(err))?; Ok(()) } -} - -impl Executor for WasmEdgeExecutor { - fn exec(&self, spec: &Spec) -> Result<(), ExecutorError> { - Self::exec_inner(spec).map_err(|err| { - tracing::error!(?err, "failed to execute workload with wasmedge handler"); - ExecutorError::Execution(err.into()) - }) - } fn can_handle(&self, spec: &Spec) -> bool { if let Some(annotations) = spec.annotations() { diff --git a/crates/youki/src/workload/wasmer.rs b/crates/youki/src/workload/wasmer.rs index dbfa640cb..9e6037cf0 100644 --- a/crates/youki/src/workload/wasmer.rs +++ b/crates/youki/src/workload/wasmer.rs @@ -1,4 +1,3 @@ -use anyhow::{bail, Context, Result}; use oci_spec::runtime::Spec; use wasmer::{Instance, Module, Store}; use wasmer_wasix::WasiEnv; @@ -10,9 +9,9 @@ const EXECUTOR_NAME: &str = "wasmer"; #[derive(Default)] pub struct WasmerExecutor {} -impl WasmerExecutor { - fn exec_inner(spec: &Spec) -> anyhow::Result<()> { - tracing::debug!("Executing workload with wasmer handler"); +impl Executor for WasmerExecutor { + fn exec(&self, spec: &Spec) -> Result<(), ExecutorError> { + tracing::debug!("executing workload with wasmer handler"); let process = spec.process().as_ref(); let args = process.and_then(|p| p.args().as_ref()).unwrap_or(&EMPTY); @@ -27,54 +26,56 @@ impl WasmerExecutor { }); if args.is_empty() { - bail!("at least one process arg must be specified") + tracing::error!("at least one process arg must be specified"); + return Err(ExecutorError::InvalidArg); } if !args[0].ends_with(".wasm") && !args[0].ends_with(".wat") { - bail!( + tracing::error!( "first argument must be a wasm or wat module, but was {}", args[0] - ) + ); + return Err(ExecutorError::InvalidArg); } let mut store = Store::default(); - let module = Module::from_file(&store, &args[0]) - .with_context(|| format!("could not load wasm module from {}", &args[0]))?; + let module = Module::from_file(&store, &args[0]).map_err(|err| { + tracing::error!(err = ?err, file = ?args[0], "could not load wasm module from file"); + ExecutorError::Other("could not load wasm module from file".to_string()) + })?; let mut wasi_env = WasiEnv::builder("youki_wasm_app") .args(args.iter().skip(1)) .envs(env) - .finalize(&mut store)?; - - let imports = wasi_env - .import_object(&mut store, &module) - .context("could not retrieve wasm imports")?; - let instance = Instance::new(&mut store, &module, &imports) - .context("wasm module could not be instantiated")?; - - wasi_env.initialize(&mut store, instance.clone())?; - - let start = instance - .exports - .get_function("_start") - .context("could not retrieve wasm module main function")?; + .finalize(&mut store) + .map_err(|err| ExecutorError::Other(format!("could not create wasi env: {}", err)))?; + + let imports = wasi_env.import_object(&mut store, &module).map_err(|err| { + ExecutorError::Other(format!("could not retrieve wasm imports: {}", err)) + })?; + let instance = Instance::new(&mut store, &module, &imports).map_err(|err| { + ExecutorError::Other(format!("could not instantiate wasm module: {}", err)) + })?; + + wasi_env + .initialize(&mut store, instance.clone()) + .map_err(|err| { + ExecutorError::Other(format!("could not initialize wasi env: {}", err)) + })?; + + let start = instance.exports.get_function("_start").map_err(|err| { + ExecutorError::Other(format!( + "could not retrieve wasm module main function: {err}" + )) + })?; start .call(&mut store, &[]) - .context("wasm module was not executed successfully")?; + .map_err(|err| ExecutorError::Execution(err.into()))?; wasi_env.cleanup(&mut store, None); Ok(()) } -} - -impl Executor for WasmerExecutor { - fn exec(&self, spec: &Spec) -> Result<(), ExecutorError> { - Self::exec_inner(spec).map_err(|err| { - tracing::error!(?err, "failed to execute workload with wasmer handler"); - ExecutorError::Execution(err.into()) - }) - } fn can_handle(&self, spec: &Spec) -> bool { if let Some(annotations) = spec.annotations() { @@ -98,6 +99,7 @@ impl Executor for WasmerExecutor { #[cfg(test)] mod tests { use super::*; + use anyhow::{Context, Result}; use oci_spec::runtime::SpecBuilder; use std::collections::HashMap; diff --git a/crates/youki/src/workload/wasmtime.rs b/crates/youki/src/workload/wasmtime.rs index dc1713829..d0c046ff0 100644 --- a/crates/youki/src/workload/wasmtime.rs +++ b/crates/youki/src/workload/wasmtime.rs @@ -1,4 +1,3 @@ -use anyhow::{anyhow, bail, Context, Result}; use oci_spec::runtime::Spec; use wasmtime::*; use wasmtime_wasi::WasiCtxBuilder; @@ -10,8 +9,8 @@ const EXECUTOR_NAME: &str = "wasmtime"; #[derive(Default)] pub struct WasmtimeExecutor {} -impl WasmtimeExecutor { - fn exec_inner(spec: &Spec) -> anyhow::Result<()> { +impl Executor for WasmtimeExecutor { + fn exec(&self, spec: &Spec) -> Result<(), ExecutorError> { tracing::info!("Executing workload with wasmtime handler"); let process = spec.process().as_ref(); @@ -21,14 +20,16 @@ impl WasmtimeExecutor { .and_then(|p| p.args().as_ref()) .unwrap_or(&EMPTY); if args.is_empty() { - bail!("at least one process arg must be specified") + tracing::error!("at least one process arg must be specified"); + return Err(ExecutorError::InvalidArg); } if !args[0].ends_with(".wasm") && !args[0].ends_with(".wat") { - bail!( + tracing::error!( "first argument must be a wasm or wat module, but was {}", args[0] - ) + ); + return Err(ExecutorError::InvalidArg); } let mut cmd = args[0].clone(); @@ -48,42 +49,42 @@ impl WasmtimeExecutor { .collect(); let engine = Engine::default(); - let module = Module::from_file(&engine, &cmd) - .with_context(|| format!("could not load wasm module from {}", &cmd))?; + let module = Module::from_file(&engine, &cmd).map_err(|err| { + tracing::error!(err = ?err, file = ?cmd, "could not load wasm module from file"); + ExecutorError::Other("could not load wasm module from file".to_string()) + })?; let mut linker = Linker::new(&engine); - wasmtime_wasi::add_to_linker(&mut linker, |s| s) - .context("cannot add wasi context to linker")?; + wasmtime_wasi::add_to_linker(&mut linker, |s| s).map_err(|err| { + tracing::error!(err = ?err, "cannot add wasi context to linker"); + ExecutorError::Other("cannot add wasi context to linker".to_string()) + })?; let wasi = WasiCtxBuilder::new() .inherit_stdio() .args(args) - .context("cannot add args to wasi context")? + .map_err(|err| { + ExecutorError::Other(format!("cannot add args to wasi context: {}", err)) + })? .envs(&envs) - .context("cannot add environment variables to wasi context")? + .map_err(|err| { + ExecutorError::Other(format!("cannot add envs to wasi context: {}", err)) + })? .build(); let mut store = Store::new(&engine, wasi); - let instance = linker - .instantiate(&mut store, &module) - .context("wasm module could not be instantiated")?; - let start = instance - .get_func(&mut store, "_start") - .ok_or_else(|| anyhow!("could not retrieve wasm module main function"))?; + let instance = linker.instantiate(&mut store, &module).map_err(|err| { + tracing::error!(err = ?err, "wasm module could not be instantiated"); + ExecutorError::Other("wasm module could not be instantiated".to_string()) + })?; + let start = instance.get_func(&mut store, "_start").ok_or_else(|| { + ExecutorError::Other("could not retrieve wasm module main function".into()) + })?; start .call(&mut store, &[], &mut []) - .context("wasm module was not executed successfully") - } -} - -impl Executor for WasmtimeExecutor { - fn exec(&self, spec: &Spec) -> Result<(), ExecutorError> { - Self::exec_inner(spec).map_err(|err| { - tracing::error!(?err, "failed to execute workload with wasmtime handler"); - ExecutorError::Execution(err.into()) - }) + .map_err(|err| ExecutorError::Execution(err.into())) } fn can_handle(&self, spec: &Spec) -> bool {