Reuse unioned_filesystem() for WCGI

This commit is contained in:
Michael-F-Bryan
2023-03-17 01:35:14 +08:00
parent e2a933c83b
commit 702972fb10
6 changed files with 38 additions and 48 deletions

View File

@@ -409,7 +409,7 @@ impl RunWithPathBuf {
.addr(self.wcgi.addr) .addr(self.wcgi.addr)
.envs(self.wasi.env_vars.clone()) .envs(self.wasi.env_vars.clone())
.map_directories(self.wasi.mapped_dirs.clone()); .map_directories(self.wasi.mapped_dirs.clone());
if self.wcgi.forward_host_env { if self.wasi.forward_host_env {
runner.config().forward_host_env(); runner.config().forward_host_env();
} }
if runner.can_run_command(id, command).unwrap_or(false) { if runner.can_run_command(id, command).unwrap_or(false) {
@@ -706,16 +706,12 @@ pub(crate) struct WcgiOptions {
/// The address to serve on. /// The address to serve on.
#[clap(long, short, env, default_value_t = ([127, 0, 0, 1], 8000).into())] #[clap(long, short, env, default_value_t = ([127, 0, 0, 1], 8000).into())]
pub(crate) addr: SocketAddr, pub(crate) addr: SocketAddr,
/// Forward all host env variables to the wcgi task.
#[clap(long)]
pub(crate) forward_host_env: bool,
} }
impl Default for WcgiOptions { impl Default for WcgiOptions {
fn default() -> Self { fn default() -> Self {
Self { Self {
addr: ([127, 0, 0, 1], 8000).into(), addr: ([127, 0, 0, 1], 8000).into(),
forward_host_env: false,
} }
} }
} }

View File

@@ -197,8 +197,7 @@ where
let start: usize = self.cursor.try_into().unwrap(); let start: usize = self.cursor.try_into().unwrap();
let remaining = &bytes[start..]; let remaining = &bytes[start..];
let bytes_read = remaining.len().min(buf.remaining()); let bytes_read = remaining.len().min(buf.remaining());
let end = start + bytes_read; let bytes = &remaining[..bytes_read];
let bytes = &bytes[start..end];
buf.put_slice(bytes); buf.put_slice(bytes);
self.cursor += u64::try_from(bytes_read).unwrap(); self.cursor += u64::try_from(bytes_read).unwrap();

View File

@@ -132,13 +132,17 @@ impl WasiRunner {
container: &WapmContainer, container: &WapmContainer,
command: &str, command: &str,
) -> Result<WasiEnvBuilder, anyhow::Error> { ) -> Result<WasiEnvBuilder, anyhow::Error> {
let root_fs = unioned_filesystem(&self.mapped_dirs, container)?; let fs = unioned_filesystem(&self.mapped_dirs, container)?;
let fs = container.container_fs();
let mut builder = WasiEnv::builder(command) let mut builder = WasiEnv::builder(command)
.args(&self.args) .args(&self.args)
.fs(Box::new(root_fs))
.preopen_dir("/")?; .preopen_dir("/")?;
preopen(&fs, "/".as_ref(), &mut builder)?;
builder.set_fs(Box::new(fs));
if self.forward_host_env { if self.forward_host_env {
for (k, v) in std::env::vars() { for (k, v) in std::env::vars() {
builder.add_env(k, v); builder.add_env(k, v);
@@ -192,7 +196,7 @@ impl crate::runners::Runner for WasiRunner {
/// Create a [`FileSystem`] which merges the WAPM container's volumes with any /// Create a [`FileSystem`] which merges the WAPM container's volumes with any
/// directories that were mapped from the host. /// directories that were mapped from the host.
fn unioned_filesystem( pub(crate) fn unioned_filesystem(
mapped_dirs: &[MappedDirectory], mapped_dirs: &[MappedDirectory],
container: &WapmContainer, container: &WapmContainer,
) -> Result<impl FileSystem, Error> { ) -> Result<impl FileSystem, Error> {
@@ -236,6 +240,19 @@ fn unioned_filesystem(
Ok(OverlayFileSystem::new(primary, [container.container_fs()])) Ok(OverlayFileSystem::new(primary, [container.container_fs()]))
} }
fn preopen(fs: &dyn FileSystem, path: &Path, builder: &mut WasiEnvBuilder) -> Result<(), Error> {
for result in fs.read_dir(path)? {
let entry = result?;
if entry.file_type()?.is_dir() {
builder.add_preopen_dir(&entry.path)?;
preopen(fs, &entry.path, builder)?;
}
}
Ok(())
}
fn create_dir_all(fs: &(impl FileSystem + ?Sized), path: &Path) -> Result<(), Error> { fn create_dir_all(fs: &(impl FileSystem + ?Sized), path: &Path) -> Result<(), Error> {
match fs.metadata(path) { match fs.metadata(path) {
Ok(meta) if meta.is_dir() => return Ok(()), Ok(meta) if meta.is_dir() => return Ok(()),
@@ -257,7 +274,6 @@ fn create_dir_all(fs: &(impl FileSystem + ?Sized), path: &Path) -> Result<(), Er
mod tests { mod tests {
use tempfile::TempDir; use tempfile::TempDir;
use tokio::io::AsyncReadExt; use tokio::io::AsyncReadExt;
use wasmer_vfs::host_fs;
use super::*; use super::*;
@@ -313,6 +329,9 @@ mod tests {
] ]
); );
let abc = read_file(&fs, "/lib/python3.6/collections/abc.py").await; let abc = read_file(&fs, "/lib/python3.6/collections/abc.py").await;
assert_eq!(abc, "from _collections_abc import *"); assert_eq!(
abc,
"from _collections_abc import *\nfrom _collections_abc import __all__\n"
);
} }
} }

View File

@@ -23,7 +23,7 @@ use wcgi_host::CgiDialect;
use crate::{ use crate::{
capabilities::Capabilities, capabilities::Capabilities,
http::HttpClientCapabilityV1, http::HttpClientCapabilityV1,
runners::{wcgi::Callbacks, MappedDirectory}, runners::{wcgi::Callbacks, MappedDirectory, WapmContainer},
Pipe, PluggableRuntime, VirtualTaskManager, WasiEnv, Pipe, PluggableRuntime, VirtualTaskManager, WasiEnv,
}; };
@@ -134,37 +134,8 @@ impl Handler {
Ok(response) Ok(response)
} }
fn fs(&self) -> Result<TmpFileSystem, Error> { fn fs(&self) -> Result<impl FileSystem, Error> {
let root_fs = RootFileSystemBuilder::new().build(); crate::runners::wasi::unioned_filesystem(&self.mapped_dirs, &self.container)
if !self.mapped_dirs.is_empty() {
let fs_backing: Arc<dyn FileSystem + Send + Sync> =
Arc::new(PassthruFileSystem::new(crate::default_fs_backing()));
for MappedDirectory { host, guest } in self.mapped_dirs.iter() {
let guest = match guest.starts_with('/') {
true => PathBuf::from(guest),
false => Path::new("/").join(guest),
};
tracing::debug!(
host=%host.display(),
guest=%guest.display(),
"mounting host directory",
);
root_fs
.mount(guest.clone(), &fs_backing, host.clone())
.with_context(|| {
format!(
"Unable to mount \"{}\" to \"{}\"",
host.display(),
guest.display()
)
})
.unwrap();
}
}
Ok(root_fs)
} }
} }
@@ -255,6 +226,7 @@ pub(crate) struct SharedState {
pub(crate) env: HashMap<String, String>, pub(crate) env: HashMap<String, String>,
pub(crate) args: Vec<String>, pub(crate) args: Vec<String>,
pub(crate) mapped_dirs: Vec<MappedDirectory>, pub(crate) mapped_dirs: Vec<MappedDirectory>,
pub(crate) container: WapmContainer,
pub(crate) module: Module, pub(crate) module: Module,
pub(crate) dialect: CgiDialect, pub(crate) dialect: CgiDialect,
pub(crate) task_manager: Arc<dyn VirtualTaskManager>, pub(crate) task_manager: Arc<dyn VirtualTaskManager>,

View File

@@ -148,6 +148,7 @@ impl WcgiRunner {
.clone() .clone()
.unwrap_or_else(|| Arc::new(TokioTaskManager::default())), .unwrap_or_else(|| Arc::new(TokioTaskManager::default())),
module, module,
container: ctx.container.clone(),
dialect, dialect,
callbacks: Arc::clone(&self.config.callbacks), callbacks: Arc::clone(&self.config.callbacks),
}; };
@@ -225,8 +226,8 @@ impl RunnerContext<'_> {
&self.store &self.store
} }
fn volume(&self, _name: &str) -> Option<Box<dyn FileSystem>> { fn container_fs(&self) -> Box<dyn FileSystem + Send + Sync> {
todo!("Implement a read-only filesystem backed by a volume"); self.container.container_fs()
} }
fn get_atom(&self, name: &str) -> Option<&[u8]> { fn get_atom(&self, name: &str) -> Option<&[u8]> {

View File

@@ -15,6 +15,7 @@ use tempfile::TempDir;
use wasmer_integration_tests_cli::get_wasmer_path; use wasmer_integration_tests_cli::get_wasmer_path;
const RUST_LOG: &str = "info,wasmer_wasi::runners=debug"; const RUST_LOG: &str = "info,wasmer_wasi::runners=debug";
// const RUST_LOG: &str = "info,wasmer_wasi=trace";
mod webc_on_disk { mod webc_on_disk {
use super::*; use super::*;
@@ -81,13 +82,15 @@ mod webc_on_disk {
let assert = Command::new(get_wasmer_path()) let assert = Command::new(get_wasmer_path())
.arg("run2") .arg("run2")
.arg(fixtures::python()) .arg(fixtures::python())
.arg("--env") .arg("--env=SOME_VAR=Hello, World!")
.arg("SOME_VAR=Hello, World!")
.arg("--") .arg("--")
.arg("-c") .arg("-c")
.arg("import os; print(os.environ['SOME_VAR'])") .arg("import os; print(os.environ['SOME_VAR'])")
.env("RUST_LOG", RUST_LOG)
.assert(); .assert();
panic!("{}", String::from_utf8_lossy(&assert.get_output().stderr));
assert.success().stdout(contains("Hello, World!")); assert.success().stdout(contains("Hello, World!"));
} }