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}