1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
use std::fs::File;
use std::io::Read;
use anyhow::{bail, Context, Result};
use super::Source;
use crate::container::{PathResolve, RuntimeContext};
use crate::sandbox::oci::WasmLayer;
use crate::sandbox::Stdio;
pub trait Engine: Clone + Send + Sync + 'static {
/// The name to use for this engine
fn name() -> &'static str;
/// Run a WebAssembly container
fn run_wasi(&self, ctx: &impl RuntimeContext, stdio: Stdio) -> Result<i32>;
/// Check that the runtime can run the container.
/// This checks runs after the container creation and before the container starts.
/// By it checks that the wasi_entrypoint is either:
/// * a OCI image with wasm layers
/// * a file with the `wasm` filetype header
/// * a parsable `wat` file.
fn can_handle(&self, ctx: &impl RuntimeContext) -> Result<()> {
let source = ctx.entrypoint().source;
let path = match source {
Source::File(path) => path,
Source::Oci(_) => return Ok(()),
};
path.resolve_in_path_or_cwd()
.next()
.context("module not found")?;
let mut buffer = [0; 4];
File::open(&path)?.read_exact(&mut buffer)?;
if buffer.as_slice() != b"\0asm" {
// Check if this is a `.wat` file
wat::parse_file(&path)?;
}
Ok(())
}
/// Return the supported OCI layer types
/// This is used to filter only layers that are supported by the runtime.
/// The default implementation returns the OCI layer type 'application/vnd.bytecodealliance.wasm.component.layer.v0+wasm'
/// for WASM modules which can be contain with wasip1 or wasip2 components.
/// Runtimes can override this to support other layer types
/// such as lays that contain runtime specific configuration
fn supported_layers_types() -> &'static [&'static str] {
&["application/vnd.bytecodealliance.wasm.component.layer.v0+wasm"]
}
/// Precompile passes supported OCI layers to engine for compilation
/// This is used to precompile the layers before they are run and will be called if `can_precompile` returns `true`.
/// It is called only the first time a module is run and the resulting bytes will be cached in the containerd content store.
/// The cached, precompiled layers will be reloaded on subsequent runs.
/// The runtime is expected to return the same number of layers passed in, if the layer cannot be precompiled it should return `None` for that layer.
/// In some edge cases it is possible that the layers may already be precompiled and None should be returned in this case.
fn precompile(&self, _layers: &[WasmLayer]) -> Result<Vec<Option<Vec<u8>>>> {
bail!("precompile not supported");
}
/// Can_precompile lets the shim know if the runtime supports precompilation.
/// When it returns Some(unique_string) the `unique_string` will be used as a cache key for the precompiled module.
///
/// `unique_string` should at least include the version of the shim running but could include other information such as a hash
/// of the version and cpu type and other important information in the validation of being able to use precompiled module.
/// If the string doesn't match then the module will be recompiled and cached with the new `unique_string`.
///
/// This string will be used in the following way:
/// "runwasi.io/precompiled/<Engine.name()>/<unique_string>"
///
/// When it returns None the runtime will not be asked to precompile the module. This is the default value.
fn can_precompile(&self) -> Option<String> {
None
}
}