Unverified Commit 5f7113f5 authored by Zelda Hessler's avatar Zelda Hessler Committed by GitHub
Browse files

Sourcing service config from the environment. (#3493)

## 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 -->
https://github.com/smithy-lang/smithy-rs/issues/2863
https://github.com/awslabs/aws-sdk-rust/issues/1060

## Description
<!--- Describe your changes in detail -->
This PR adds a new feature: the ability to source service-specific
config from the environment.
This is **only** supported when creating a service config from an
`SdkConfig`. I've posted [a
guide](https://github.com/smithy-lang/smithy-rs/discussions/3537) to our
discussions board.

[This also adds support for setting an endpoint URL in environment
config.](https://github.com/smithy-lang/smithy-rs/issues/2863

)

## 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. -->
I have written several tests ensuring config is extracted with the
correct precedence.

## 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 AWS
SDK, generated SDK code, or SDK 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: default avatarJohn DiSanti <jdisanti@amazon.com>
Co-authored-by: default avatarysaito1001 <awsaito@amazon.com>
parent 8af34495
Loading
Loading
Loading
Loading
+42 −0
Original line number Diff line number Diff line
@@ -22,3 +22,45 @@ message = "Make `BehaviorVersion` be future-proof by disallowing it to be constr
references = ["aws-sdk-rust#1111", "smithy-rs#3513"]
meta = { "breaking" = true, "tada" = false, "bug" = true, "target" = "client" }
author = "Ten0"

[[smithy-rs]]
message = """
Stalled stream protection now supports request upload streams. It is currently off by default, but will be enabled by default in a future release. To enable it now, you can do the following:

```rust
let config = my_service::Config::builder()
    .stalled_stream_protection(StalledStreamProtectionConfig::enabled().build())
    // ...
    .build();
```
"""
references = ["smithy-rs#3485"]
meta = { "breaking" = false, "tada" = true, "bug" = false }
authors = ["jdisanti"]

[[aws-sdk-rust]]
message = """
Stalled stream protection now supports request upload streams. It is currently off by default, but will be enabled by default in a future release. To enable it now, you can do the following:

```rust
let config = aws_config::defaults(BehaviorVersion::latest())
    .stalled_stream_protection(StalledStreamProtectionConfig::enabled().build())
    .load()
    .await;
```
"""
references = ["smithy-rs#3485"]
meta = { "breaking" = false, "tada" = true, "bug" = false }
author = "jdisanti"

[[smithy-rs]]
message = "Stalled stream protection on downloads will now only trigger if the upstream source is too slow. Previously, stalled stream protection could be erroneously triggered if the user was slowly consuming the stream slower than the minimum speed limit."
references = ["smithy-rs#3485"]
meta = { "breaking" = false, "tada" = false, "bug" = true }
authors = ["jdisanti"]

[[aws-sdk-rust]]
message = "Users may now set service-specific configuration in the environment. For more information, see [this discussion topic](https://github.com/smithy-lang/smithy-rs/discussions/3537)."
references = ["smithy-rs#3493"]
meta = { "breaking" = false, "tada" = true, "bug" = false }
author = "Velfi"
+2 −7
Original line number Diff line number Diff line
@@ -35,6 +35,8 @@ aws-smithy-runtime = { path = "../../sdk/build/aws-sdk/sdk/aws-smithy-runtime",
aws-smithy-runtime-api = { path = "../../sdk/build/aws-sdk/sdk/aws-smithy-runtime-api", features = ["client"] }
aws-smithy-types = { path = "../../sdk/build/aws-sdk/sdk/aws-smithy-types" }
aws-types = { path = "../../sdk/build/aws-sdk/sdk/aws-types" }
bytes = "1.1.0"
http = "0.2.4"
hyper = { version = "0.14.26", default-features = false }
time = { version = "0.3.4", features = ["parsing"] }
tokio = { version = "1.13.1", features = ["sync"] }
@@ -44,9 +46,6 @@ url = "2.3.1"
# implementation detail of IMDS credentials provider
fastrand = "2.0.0"

bytes = "1.1.0"
http = "0.2.4"

# implementation detail of SSO credential caching
aws-sdk-sso = { path = "../../sdk/build/aws-sdk/sdk/sso", default-features = false, optional = true }
ring = { version = "0.17.5", optional = true }
@@ -62,12 +61,8 @@ aws-smithy-runtime-api = { path = "../../sdk/build/aws-sdk/sdk/aws-smithy-runtim
futures-util = { version = "0.3.29", default-features = false }
tracing-test = "0.2.4"
tracing-subscriber = { version = "0.3.16", features = ["fmt", "json"] }

tokio = { version = "1.23.1", features = ["full", "test-util"] }

# used for fuzzing profile parsing
arbitrary = "1.3"

# used for test case deserialization
serde = { version = "1", features = ["derive"] }
serde_json = "1"
+9 −1
Original line number Diff line number Diff line
@@ -8,13 +8,21 @@ allowed_external_types = [
   "aws_credential_types::provider::credentials::Result",
   "aws_credential_types::provider::credentials::SharedCredentialsProvider",
   "aws_credential_types::provider::token::ProvideToken",
   "aws_runtime::env_config::error::EnvConfigFileLoadError",
   "aws_runtime::env_config::file::Builder",
   "aws_runtime::env_config::file::EnvConfigFileKind",
   "aws_runtime::env_config::file::EnvConfigFiles",
   "aws_runtime::env_config::parse::EnvConfigParseError",
   "aws_runtime::env_config::property::Property",
   "aws_runtime::env_config::section::EnvConfigSections",
   "aws_runtime::env_config::section::Profile",
   "aws_smithy_async::rt::sleep::AsyncSleep",
   "aws_smithy_async::rt::sleep::SharedAsyncSleep",
   "aws_smithy_async::time::SharedTimeSource",
   "aws_smithy_async::time::TimeSource",
   "aws_smithy_runtime_api::box_error::BoxError",
   "aws_smithy_runtime::client::identity::cache::IdentityCache",
   "aws_smithy_runtime::client::identity::cache::lazy::LazyCacheBuilder",
   "aws_smithy_runtime_api::box_error::BoxError",
   "aws_smithy_runtime_api::client::behavior_version::BehaviorVersion",
   "aws_smithy_runtime_api::client::dns::ResolveDns",
   "aws_smithy_runtime_api::client::dns::SharedDnsResolver",
+19 −11
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@
 */

use crate::provider_config::ProviderConfig;
use crate::standard_property::{PropertyResolutionError, StandardProperty};
use aws_runtime::env_config::{EnvConfigError, EnvConfigValue};
use aws_smithy_types::error::display::DisplayErrorContext;
use aws_types::app_name::{AppName, InvalidAppName};

@@ -56,22 +56,24 @@ impl Builder {
        self
    }

    async fn fallback_app_name(
        &self,
    ) -> Result<Option<AppName>, PropertyResolutionError<InvalidAppName>> {
        StandardProperty::new()
    async fn fallback_app_name(&self) -> Result<Option<AppName>, EnvConfigError<InvalidAppName>> {
        let env = self.provider_config.env();
        let profiles = self.provider_config.profile().await;

        EnvConfigValue::new()
            .profile("sdk-ua-app-id")
            .validate(&self.provider_config, |name| AppName::new(name.to_string()))
            .await
            .validate(&env, profiles, |name| AppName::new(name.to_string()))
    }

    /// Build an [`AppName`] from the default chain
    pub async fn app_name(self) -> Option<AppName> {
        let standard = StandardProperty::new()
        let env = self.provider_config.env();
        let profiles = self.provider_config.profile().await;

        let standard = EnvConfigValue::new()
            .env("AWS_SDK_UA_APP_ID")
            .profile("sdk_ua_app_id")
            .validate(&self.provider_config, |name| AppName::new(name.to_string()))
            .await;
            .validate(&env, profiles, |name| AppName::new(name.to_string()));
        let with_fallback = match standard {
            Ok(None) => self.fallback_app_name().await,
            other => other,
@@ -87,6 +89,7 @@ impl Builder {
#[cfg(test)]
mod tests {
    use super::*;
    #[allow(deprecated)]
    use crate::profile::profile_file::{ProfileFileKind, ProfileFiles};
    use crate::provider_config::ProviderConfig;
    use crate::test_case::{no_traffic_client, InstantSleep};
@@ -123,8 +126,13 @@ mod tests {
            .http_client(no_traffic_client())
            .profile_name("custom")
            .profile_files(
                #[allow(deprecated)]
                ProfileFiles::builder()
                    .with_file(ProfileFileKind::Config, "test_config")
                    .with_file(
                        #[allow(deprecated)]
                        ProfileFileKind::Config,
                        "test_config",
                    )
                    .build(),
            )
            .load()
+13 −5
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@

use crate::environment::parse_url;
use crate::provider_config::ProviderConfig;
use crate::standard_property::StandardProperty;
use aws_runtime::env_config::EnvConfigValue;
use aws_smithy_types::error::display::DisplayErrorContext;

mod env {
@@ -24,11 +24,13 @@ mod profile_key {
///
/// If invalid values are found, the provider will return None and an error will be logged.
pub async fn endpoint_url_provider(provider_config: &ProviderConfig) -> Option<String> {
    StandardProperty::new()
    let env = provider_config.env();
    let profiles = provider_config.profile().await;

    EnvConfigValue::new()
        .env(env::ENDPOINT_URL)
        .profile(profile_key::ENDPOINT_URL)
        .validate(provider_config, parse_url)
        .await
        .validate(&env, profiles, parse_url)
        .map_err(
            |err| tracing::warn!(err = %DisplayErrorContext(&err), "invalid value for endpoint URL setting"),
        )
@@ -39,6 +41,7 @@ pub async fn endpoint_url_provider(provider_config: &ProviderConfig) -> Option<S
mod test {
    use super::endpoint_url_provider;
    use super::env;
    #[allow(deprecated)]
    use crate::profile::profile_file::{ProfileFileKind, ProfileFiles};
    use crate::provider_config::ProviderConfig;
    use aws_types::os_shim_internal::{Env, Fs};
@@ -61,8 +64,13 @@ mod test {
            .with_env(Env::from_slice(&[(env::ENDPOINT_URL, "http://localhost")]))
            .with_profile_config(
                Some(
                    #[allow(deprecated)]
                    ProfileFiles::builder()
                        .with_file(ProfileFileKind::Config, "conf")
                        .with_file(
                            #[allow(deprecated)]
                            ProfileFileKind::Config,
                            "conf",
                        )
                        .build(),
                ),
                None,
Loading