containerd_shim_wasm/shim/shim.rs
1use std::hash::Hash;
2
3use anyhow::Result;
4#[doc(inline)]
5pub use containerd_shimkit::sandbox::cli::Version;
6
7use crate::sandbox::Sandbox;
8use crate::sandbox::context::WasmLayer;
9
10/// The `Shim` trait provides a simplified API for running WebAssembly containers.
11///
12/// It handles the lifecycle of the container and OCI spec details for you.
13#[trait_variant::make(Send)]
14pub trait Shim: Sync + 'static {
15 /// The name to use for this shim
16 fn name() -> &'static str;
17
18 /// Returns the shim version.
19 /// Usually implemented using the [`version!()`](crate::shim::version) macro.
20 fn version() -> Version {
21 Version::default()
22 }
23
24 type Sandbox: Sandbox;
25
26 /// When `compiler` returns `Some`, the returned `Compiler` will be used to precompile
27 /// the layers before they are run.
28 /// Returns the compiler to be used by this engine
29 /// to precompile layers.
30 async fn compiler() -> Option<impl Compiler> {
31 async move { NO_COMPILER }
32 }
33
34 /// Return the supported OCI layer types
35 /// This is used to filter only layers that are supported by the runtime.
36 /// The default implementation returns the OCI layer type 'application/vnd.bytecodealliance.wasm.component.layer.v0+wasm'
37 /// for WASM modules which can be contain with wasip1 or wasip2 components.
38 /// Runtimes can override this to support other layer types
39 /// such as lays that contain runtime specific configuration
40 fn supported_layers_types() -> &'static [&'static str] {
41 &[
42 "application/vnd.bytecodealliance.wasm.component.layer.v0+wasm",
43 "application/wasm",
44 ]
45 }
46}
47
48#[trait_variant::make(Send)]
49pub trait Compiler: Sync {
50 /// `cache_key` returns a hasable type that will be used as a cache key for the precompiled module.
51 ///
52 /// the return value should at least include the version of the shim running but could include other information such as
53 /// a hash of the version and cpu type and other important information in the validation of being able to use precompiled module.
54 /// If the hash doesn't match then the module will be recompiled and cached with the new cache_key.
55 ///
56 /// This hash will be used in the following way:
57 /// "runwasi.io/precompiled/<Shim::name()>/<cache_key>"
58 fn cache_key(&self) -> impl Hash;
59
60 /// `compile` passes supported OCI layers to engine for compilation.
61 /// This is used to precompile the layers before they are run.
62 /// It is called only the first time a module is run and the resulting bytes will be cached in the containerd content store.
63 /// The cached, precompiled layers will be reloaded on subsequent runs.
64 /// 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.
65 /// In some edge cases it is possible that the layers may already be precompiled and None should be returned in this case.
66 async fn compile(&self, _layers: &[WasmLayer]) -> Result<Vec<Option<Vec<u8>>>>;
67}
68
69/// Like the unstable never type, this type can never be constructed.
70/// Ideally we should use the never type (`!`), but it's unstable.
71/// This type can be used to indicate that an engine doesn't support
72/// precompilation
73#[doc(hidden)]
74#[derive(Clone, Copy)]
75pub enum NoCompiler {}
76
77#[doc(hidden)]
78pub const NO_COMPILER: Option<NoCompiler> = None;
79
80impl Compiler for NoCompiler {
81 fn cache_key(&self) -> impl Hash {
82 unreachable!()
83 }
84
85 async fn compile(&self, _layers: &[WasmLayer]) -> anyhow::Result<Vec<Option<Vec<u8>>>> {
86 unreachable!()
87 }
88}