Skip to content

WASM support and Kuksa

Sven Erik Jeroschewski edited this page Sep 2, 2024 · 2 revisions

Databroker as WASM

At the moment, Eclipse Kuksa is often deployed as a container using runtimes like Docker or Podman. In this page, we investigate approaches for running the Databroker in a WASM runtime like Wasmtime or wasmi. These runtimes have in common that they implement and expose the interfaces defined in WASI.

Thus, it is interesting to compile the Kuksa Databroker for the execution in one of these runtimes independently from the underlying hardware and software stack to ease interoperability. The name of the target to which we need to compile is:

wasm32-wasip1

(Note that the target wasm32-wasi has been renamed to wasm32-wasip1 to reflect that this is actually "WASI preview One")

There is a guide on how to develop Rust applications for WASMEdge.

Essentially, we need to install the respective toolchain with:

rustup target add wasm32-wasip1

Failing Build due to "socket2"

So far, the compilation of the Databroker fails when building socket2 because this crate cannot find the module sys. In this issue, it seems like there is no support for WASM in socket2 yet. The socket2 dependency gets introduced through tonic and axum, as you can see in the following dependency tree:

databroker-proto v0.4.4 (/Users/jes1be/Documents/SDV/GIT/kuksa/kuksa-databroker/databroker-proto)
│   └── tonic v0.9.2
│       ├── axum v0.6.20
│       │   ├── hyper v0.14.28
│       │   │   ├── h2 v0.3.26
│       │   │   │   ├── tokio v1.37.0
│       │   │   │       ├── socket2 v0.5.6
│       │   │   ├── socket2 v0.5.6 (*)

Part of the detailed error are:

error[E0583]: file not found for module `sys`
   --> /Users/jes1be/.cargo/registry/src/index.crates.io-6f17d22bba15001f/socket2-0.5.6/src/lib.rs:179:1
    |
179 | mod sys;
    | ^^^^^^^^
    |
    = help: to create the module `sys`, create file "/Users/jes1be/.cargo/registry/src/index.crates.io-6f17d22bba15001f/socket2-0.5.6/src/sys.rs" or "/Users/jes1be/.cargo/registry/src/index.crates.io-6f17d22bba15001f/socket2-0.5.6/src/sys/mod.rs"
    = note: if there is a `mod sys` elsewhere in the crate already, import it with `use crate::...` instead

error: Socket2 doesn't support the compile target
   --> /Users/jes1be/.cargo/registry/src/index.crates.io-6f17d22bba15001f/socket2-0.5.6/src/lib.rs:182:1
    |
182 | compile_error!("Socket2 doesn't support the compile target");
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0432]: unresolved imports `crate::sys::c_int`, `crate::sys::sa_family_t`, `crate::sys::sockaddr`, `crate::sys::sockaddr_in`, `crate::sys::sockaddr_in6`, `crate::sys::sockaddr_storage`, `crate::sys::socklen_t`, `crate::sys::AF_INET`, `crate::sys::AF_INET6`, `crate::sys::AF_UNIX`
  --> /Users/jes1be/.cargo/registry/src/index.crates.io-6f17d22bba15001f/socket2-0.5.6/src/sockaddr.rs:11:5
   |
11 |     c_int, sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t, AF_IN...
   |     ^^^^^  ^^^^^^^^^^^  ^^^^^^^^  ^^^^^^^^^^^  ^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^  ^^^^^^^^^  ^^^^^^^ no `AF_INET` in `sys`
   |     |      |            |         |            |             |                 |
   |     |      |            |         |            |             |                 no `socklen_t` in `sys`
   |     |      |            |         |            |             no `sockaddr_storage` in `sys`
   |     |      |            |         |            no `sockaddr_in6` in `sys`
   |     |      |            |         no `sockaddr_in` in `sys`
   |     |      |            no `sockaddr` in `sys`
   |     |      no `sa_family_t` in `sys`
   |     no `c_int` in `sys`
12 |     AF_INET6, AF_UNIX,
   |     ^^^^^^^^  ^^^^^^^ no `AF_UNIX` in `sys`
   |     |
   |     no `AF_INET6` in `sys`
   |
   = help: consider importing one of these items instead:
           core::ffi::c_int
           std::ffi::c_int
           std::os::raw::c_int
   = help: consider importing this module instead:
           crate::sockaddr

Tokio

The Kuksa Databroker depends on Tokio for asynchronous networking.

One approach for the build would be:

RUSTFLAGS="--cfg wasmedge --cfg tokio_unstable" cargo build --target wasm32-wasi --release

Another idea was to configure Tokio to execute everything in the current thread to avoid the need of starting new threads in the WASM runtime. To do this we add the following annotation to the main() function in databroker/src/main.rs:

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn std::error::Error>> {

(Note, that there is another target wasm32-wasip1-threads which specifically adds multi-threading capabilities. But I have not tried it yet due to the socket2 issue described above.)

Mac Specific for TLS

To support TLS, the databroker uses the ring Library. The compilation of ring involves some compiling of C++ components, which does not work (at least for me) out-of-the box on macOS because the installed version of clang was a bit older.

brew

One solution is to use brew to install llvm which install a more recent version of clang:

brew install clang
echo 'export PATH="/usr/local/opt/llvm/bin:$PATH"' >> ~/.zshrc

In my case, this worked for the target wasm_wasi but not wasm_wasi32p1, probably because there was no sysroot configured for that target. Instead I used the next approach of installing the wasi_sdk.

install wasi_sdk

As an alternative solution, the WasmEdge Tutorial proposes to download the latest wasi-sdk and then change the CC environment variable to point to the alternative location:

export WASI_SDK_PATH=/path/to/wasi-sdk-22.0
export CC="${WASI_SDK_PATH}/bin/clang --sysroot=${WASI_SDK_PATH}/share/wasi-sysroot"

In macOS, the execution of the wasi_sdk may get stopped due to security concerns since the binaries are not from a trusted source. Because of that, you might see a notification asking to delete the binary. Instead, you can go to the macOS settings application and select "Privacy & Security". There, you find the option to allow the execution anyway. When you now trigger the build again, there will be another notification where you can select to run the binary. This may happen for multiple binaries from the SDK, and you then have to re-run the build until no further binaries need to be allowed.