diff --git a/containerd-shim-spin-v1/Cargo.lock b/containerd-shim-spin-v1/Cargo.lock index fc986ed3..9ee0d244 100644 --- a/containerd-shim-spin-v1/Cargo.lock +++ b/containerd-shim-spin-v1/Cargo.lock @@ -755,6 +755,7 @@ dependencies = [ "spin-core", "spin-loader", "spin-manifest", + "spin-redis-engine", "spin-trigger", "spin-trigger-http", "tokio", @@ -2987,7 +2988,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "059a34f111a9dee2ce1ac2826a68b24601c4298cfeb1a587c3cb493d5ab46f52" dependencies = [ "libc", - "nix 0.26.2", + "nix 0.22.3", ] [[package]] @@ -3996,6 +3997,23 @@ dependencies = [ "toml", ] +[[package]] +name = "spin-redis-engine" +version = "1.4.0" +source = "git+https://github.com/fermyon/spin?tag=v1.4.0#7aab1fe43be70a271ba6336b959cd52191fc2253" +dependencies = [ + "anyhow", + "async-trait", + "futures", + "redis", + "serde", + "spin-app", + "spin-core", + "spin-trigger", + "spin-world", + "tracing", +] + [[package]] name = "spin-sqlite" version = "1.4.0" @@ -4613,7 +4631,7 @@ version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ - "cfg-if 1.0.0", + "cfg-if 0.1.10", "rand 0.8.5", "static_assertions", ] diff --git a/containerd-shim-spin-v1/Cargo.toml b/containerd-shim-spin-v1/Cargo.toml index 6c7ae9fc..2c6a23a6 100644 --- a/containerd-shim-spin-v1/Cargo.toml +++ b/containerd-shim-spin-v1/Cargo.toml @@ -20,6 +20,7 @@ spin-trigger = { git = "https://github.com/fermyon/spin", tag = "v1.4.0" } spin-app = { git = "https://github.com/fermyon/spin", tag = "v1.4.0" } spin-core = { git = "https://github.com/fermyon/spin", tag = "v1.4.0" } spin-trigger-http = { git = "https://github.com/fermyon/spin", tag = "v1.4.0" } +spin-redis-engine = { git = "https://github.com/fermyon/spin", tag = "v1.4.0" } spin-loader = { git = "https://github.com/fermyon/spin", tag = "v1.4.0" } spin-manifest = { git = "https://github.com/fermyon/spin", tag = "v1.4.0" } wasmtime = "10.0.1" diff --git a/containerd-shim-spin-v1/src/main.rs b/containerd-shim-spin-v1/src/main.rs index 22a67f44..a7409cfe 100644 --- a/containerd-shim-spin-v1/src/main.rs +++ b/containerd-shim-spin-v1/src/main.rs @@ -1,8 +1,10 @@ +use std::future::Future; use std::net::SocketAddr; use std::net::ToSocketAddrs; use std::option::Option; use std::path::Path; use std::path::PathBuf; +use std::pin::Pin; use std::sync::mpsc::channel; use std::sync::mpsc::Sender; use std::sync::{Arc, Condvar, Mutex}; @@ -19,6 +21,7 @@ use containerd_shim_wasm::sandbox::{ use log::info; use reqwest::Url; use spin_manifest::Application; +use spin_redis_engine::RedisTrigger; use spin_trigger::{loader, RuntimeConfig, TriggerExecutor, TriggerExecutorBuilder}; use spin_trigger_http::HttpTrigger; use tokio::runtime::Runtime; @@ -61,13 +64,16 @@ impl Wasi { Ok(spin_loader::from_file(mod_path, Some(working_dir)).await?) } - async fn build_spin_trigger( + async fn build_spin_trigger( working_dir: PathBuf, app: Application, stdout_pipe_path: PathBuf, stderr_pipe_path: PathBuf, stdin_pipe_path: PathBuf, - ) -> Result { + ) -> Result + where + for<'de> ::TriggerConfig: serde::de::Deserialize<'de>, + { // Build and write app lock file let locked_app = spin_trigger::locked::build_locked_app(app, &working_dir)?; let locked_path = working_dir.join("spin.lock"); @@ -155,26 +161,6 @@ impl Instance for Wasi { } }; - info!(" >>> building spin trigger"); - let http_trigger = match Wasi::build_spin_trigger( - working_dir, - app, - PathBuf::from(stdout), - PathBuf::from(stderr), - PathBuf::from(stdin), - ) - .await - { - Ok(http_trigger) => http_trigger, - Err(err) => { - tx.send(Err(Error::Others(format!( - "could not build spin trigger: {err}" - )))) - .unwrap(); - return; - } - }; - let rx_future = tokio::task::spawn_blocking(move || { let (lock, cvar) = &*shutdown_signal; let mut shutdown = lock.lock().unwrap(); @@ -183,12 +169,64 @@ impl Instance for Wasi { } }); - info!(" >>> running spin trigger"); - let f = http_trigger.run(spin_trigger_http::CliArgs { - address: parse_addr(SPIN_ADDR).unwrap(), - tls_cert: None, - tls_key: None, - }); + let trigger = app.info.trigger.clone(); + info!(" >>> building spin trigger {:?}", trigger); + + let f: Pin> + Send>>; + + match trigger { + spin_manifest::ApplicationTrigger::Http(_config) => { + let http_trigger: HttpTrigger = match Wasi::build_spin_trigger( + working_dir, + app, + PathBuf::from(stdout), + PathBuf::from(stderr), + PathBuf::from(stdin), + ) + .await + { + Ok(http_trigger) => http_trigger, + Err(err) => { + tx.send(Err(Error::Others(format!( + "could not build spin trigger: {err}" + )))) + .unwrap(); + return; + } + }; + + info!(" >>> running spin trigger"); + f = http_trigger.run(spin_trigger_http::CliArgs { + address: parse_addr(SPIN_ADDR).unwrap(), + tls_cert: None, + tls_key: None, + }); + } + spin_manifest::ApplicationTrigger::Redis(_config) => { + let redis_trigger: RedisTrigger = match Wasi::build_spin_trigger( + working_dir, + app, + PathBuf::from(stdout), + PathBuf::from(stderr), + PathBuf::from(stdin), + ) + .await + { + Ok(redis_trigger) => redis_trigger, + Err(err) => { + tx.send(Err(Error::Others(format!( + "could not build spin trigger: {err}" + )))) + .unwrap(); + return; + } + }; + + info!(" >>> running spin trigger"); + f = redis_trigger.run(spin_trigger::cli::NoArgs); + } + _ => todo!("Only Http and Redis triggers are currently supported."), + } info!(" >>> notifying main thread we are about to start"); tx.send(Ok(())).unwrap(); diff --git a/images/spin-inbound-redis/Cargo.lock b/images/spin-inbound-redis/Cargo.lock new file mode 100644 index 00000000..88b851fb --- /dev/null +++ b/images/spin-inbound-redis/Cargo.lock @@ -0,0 +1,361 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" + +[[package]] +name = "async-trait" +version = "0.1.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86ea188f25f0255d8f92797797c97ebf5631fa88178beb1a46fdf5622c9a00e4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.4", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "http" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "id-arena" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" + +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + +[[package]] +name = "proc-macro2" +version = "1.0.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pulldown-cmark" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8" +dependencies = [ + "bitflags", + "memchr", + "unicase", +] + +[[package]] +name = "quote" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "routefinder" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94f8f99b10dedd317514253dda1fa7c14e344aac96e1f78149a64879ce282aca" +dependencies = [ + "smartcow", + "smartstring", +] + +[[package]] +name = "smartcow" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "656fcb1c1fca8c4655372134ce87d8afdf5ec5949ebabe8d314be0141d8b5da2" +dependencies = [ + "smartstring", +] + +[[package]] +name = "smartstring" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" +dependencies = [ + "autocfg", + "static_assertions", + "version_check", +] + +[[package]] +name = "spin-inbound-redis" +version = "0.1.0" +dependencies = [ + "anyhow", + "bytes", + "http", + "spin-sdk", + "wit-bindgen-rust", +] + +[[package]] +name = "spin-macro" +version = "0.1.0" +source = "git+https://github.com/fermyon/spin?tag=v1.3.0#9fb8256d1380a046414b22bf2c17d1543f5029e4" +dependencies = [ + "anyhow", + "bytes", + "http", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "spin-sdk" +version = "1.3.0" +source = "git+https://github.com/fermyon/spin?tag=v1.3.0#9fb8256d1380a046414b22bf2c17d1543f5029e4" +dependencies = [ + "anyhow", + "bytes", + "form_urlencoded", + "http", + "routefinder", + "spin-macro", + "thiserror", + "wit-bindgen-rust", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c622ae390c9302e214c31013517c2061ecb2699935882c60a9b37f82f8625ae" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.4", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wit-bindgen-gen-core" +version = "0.2.0" +source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=cb871cfa1ee460b51eb1d144b175b9aab9c50aba#cb871cfa1ee460b51eb1d144b175b9aab9c50aba" +dependencies = [ + "anyhow", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-gen-rust" +version = "0.2.0" +source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=cb871cfa1ee460b51eb1d144b175b9aab9c50aba#cb871cfa1ee460b51eb1d144b175b9aab9c50aba" +dependencies = [ + "heck", + "wit-bindgen-gen-core", +] + +[[package]] +name = "wit-bindgen-gen-rust-wasm" +version = "0.2.0" +source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=cb871cfa1ee460b51eb1d144b175b9aab9c50aba#cb871cfa1ee460b51eb1d144b175b9aab9c50aba" +dependencies = [ + "heck", + "wit-bindgen-gen-core", + "wit-bindgen-gen-rust", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.2.0" +source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=cb871cfa1ee460b51eb1d144b175b9aab9c50aba#cb871cfa1ee460b51eb1d144b175b9aab9c50aba" +dependencies = [ + "async-trait", + "bitflags", + "wit-bindgen-rust-impl", +] + +[[package]] +name = "wit-bindgen-rust-impl" +version = "0.2.0" +source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=cb871cfa1ee460b51eb1d144b175b9aab9c50aba#cb871cfa1ee460b51eb1d144b175b9aab9c50aba" +dependencies = [ + "proc-macro2", + "syn 1.0.109", + "wit-bindgen-gen-core", + "wit-bindgen-gen-rust-wasm", +] + +[[package]] +name = "wit-parser" +version = "0.2.0" +source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=cb871cfa1ee460b51eb1d144b175b9aab9c50aba#cb871cfa1ee460b51eb1d144b175b9aab9c50aba" +dependencies = [ + "anyhow", + "id-arena", + "pulldown-cmark", + "unicode-normalization", + "unicode-xid", +] diff --git a/images/spin-inbound-redis/Cargo.toml b/images/spin-inbound-redis/Cargo.toml new file mode 100644 index 00000000..0867eb35 --- /dev/null +++ b/images/spin-inbound-redis/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "spin-inbound-redis" +version = "0.1.0" +authors = ["Suneet Nangia "] +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +anyhow = "1" +bytes = "1" +http = "0.2" +# Do not change spin sdk version without testing the e2e. +spin-sdk = { git = "https://github.com/fermyon/spin", tag = "v1.3.0" } +wit-bindgen-rust = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "cb871cfa1ee460b51eb1d144b175b9aab9c50aba" } + +[workspace] + +[profile.release] +strip = true \ No newline at end of file diff --git a/images/spin-inbound-redis/Dockerfile b/images/spin-inbound-redis/Dockerfile new file mode 100644 index 00000000..f8f1d916 --- /dev/null +++ b/images/spin-inbound-redis/Dockerfile @@ -0,0 +1,8 @@ +FROM --platform=${BUILDPLATFORM} rust:1.70 AS build +WORKDIR /opt/build +COPY . . +RUN rustup target add wasm32-wasi && cargo build --target wasm32-wasi --release + +FROM scratch +COPY --from=build /opt/build/target/wasm32-wasi/release/spin_inbound_redis.wasm . +COPY --from=build /opt/build/spin.toml . \ No newline at end of file diff --git a/images/spin-inbound-redis/spin.toml b/images/spin-inbound-redis/spin.toml new file mode 100644 index 00000000..ee480220 --- /dev/null +++ b/images/spin-inbound-redis/spin.toml @@ -0,0 +1,13 @@ +spin_version = "1" +authors = ["Suneet Nangia "] +name = "spin-hello" +trigger = { type = "redis", address = "redis:/localhost:6379" } +version = "1.0.0" + +[[component]] +environment = { REDIS_ADDRESS = "redis://localhost:6379", REDIS_CHANNEL = "messages-out" } +id = "hello" +source = "spin_inbound_redis.wasm" +allowed_http_hosts = [] +[component.trigger] +channel = "messages-in" \ No newline at end of file diff --git a/images/spin-inbound-redis/src/lib.rs b/images/spin-inbound-redis/src/lib.rs new file mode 100644 index 00000000..9fa440cd --- /dev/null +++ b/images/spin-inbound-redis/src/lib.rs @@ -0,0 +1,23 @@ +use anyhow::Result; +use bytes::Bytes; +use spin_sdk::redis_component; +use std::str::from_utf8; +use spin_sdk::redis; + +const REDIS_ADDRESS_ENV: &str = "REDIS_ADDRESS"; +const REDIS_CHANNEL_ENV: &str = "REDIS_CHANNEL"; + +/// A simple Spin Redis component. +#[redis_component] +fn on_message(message: Bytes) -> Result<()> { + + let address = std::env::var(REDIS_ADDRESS_ENV)?; + let channel = std::env::var(REDIS_CHANNEL_ENV)?; + + println!("{}", from_utf8(&message)?); + + // Publish to Redis + redis::publish(&address, &channel, &message).unwrap(); + + Ok(()) +}