Unverified Commit b30b063e authored by Russell Cohen's avatar Russell Cohen Committed by GitHub
Browse files

Integrate TimeSource into the orchestrator and middleware (breaking change...

Integrate TimeSource into the orchestrator and middleware (breaking change warning is spurious) (#2728)

## Motivation and Context
- #2262 
- #2087 
- #2707 

This adds `TimeSource` in SDK and service configs so we can effectively
control time when executing requests with the SDK at the client level.

_note:_ the breaking change is in a trait implementation of a struct
we're going to delete, not a real breaking change

## Description
- Add `SharedTimeSource` and use it in SdkConfig / `aws-config` /
<service>::Config
- Wire up the signer and other uses of `SystemTime::now()` that I could
find
- track down broken tests

## Testing
- [x] various unit tests that all still pass

## 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
- [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._
parent cf292d58
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -81,8 +81,27 @@ references = ["smithy-rs#2539"]
meta = { "breaking" = true, "tada" = false, "bug" = false, "target" = "server" }
author = "david-perez"

[[smithy-rs]]
message = "Time is now controlled by the `TimeSource` trait. This facilitates testing as well as use cases like WASM where `SystemTime::now()` is not supported."
references = ["smithy-rs#2728", "smithy-rs#2262", "aws-sdk-rust#2087"]
meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "client" }
author = "rcoh"

[[smithy-rs]]
message = "The property bag type for Time is now `SharedTimeSource`, not `SystemTime`. If your code relies on setting request time, use `aws_smithy_async::time::SharedTimeSource`."
references = ["smithy-rs#2728", "smithy-rs#2262", "aws-sdk-rust#2087"]
meta = { "breaking" = true, "tada" = false, "bug" = false, "target" = "client" }
author = "rcoh"

[[aws-sdk-rust]]
message = "Time is now controlled by the `TimeSource` trait. This facilitates testing as well as use cases like WASM where `SystemTime::now()` is not supported."
references = ["smithy-rs#2728", "smithy-rs#2262", "aws-sdk-rust#2087"]
meta = { "breaking" = false, "tada" = false, "bug" = false }
author = "rcoh"

[[smithy-rs]]
message = "Bump dependency on `lambda_http` by `aws-smithy-http-server` to 0.8.0. This version of `aws-smithy-http-server` is only guaranteed to be compatible with 0.8.0, or semver-compatible versions of 0.8.0 of the `lambda_http` crate. It will not work with versions prior to 0.8.0 _at runtime_, making requests to your smithy-rs service unroutable, so please make sure you're running your service in a compatible configuration"
author = "david-perez"
references = ["smithy-rs#2676", "smithy-rs#2685"]
meta = { "breaking" = true, "tada" = false, "bug" = false }
+1 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ allowed_external_types = [
   "aws_credential_types::provider::SharedCredentialsProvider",
   "aws_sdk_sts::types::_policy_descriptor_type::PolicyDescriptorType",
   "aws_smithy_async::rt::sleep::AsyncSleep",
   "aws_smithy_async::time::TimeSource",
   "aws_smithy_client::bounds::SmithyConnector",
   "aws_smithy_client::conns::default_connector::default_connector",
   "aws_smithy_client::erase::DynConnector",
+4 −4
Original line number Diff line number Diff line
@@ -17,9 +17,9 @@
use crate::imds::client::error::{ImdsError, TokenError, TokenErrorKind};
use crate::imds::client::ImdsResponseRetryClassifier;
use aws_credential_types::cache::ExpiringCache;
use aws_credential_types::time_source::TimeSource;
use aws_http::user_agent::UserAgentStage;
use aws_smithy_async::rt::sleep::AsyncSleep;
use aws_smithy_async::time::SharedTimeSource;
use aws_smithy_client::erase::DynConnector;
use aws_smithy_client::retry;
use aws_smithy_http::body::SdkBody;
@@ -65,7 +65,7 @@ pub(super) struct TokenMiddleware {
    client: Arc<aws_smithy_client::Client<DynConnector, MapRequestLayer<UserAgentStage>>>,
    token_parser: GetTokenResponseHandler,
    token: ExpiringCache<Token, ImdsError>,
    time_source: TimeSource,
    time_source: SharedTimeSource,
    endpoint: Uri,
    token_ttl: Duration,
}
@@ -79,7 +79,7 @@ impl Debug for TokenMiddleware {
impl TokenMiddleware {
    pub(super) fn new(
        connector: DynConnector,
        time_source: TimeSource,
        time_source: SharedTimeSource,
        endpoint: Uri,
        token_ttl: Duration,
        retry_config: retry::Config,
@@ -170,7 +170,7 @@ impl AsyncMapRequest for TokenMiddleware {

#[derive(Clone)]
struct GetTokenResponseHandler {
    time: TimeSource,
    time: SharedTimeSource,
}

impl ParseStrictResponse for GetTokenResponseHandler {
+6 −3
Original line number Diff line number Diff line
@@ -14,8 +14,8 @@ use crate::imds::client::LazyClient;
use crate::json_credentials::{parse_json_credentials, JsonCredentials, RefreshableCredentials};
use crate::provider_config::ProviderConfig;
use aws_credential_types::provider::{self, error::CredentialsError, future, ProvideCredentials};
use aws_credential_types::time_source::TimeSource;
use aws_credential_types::Credentials;
use aws_smithy_async::time::SharedTimeSource;
use aws_types::os_shim_internal::Env;
use std::borrow::Cow;
use std::error::Error as StdError;
@@ -53,7 +53,7 @@ pub struct ImdsCredentialsProvider {
    client: LazyClient,
    env: Env,
    profile: Option<String>,
    time_source: TimeSource,
    time_source: SharedTimeSource,
    last_retrieved_credentials: Arc<RwLock<Option<Credentials>>>,
}

@@ -390,7 +390,10 @@ mod test {
            .build();
        let creds = provider.provide_credentials().await.expect("valid creds");
        // The expiry should be equal to what is originally set (==2021-09-21T04:16:53Z).
        assert!(creds.expiry() == UNIX_EPOCH.checked_add(Duration::from_secs(1632197813)));
        assert_eq!(
            creds.expiry(),
            UNIX_EPOCH.checked_add(Duration::from_secs(1632197813))
        );
        connection.assert_requests_match(&[]);

        // There should not be logs indicating credentials are extended for stability.
+14 −1
Original line number Diff line number Diff line
@@ -155,6 +155,7 @@ mod loader {
    use aws_credential_types::cache::CredentialsCache;
    use aws_credential_types::provider::{ProvideCredentials, SharedCredentialsProvider};
    use aws_smithy_async::rt::sleep::{default_async_sleep, AsyncSleep};
    use aws_smithy_async::time::{SharedTimeSource, TimeSource};
    use aws_smithy_client::http_connector::HttpConnector;
    use aws_smithy_types::retry::RetryConfig;
    use aws_smithy_types::timeout::TimeoutConfig;
@@ -192,6 +193,7 @@ mod loader {
        profile_files_override: Option<ProfileFiles>,
        use_fips: Option<bool>,
        use_dual_stack: Option<bool>,
        time_source: Option<SharedTimeSource>,
    }

    impl ConfigLoader {
@@ -262,6 +264,12 @@ mod loader {
            self
        }

        /// Set the time source used for tasks like signing requests
        pub fn time_source(mut self, time_source: impl TimeSource + 'static) -> Self {
            self.time_source = Some(SharedTimeSource::new(time_source));
            self
        }

        /// Override the [`HttpConnector`] for this [`ConfigLoader`]. The connector will be used when
        /// sending operations. This **does not set** the HTTP connector used by config providers.
        /// To change that connector, use [ConfigLoader::configure].
@@ -563,7 +571,9 @@ mod loader {
                .unwrap_or_else(|| HttpConnector::ConnectorFn(Arc::new(default_connector)));

            let credentials_cache = self.credentials_cache.unwrap_or_else(|| {
                let mut builder = CredentialsCache::lazy_builder().time_source(conf.time_source());
                let mut builder = CredentialsCache::lazy_builder().time_source(
                    aws_credential_types::time_source::TimeSource::shared(conf.time_source()),
                );
                builder.set_sleep(conf.sleep());
                builder.into_credentials_cache()
            });
@@ -588,12 +598,15 @@ mod loader {
                SharedCredentialsProvider::new(builder.build().await)
            };

            let ts = self.time_source.unwrap_or_default();

            let mut builder = SdkConfig::builder()
                .region(region)
                .retry_config(retry_config)
                .timeout_config(timeout_config)
                .credentials_cache(credentials_cache)
                .credentials_provider(credentials_provider)
                .time_source(ts)
                .http_connector(http_connector);

            builder.set_app_name(app_name);
Loading