Skip to content

Commit

Permalink
enable handle_run to accept io redirect paths
Browse files Browse the repository at this point in the history
Signed-off-by: David Justice <[email protected]>
  • Loading branch information
devigned committed Mar 8, 2023
1 parent 846ec65 commit 54768b9
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 31 deletions.
8 changes: 4 additions & 4 deletions Cargo.lock

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

9 changes: 2 additions & 7 deletions crates/runtime-configs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,10 @@ impl ConfigsInner {
/// This defines the available implementor implementations for the `Configs` interface.
///
/// As per its' usage in `ConfigsInner`, it must `derive` `Debug`, and `Clone`.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Default)]
pub enum ConfigsImplementor {
Local,
#[default]
EnvVars,
UserSecrets, // user creates configs at compile time that are encrypted and stored in their slightfile
AzApp,
Expand Down Expand Up @@ -164,12 +165,6 @@ impl From<&str> for ConfigsImplementor {
}
}

impl Default for ConfigsImplementor {
fn default() -> Self {
ConfigsImplementor::EnvVars
}
}

/// SDK-ish bit
pub async fn get(
config_type: &str,
Expand Down
74 changes: 62 additions & 12 deletions crates/runtime/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
mod ctx;
pub mod resource;

use std::path::Path;
use std::{
fs::{File, OpenOptions},
path::{Path, PathBuf},
};

use anyhow::Result;
use async_trait::async_trait;
use ctx::SlightCtxBuilder;
use resource::{get_host_state, HttpData};
use slight_common::{CapabilityBuilder, WasmtimeBuildable, WasmtimeLinkable};
use wasi_cap_std_sync::{ambient_authority, Dir, WasiCtxBuilder};
use wasi_common::pipe::{ReadPipe, WritePipe};
use wasi_common::WasiCtx;
use wasmtime::{Config, Engine, Instance, Linker, Module, Store};

Expand Down Expand Up @@ -45,6 +49,14 @@ impl slight_common::Ctx for RuntimeContext {
}
}

/// Input and output redirects to be used for the running module
#[derive(Clone)]
pub struct IORedirects {
pub stdout_path: PathBuf,
pub stderr_path: PathBuf,
pub stdin_path: PathBuf,
}

/// A wasmtime-based runtime builder.
///
/// It knows how to build a `Store` and `Instance` for a wasm module, given
Expand All @@ -55,6 +67,7 @@ pub struct Builder {
engine: Engine,
module: Module,
state_builder: SlightCtxBuilder,
io_redirects: Option<IORedirects>,
}

impl Builder {
Expand All @@ -70,9 +83,16 @@ impl Builder {
engine,
module,
state_builder: SlightCtxBuilder::default(),
io_redirects: None,
})
}

/// Set the I/O redirects for the module
pub fn set_io(mut self, io_redirects: IORedirects) -> Self {
self.io_redirects = Some(io_redirects);
self
}

/// Link wasi to the wasmtime::Linker
pub fn link_wasi(&mut self) -> Result<&mut Self> {
wasmtime_wasi::add_to_linker(&mut self.linker, |cx: &mut Ctx| cx.wasi.as_mut().unwrap())?;
Expand All @@ -97,14 +117,27 @@ impl Builder {
}
}

fn maybe_open_stdio(pipe_path: &Path) -> Option<File> {
if pipe_path.as_os_str().is_empty() {
None
} else {
Some(
OpenOptions::new()
.read(true)
.write(true)
.open(pipe_path)
.expect("could not open pipe"),
)
}
}

