Skip to content

Commit

Permalink
Change the default runtime mode to orchestrator (#2847)
Browse files Browse the repository at this point in the history
This PR changes the default runtime mode to orchestrator for generated
clients and the AWS SDK.

----

_By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice._
  • Loading branch information
jdisanti authored Jul 20, 2023
1 parent f310668 commit 25abe5a
Show file tree
Hide file tree
Showing 67 changed files with 1,315 additions and 415 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ jobs:
test:
- action: check-aws-sdk-adhoc-tests
runner: ubuntu-latest
# TODO(enableNewSmithyRuntimeCleanup): Remove `check-aws-sdk-orchestrator-impl` when cleaning up middleware
- action: check-aws-sdk-orchestrator-impl
# TODO(enableNewSmithyRuntimeCleanup): Remove `check-aws-sdk-middleware-impl` when cleaning up middleware
- action: check-aws-sdk-middleware-impl
runner: smithy_ubuntu-latest_8-core
- action: check-client-codegen-integration-tests
runner: smithy_ubuntu-latest_8-core
Expand Down
2 changes: 1 addition & 1 deletion aws/rust-runtime/aws-config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ tokio = { version = "1.13.1", features = ["sync"] }
tracing = { version = "0.1" }

# implementation detail of IMDS credentials provider
fastrand = "1"
fastrand = "2.0.0"

bytes = "1.1.0"
http = "0.2.4"
Expand Down
9 changes: 6 additions & 3 deletions aws/rust-runtime/aws-config/src/connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@

use aws_smithy_client::erase::DynConnector;

// unused when all crate features are disabled
/// Unwrap an [`Option<DynConnector>`](aws_smithy_client::erase::DynConnector), and panic with a helpful error message if it's `None`
pub(crate) fn expect_connector(connector: Option<DynConnector>) -> DynConnector {
connector.expect("No HTTP connector was available. Enable the `rustls` crate feature or set a connector to fix this.")
pub(crate) fn expect_connector(for_what: &str, connector: Option<DynConnector>) -> DynConnector {
if let Some(conn) = connector {
conn
} else {
panic!("{for_what} require(s) a HTTP connector, but none was available. Enable the `rustls` crate feature or set a connector to fix this.")
}
}

#[cfg(feature = "client-hyper")]
Expand Down
5 changes: 4 additions & 1 deletion aws/rust-runtime/aws-config/src/http_credential_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,10 @@ impl Builder {
.read_timeout(DEFAULT_READ_TIMEOUT)
.build()
});
let connector = expect_connector(provider_config.connector(&connector_settings));
let connector = expect_connector(
"The HTTP credentials provider",
provider_config.connector(&connector_settings),
);
let mut client_builder = aws_smithy_client::Client::builder()
.connector(connector)
.middleware(Identity::new());
Expand Down
5 changes: 4 additions & 1 deletion aws/rust-runtime/aws-config/src/imds/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,10 @@ impl Builder {
.read_timeout(self.read_timeout.unwrap_or(DEFAULT_READ_TIMEOUT))
.build();
let connector_settings = ConnectorSettings::from_timeout_config(&timeout_config);
let connector = expect_connector(config.connector(&connector_settings));
let connector = expect_connector(
"The IMDS credentials provider",
config.connector(&connector_settings),
);
let endpoint_source = self
.endpoint
.unwrap_or_else(|| EndpointSource::Env(config.clone()));
Expand Down
2 changes: 1 addition & 1 deletion aws/rust-runtime/aws-config/src/imds/credentials.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ impl ImdsCredentialsProvider {
return expiration;
}

let rng = fastrand::Rng::with_seed(
let mut rng = fastrand::Rng::with_seed(
now.duration_since(SystemTime::UNIX_EPOCH)
.expect("now should be after UNIX EPOCH")
.as_secs(),
Expand Down
2 changes: 1 addition & 1 deletion aws/rust-runtime/aws-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -764,7 +764,7 @@ mod loader {
assert_eq!(Some(&app_name), conf.app_name());
}

#[cfg(aws_sdk_orchestrator_mode)]
#[cfg(all(not(aws_sdk_middleware_mode), feature = "rustls"))]
#[tokio::test]
async fn disable_default_credentials() {
let config = from_env().no_credentials().load().await;
Expand Down
1 change: 1 addition & 0 deletions aws/rust-runtime/aws-config/src/sso.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ impl SsoCredentialsProvider {

let mut sso_config = SsoConfig::builder()
.http_connector(expect_connector(
"The SSO credentials provider",
provider_config.connector(&Default::default()),
))
.retry_config(RetryConfig::standard());
Expand Down
5 changes: 4 additions & 1 deletion aws/rust-runtime/aws-config/src/sts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ use aws_smithy_types::retry::RetryConfig;
impl crate::provider_config::ProviderConfig {
pub(crate) fn sts_client_config(&self) -> StsConfigBuilder {
let mut builder = aws_sdk_sts::Config::builder()
.http_connector(expect_connector(self.connector(&Default::default())))
.http_connector(expect_connector(
"The STS features of aws-config",
self.connector(&Default::default()),
))
.retry_config(RetryConfig::standard())
.region(self.region())
.time_source(self.time_source());
Expand Down
5 changes: 4 additions & 1 deletion aws/rust-runtime/aws-config/src/sts/assume_role.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,10 @@ impl AssumeRoleProviderBuilder {
.credentials_provider(provider)
.time_source(conf.time_source())
.region(self.region.clone())
.http_connector(expect_connector(conf.connector(&Default::default())));
.http_connector(expect_connector(
"The AssumeRole credentials provider",
conf.connector(&Default::default()),
));
config.set_sleep_impl(conf.sleep());

let session_name = self.session_name.unwrap_or_else(|| {
Expand Down
2 changes: 1 addition & 1 deletion aws/rust-runtime/aws-credential-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ test-util = []
[dependencies]
aws-smithy-async = { path = "../../../rust-runtime/aws-smithy-async" }
aws-smithy-types = { path = "../../../rust-runtime/aws-smithy-types" }
fastrand = "1.4.0"
fastrand = "2.0.0"
tokio = { version = "1.23.1", features = ["sync"] }
tracing = "0.1"
zeroize = "1"
Expand Down
3 changes: 2 additions & 1 deletion aws/rust-runtime/aws-runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ aws-smithy-runtime = { path = "../../../rust-runtime/aws-smithy-runtime" }
aws-smithy-runtime-api = { path = "../../../rust-runtime/aws-smithy-runtime-api" }
aws-smithy-types = { path = "../../../rust-runtime/aws-smithy-types" }
aws-types = { path = "../aws-types" }
fastrand = "2.0.0"
http = "0.2.3"
percent-encoding = "2.1.0"
tracing = "0.1"
uuid = { version = "1", features = ["v4", "fast-rng"] }
uuid = { version = "1" }

[dev-dependencies]
aws-credential-types = { path = "../aws-credential-types", features = ["test-util"] }
Expand Down
119 changes: 89 additions & 30 deletions aws/rust-runtime/aws-runtime/src/invocation_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ use aws_smithy_runtime_api::client::interceptors::Interceptor;
use aws_smithy_types::config_bag::{ConfigBag, Storable, StoreReplace};
use http::{HeaderName, HeaderValue};
use std::fmt::Debug;
use uuid::Uuid;

use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents;
use fastrand::Rng;
use std::sync::Mutex;
#[cfg(feature = "test-util")]
pub use test_util::{NoInvocationIdGenerator, PredefinedInvocationIdGenerator};

Expand Down Expand Up @@ -46,10 +47,43 @@ impl Storable for DynInvocationIdGenerator {
type Storer = StoreReplace<Self>;
}

/// An invocation ID generator that uses random UUIDs for the invocation ID.
#[derive(Debug, Default)]
pub struct DefaultInvocationIdGenerator {
rng: Mutex<Rng>,
}

impl DefaultInvocationIdGenerator {
/// Creates a new [`DefaultInvocationIdGenerator`].
pub fn new() -> Self {
Default::default()
}

/// Creates a [`DefaultInvocationIdGenerator`] with the given seed.
pub fn with_seed(seed: u64) -> Self {
Self {
rng: Mutex::new(Rng::with_seed(seed)),
}
}
}

impl InvocationIdGenerator for DefaultInvocationIdGenerator {
fn generate(&self) -> Result<Option<InvocationId>, BoxError> {
let mut rng = self.rng.lock().unwrap();
let mut random_bytes = [0u8; 16];
rng.fill(&mut random_bytes);

let id = uuid::Builder::from_random_bytes(random_bytes).into_uuid();
Ok(Some(InvocationId::new(id.to_string())))
}
}

/// This interceptor generates a UUID and attaches it to all request attempts made as part of this operation.
#[non_exhaustive]
#[derive(Debug, Default)]
pub struct InvocationIdInterceptor {}
pub struct InvocationIdInterceptor {
default: DefaultInvocationIdGenerator,
}

impl InvocationIdInterceptor {
/// Creates a new `InvocationIdInterceptor`
Expand All @@ -65,13 +99,13 @@ impl Interceptor for InvocationIdInterceptor {
_runtime_components: &RuntimeComponents,
cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
let id = cfg
let gen = cfg
.load::<DynInvocationIdGenerator>()
.map(|gen| gen.generate())
.transpose()?
.flatten();
cfg.interceptor_state()
.store_put::<InvocationId>(id.unwrap_or_default());
.map(|gen| gen as &dyn InvocationIdGenerator)
.unwrap_or(&self.default);
if let Some(id) = gen.generate()? {
cfg.interceptor_state().store_put::<InvocationId>(id);
}

Ok(())
}
Expand All @@ -83,10 +117,9 @@ impl Interceptor for InvocationIdInterceptor {
cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
let headers = ctx.request_mut().headers_mut();
let id = cfg
.load::<InvocationId>()
.ok_or("Expected an InvocationId in the ConfigBag but none was present")?;
headers.append(AMZ_SDK_INVOCATION_ID, id.0.clone());
if let Some(id) = cfg.load::<InvocationId>() {
headers.append(AMZ_SDK_INVOCATION_ID, id.0.clone());
}
Ok(())
}
}
Expand All @@ -96,21 +129,15 @@ impl Interceptor for InvocationIdInterceptor {
pub struct InvocationId(HeaderValue);

impl InvocationId {
/// Create a new, random, invocation ID.
pub fn new() -> Self {
Self::default()
}
}

/// Defaults to a random UUID.
impl Default for InvocationId {
fn default() -> Self {
let id = Uuid::new_v4();
let id = id
.to_string()
.parse()
.expect("UUIDs always produce a valid header value");
Self(id)
/// Create an invocation ID with the given value.
///
/// # Panics
/// This constructor will panic if the given invocation ID is not a valid HTTP header value.
pub fn new(invocation_id: String) -> Self {
Self(
HeaderValue::try_from(invocation_id)
.expect("invocation ID must be a valid HTTP header value"),
)
}
}

Expand Down Expand Up @@ -181,14 +208,14 @@ mod test_util {

#[cfg(test)]
mod tests {
use crate::invocation_id::{InvocationId, InvocationIdInterceptor};
use super::*;
use aws_smithy_http::body::SdkBody;
use aws_smithy_runtime_api::client::interceptors::context::{
BeforeTransmitInterceptorContextMut, InterceptorContext,
};
use aws_smithy_runtime_api::client::interceptors::Interceptor;
use aws_smithy_runtime_api::client::runtime_components::RuntimeComponentsBuilder;
use aws_smithy_types::config_bag::ConfigBag;
use aws_smithy_types::config_bag::{ConfigBag, Layer};
use aws_smithy_types::type_erasure::TypeErasedBox;
use http::HeaderValue;

Expand All @@ -200,7 +227,7 @@ mod tests {
}

#[test]
fn test_id_is_generated_and_set() {
fn default_id_generator() {
let rc = RuntimeComponentsBuilder::for_tests().build().unwrap();
let mut ctx = InterceptorContext::new(TypeErasedBox::doesnt_matter());
ctx.enter_serialization_phase();
Expand All @@ -224,4 +251,36 @@ mod tests {
// UUID should include 32 chars and 4 dashes
assert_eq!(header.len(), 36);
}

#[cfg(feature = "test-util")]
#[test]
fn custom_id_generator() {
let rc = RuntimeComponentsBuilder::for_tests().build().unwrap();
let mut ctx = InterceptorContext::new(TypeErasedBox::doesnt_matter());
ctx.enter_serialization_phase();
ctx.set_request(http::Request::builder().body(SdkBody::empty()).unwrap());
let _ = ctx.take_input();
ctx.enter_before_transmit_phase();

let mut cfg = ConfigBag::base();
let mut layer = Layer::new("test");
layer.store_put(DynInvocationIdGenerator::new(
PredefinedInvocationIdGenerator::new(vec![InvocationId::new(
"the-best-invocation-id".into(),
)]),
));
cfg.push_layer(layer);

let interceptor = InvocationIdInterceptor::new();
let mut ctx = Into::into(&mut ctx);
interceptor
.modify_before_retry_loop(&mut ctx, &rc, &mut cfg)
.unwrap();
interceptor
.modify_before_transmit(&mut ctx, &rc, &mut cfg)
.unwrap();

let header = expect_header(&ctx, "amz-sdk-invocation-id");
assert_eq!("the-best-invocation-id", header);
}
}
4 changes: 2 additions & 2 deletions aws/rust-runtime/aws-types/src/sdk_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ impl Builder {
self
}

/// Set the endpoint url to use when making requests.
/// Set the endpoint URL to use when making requests.
/// # Examples
/// ```
/// use aws_types::SdkConfig;
Expand All @@ -128,7 +128,7 @@ impl Builder {
self
}

/// Set the endpoint url to use when making requests.
/// Set the endpoint URL to use when making requests.
pub fn set_endpoint_url(&mut self, endpoint_url: Option<String>) -> &mut Self {
self.endpoint_url = endpoint_url;
self
Expand Down
2 changes: 1 addition & 1 deletion aws/sdk-adhoc-test/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ dependencies {
implementation("software.amazon.smithy:smithy-aws-traits:$smithyVersion")
}

fun getSmithyRuntimeMode(): String = properties.get("smithy.runtime.mode") ?: "middleware"
fun getSmithyRuntimeMode(): String = properties.get("smithy.runtime.mode") ?: "orchestrator"

val allCodegenTests = listOf(
CodegenTest(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
import software.amazon.smithy.rust.codegen.core.rustlang.withBlock
import software.amazon.smithy.rust.codegen.core.rustlang.writable
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.preludeScope
import software.amazon.smithy.rust.codegen.core.smithy.contextName
import software.amazon.smithy.rust.codegen.core.util.cloneOperation
import software.amazon.smithy.rust.codegen.core.util.expectTrait
Expand Down Expand Up @@ -359,17 +360,18 @@ class AwsPresignedFluentBuilderMethod(
val smithyTypes = RuntimeType.smithyTypes(codegenContext.runtimeConfig)
rustTemplate(
"""
##[derive(Debug)]
##[derive(::std::fmt::Debug)]
struct AlternatePresigningSerializerRuntimePlugin;
impl #{RuntimePlugin} for AlternatePresigningSerializerRuntimePlugin {
fn config(&self) -> Option<#{FrozenLayer}> {
fn config(&self) -> #{Option}<#{FrozenLayer}> {
use #{ConfigBagAccessors};
let mut cfg = #{Layer}::new("presigning_serializer");
cfg.set_request_serializer(#{SharedRequestSerializer}::new(#{AlternateSerializer}));
Some(cfg.freeze())
#{Some}(cfg.freeze())
}
}
""",
*preludeScope,
"AlternateSerializer" to alternateSerializer(operationShape),
"ConfigBagAccessors" to RuntimeType.configBagAccessors(runtimeConfig),
"FrozenLayer" to smithyTypes.resolve("config_bag::FrozenLayer"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,12 +195,8 @@ class CredentialCacheConfig(codegenContext: ClientCodegenContext) : ConfigCustom
rustTemplate(
"""
match (
layer
.load::<#{CredentialsCache}>()
.cloned(),
layer
.load::<#{SharedCredentialsProvider}>()
.cloned(),
resolver.config_mut().load::<#{CredentialsCache}>().cloned(),
resolver.config_mut().load::<#{SharedCredentialsProvider}>().cloned(),
) {
(#{None}, #{None}) => {}
(#{None}, _) => {
Expand All @@ -213,7 +209,7 @@ class CredentialCacheConfig(codegenContext: ClientCodegenContext) : ConfigCustom
#{Some}(credentials_cache),
#{Some}(credentials_provider),
) => {
layer.store_put(credentials_cache.create_cache(credentials_provider));
resolver.config_mut().store_put(credentials_cache.create_cache(credentials_provider));
}
}
""",
Expand Down
Loading

0 comments on commit 25abe5a

Please sign in to comment.