use crate::meta::region::{future, ProvideRegion};
use crate::provider_config::ProviderConfig;
use aws_types::os_shim_internal::{Env, Fs};
use aws_types::region::Region;
#[derive(Debug, Default)]
pub struct ProfileFileRegionProvider {
fs: Fs,
env: Env,
profile_override: Option<String>,
}
#[derive(Default)]
pub struct Builder {
config: Option<ProviderConfig>,
profile_override: Option<String>,
}
impl Builder {
pub fn configure(mut self, config: &ProviderConfig) -> Self {
self.config = Some(config.clone());
self
}
pub fn profile_name(mut self, profile_name: impl Into<String>) -> Self {
self.profile_override = Some(profile_name.into());
self
}
pub fn build(self) -> ProfileFileRegionProvider {
let conf = self.config.unwrap_or_default();
ProfileFileRegionProvider {
env: conf.env(),
fs: conf.fs(),
profile_override: self.profile_override,
}
}
}
impl ProfileFileRegionProvider {
pub fn new() -> Self {
Self {
fs: Fs::real(),
env: Env::real(),
profile_override: None,
}
}
pub fn builder() -> Builder {
Builder::default()
}
async fn region(&self) -> Option<Region> {
let profile = super::parser::load(&self.fs, &self.env)
.await
.map_err(|err| tracing::warn!(err = %err, "failed to parse profile"))
.ok()?;
let selected_profile = self
.profile_override
.as_deref()
.unwrap_or_else(|| profile.selected_profile());
let selected_profile = profile.get_profile(selected_profile)?;
selected_profile
.get("region")
.map(|region| Region::new(region.to_owned()))
}
}
impl ProvideRegion for ProfileFileRegionProvider {
fn region(&self) -> future::ProvideRegion {
future::ProvideRegion::new(self.region())
}
}
#[cfg(test)]
mod test {
use crate::profile::ProfileFileRegionProvider;
use crate::provider_config::ProviderConfig;
use crate::test_case::no_traffic_connector;
use aws_sdk_sts::Region;
use aws_types::os_shim_internal::{Env, Fs};
use futures_util::FutureExt;
use tracing_test::traced_test;
fn provider_config(dir_name: &str) -> ProviderConfig {
let fs = Fs::from_test_dir(format!("test-data/profile-provider/{}/fs", dir_name), "/");
let env = Env::from_slice(&[("HOME", "/home")]);
ProviderConfig::empty()
.with_fs(fs)
.with_env(env)
.with_http_connector(no_traffic_connector())
}
#[traced_test]
#[test]
fn load_region() {
let provider = ProfileFileRegionProvider::builder()
.configure(&provider_config("region_override"))
.build();
assert_eq!(
provider.region().now_or_never().unwrap(),
Some(Region::from_static("us-east-1"))
);
}
#[test]
fn load_region_env_profile_override() {
let conf = provider_config("region_override").with_env(Env::from_slice(&[
("HOME", "/home"),
("AWS_PROFILE", "base"),
]));
let provider = ProfileFileRegionProvider::builder()
.configure(&conf)
.build();
assert_eq!(
provider.region().now_or_never().unwrap(),
Some(Region::from_static("us-east-1"))
);
}
#[test]
fn load_region_nonexistent_profile() {
let conf = provider_config("region_override").with_env(Env::from_slice(&[
("HOME", "/home"),
("AWS_PROFILE", "doesnotexist"),
]));
let provider = ProfileFileRegionProvider::builder()
.configure(&conf)
.build();
assert_eq!(provider.region().now_or_never().unwrap(), None);
}
#[test]
fn load_region_explicit_override() {
let conf = provider_config("region_override");
let provider = ProfileFileRegionProvider::builder()
.configure(&conf)
.profile_name("base")
.build();
assert_eq!(
provider.region().now_or_never().unwrap(),
Some(Region::from_static("us-east-1"))
);
}
}