Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add host directory mapping to the WasiRunner #3660

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions lib/wasi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ wasm-bindgen = "0.2.74"
[dev-dependencies]
wasmer = { path = "../api", version = "=3.2.0-alpha.1", default-features = false, features = ["wat", "js-serializable-module"] }
tokio = { version = "1", features = [ "sync", "macros", "rt" ], default_features = false }
tempfile = "3.4.0"

[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
wasm-bindgen-test = "0.3.0"
Expand Down
57 changes: 53 additions & 4 deletions lib/wasi/src/runners/wasi.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
//! WebC container support for running WASI modules

use std::sync::Arc;
use std::{path::PathBuf, sync::Arc};

use crate::{runners::WapmContainer, PluggableRuntimeImplementation, VirtualTaskManager};
use crate::{WasiEnv, WasiEnvBuilder};
use crate::{
runners::{wcgi::MappedDirectory, WapmContainer},
PluggableRuntimeImplementation, VirtualTaskManager, WasiEnvBuilder,
};
use anyhow::{Context, Error};
use serde::{Deserialize, Serialize};
use wasmer::{Module, Store};
Expand All @@ -12,6 +14,7 @@ use webc::metadata::{annotations::Wasi, Command};
#[derive(Debug, Serialize, Deserialize)]
pub struct WasiRunner {
args: Vec<String>,
mapped_dirs: Vec<MappedDirectory>,
#[serde(skip, default)]
store: Store,
#[serde(skip, default)]
Expand All @@ -24,6 +27,7 @@ impl WasiRunner {
Self {
args: Vec::new(),
store,
mapped_dirs: Vec::new(),
tasks: None,
}
}
Expand Down Expand Up @@ -52,6 +56,51 @@ impl WasiRunner {
self.args = args.into_iter().map(|s| s.into()).collect();
}

pub fn with_mapped_directory(
mut self,
host: impl Into<PathBuf>,
guest: impl Into<String>,
) -> Self {
self.map_directory(host, guest);
self
}

pub fn map_directory(
&mut self,
host: impl Into<PathBuf>,
guest: impl Into<String>,
) -> &mut Self {
self.mapped_dirs.push(MappedDirectory {
host: host.into(),
guest: guest.into(),
});
self
}

pub fn with_map_directories<I, H, G>(mut self, mappings: I) -> Self
where
I: IntoIterator<Item = (H, G)>,
H: Into<PathBuf>,
G: Into<String>,
{
self.map_directories(mappings);
self
}

pub fn map_directories<I, H, G>(&mut self, mappings: I) -> &mut Self
where
I: IntoIterator<Item = (H, G)>,
H: Into<PathBuf>,
G: Into<String>,
{
let mappings = mappings.into_iter().map(|(h, g)| MappedDirectory {
host: h.into(),
guest: g.into(),
});
self.mapped_dirs.extend(mappings);
self
}

pub fn with_task_manager(mut self, tasks: impl VirtualTaskManager) -> Self {
self.set_task_manager(tasks);
self
Expand Down Expand Up @@ -108,7 +157,7 @@ fn prepare_webc_env(
args: &[String],
) -> Result<WasiEnvBuilder, anyhow::Error> {
let (filesystem, preopen_dirs) = container.container_fs();
let mut builder = WasiEnv::builder(command).args(args);
let mut builder = WasiEnvBuilder::new(command).args(args);

for entry in preopen_dirs {
builder.add_preopen_build(|p| p.directory(&entry).read(true).write(true).create(true))?;
Expand Down
2 changes: 1 addition & 1 deletion lib/wasi/src/runners/wcgi/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use crate::{
Capabilities, Pipe, PluggableRuntimeImplementation, VirtualTaskManager, WasiEnv,
};

/// The shared object that manages the instantiaion of WASI executables and
/// The shared object that manages the instantiation of WASI executables and
/// communicating with them via the CGI protocol.
#[derive(Clone, Debug)]
pub(crate) struct Handler(Arc<SharedState>);
Expand Down
2 changes: 1 addition & 1 deletion lib/wasi/src/runners/wcgi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::path::PathBuf;

pub use self::runner::{Callbacks, Config, WcgiRunner};

#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub(crate) struct MappedDirectory {
pub host: PathBuf,
pub guest: String,
Expand Down
21 changes: 16 additions & 5 deletions lib/wasi/src/state/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,13 +223,24 @@ impl WasiEnvBuilder {
I: IntoIterator<Item = Arg>,
Arg: AsRef<[u8]>,
{
args.into_iter().for_each(|arg| {
self.add_arg(arg);
});
self.add_args(args);

self
}

/// Add multiple arguments.
///
/// Arguments must not contain the nul (0x0) byte
pub fn add_args<I, Arg>(&mut self, args: I)
where
I: IntoIterator<Item = Arg>,
Arg: AsRef<[u8]>,
{
for arg in args {
self.add_arg(arg);
}
}

/// Get a reference to the configured arguments.
pub fn get_args(&self) -> &[String] {
&self.args
Expand Down Expand Up @@ -351,7 +362,7 @@ impl WasiEnvBuilder {
/// ```
pub fn preopen_build<F>(mut self, inner: F) -> Result<Self, WasiStateCreationError>
where
F: Fn(&mut PreopenDirBuilder) -> &mut PreopenDirBuilder,
F: FnOnce(&mut PreopenDirBuilder) -> &mut PreopenDirBuilder,
{
self.add_preopen_build(inner)?;
Ok(self)
Expand All @@ -373,7 +384,7 @@ impl WasiEnvBuilder {
/// ```
pub fn add_preopen_build<F>(&mut self, inner: F) -> Result<(), WasiStateCreationError>
where
F: Fn(&mut PreopenDirBuilder) -> &mut PreopenDirBuilder,
F: FnOnce(&mut PreopenDirBuilder) -> &mut PreopenDirBuilder,
{
let mut pdb = PreopenDirBuilder::new();
let po_dir = inner(&mut pdb).build()?;
Expand Down
52 changes: 34 additions & 18 deletions lib/wasi/tests/runners.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use wasmer_wasi::runners::{Runner, WapmContainer};

#[cfg(feature = "webc_runner_rt_wasi")]
mod wasi {
use anyhow::Error;
use tempfile::TempDir;
use tokio::runtime::Handle;
use wasmer::Store;
use wasmer_wasi::{
Expand Down Expand Up @@ -43,15 +45,7 @@ mod wasi {
});
let err = handle.join().unwrap().unwrap_err();

let runtime_error = err
.chain()
.find_map(|e| e.downcast_ref::<WasiError>())
.unwrap();
let exit_code = match runtime_error {
WasiError::Exit(code) => *code,
other => unreachable!("Something else went wrong: {:?}", other),
};
assert_eq!(exit_code, 1);
assert_eq!(wasi_exit_code(&err), 1);
}

#[tokio::test]
Expand All @@ -69,15 +63,37 @@ mod wasi {
});
let err = handle.join().unwrap().unwrap_err();

let runtime_error = err
.chain()
.find_map(|e| e.downcast_ref::<WasiError>())
.unwrap();
let exit_code = match runtime_error {
WasiError::Exit(code) => *code,
other => unreachable!("Something else went wrong: {:?}", other),
};
assert_eq!(exit_code, 42);
assert_eq!(wasi_exit_code(&err), 42);
}

#[tokio::test]
async fn python_with_mapped_dir() {
let webc = download_cached("https://wapm.io/python/python").await;
let store = Store::default();
let tasks = TokioTaskManager::new(Handle::current());
let container = WapmContainer::from_bytes(webc).unwrap();
let temp = TempDir::new().unwrap();
std::fs::write(temp.path().join("main.py"), b"import sys\nsys.exit(42)").unwrap();

let handle = std::thread::spawn(move || {
WasiRunner::new(store)
.with_task_manager(tasks)
.with_mapped_directory(temp.path(), "/path/to/")
.with_args(["/path/to/main.py"])
.run_cmd(&container, "python")
});
let err = handle.join().unwrap().unwrap_err();

assert_eq!(wasi_exit_code(&err), 42);
}

fn wasi_exit_code(err: &Error) -> u32 {
let runtime_error = err.chain().find_map(|e| e.downcast_ref::<WasiError>());

match runtime_error {
Some(WasiError::Exit(code)) => *code,
_ => panic!("The runner exited abnormally: {:?}", err),
}
}
}

Expand Down