Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a Rust based Wasm language module that supports the component model #1122

Merged
merged 15 commits into from
Feb 21, 2024

Conversation

ac000
Copy link
Member

@ac000 ac000 commented Feb 9, 2024

The first thing that probably stands out here is: 'Rust'!

Indeed, this new language module is written in Rust, not ideal, but unfortunately there is currently no component model support on the runtime side of things in the C toolchain (you can write components themselves in C however...)

We need component model support to run WASI 0.2.0 components. Components are the way ahead.

This module doesn't replace the existing 'wasm' module and the two can happily co-exist. The exiting module currently has some advantages including the ability to transfer in and out files/data > ~4GiB.

This new language module was written by Alex Crichton, I have tried to keep his work intact and separate from extra changes to the module we make, such as updating to wasmtime 17.

The Rust code is limited purely to the language module and if you don't build it then there is no Rust involved.

The language module talks to the rest of Unit via automatically generated bindings at module build time.

This new module registers itself as a type of wasm-wasi-component as discussed here.

@ac000 ac000 added the z-roadmap label Feb 9, 2024
@ac000 ac000 added this to the 1.32 milestone Feb 9, 2024
@ac000
Copy link
Member Author

ac000 commented Feb 13, 2024

Make it clear that you can use either the 'proxy' or 'reactor' adaptor.

$ git range-diff f35cf09e...bfe77292
1:  f35cf09e ! 1:  bfe77292 Wasm-wc: Allow to use the 'reactor' adaptor again
    @@ Commit message
         With this we can go back to using the 'reactor' adaptor again and things
         are back to working as before.
     
    +    It's worth noting that you can use either the 'proxy' or 'reactor'
    +    adaptor depending on your requirements.
    +
         Cc: Joel Dice <[email protected]>
         Signed-off-by: Andrew Clayton <[email protected]>
     

@ac000 ac000 mentioned this pull request Feb 16, 2024
Copy link
Member

@thresheek thresheek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eh, I suck at github interface.

The Docker part needs to be implemented as a target in pkg/docker/Makefile, similarly to 5ed7dd5

@ac000
Copy link
Member Author

ac000 commented Feb 17, 2024

Move the re-enablement of the 'reactor' adaptor patch to before wiring the module up to the config system so the all the module changes are in before it's actually usable.

$ git range-diff bfe77292...2b6a624c
1:  a3177ae3 = 1:  09dac2b7 Wasm-wc: Upgrade to wasmtime 17
7:  bfe77292 = 2:  6733a579 Wasm-wc: Allow to use the 'reactor' adaptor again
2:  3b3a82a1 = 3:  ea1efcef Wasm-wc: Wire up the language module to the config system
3:  ac1e19c0 = 4:  9b3edc23 Fix alignment of wasm options text in auto/help
4:  82f0c74e = 5:  7ad8ff3e Wasm-wc: Wire it up to the build system
5:  2619c91e = 6:  30bae7b2 Wasm-wc: Add sample wasmtime Dockerfile
6:  df7a5302 = 7:  2b6a624c Wasm-wc: Dockerfile changed to pull sources from the right repository

@ac000
Copy link
Member Author

ac000 commented Feb 19, 2024

Eh, I suck at github interface.

The Docker part needs to be implemented as a target in pkg/docker/Makefile, similarly to 5ed7dd5

Right, I'll see if I can hack that in.

But we still want the Dockerfile right? (Yes, it also needs some updating in terms of configuring/building/installing the module).

@ac000
Copy link
Member Author

ac000 commented Feb 19, 2024

Updated dockerfile module build commands

