Skip to content

Commit

Permalink
Update docs & and add test
Browse files Browse the repository at this point in the history
  • Loading branch information
rcoh committed Dec 30, 2022
1 parent 1ac04df commit 47d39d6
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 37 deletions.
43 changes: 43 additions & 0 deletions CHANGELOG.next.toml
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,46 @@ message = "The constraint `@length` on non-streaming blob shapes is supported."
references = ["smithy-rs#2131"]
meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "server"}
author = "82marbag"

[[aws-sdk-rust]]
references = ["smithy-rs#2152"]
meta = { "breaking" = false, "tada" = false, "bug" = false }
author = "rcoh"
message = """Add support for overriding profile name and profile file location across all providers. Prior to this change, each provider needed to be updated individually.
### Before
```rust
use aws_config::profile::{ProfileFileCredentialsProvider, ProfileFileRegionProvider};
use aws_config::profile::profile_file::{ProfileFiles, ProfileFileKind};
let profile_files = ProfileFiles::builder()
.with_file(ProfileFileKind::Credentials, "some/path/to/credentials-file")
.build();
let credentials_provider = ProfileFileCredentialsProvider::builder()
.profile_files(profile_files.clone())
.build();
let region_provider = ProfileFileRegionProvider::builder()
.profile_files(profile_files)
.build();
let sdk_config = aws_config::from_env()
.credentials_provider(credentials_provider)
.region(region_provider)
.load()
.await;
```
### After
```rust
use aws_config::profile::{ProfileFileCredentialsProvider, ProfileFileRegionProvider};
use aws_config::profile::profile_file::{ProfileFiles, ProfileFileKind};
let profile_files = ProfileFiles::builder()
.with_file(ProfileFileKind::Credentials, "some/path/to/credentials-file")
.build();
let sdk_config = aws_config::from_env()
.profile_files(profile_files)
.load()
.await;
/// ```
"""
25 changes: 24 additions & 1 deletion aws/rust-runtime/aws-config/src/default_provider/app_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@ impl Builder {
#[cfg(test)]
mod tests {
use super::*;
use crate::profile::profile_file::{ProfileFileKind, ProfileFiles};
use crate::provider_config::ProviderConfig;
use crate::test_case::no_traffic_connector;
use crate::test_case::{no_traffic_connector, InstantSleep};
use aws_types::os_shim_internal::{Env, Fs};

#[tokio::test]
Expand All @@ -76,6 +77,28 @@ mod tests {
assert_eq!(Some(AppName::new("correct").unwrap()), app_name);
}

// test that overriding profile_name on the root level is deprecated
#[tokio::test]
async fn profile_name_override() {
let fs = Fs::from_slice(&[("test_config", "[profile custom]\nsdk-ua-app-id = correct")]);
let conf = crate::from_env()
.configure(
ProviderConfig::empty()
.with_fs(fs)
.with_sleep(InstantSleep)
.with_http_connector(no_traffic_connector()),
)
.profile_name("custom")
.profile_files(
ProfileFiles::builder()
.with_file(ProfileFileKind::Config, "test_config")
.build(),
)
.load()
.await;
assert_eq!(conf.app_name(), Some(&AppName::new("correct").unwrap()));
}

#[tokio::test]
async fn load_from_profile() {
let fs = Fs::from_slice(&[("test_config", "[default]\nsdk-ua-app-id = correct")]);
Expand Down
81 changes: 76 additions & 5 deletions aws/rust-runtime/aws-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ mod loader {
use crate::connector::default_connector;
use crate::default_provider::{app_name, credentials, region, retry_config, timeout_config};
use crate::meta::region::ProvideRegion;
use crate::profile::profile_file::ProfileFiles;
use crate::provider_config::ProviderConfig;

/// Load a cross-service [`SdkConfig`](aws_types::SdkConfig) from the environment
Expand All @@ -181,6 +182,8 @@ mod loader {
timeout_config: Option<TimeoutConfig>,
provider_config: Option<ProviderConfig>,
http_connector: Option<HttpConnector>,
profile_name_override: Option<String>,
profile_files_override: Option<ProfileFiles>,
}

impl ConfigLoader {
Expand Down Expand Up @@ -344,6 +347,73 @@ mod loader {
self
}

/// Provides the ability to programmatically override the profile files that get loaded by the SDK.
///
/// The [`Default`] for `ProfileFiles` includes the default SDK config and credential files located in
/// `~/.aws/config` and `~/.aws/credentials` respectively.
///
/// Any number of config and credential files may be added to the `ProfileFiles` file set, with the
/// only requirement being that there is at least one of them. Custom file locations that are added
/// will produce errors if they don't exist, while the default config/credentials files paths are
/// allowed to not exist even if they're included.
///
/// # Example: Using a custom profile file path
///
/// ```
/// use aws_config::profile::{ProfileFileCredentialsProvider, ProfileFileRegionProvider};
/// use aws_config::profile::profile_file::{ProfileFiles, ProfileFileKind};
///
/// # async fn example() {
/// let profile_files = ProfileFiles::builder()
/// .with_file(ProfileFileKind::Credentials, "some/path/to/credentials-file")
/// .build();
/// let sdk_config = aws_config::from_env()
/// .profile_files(profile_files)
/// .load()
/// .await;
/// # }
pub fn profile_files(mut self, profile_files: ProfileFiles) -> Self {
self.profile_files_override = Some(profile_files);
self
}

/// Override the profile name used by configuration providers
///
/// Profile name is selected from an ordered list of sources:
/// 1. This override.
/// 2. The value of the `AWS_PROFILE` environment variable.
/// 3. `default`
///
/// Each AWS profile has a name. For example, in the file below, the profiles are named
/// `dev`, `prod` and `staging`:
/// ```ini
/// [dev]
/// ec2_metadata_service_endpoint = http://my-custom-endpoint:444
///
/// [staging]
/// ec2_metadata_service_endpoint = http://my-custom-endpoint:444
///
/// [prod]
/// ec2_metadata_service_endpoint = http://my-custom-endpoint:444
/// ```
///
/// # Example: Using a custom profile name
///
/// ```
/// use aws_config::profile::{ProfileFileCredentialsProvider, ProfileFileRegionProvider};
/// use aws_config::profile::profile_file::{ProfileFiles, ProfileFileKind};
///
/// # async fn example() {
/// let sdk_config = aws_config::from_env()
/// .profile_name("prod")
/// .load()
/// .await;
/// # }
pub fn profile_name(mut self, profile_name: impl Into<String>) -> Self {
self.profile_name_override = Some(profile_name.into());
self
}

/// Override the endpoint URL used for **all** AWS services.
///
/// This method will override the endpoint URL used for **all** AWS services. This primarily
Expand Down Expand Up @@ -372,16 +442,14 @@ mod loader {
///
/// Update the `ProviderConfig` used for all nested loaders. This can be used to override
/// the HTTPs connector used by providers or to stub in an in memory `Env` or `Fs` for testing.
/// This **does not set** the HTTP connector used when sending operations. To change that
/// connector, use [ConfigLoader::http_connector].
///
/// # Examples
/// ```no_run
/// # #[cfg(feature = "hyper-client")]
/// # async fn create_config() {
/// use aws_config::provider_config::ProviderConfig;
/// let custom_https_connector = hyper_rustls::HttpsConnectorBuilder::new().
/// with_webpki_roots()
/// let custom_https_connector = hyper_rustls::HttpsConnectorBuilder::new()
/// .with_webpki_roots()
/// .https_only()
/// .enable_http1()
/// .build();
Expand All @@ -404,7 +472,10 @@ mod loader {
/// This means that if you provide a region provider that does not return a region, no region will
/// be set in the resulting [`SdkConfig`](aws_types::SdkConfig)
pub async fn load(self) -> SdkConfig {
let conf = self.provider_config.unwrap_or_default();
let conf = self
.provider_config
.unwrap_or_default()
.with_profile_config(self.profile_files_override, self.profile_name_override);
let region = if let Some(provider) = self.region {
provider.region().await
} else {
Expand Down
12 changes: 2 additions & 10 deletions aws/rust-runtime/aws-config/src/profile/profile_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use std::path::PathBuf;
/// will produce errors if they don't exist, while the default config/credentials files paths are
/// allowed to not exist even if they're included.
///
/// # Example: Using a custom profile file path for credentials and region
/// # Example: Using a custom profile file path
///
/// ```
/// use aws_config::profile::{ProfileFileCredentialsProvider, ProfileFileRegionProvider};
Expand All @@ -28,16 +28,8 @@ use std::path::PathBuf;
/// let profile_files = ProfileFiles::builder()
/// .with_file(ProfileFileKind::Credentials, "some/path/to/credentials-file")
/// .build();
/// let credentials_provider = ProfileFileCredentialsProvider::builder()
/// .profile_files(profile_files.clone())
/// .build();
/// let region_provider = ProfileFileRegionProvider::builder()
/// .profile_files(profile_files)
/// .build();
///
/// let sdk_config = aws_config::from_env()
/// .credentials_provider(credentials_provider)
/// .region(region_provider)
/// .profile_files(profile_files)
/// .load()
/// .await;
/// # }
Expand Down
4 changes: 1 addition & 3 deletions aws/rust-runtime/aws-config/src/profile/retry_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,7 @@ impl ProfileFileRetryConfigProvider {
///
/// To override the selected profile, set the `AWS_PROFILE` environment variable or use the [Builder].
pub fn new() -> Self {
Self {
provider_config: Default::default(),
}
Self::default()
}

/// [Builder] to construct a [ProfileFileRetryConfigProvider]
Expand Down
26 changes: 9 additions & 17 deletions aws/rust-runtime/aws-config/src/provider_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ pub struct ProviderConfig {
connector: HttpConnector,
sleep: Option<Arc<dyn AsyncSleep>>,
region: Option<Region>,
profile: Arc<OnceCell<Result<ProfileSet, ProfileFileLoadError>>>,
parsed_profile: Arc<OnceCell<Result<ProfileSet, ProfileFileLoadError>>>,
profile_files: ProfileFiles,
profile_name_override: Option<Cow<'static, str>>,
}
Expand Down Expand Up @@ -73,7 +73,7 @@ impl Default for ProviderConfig {
connector,
sleep: default_async_sleep(),
region: None,
profile: Default::default(),
parsed_profile: Default::default(),
profile_files: ProfileFiles::default(),
profile_name_override: None,
}
Expand All @@ -93,7 +93,7 @@ impl ProviderConfig {
let fs = Fs::from_raw_map(HashMap::new());
let env = Env::from_slice(&[]);
Self {
profile: Default::default(),
parsed_profile: Default::default(),
profile_files: ProfileFiles::default(),
env,
fs,
Expand Down Expand Up @@ -141,7 +141,7 @@ impl ProviderConfig {
connector: HttpConnector::Prebuilt(None),
sleep: None,
region: None,
profile: Default::default(),
parsed_profile: Default::default(),
profile_files: ProfileFiles::default(),
profile_name_override: None,
}
Expand Down Expand Up @@ -203,7 +203,7 @@ impl ProviderConfig {

pub(crate) async fn try_profile(&self) -> Result<&ProfileSet, &ProfileFileLoadError> {
let parsed_profile = self
.profile
.parsed_profile
.get_or_init(|| async {
let profile = profile::load(
&self.fs,
Expand Down Expand Up @@ -231,22 +231,14 @@ impl ProviderConfig {
self
}

/// Override the profile files for the configuration
pub fn with_profile_files(self, profile_files: ProfileFiles) -> Self {
ProviderConfig {
profile: Default::default(),
profile_files,
..self
}
}

pub(crate) fn with_profile_config(
self,
profile_files: Option<ProfileFiles>,
profile_name_override: Option<String>,
) -> Self {
ProviderConfig {
profile: Default::default(),
// clear out the profile since we need to reparse it
parsed_profile: Default::default(),
profile_files: profile_files.unwrap_or(self.profile_files),
profile_name_override: profile_name_override
.map(Cow::Owned)
Expand All @@ -270,7 +262,7 @@ impl ProviderConfig {
#[doc(hidden)]
pub fn with_fs(self, fs: Fs) -> Self {
ProviderConfig {
profile: Default::default(),
parsed_profile: Default::default(),
fs,
..self
}
Expand All @@ -279,7 +271,7 @@ impl ProviderConfig {
#[doc(hidden)]
pub fn with_env(self, env: Env) -> Self {
ProviderConfig {
profile: Default::default(),
parsed_profile: Default::default(),
env,
..self
}
Expand Down
2 changes: 1 addition & 1 deletion aws/rust-runtime/aws-config/src/test_case.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ pub(crate) fn no_traffic_connector() -> DynConnector {
}

#[derive(Debug)]
struct InstantSleep;
pub(crate) struct InstantSleep;
impl AsyncSleep for InstantSleep {
fn sleep(&self, _duration: Duration) -> Sleep {
Sleep::new(std::future::ready(()))
Expand Down

0 comments on commit 47d39d6

Please sign in to comment.