Skip to content

Commit

Permalink
Add aws-smithy-wasm crate with WASI http client (#3409)
Browse files Browse the repository at this point in the history
## Motivation and Context
<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here -->
This change adds a new crate, `aws-smithy-wasm`, that exports a SDK
compatible WASI http client. This is a continuation of the work in #2520
using the now stabilized WASI 0.2.0 interfaces from the [wasi
crate](https://crates.io/crates/wasi). This supports, but does not
finalize the work for #2087

## Description
<!--- Describe your changes in detail -->

Add a new crate, `aws-smithy-wasm` which exports a function
`wasi_http_client` that will provide the user with a WASI compatible
http client. This client is implemented by using the
`wasi::http::outgoing_handler`
[ref](https://docs.rs/wasi/0.12.0+wasi-0.2.0/wasi/http/outgoing_handler/index.html)
along with some utility implementations of `TryFrom` to transform back
and worth between the types from the `http` crate and the `wasi::http`
types. It also exports a unit struct `WasmSleep` that impls the
`AsyncSleep` trait needed by the SDK.

## Testing
<!--- Please describe in detail how you tested your changes -->
<!--- Include details of your testing environment, and the tests you ran
to -->
<!--- see how your change affects other areas of the code, etc. -->
This is tested via an integration test in
`aws/sdk/integration-tests/webassembly` that uses the wasi http-client
to vuild a config and an operation (that is not sent). It is further
tested in a new canary (`wasm_canary`) that calls the S3
`list_objects_v2` API.

## Checklist
<!--- If a checkbox below is not applicable, then please DELETE it
rather than leaving it unchecked -->
- [X] I have updated `CHANGELOG.next.toml` if I made changes to the
smithy-rs codegen or runtime crates

----

_By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice._

---------

Co-authored-by: Eduardo Rodrigues <eduardomourar@users.noreply.github.com>
Co-authored-by: Eduardo de Moura Rodrigues <16357187+eduardomourar@users.noreply.github.com>
Co-authored-by: ysaito1001 <awsaito@amazon.com>
Co-authored-by: John DiSanti <jdisanti@amazon.com>
Co-authored-by: Russell Cohen <rcoh@amazon.com>
Co-authored-by: John DiSanti <john@vinylsquid.com>
  • Loading branch information
7 people authored Feb 27, 2024
1 parent 5b9d0c0 commit d95cc86
Show file tree
Hide file tree
Showing 35 changed files with 2,371 additions and 152 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.next.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,15 @@ message = "EKS Pod Identity is now supported as part of the default ECS credenti
references = ["smithy-rs#3416"]
meta = { "breaking" = false, "bug" = false, "tada" = true }
author = "jackkleeman"

[[aws-sdk-rust]]
message = "Added aws-smithy-wasm crate to enable SDK use in WASI compliant environments"
references = ["smithy-rs#2087", "smithy-rs#2520", "smithy-rs#3409", "aws-sdk-rust#59"]
meta = { "breaking" = false, "tada" = true, "bug" = false }
author = "landonxjames"

[[smithy-rs]]
message = "Added aws-smithy-wasm crate to enable SDK use in WASI compliant environments"
references = ["smithy-rs#2087", "smithy-rs#2520", "smithy-rs#3409"]
meta = { "breaking" = false, "tada" = true, "bug" = false, "target" = "client"}
author = "landonxjames"
5 changes: 4 additions & 1 deletion aws/rust-runtime/aws-config/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
[package]
name = "aws-config"
version = "0.0.0-smithy-rs-head"
authors = ["AWS Rust SDK Team <aws-sdk-rust@amazon.com>", "Russell Cohen <rcoh@amazon.com>"]
authors = [
"AWS Rust SDK Team <aws-sdk-rust@amazon.com>",
"Russell Cohen <rcoh@amazon.com>",
]
description = "AWS SDK config and credential provider implementations."
edition = "2021"
exclude = ["test-data/*", "integration-tests/*"]
Expand Down
1 change: 1 addition & 0 deletions aws/sdk/integration-tests/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
Cargo.lock
target/
webassembly/src/bindings.rs
8 changes: 7 additions & 1 deletion aws/sdk/integration-tests/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ for f in *; do
echo
echo "Testing ${f}..."
echo "###############"
cargo test --manifest-path "${f}/Cargo.toml" --all-features
if [ "$f" != "webassembly" ]; then
cargo test --manifest-path "${f}/Cargo.toml" --all-features
else
# The webassembly tests use a custom runner set in config.toml that
# is not picked up when running the tests outside of the package
cd webassembly && cargo component test --all-features --all-targets && cd ..
fi
fi
done
6 changes: 6 additions & 0 deletions aws/sdk/integration-tests/webassembly/.cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,9 @@ target = "wasm32-wasi"

[target.wasm32-wasi]
rustflags = ["-C", "opt-level=1"]
runner = [
"wasmtime",
"-C", "cache=n",
"-S", "preview2=y",
"-S", "http=y"
]
34 changes: 25 additions & 9 deletions aws/sdk/integration-tests/webassembly/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
[package]
name = "webassembly"
version = "0.1.0"
authors = ["Eduardo Rodrigues <16357187+eduardomourar@users.noreply.github.com>"]
authors = [
"Eduardo Rodrigues <16357187+eduardomourar@users.noreply.github.com>",
]
description = """
These tests ensure that things will fail (or not fail) as expected
when target is set to wasm32-wasi for all SDK and runtime crates.
Expand All @@ -12,20 +14,34 @@ license = "Apache-2.0"
repository = "https://github.com/smithy-lang/smithy-rs"
publish = false

[lib]
crate-type = ["cdylib"]

[features]
default = ["test-util"]
test-util = []
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
aws-config = { path = "../../build/aws-sdk/sdk/aws-config", default-features = false, features = ["rt-tokio", "behavior-version-latest"]}
[target.'cfg(target_family = "wasm")'.dependencies]
aws-config = { path = "../../build/aws-sdk/sdk/aws-config", default-features = false, features = [
"rt-tokio",
"behavior-version-latest"
] }
aws-credential-types = { path = "../../build/aws-sdk/sdk/aws-credential-types", features = ["hardcoded-credentials"] }
aws-sdk-s3 = { path = "../../build/aws-sdk/sdk/s3", default-features = false }
aws-smithy-http = { path = "../../build/aws-sdk/sdk/aws-smithy-http" }
aws-smithy-runtime = { path = "../../build/aws-sdk/sdk/aws-smithy-runtime", features = ["client"] }
aws-smithy-runtime-api = { path = "../../build/aws-sdk/sdk/aws-smithy-runtime-api", features = ["client"] }
aws-smithy-types = { path = "../../build/aws-sdk/sdk/aws-smithy-types" }
aws-types = { path = "../../build/aws-sdk/sdk/aws-types" }
http = "0.2.8"
tokio = { version = "1.24.2", features = ["macros", "rt"] }
tower = "0.4.13"
aws-smithy-wasm = { path = "../../build/aws-sdk/sdk/aws-smithy-wasm" }
http = "0.2.9"
tokio = { version = "1.32.0", features = ["macros", "rt"] }

[target.'cfg(all(target_family = "wasm", target_os = "wasi"))'.dependencies]
wit-bindgen = { version = "0.16.0", features = ["macros", "realloc"] }


[lib]
crate-type = ["cdylib"]

# metadata used by cargo-component to identify which wit world to embed in the binary
[package.metadata.component]
package = "aws:component"
32 changes: 0 additions & 32 deletions aws/sdk/integration-tests/webassembly/src/default_config.rs

This file was deleted.

62 changes: 0 additions & 62 deletions aws/sdk/integration-tests/webassembly/src/http.rs

This file was deleted.

54 changes: 54 additions & 0 deletions aws/sdk/integration-tests/webassembly/src/http_client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

use aws_config::retry::RetryConfig;
use aws_sdk_s3::operation::list_objects_v2::builders::ListObjectsV2FluentBuilder;
use aws_sdk_s3::Client;
use aws_smithy_types::timeout::TimeoutConfig;
use aws_smithy_wasm::wasi::WasiHttpClientBuilder;

pub(crate) async fn get_default_wasi_config() -> aws_config::SdkConfig {
let http_client = WasiHttpClientBuilder::new().build();
aws_config::from_env()
.region("us-east-2")
.timeout_config(TimeoutConfig::disabled())
.retry_config(RetryConfig::disabled())
.no_credentials()
.http_client(http_client)
.load()
.await
}

#[tokio::test]
pub async fn test_default_config() {
let shared_config = get_default_wasi_config().await;
let client = aws_sdk_s3::Client::new(&shared_config);
assert_eq!(client.config().region().unwrap().to_string(), "us-east-2")
}

async fn s3_list_objects_operation() -> ListObjectsV2FluentBuilder {
let shared_config = get_default_wasi_config().await;
let client = Client::new(&shared_config);
let operation = client
.list_objects_v2()
.bucket("nara-national-archives-catalog")
.delimiter("/")
.prefix("authority-records/organization/")
.max_keys(5);

operation
}

// Test constructing an operation using an SdkConfig with a WASI http client
// We do not send the request to keep these tests sandboxable, a full test of
// the client is in the SDK canary.
#[tokio::test]
pub async fn test_operation_construction() {
let operation = s3_list_objects_operation().await;
assert_eq!(
operation.get_bucket(),
&Some("nara-national-archives-catalog".to_string())
);
}
12 changes: 5 additions & 7 deletions aws/sdk/integration-tests/webassembly/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@
* SPDX-License-Identifier: Apache-2.0
*/

mod default_config;
mod http;
mod list_buckets;
#![allow(dead_code)]

#[tokio::main(flavor = "current_thread")]
pub async fn main() {
crate::list_buckets::s3_list_buckets().await
}
#[cfg(target_family = "wasm")]
mod http_client;
#[cfg(all(target_family = "wasm", target_os = "wasi"))]
mod wasi;
20 changes: 0 additions & 20 deletions aws/sdk/integration-tests/webassembly/src/list_buckets.rs

This file was deleted.

32 changes: 32 additions & 0 deletions aws/sdk/integration-tests/webassembly/src/wasi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

// Needed for WASI-compliant environment as it expects specific functions
// to be exported such as `cabi_realloc`, `_start`, etc.

wit_bindgen::generate!({
inline: "
package aws:component;
interface run {
run: func() -> result;
}
world main {
export run;
}
",
exports: {
"aws:component/run": Component
}
});

struct Component;

impl exports::aws::component::run::Guest for Component {
fn run() -> Result<(), ()> {
Ok(())
}
}
1 change: 1 addition & 0 deletions buildSrc/src/main/kotlin/CrateSet.kt
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ object CrateSet {
"aws-smithy-runtime-api",
"aws-smithy-types",
"aws-smithy-types-convert",
"aws-smithy-wasm",
"aws-smithy-xml",
).map { Crate(it, version(it)) }

Expand Down
1 change: 1 addition & 0 deletions rust-runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ members = [
"aws-smithy-runtime-api",
"aws-smithy-types",
"aws-smithy-types-convert",
"aws-smithy-wasm",
"aws-smithy-mocks-experimental",
"aws-smithy-xml",
]
29 changes: 29 additions & 0 deletions rust-runtime/aws-smithy-wasm/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[package]
name = "aws-smithy-wasm"
version = "0.1.0"
authors = [
"AWS Rust SDK Team <aws-sdk-rust@amazon.com>",
"Eduardo Rodrigues <16357187+eduardomourar@users.noreply.github.com>",
]
description = "Smithy WebAssembly configuration for smithy-rs."
edition = "2021"
license = "Apache-2.0"
repository = "https://github.com/awslabs/smithy-rs"

[dependencies]
aws-smithy-runtime-api = { path = "../aws-smithy-runtime-api", features = ["http-1x"]}
aws-smithy-http = { path = "../aws-smithy-http" }
aws-smithy-types = { path = "../aws-smithy-types" }
bytes = "1"
http = "1.0.0"
tracing = "0.1.40"
# Note the wasi crate will only build for target wasm32-wasi, but having a target
# statement here breaks some of the CI tests, so we leave it with the rest of the deps
wasi = "0.12.0+wasi-0.2.0"

[package.metadata.docs.rs]
all-features = true
targets = ["x86_64-unknown-linux-gnu"]
cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"]
rustdoc-args = ["--cfg", "docsrs"]
# End of docs.rs metadata
Loading

0 comments on commit d95cc86

Please sign in to comment.