#[async_trait]
impl WasmtimeBuildable for Builder {
type Ctx = Ctx;

/// Instantiate the guest module.
async fn build(self) -> (Store<Self::Ctx>, Instance) {
let wasi = default_wasi().unwrap();

let wasi = build_wasi_context(self.io_redirects).unwrap();
let ctx = RuntimeContext {
wasi: Some(wasi),
slight: self.state_builder.build(),
Expand All @@ -121,6 +154,32 @@ impl WasmtimeBuildable for Builder {
}
}

fn build_wasi_context(io_redirects: Option<IORedirects>) -> Result<WasiCtx> {
let mut ctx: WasiCtxBuilder = WasiCtxBuilder::new();
if let Some(io_redirects) = io_redirects {
let maybe_stdout_pipe = maybe_open_stdio(&io_redirects.stdout_path);
let maybe_stderr_pipe = maybe_open_stdio(&io_redirects.stderr_path);
let maybe_stdin_pipe = maybe_open_stdio(&io_redirects.stdin_path);
if let Some(stdout_pipe) = maybe_stdout_pipe {
ctx = ctx.stdout(Box::new(WritePipe::new(stdout_pipe)));
}
if let Some(stderr_pipe) = maybe_stderr_pipe {
ctx = ctx.stderr(Box::new(WritePipe::new(stderr_pipe)));
}
if let Some(stdin_pipe) = maybe_stdin_pipe {
ctx = ctx.stdin(Box::new(ReadPipe::new(stdin_pipe)));
}
} else {
ctx = ctx.inherit_stdio();
}

Ok(ctx
.inherit_args()?
.preopened_dir(Dir::open_ambient_dir(".", ambient_authority())?, ".")?
.build()
)
}

// TODO (Joe): expose the wasmtime config as a capability?
pub fn default_config() -> Result<Config> {
let mut config = Config::new();
Expand All @@ -130,15 +189,6 @@ pub fn default_config() -> Result<Config> {
Ok(config)
}

// TODO (Joe): expose the wasmtime wasi context as a capability?
pub fn default_wasi() -> Result<WasiCtx> {
let ctx: WasiCtxBuilder = WasiCtxBuilder::new()
.preopened_dir(Dir::open_ambient_dir(".", ambient_authority())?, ".")?
.inherit_stdio()
.inherit_args()?;
Ok(ctx.build())
}

#[cfg(test)]
mod unittest {
use std::collections::HashMap;
Expand Down
25 changes: 19 additions & 6 deletions src/commands/run.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use std::{
collections::{HashMap, HashSet},
path::Path,
path::{Path, PathBuf},
};

use anyhow::{bail, Result};
use as_any::Downcast;
use wit_bindgen_wasmtime::wasmtime::Store;

use slight_common::{BasicState, Capability, WasmtimeBuildable};
use slight_core::slightfile::{Capability as TomlCapability, TomlFile};
#[cfg(feature = "distributed-locking")]
Expand All @@ -22,7 +24,6 @@ use slight_runtime::{Builder, Ctx};
use slight_runtime_configs::Configs;
#[cfg(feature = "sql")]
use slight_sql::Sql;
use wit_bindgen_wasmtime::wasmtime::Store;

#[cfg(feature = "keyvalue")]
const KEYVALUE_HOST_IMPLEMENTORS: [&str; 8] = [
Expand Down Expand Up @@ -58,15 +59,27 @@ const CONFIGS_HOST_IMPLEMENTORS: [&str; 3] =
#[cfg(feature = "sql")]
const SQL_HOST_IMPLEMENTORS: [&str; 1] = ["sql.postgres"];

pub async fn handle_run(module: impl AsRef<Path>, toml_file_path: impl AsRef<Path>) -> Result<()> {
pub type IORedirects = slight_runtime::IORedirects;

#[derive(Clone, Default)]
pub struct RunArgs {
pub module: PathBuf,
pub slightfile: PathBuf,
pub io_redirects: Option<IORedirects>,
}

pub async fn handle_run(args: RunArgs) -> Result<()> {
let toml_file_contents =
std::fs::read_to_string(&toml_file_path).expect("could not locate slightfile");
std::fs::read_to_string(args.slightfile.clone()).expect("could not locate slightfile");
let toml =
toml::from_str::<TomlFile>(&toml_file_contents).expect("provided file is not a slightfile");

tracing::info!("Starting slight");

let host_builder = build_store_instance(&toml, &toml_file_path, &module).await?;
let mut host_builder = build_store_instance(&toml, &args.slightfile, &args.module).await?;
if let Some(io_redirects) = args.io_redirects {
host_builder = host_builder.set_io(io_redirects);
}
let (mut store, instance) = host_builder.build().await;

let caps = toml.capability.as_ref().unwrap();
Expand All @@ -87,7 +100,7 @@ pub async fn handle_run(module: impl AsRef<Path>, toml_file_path: impl AsRef<Pat

if http_enabled {
log::debug!("Http capability enabled");
update_http_states(toml, toml_file_path, module, &mut store).await?;
update_http_states(toml, &args.slightfile, &args.module, &mut store).await?;
}
http_enabled
} else {
Expand Down
19 changes: 17 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
use std::path::PathBuf;

use anyhow::Result;
use clap::Parser;

use slight_lib::{
cli::{Args, Commands},
commands::{add::handle_add, new::handle_new, run::handle_run, secret::handle_secret},
commands::{
add::handle_add,
new::handle_new,
run::{handle_run, RunArgs},
secret::handle_secret,
},
};

/// The entry point for slight CLI
Expand All @@ -15,7 +23,14 @@ async fn main() -> Result<()> {
let args = Args::parse();

match &args.command {
Commands::Run { module } => handle_run(&module.path, args.config.unwrap()).await,
Commands::Run { module } => {
let run_args = RunArgs {
module: PathBuf::from(&module.path),
slightfile: PathBuf::from(args.config.unwrap()),
..Default::default()
};
handle_run(run_args).await
}
Commands::Secret { key, value } => handle_secret(key, value, args.config.unwrap()),
Commands::Add {
interface_at_release,
Expand Down

0 comments on commit 54768b9

Please sign in to comment.