$ git range-diff 2b6a624c...73cc33ad
1:  2b6a624c ! 1:  73cc33ad Wasm-wc: Dockerfile changed to pull sources from the right repository
    @@ pkg/docker/Dockerfile.wasm-wasi-component: RUN set -ex \
          && NCPU="$(getconf _NPROCESSORS_ONLN)" \
          && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \
     @@ pkg/docker/Dockerfile.wasm-wasi-component: RUN set -ex \
    +     && cargo --version \
          && rustc --version \
          && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/modules \
    -     && make build/src/nxt_unit.o \
    +-    && make build/src/nxt_unit.o \
     -    && cargo build --release --manifest-path wasmtime/Cargo.toml \
     -    && install -pm755 wasmtime/target/release/libnxt_wasmtime.so /usr/lib/unit/modules/wasmtime.unit.so \
     -    && rm -rf wasmtime/target \
    -+    && cargo build --release --manifest-path src/wasm-wasi-component/Cargo.toml \
    -+    && install -pm755 src/wasm-wasi-component/target/release/libnxt_wasmtime.so /usr/lib/unit/modules/wasm_wasi_component.unit.so \
    -+    && rm -rf src/wasm-wasi-component/target \
    ++    && ./configure wasm-wasi-component \
    ++    && make wasm-wasi-component-install \
    ++    && cd \
          && rm -rf /usr/src/unit \
          && for f in /usr/sbin/unitd /usr/lib/unit/modules/*.unit.so; do \
              ldd $f | awk '/=>/{print $(NF-1)}' | while read n; do dpkg-query -S $n; done | sed 's/^\([^:]\+\):.*$/\1/' | sort | uniq >> /requirements.apt; \

@tippexs You might want to check I didn't break anything...

@ac000
Copy link
Member Author

ac000 commented Feb 19, 2024

Rebase with master for latest docker changes... (there's also a new commit, f915288 Docker: Genericise MODULE_PREBUILD_wasm for re-use, which may or may not last)

$ git range-diff 73cc33ad...f9152882
 -:  -------- >  1:  9e986704 Configuration: Fix validation of "processes"
 -:  -------- >  2:  3a2687bb Packages: added Ubuntu 23.10 "mantic" support.
 -:  -------- >  3:  8ebe04fd contrib: Bump libunit-wasm to 0.3.0.
 -:  -------- >  4:  ca1bc062 contrib: updated njs to 0.8.2.
 -:  -------- >  5:  bad2c181 Packages: Added Fedora 39 support.
 -:  -------- >  6:  661e918a Docker: added python3.12 to versions
 -:  -------- >  7:  2b0d93d1 Docker: Generated Dockerfile for Unit 1.31.1.
 -:  -------- >  8:  fbeb2065 fix: Take options as well as requestListener (#1091)
 -:  -------- >  9:  c3af21e9 Docker: Switch to github
 -:  -------- > 10:  baff936b Packages: Move dist target to git archive
 -:  -------- > 11:  34b3a812 Add nxt_file_chown()
 -:  -------- > 12:  b500c36d Allow to set the permissions of the Unix domain control socket
 -:  -------- > 13:  2bd3b418 Docs: Update man page for new --control-* options
 -:  -------- > 14:  1dca8602 Tools: disambiguate unitc control socket detection
 1:  3bb4526b = 15:  d3ef175d Wasm-wc: Register a new Wasm component model language module type
 2:  89df7881 = 16:  54ea7dcb Wasm-wc: Add core configuration data structure
 3:  445b5d79 = 17:  8388b4c1 Wasm-wc: Core of initial Wasm component model language module support
 4:  1ea2537b = 18:  2edb2d39 Add a .rustfmt.toml file
 5:  63fa352e = 19:  dc5d786b Wasm-wc: Run src/lib.rs through rustfmt
 6:  6bf04a3a = 20:  8bdaf3d8 Wasm-wc: Improve request buffer handling
 7:  09dac2b7 = 21:  6979a259 Wasm-wc: Upgrade to wasmtime 17
 8:  6733a579 = 22:  243a5900 Wasm-wc: Allow to use the 'reactor' adaptor again
 9:  ea1efcef = 23:  514c18f1 Wasm-wc: Wire up the language module to the config system
10:  9b3edc23 = 24:  29cf5d2e Fix alignment of wasm options text in auto/help
11:  7ad8ff3e = 25:  d73a5673 Wasm-wc: Wire it up to the build system
12:  30bae7b2 = 26:  bf42a05c Wasm-wc: Add sample wasmtime Dockerfile
13:  73cc33ad = 27:  ef369cf3 Wasm-wc: Dockerfile changed to pull sources from the right repository
 -:  -------- > 28:  f9152882 Docker: Genericise MODULE_PREBUILD_wasm for re-use

@ac000
Copy link
Member Author

ac000 commented Feb 19, 2024

  • Add a wasm_wasi_component docker target
  • Rename the wasm-wasi-component dockerfile to Dockerfile.wasm_wasi_component, due to -'s being stripped from the name
$ git range-diff f9152882...23db1cb1
-:  -------- > 1:  94ced44e Docker: Add a wasm_wasi_component target
-:  -------- > 2:  23db1cb1 Docker: Rename Dockerfile.wasm-wasi-component

@@ -76,7 +76,12 @@ cat << END
java OPTIONS configure Java module
run "./configure java --help" to see available options

wasm OPTIONS configure WebAssembly module
run "./configure wasm --help" to see available options
wasm OPTIONS configure WebAssembly module
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

99% of our users will want wasm-wasi-component... I wonder if we can signpost this better?

Suggested change
wasm OPTIONS configure WebAssembly module
wasm OPTIONS configure raw (not Component Model) WebAssembly module

Hm. I don't like that either. Food for thought if you have something better that immediately comes to mind.

Not blocking on this feedback.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Users should be consuming it via packages... If they're building from source they hopefully have some idea of what they're doing and then there's documentation...

Comment on lines 83 to 91
NXT_OS=$(uname -o)

if [ $NXT_OS = "Darwin" ]; then
NXT_CARGO_CMD="cargo rustc --release --manifest-path src/wasm-wasi-component/Cargo.toml -- --emit link=target/release/libnxt_wasmtime.so -C link-args='-undefined dynamic_lookup'"
else
NXT_CARGO_CMD="cargo build --release --manifest-path src/wasm-wasi-component/Cargo.toml"
fi


Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's handle -link-args in build.rs instead of auto/modules/wasm-wasi-component

I'll provide a patch tonight after I figure out if there's an easy way to duplicate the function of --emit during a normal cargo build

@@ -0,0 +1,3 @@
Cargo.lock
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect we do want the Cargo.lock committed, to ensure we can deterministically build this module.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've also generally read that you should ignore Cargo.lock for libraries. E.g rust-lang/cargo#315 (comment)

@ac000
Copy link
Member Author

ac000 commented Feb 19, 2024 via email

@callahad
Copy link
Collaborator

re: Cargo.lock, was there any other discussion about whether we should include it or not that I'm missing / contradicting?

The general recommendation for the past decade has been "commit the lockfile for binaries, ignore it for libraries." Last year, the guidance changed to be more nuanced, but to default to tracking the lockfile even for libraries.

The Cargo Book has a FAQ entry, "Why have Cargo.lock in version control?", which goes into more detail about the benefits of tracking the lockfile by default, but even under the old definition, I'd argue we should track the lockfile as our crate is not intended to be consumed by other crates; it's a leaf node producing a binary artifact.

@ac000
Copy link
Member Author

ac000 commented Feb 19, 2024

I'd say unless there's a very good reason to include the lock file, ignore it... so far I haven't seen ignoring it having ill effect.

@callahad
Copy link
Collaborator

callahad commented Feb 19, 2024

The guidance and FAQ linked above discuss reasons to include the lockfile, and inclusion has always been the default recommendation for binary crates. Omitting the lockfile is the exceptional behavior, and thus should have exceptional justification for why we're deviating from standard practices.

@callahad
Copy link
Collaborator

If you don't want the faff, I'm happy to get us to merge these patches as-is (it's already a large series), and we can add the lockfile in a followup

@callahad
Copy link
Collaborator

Same goes for my tweaks to build.rs and auto/modules/wasm-wasi-component to be honest.

@ac000
Copy link
Member Author

ac000 commented Feb 19, 2024

Same goes for my tweaks to build.rs and auto/modules/wasm-wasi-component to be honest.

Did you figure out how to adjust the target name from build.rs? as last I looked it didn't seem possible...

@callahad
Copy link
Collaborator

Did you figure out how to adjust the target name from build.rs? as last I looked it didn't seem possible...

Nope. Was thinking there might be a way to do it via a .cargo/config.toml at the crate root, but no dice. I suspect we should let cargo spit out a dylib and then copy it as a .so as part of the make install target.

@ac000
Copy link
Member Author

ac000 commented Feb 19, 2024

Name the rust target more appropriately

$ git range-diff 23db1cb1...2fe88618
 1:  8388b4c1 !  1:  0a162f6a Wasm-wc: Core of initial Wasm component model language module support
    @@ Commit message
     
         It talks to Unit via automatically generated bindings.
     
    -    I've (Andrew) just made some minor tweaks to src/lib.rs and build.rs to
    -    adjust some paths, adjust where we get the language module config from
    -    and the module name and where it's located in the source tree,
    +    I've (Andrew) just made some minor tweaks to src/lib.rs, build.rs &
    +    Cargo.toml to adjust some paths, adjust where we get the language module
    +    config from and the module name and where it's located in the source
    +    tree,
     
         I also removed and disabled the tracking of the Cargo.lock file, this is
         constantly changing and not tracking it seems right for 'libraries' and
    @@ src/wasm-wasi-component/.gitignore (new)
      ## src/wasm-wasi-component/Cargo.toml (new) ##
     @@
     +[package]
    -+name = "nxt-wasmtime"
    ++name = "wasm-wasi-component"
     +version = "0.1.0"
     +edition = "2021"
     +publish = false
 2:  2edb2d39 =  2:  74f6b5dc Add a .rustfmt.toml file
 3:  dc5d786b =  3:  58c17212 Wasm-wc: Run src/lib.rs through rustfmt
 4:  8bdaf3d8 =  4:  39f834a4 Wasm-wc: Improve request buffer handling
 5:  6979a259 =  5:  4cca6cd1 Wasm-wc: Upgrade to wasmtime 17
 6:  243a5900 =  6:  7654d304 Wasm-wc: Allow to use the 'reactor' adaptor again
 7:  514c18f1 =  7:  670139c7 Wasm-wc: Wire up the language module to the config system
 8:  29cf5d2e =  8:  28ee6f9d Fix alignment of wasm options text in auto/help
 9:  d73a5673 !  9:  3c2a65de Wasm-wc: Wire it up to the build system
    @@ Commit message
           cargo build --release --manifest-path src/wasm-wasi-component/Cargo.toml
               Finished release [optimized] target(s) in 0.55s
           install -d /opt/unit/modules
    -      install -p src/wasm-wasi-component/target/release/libnxt_wasmtime.so \
    +      install -p src/wasm-wasi-component/target/release/libwasm_wasi_component.so \
                   /opt/unit/modules/wasm_wasi_component.unit.so
     
         Signed-off-by: Andrew Clayton <[email protected]>
    @@ auto/modules/wasm-wasi-component (new)
     +NXT_OS=$(uname -o)
     +
     +if [ $NXT_OS = "Darwin" ]; then
    -+  NXT_CARGO_CMD="cargo rustc --release --manifest-path src/wasm-wasi-component/Cargo.toml -- --emit link=target/release/libnxt_wasmtime.so -C link-args='-undefined dynamic_lookup'"
    ++  NXT_CARGO_CMD="cargo rustc --release --manifest-path src/wasm-wasi-component/Cargo.toml -- --emit link=target/release/libwasm_wasi_component.so -C link-args='-undefined dynamic_lookup'"
     +else
     +  NXT_CARGO_CMD="cargo build --release --manifest-path src/wasm-wasi-component/Cargo.toml"
     +fi
    @@ auto/modules/wasm-wasi-component (new)
     +
     +${NXT_WCM_MODULE}-install: ${NXT_WCM_MODULE} install-check
     +  install -d \$(DESTDIR)$NXT_MODULESDIR
    -+  install -p src/wasm-wasi-component/target/release/libnxt_wasmtime.so \\
    ++  install -p src/wasm-wasi-component/target/release/libwasm_wasi_component.so \\
     +          \$(DESTDIR)$NXT_MODULESDIR/$NXT_WCM_MOD_NAME
     +
     +uninstall: ${NXT_WCM_MODULE}-uninstall
10:  bf42a05c = 10:  6566e862 Wasm-wc: Add sample wasmtime Dockerfile
11:  ef369cf3 = 11:  459af1d8 Wasm-wc: Dockerfile changed to pull sources from the right repository
12:  f9152882 = 12:  f1640dc6 Docker: Genericise MODULE_PREBUILD_wasm for re-use
13:  94ced44e = 13:  cb44d455 Docker: Add a wasm_wasi_component target
14:  23db1cb1 = 14:  2fe88618 Docker: Rename Dockerfile.wasm-wasi-component

@callahad
Copy link
Collaborator

callahad commented Feb 19, 2024

Thoughts on this proposed patch?

Makes a plain cargo build work on macOS, handles the dylib->so renaming in the wasm-wasi-component-install target.

diff --git a/auto/modules/wasm-wasi-component b/auto/modules/wasm-wasi-component
index 1ec5841c..e054401c 100644
--- a/auto/modules/wasm-wasi-component
+++ b/auto/modules/wasm-wasi-component
@@ -5,6 +5,11 @@
 NXT_WCM_MODULE=wasm-wasi-component
 NXT_WCM_MOD_NAME=`echo $NXT_WCM_MODULE | tr '-' '_'`.unit.so
 
+case $(uname -o) in
+	"Darwin") NXT_WCM_MOD_EXT="dylib" ;;
+	*)        NXT_WCM_MOD_EXT="so" ;;
+esac
+
 
 shift
 
@@ -80,15 +85,6 @@ fi
 $echo " + $NXT_WCM_MODULE module: $NXT_WCM_MOD_NAME"
 
 
-NXT_OS=$(uname -o)
-
-if [ $NXT_OS = "Darwin" ]; then
-	NXT_CARGO_CMD="cargo rustc --release --manifest-path src/wasm-wasi-component/Cargo.toml -- --emit link=target/release/libwasm_wasi_component.so -C link-args='-undefined dynamic_lookup'"
-else
-	NXT_CARGO_CMD="cargo build --release --manifest-path src/wasm-wasi-component/Cargo.toml"
-fi
-
-
 cat << END >> $NXT_MAKEFILE
 
 .PHONY: ${NXT_WCM_MODULE}
@@ -101,13 +97,13 @@ ${NXT_WCM_MODULE}:  $NXT_BUILD_DIR/lib/unit/modules/$NXT_WCM_MOD_NAME
 
 $NXT_BUILD_DIR/lib/unit/modules/$NXT_WCM_MOD_NAME:
 	make build/src/nxt_unit.o
-	$NXT_CARGO_CMD
+	cargo build --release --manifest-path src/wasm-wasi-component/Cargo.toml
 
 install: ${NXT_WCM_MODULE}-install
 
 ${NXT_WCM_MODULE}-install: ${NXT_WCM_MODULE} install-check
 	install -d \$(DESTDIR)$NXT_MODULESDIR
-	install -p src/wasm-wasi-component/target/release/libwasm_wasi_component.so \\
+	install -p src/wasm-wasi-component/target/release/libwasm_wasi_component.$NXT_WCM_MOD_EXT \\
 		\$(DESTDIR)$NXT_MODULESDIR/$NXT_WCM_MOD_NAME
 
 uninstall: ${NXT_WCM_MODULE}-uninstall
diff --git a/src/wasm-wasi-component/build.rs b/src/wasm-wasi-component/build.rs
index 5ea74f17..49b904aa 100644
--- a/src/wasm-wasi-component/build.rs
+++ b/src/wasm-wasi-component/build.rs
@@ -5,6 +5,13 @@ fn main() {
     // Tell cargo to invalidate the built crate whenever the wrapper changes
     println!("cargo:rerun-if-changed=wrapper.h");
 
+    // Building fails on recent macOS due to changes in its linker.
+    // Passing `-undefined dynamic_lookup` works and matches prior behavior.
+    if cfg!(target_os = "macos") {
+        println!("cargo:rustc-link-arg=-undefined");
+        println!("cargo:rustc-link-arg=dynamic_lookup");
+    }
+
     let bindings = bindgen::Builder::default()
         .clang_args(["-I", "../"])
         .clang_args(["-I", "../../build/include"])

@callahad
Copy link
Collaborator

callahad commented Feb 19, 2024

...module names would have to be adjusted to take into account your latest revision of the patch series, which I'm only just now seeing for some reason.

Edit: The above patch has been edited to account for the rename away from libnxt_wasmtime

@ac000
Copy link
Member Author

ac000 commented Feb 21, 2024

Combine the wasm and wasm-wasi-component model docker targets

$ git range-diff b18f0bec...3243598d
1:  af71bd99 < -:  -------- Docker: Genericise MODULE_PREBUILD_wasm for re-use
2:  10ea18a7 < -:  -------- Docker: Add a wasm_wasi_component target
3:  de388d48 < -:  -------- Docker: Split building wasmtime out into a separate stage
4:  906a12d4 < -:  -------- Docker: Bump rust version to 1.76.0
5:  acc1f9c3 < -:  -------- Docker: Add a pre-generated wasm_wasi_component dockerfile
6:  b18f0bec < -:  -------- Docker: Update Dockerfile.wasm for rust 1.76.0
-:  -------- > 1:  8bddf371 Docker: Bump rust version to 1.76.0
-:  -------- > 2:  5fbe51dd Docker: Add wasm-wasi-component to the wasm target
-:  -------- > 3:  3243598d Docker: Re-generate Dockerfile.wasm

@callahad
Copy link
Collaborator

callahad commented Feb 21, 2024

Looks like the Dockerfile is still pointing at 1.32.0; could you please re-generate them with VERSION=1.31.1?

@ac000
Copy link
Member Author

ac000 commented Feb 21, 2024

That was on purpose

commit 3243598dad2fa7d6575514dcf3cc9e40864fa196
Author: Andrew Clayton <[email protected]>
Date:   Wed Feb 21 13:10:06 2024 +0000

    Docker: Re-generate Dockerfile.wasm
    
    This now includes support for the 'wasm-wasi-component' module.
    
    This targets the upcoming 1.32.0 release which is required by
    wasm-wasi-component. However of course the 1.32.0 tag doesn't exist yet,
    so there will be a small window where this image won't build.
    
    Signed-off-by: Andrew Clayton <[email protected]>

Otherwise the thing will fail anyway...

@callahad
Copy link
Collaborator

Ah, fair enough. We had discussed doing 1.31.1 upthread in #1122 (comment), but either way is fine since neither way will work until we release anyway :)

I think we're good to merge, now?

@callahad callahad dismissed thresheek’s stale review February 21, 2024 14:12

Reached agreement in discussions above

@ac000
Copy link
Member Author

ac000 commented Feb 21, 2024

One final run on BB...

@ac000
Copy link
Member Author

ac000 commented Feb 21, 2024

Let's get this sucker merged...

@ac000
Copy link
Member Author

ac000 commented Feb 21, 2024

Rebase with master

$ git range-diff 3243598d...d88048dd
 -:  -------- >  1:  f71ead5f Updated copyright notice.
 -:  -------- >  2:  697a5850 Python: bytearray body support for ASGI module.
 -:  -------- >  3:  56d3a1a7 Add GitHub Actions
 1:  a37c87b6 =  4:  c08897dd Wasm-wc: Register a new Wasm component model language module type
 2:  6fe77b02 =  5:  525a08c8 Wasm-wc: Add core configuration data structure
 3:  82b394c4 =  6:  c5062444 Wasm-wc: Core of initial Wasm component model language module support
 4:  3ad3c9b4 =  7:  3127eb2d Add a .rustfmt.toml file
 5:  a3bc4e6b =  8:  6bdd0660 Wasm-wc: Run src/lib.rs through rustfmt
 6:  d9df0dba =  9:  3f6f0090 Wasm-wc: Improve request buffer handling
 7:  eaf91c2e = 10:  9edb7e8e Wasm-wc: Upgrade to wasmtime 17
 8:  b1d37a93 = 11:  31ce7969 Wasm-wc: Allow to use the 'reactor' adaptor again
 9:  043e6b4f = 12:  92313ec3 Wasm-wc: Add Cargo.lock
10:  ee6534fb = 13:  a284a112 Wasm-wc: Wire up the language module to the config system
11:  601b5042 = 14:  d8deb2eb Fix alignment of wasm options text in auto/help
12:  05b4cd53 = 15:  fd751c46 Wasm-wc: Wire it up to the build system
13:  8bddf371 = 16:  4119a1f3 Docker: Bump rust version to 1.76.0
14:  5fbe51dd = 17:  c73edc92 Docker: Add wasm-wasi-component to the wasm target
15:  3243598d = 18:  d88048dd Docker: Re-generate Dockerfile.wasm

ac000 and others added 15 commits February 21, 2024 16:20
This is the first commit in adding WebAssembly Component Model language
module support.

This just adds a new NXT_APP_WASM_WC type, required by subsequent
commits.

The WC stands for WASI_COMPONENT

This new module will have a type of 'wasm-wasi-component'.

Link: <nginx#1098>
Signed-off-by: Andrew Clayton <[email protected]>
This is required to actually _build_ the 'wasm-wasi-componet' language
module.

The nxt_wasm_wc_app_conf_t structure consists of the component name, e.g
my_component.wasm, this is required. It also consists of an object to
store the directories that are allowed access to by the component, this
is optional.

The bulk of the configuration infrastructure will be added in a
subsequent commit.

Signed-off-by: Andrew Clayton <[email protected]>
This is the work of Alex Crichton.

This is written in Rust. The problem is that there is currently no
support on the C side of things for the component model, which is the
point of this module.

It talks to Unit via automatically generated bindings.

I've (Andrew) just made some minor tweaks to src/lib.rs, build.rs &
Cargo.toml to adjust some paths, adjust where we get the language module
config from and the module name and where it's located in the source
tree,

I also removed and disabled the tracking of the Cargo.lock file, this is
constantly changing and not tracking it seems right for 'libraries' and
dropped the README's...

Other than that I have tried to leave his work intact, subsequent
commits will make some larger changes, but I didn't want to intermix
them with Alex's work.

One such commit will update the module to use wasmtime 17 which brings
WASI 0.2.0 support.

Signed-off-by: Andrew Clayton <[email protected]>
This is used by the rustfmt program to format Rust code according to the
rules contained in this file.

Currently we just set the line width limit to 80 characters to match our
C code.

Signed-off-by: Andrew Clayton <[email protected]>
Run from the repository root like

  $ rustfmt --edition 2021 src/wasm-wasi-component/src/lib.rs

Also manually fix up some overly long comments.

Signed-off-by: Andrew Clayton <[email protected]>
When Unit receives a request, if the body of that request is greater
than a certain amount (16KiB by default) then it is written to a
temporary file.

When a language module goes to read the request body in such situations
it will end up using read(2).

The wasm-wasi-component language module was failing to properly read
request bodies of around 2GiB or more.

This is because (on Linux at least) read(2) (and other related system
calls) will only read (or write) at most 0x7ffff000 (2,147,479,552)
bytes, this is the case for both 32 and 64-bit systems.

Regardless, it's probably not a good idea doing IO in such large chunks
anyway.

This patch changes the wasm-wasi-component language module to read the
request buffer in 32MiB chunks (this matches the original 'wasm'
language module).

We are still limited to a 4GiB address space and can only upload files a
little under 4GiB.

Signed-off-by: Andrew Clayton <[email protected]>
With the initial port to wasmtime 17 we could no longer use the
'reactor' adaptor but had to switch to the more restrictive 'proxy'
adaptor.

This meant amongst other things (probably) we could no longer access the
filesystem.

Thanks to Joel Dice for pointing out the fix.

With this we can go back to using the 'reactor' adaptor again and things
are back to working as before.

It's worth noting that you can use either the 'proxy' or 'reactor'
adaptor depending on your requirements.

Cc: Joel Dice <[email protected]>
Signed-off-by: Andrew Clayton <[email protected]>
It seems we do want to track this thing. This is just the latest version
that cargo had generated for me.

Cc: Dan Callahan <[email protected]>
Signed-off-by: Andrew Clayton <[email protected]>
This exposes the various WebAssembly Component Model language module
specific options.

The application type is "wasm-wasi-component".

There is a "component" option that is required, this specifies the full
path to the WebAssembly component to be run. This component should be in
binary format, i.e a .wasm file.

There is also currently one optional option

"access"

Due to the sandboxed nature of WebAssembly, by default Wasm
modules/components don't have any access to the underlying filesystem.

There is however a capabilities based mechanism[0] for allowing such
access.

This adds a config option to the 'wasm-wasi-component' application type
(same as for 'wasm');
'access.filesystem' which takes an array of
directory paths that are then made available to the wasm
module/component. This access works recursively, i.e everything under a
specific path is allowed access to.

Example config might look like

  "applications": {
      "my-wasm-component": {
          "type": "wasm-wasi-component",
          "component": "/path/to/component.wasm",
          "access" {
              "filesystem": [
                  "/tmp",
                  "/var/tmp"
              ]
          }
      }
  }

The actual mechanism used allows directories to be mapped differently in
the guest. But at the moment we don't support that and just map say /tmp
to /tmp. This can be revisited if it's something users clamour for.

[0]: <https://github.com/bytecodealliance/wasmtime/blob/main/docs/WASI-capabilities.md>

Signed-off-by: Andrew Clayton <[email protected]>
The indentation uses spaces and not TABs.

Signed-off-by: Andrew Clayton <[email protected]>
Et voila...

  $ ./configure wasm-wasi-component
  configuring wasm-wasi-component module
  Looking for rust compiler ... found.
  Looking for cargo ... found.
   + wasm-wasi-component module: wasm_wasi_component.unit.so
  $ make install
  test -d /opt/unit/sbin          || install -d /opt/unit/sbin
  install -p build/sbin/unitd /opt/unit/sbin/
  test -d /opt/unit/state                 || install -d /opt/unit/state
  test -d /opt/unit               || install -d /opt/unit
  test -d /opt/unit               || install -d /opt/unit
  test -d /opt/unit/share/man/man8                || install -d /opt/unit/sh
man/man8
  install -p -m644 build/share/man/man8/unitd.8           /opt/unit/share/ma
n8/
  make build/src/nxt_unit.o
  make[1]: Entering directory '/home/andrew/src/unit'
  make[1]: 'build/src/nxt_unit.o' is up to date.
  make[1]: Leaving directory '/home/andrew/src/unit'
  cargo build --release --manifest-path src/wasm-wasi-component/Cargo.toml
      Finished release [optimized] target(s) in 0.55s
  install -d /opt/unit/modules
  install -p src/wasm-wasi-component/target/release/libwasm_wasi_component.so \
          /opt/unit/modules/wasm_wasi_component.unit.so

Signed-off-by: Andrew Clayton <[email protected]>
The minimum version required to build wasmtime 17 which is required by
wasm-wasi-component is 1.73.0

But no point not using the latest version.

This also now needs the libclang-dev package installed, we install this
via MODULE_PREBUILD_wasm.

Signed-off-by: Andrew Clayton <[email protected]>
Thus

  $ make build-wasm

will build _both_ the 'wasm' & 'wasm-wasi-component' modules.

Signed-off-by: Andrew Clayton <[email protected]>
This now includes support for the 'wasm-wasi-component' module.

This targets the upcoming 1.32.0 release which is required by
wasm-wasi-component. However of course the 1.32.0 tag doesn't exist yet,
so there will be a small window where this image won't build.

Signed-off-by: Andrew Clayton <[email protected]>
@ac000
Copy link
Member Author

ac000 commented Feb 21, 2024

Rebase with master

$ git range-diff d88048dd...4c558697
 -:  -------- >  1:  bca44630 .mailmap: Map Dylan's GitHub address
 1:  c08897dd =  2:  f2e64475 Wasm-wc: Register a new Wasm component model language module type
 2:  525a08c8 =  3:  f0782722 Wasm-wc: Add core configuration data structure
 3:  c5062444 =  4:  20ada4b5 Wasm-wc: Core of initial Wasm component model language module support
 4:  3127eb2d =  5:  a9345dd4 Add a .rustfmt.toml file
 5:  6bdd0660 =  6:  79c81772 Wasm-wc: Run src/lib.rs through rustfmt
 6:  3f6f0090 =  7:  ac3a54d6 Wasm-wc: Improve request buffer handling
 7:  9edb7e8e =  8:  98f808af Wasm-wc: Upgrade to wasmtime 17
 8:  31ce7969 =  9:  60eb6c43 Wasm-wc: Allow to use the 'reactor' adaptor again
 9:  92313ec3 = 10:  8d030139 Wasm-wc: Add Cargo.lock
10:  a284a112 = 11:  07a0c9a3 Wasm-wc: Wire up the language module to the config system
11:  d8deb2eb = 12:  da44dc00 Fix alignment of wasm options text in auto/help
12:  fd751c46 = 13:  4e6d7e87 Wasm-wc: Wire it up to the build system
13:  4119a1f3 = 14:  7702293d Docker: Bump rust version to 1.76.0
14:  c73edc92 = 15:  1297f6f0 Docker: Add wasm-wasi-component to the wasm target
15:  d88048dd = 16:  4c558697 Docker: Re-generate Dockerfile.wasm

@ac000 ac000 merged commit 4c55869 into nginx:master Feb 21, 2024
15 checks passed
@ac000 ac000 deleted the wasm-wasi-component branch February 22, 2024 01:21
@tippexs
Copy link
Contributor

tippexs commented Feb 22, 2024

Without libclang-dev, the error occurs when cargo build attempts to run our custom build.rs. Looks like it's required for bindgen. Full output:

error: failed to run custom build command for `wasm-wasi-component v0.1.0 (/usr/src/unit/unit/src/wasm-wasi-component)`

Caused by:
  process didn't exit successfully: `/usr/src/unit/unit/src/wasm-wasi-component/target/release/build/wasm-wasi-component-970591f24f7a8dbb/build-script-build` (exit status: 101)
  --- stdout
  cargo:rerun-if-changed=wrapper.h
  cargo:rerun-if-env-changed=TARGET
  cargo:rerun-if-env-changed=BINDGEN_EXTRA_CLANG_ARGS_aarch64-unknown-linux-gnu
  cargo:rerun-if-env-changed=BINDGEN_EXTRA_CLANG_ARGS_aarch64_unknown_linux_gnu
  cargo:rerun-if-env-changed=BINDGEN_EXTRA_CLANG_ARGS

  --- stderr
  thread 'main' panicked at /usr/src/unit/cargo/registry/src/index.crates.io-6f17d22bba15001f/bindgen-0.68.1/lib.rs:611:31:
  Unable to find libclang: "couldn't find any valid shared libraries matching: ['libclang.so', 'libclang-*.so', 'libclang.so.*', 'libclang-*.so.*'], set the `LIBCLANG_PATH` environment variable to a path where one of these files can be found (invalid: [])"
  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
make: *** [build/Makefile:1945: build/lib/unit/modules/wasm_wasi_component.unit.so] Error 101
Error: building at STEP "RUN set -ex     && savedAptMark="$(apt-mark showmanual)"     && apt-get update     && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config     && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules     && mkdir -p /usr/src/unit     && cd /usr/src/unit     && git clone --depth 1 -b wasm-wasi-component https://github.com/ac000/unit     && cd unit     && NCPU="$(getconf _NPROCESSORS_ONLN)"     && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)"     && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)"     && LD_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_LDFLAGS_MAINT_APPEND="-Wl,--as-needed -pie" dpkg-buildflags --get LDFLAGS)"     && CONFIGURE_ARGS_MODULES="--prefix=/usr                 --statedir=/var/lib/unit                 --control=unix:/var/run/control.unit.sock                 --runstatedir=/var/run                 --pid=/var/run/unit.pid                 --logdir=/var/log                 --log=/var/log/unit.log                 --tmpdir=/var/tmp                 --user=unit                 --group=unit                 --openssl                 --libdir=/usr/lib/$DEB_HOST_MULTIARCH"     && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES                 --njs"     && make -j $NCPU -C pkg/contrib .njs     && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build     && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug     && make -j $NCPU unitd     && install -pm755 build/sbin/unitd /usr/sbin/unitd-debug     && make clean     && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/modules     && make -j $NCPU unitd     && install -pm755 build/sbin/unitd /usr/sbin/unitd     && make clean     && export RUST_VERSION=1.76.0     && export RUSTUP_HOME=/usr/src/unit/rustup     && export CARGO_HOME=/usr/src/unit/cargo     && export PATH=/usr/src/unit/cargo/bin:$PATH     && dpkgArch="$(dpkg --print-architecture)"     && case "${dpkgArch##*-}" in        amd64) rustArch="x86_64-unknown-linux-gnu"; rustupSha256="0b2f6c8f85a3d02fde2efc0ced4657869d73fccfce59defb4e8d29233116e6db" ;;        arm64) rustArch="aarch64-unknown-linux-gnu"; rustupSha256="673e336c81c65e6b16dcdede33f4cc9ed0f08bde1dbe7a935f113605292dc800" ;;        *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;;     esac     && url="https://static.rust-lang.org/rustup/archive/1.26.0/${rustArch}/rustup-init"     && curl -L -O "$url"     && echo "${rustupSha256} *rustup-init" | sha256sum -c -     && chmod +x rustup-init     && ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host ${rustArch}     && rm rustup-init     && rustup --version     && cargo --version     && rustc --version     && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug     && ./configure wasm-wasi-component     && make -j $NCPU wasm-wasi-component-install     && make clean     && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/modules     && ./configure wasm-wasi-component     && make -j $NCPU wasm-wasi-component-install     && cd     && rm -rf /usr/src/unit     && for f in /usr/sbin/unitd /usr/lib/unit/modules/*.unit.so; do         ldd $f | awk '/=>/{print $(NF-1)}' | while read n; do dpkg-query -S $n; done | sed 's/^\([^:]\+\):.*$/\1/' | sort | uniq >> /requirements.apt;        done     && apt-mark showmanual | xargs apt-mark auto > /dev/null     && { [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; }     && /bin/true     && mkdir -p /var/lib/unit/     && mkdir -p /docker-entrypoint.d/     && groupadd --gid 999 unit     && useradd          --uid 999          --gid unit          --no-create-home          --home /nonexistent          --comment "unit user"          --shell /bin/false          unit     && apt-get update     && apt-get --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt)     && apt-get purge -y --auto-remove build-essential     && rm -rf /var/lib/apt/lists/*     && rm -f /requirements.apt     && ln -sf /dev/stderr /var/log/unit.log": while running runtime: exit status 2

make: *** [Makefile:155: build-wasm_wasi_component] Error 2

Edit: Yep, from the bindgen docs

bindgen leverages libclang to preprocess, parse, and type check C and C++ header files. It is required to use Clang 5.0 or greater.

Thanks! This one felt of my radar! I will make sure we adding this to the build from source docs!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants