Skip to content

Commit

Permalink
Revamp errors in aws-smithy-types (#1893)
Browse files Browse the repository at this point in the history
  • Loading branch information
jdisanti authored Nov 15, 2022
1 parent 7b6d2d4 commit e36d346
Show file tree
Hide file tree
Showing 24 changed files with 498 additions and 410 deletions.
5 changes: 3 additions & 2 deletions aws/rust-runtime/aws-config/external-types.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ allowed_external_types = [
"aws_smithy_types::retry",
"aws_smithy_types::retry::*",
"aws_smithy_types::timeout",
"aws_smithy_types::timeout::config::TimeoutConfig",
"aws_smithy_types::timeout::error::ConfigError",
"aws_smithy_types::timeout::OperationTimeoutConfig",
"aws_smithy_types::timeout::TimeoutConfig",
"aws_smithy_types::timeout::TimeoutConfigBuilder",
"aws_types::*",
"http::response::Response",
"http::uri::Uri",
Expand Down
7 changes: 5 additions & 2 deletions aws/rust-runtime/aws-config/src/default_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
* SPDX-License-Identifier: Apache-2.0
*/

//! Default Provider chains for [`region`](default_provider::region), [`credentials`](default_provider::credentials),
//! [retries](default_provider::retry_config), [timeouts](default_provider::timeout_config) and [app name](default_provider::app_name).
//! Providers that implement the default AWS provider chain
//!
//! Default Provider chains for [`region`](crate::default_provider::region), [`credentials`](crate::default_provider::credentials),
//! [retries](crate::default_provider::retry_config), [timeouts](crate::default_provider::timeout_config) and
//! [app name](crate::default_provider::app_name).
//!
//! Typically, this module is used via [`load_from_env`](crate::load_from_env) or [`from_env`](crate::from_env). It should only be used directly
//! if you need to set custom configuration options to override the default resolution chain.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
* SPDX-License-Identifier: Apache-2.0
*/

use aws_smithy_types::retry::RetryConfig;

use crate::environment::retry_config::EnvironmentVariableRetryConfigProvider;
use crate::profile;
use crate::provider_config::ProviderConfig;
use aws_smithy_types::error::display::DisplayErrorContext;
use aws_smithy_types::retry::RetryConfig;

/// Default RetryConfig Provider chain
///
Expand Down Expand Up @@ -90,11 +90,11 @@ impl Builder {
// We match this instead of unwrapping so we can print the error with the `Display` impl instead of the `Debug` impl that unwrap uses
let builder_from_env = match self.env_provider.retry_config_builder() {
Ok(retry_config_builder) => retry_config_builder,
Err(err) => panic!("{}", err),
Err(err) => panic!("{}", DisplayErrorContext(&err)),
};
let builder_from_profile = match self.profile_file.build().retry_config_builder().await {
Ok(retry_config_builder) => retry_config_builder,
Err(err) => panic!("{}", err),
Err(err) => panic!("{}", DisplayErrorContext(&err)),
};

builder_from_env
Expand Down
2 changes: 2 additions & 0 deletions aws/rust-runtime/aws-config/src/environment/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
* SPDX-License-Identifier: Apache-2.0
*/

//! Providers that load configuration from environment variables

/// Load app name from the environment
pub mod app_name;
pub use app_name::EnvironmentVariableAppNameProvider;
Expand Down
39 changes: 24 additions & 15 deletions aws/rust-runtime/aws-config/src/environment/retry_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
* SPDX-License-Identifier: Apache-2.0
*/

use std::str::FromStr;

use aws_smithy_types::retry::{RetryConfigBuilder, RetryConfigErr, RetryMode};
use crate::retry::{
error::RetryConfigError, error::RetryConfigErrorKind, RetryConfigBuilder, RetryMode,
};
use aws_types::os_shim_internal::Env;
use std::str::FromStr;

const ENV_VAR_MAX_ATTEMPTS: &str = "AWS_MAX_ATTEMPTS";
const ENV_VAR_RETRY_MODE: &str = "AWS_RETRY_MODE";
Expand Down Expand Up @@ -35,20 +36,22 @@ impl EnvironmentVariableRetryConfigProvider {
}

/// Attempt to create a new `RetryConfig` from environment variables
pub fn retry_config_builder(&self) -> Result<RetryConfigBuilder, RetryConfigErr> {
pub fn retry_config_builder(&self) -> Result<RetryConfigBuilder, RetryConfigError> {
let max_attempts = match self.env.get(ENV_VAR_MAX_ATTEMPTS).ok() {
Some(max_attempts) => match max_attempts.parse::<u32>() {
Ok(max_attempts) if max_attempts == 0 => {
return Err(RetryConfigErr::MaxAttemptsMustNotBeZero {
return Err(RetryConfigErrorKind::MaxAttemptsMustNotBeZero {
set_by: "environment variable".into(),
});
}
.into());
}
Ok(max_attempts) => Some(max_attempts),
Err(source) => {
return Err(RetryConfigErr::FailedToParseMaxAttempts {
return Err(RetryConfigErrorKind::FailedToParseMaxAttempts {
set_by: "environment variable".into(),
source,
});
}
.into());
}
},
None => None,
Expand All @@ -58,10 +61,11 @@ impl EnvironmentVariableRetryConfigProvider {
Ok(retry_mode) => match RetryMode::from_str(&retry_mode) {
Ok(retry_mode) => Some(retry_mode),
Err(retry_mode_err) => {
return Err(RetryConfigErr::InvalidRetryMode {
return Err(RetryConfigErrorKind::InvalidRetryMode {
set_by: "environment variable".into(),
source: retry_mode_err,
});
}
.into());
}
},
Err(_) => None,
Expand All @@ -78,10 +82,11 @@ impl EnvironmentVariableRetryConfigProvider {

#[cfg(test)]
mod test {
use aws_smithy_types::retry::{RetryConfig, RetryConfigErr, RetryMode};
use aws_types::os_shim_internal::Env;

use super::{EnvironmentVariableRetryConfigProvider, ENV_VAR_MAX_ATTEMPTS, ENV_VAR_RETRY_MODE};
use crate::retry::{
error::RetryConfigError, error::RetryConfigErrorKind, RetryConfig, RetryMode,
};
use aws_types::os_shim_internal::Env;

fn test_provider(vars: &[(&str, &str)]) -> EnvironmentVariableRetryConfigProvider {
EnvironmentVariableRetryConfigProvider::new_with_env(Env::from_slice(vars))
Expand Down Expand Up @@ -112,7 +117,9 @@ mod test {
test_provider(&[(ENV_VAR_MAX_ATTEMPTS, "not an integer")])
.retry_config_builder()
.unwrap_err(),
RetryConfigErr::FailedToParseMaxAttempts { .. }
RetryConfigError {
kind: RetryConfigErrorKind::FailedToParseMaxAttempts { .. }
}
));
}

Expand Down Expand Up @@ -148,7 +155,9 @@ mod test {
.unwrap_err();
assert!(matches!(
err,
RetryConfigErr::MaxAttemptsMustNotBeZero { .. }
RetryConfigError {
kind: RetryConfigErrorKind::MaxAttemptsMustNotBeZero { .. }
}
));
}
}
46 changes: 14 additions & 32 deletions aws/rust-runtime/aws-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
unreachable_pub
)]

//! `aws-config` provides implementations of region, credential resolution.
//! `aws-config` provides implementations of region and credential resolution.
//!
//! These implementations can be used either via the default chain implementation
//! [`from_env`]/[`ConfigLoader`] or ad-hoc individual credential and region providers.
Expand Down Expand Up @@ -92,9 +92,6 @@
//! ```

pub use aws_smithy_http::endpoint;
// Re-export types from smithy-types
pub use aws_smithy_types::retry;
pub use aws_smithy_types::timeout;
// Re-export types from aws-types
pub use aws_types::{
app_name::{AppName, InvalidAppName},
Expand All @@ -106,43 +103,28 @@ pub use loader::ConfigLoader;
#[allow(dead_code)]
const PKG_VERSION: &str = env!("CARGO_PKG_VERSION");

/// Providers that implement the default AWS provider chain
pub mod default_provider;

/// Providers that load configuration from environment variables
pub mod environment;

/// Meta-providers that augment existing providers with new behavior
pub mod meta;

pub mod profile;

pub mod sts;

#[cfg(test)]
mod test_case;

pub mod web_identity_token;

pub mod ecs;

pub mod provider_config;

mod cache;

pub mod imds;

mod json_credentials;

mod fs_util;

mod http_credential_provider;

pub mod sso;
mod json_credentials;

pub mod connector;

pub mod credential_process;
pub mod default_provider;
pub mod ecs;
pub mod environment;
pub mod imds;
pub mod meta;
pub mod profile;
pub mod provider_config;
pub mod retry;
pub mod sso;
pub mod sts;
pub mod timeout;
pub mod web_identity_token;

/// Create an environment loader for AWS Configuration
///
Expand Down
3 changes: 2 additions & 1 deletion aws/rust-runtime/aws-config/src/meta/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

pub mod region;
//! Meta-providers that augment existing providers with new behavior

pub mod credentials;
pub mod region;
2 changes: 1 addition & 1 deletion aws/rust-runtime/aws-config/src/profile/parser/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ struct Location {
}

/// An error encountered while parsing a profile
#[derive(Debug, Clone)]
#[derive(Debug)]
pub struct ProfileParseError {
/// Location where this error occurred
location: Location,
Expand Down
21 changes: 13 additions & 8 deletions aws/rust-runtime/aws-config/src/profile/retry_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@

use crate::profile::profile_file::ProfileFiles;
use crate::provider_config::ProviderConfig;
use crate::retry::{
error::RetryConfigError, error::RetryConfigErrorKind, RetryConfigBuilder, RetryMode,
};
use aws_smithy_types::error::display::DisplayErrorContext;
use aws_smithy_types::retry::{RetryConfigBuilder, RetryConfigErr, RetryMode};
use aws_types::os_shim_internal::{Env, Fs};
use std::str::FromStr;

Expand Down Expand Up @@ -101,7 +103,7 @@ impl ProfileFileRetryConfigProvider {
}

/// Attempt to create a new RetryConfigBuilder from a profile file.
pub async fn retry_config_builder(&self) -> Result<RetryConfigBuilder, RetryConfigErr> {
pub async fn retry_config_builder(&self) -> Result<RetryConfigBuilder, RetryConfigError> {
let profile = match super::parser::load(&self.fs, &self.env, &self.profile_files).await {
Ok(profile) => profile,
Err(err) => {
Expand Down Expand Up @@ -130,16 +132,18 @@ impl ProfileFileRetryConfigProvider {
let max_attempts = match selected_profile.get("max_attempts") {
Some(max_attempts) => match max_attempts.parse::<u32>() {
Ok(max_attempts) if max_attempts == 0 => {
return Err(RetryConfigErr::MaxAttemptsMustNotBeZero {
return Err(RetryConfigErrorKind::MaxAttemptsMustNotBeZero {
set_by: "aws profile".into(),
});
}
.into());
}
Ok(max_attempts) => Some(max_attempts),
Err(source) => {
return Err(RetryConfigErr::FailedToParseMaxAttempts {
return Err(RetryConfigErrorKind::FailedToParseMaxAttempts {
set_by: "aws profile".into(),
source,
});
}
.into());
}
},
None => None,
Expand All @@ -149,10 +153,11 @@ impl ProfileFileRetryConfigProvider {
Some(retry_mode) => match RetryMode::from_str(retry_mode) {
Ok(retry_mode) => Some(retry_mode),
Err(retry_mode_err) => {
return Err(RetryConfigErr::InvalidRetryMode {
return Err(RetryConfigErrorKind::InvalidRetryMode {
set_by: "aws profile".into(),
source: retry_mode_err,
});
}
.into());
}
},
None => None,
Expand Down
87 changes: 87 additions & 0 deletions aws/rust-runtime/aws-config/src/retry.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

//! Retry configuration

// Re-export from aws-smithy-types
pub use aws_smithy_types::retry::ErrorKind;
pub use aws_smithy_types::retry::ProvideErrorKind;
pub use aws_smithy_types::retry::RetryConfig;
pub use aws_smithy_types::retry::RetryConfigBuilder;
pub use aws_smithy_types::retry::RetryKind;
pub use aws_smithy_types::retry::RetryMode;

/// Errors for retry configuration
pub mod error {
use std::borrow::Cow;
use std::fmt;
use std::num::ParseIntError;

// Re-export from aws-smithy-types
pub use aws_smithy_types::retry::RetryModeParseError;

#[derive(Debug)]
pub(crate) enum RetryConfigErrorKind {
/// The configured retry mode wasn't recognized.
InvalidRetryMode {
/// Cause of the error.
source: RetryModeParseError,
/// Where the invalid retry mode value originated from.
set_by: Cow<'static, str>,
},
/// Max attempts must be greater than zero.
MaxAttemptsMustNotBeZero {
/// Where the invalid max attempts value originated from.
set_by: Cow<'static, str>,
},
/// The max attempts value couldn't be parsed to an integer.
FailedToParseMaxAttempts {
/// Cause of the error.
source: ParseIntError,
/// Where the invalid max attempts value originated from.
set_by: Cow<'static, str>,
},
}

/// Failure to parse retry config from profile file or environment variable.
#[derive(Debug)]
pub struct RetryConfigError {
pub(crate) kind: RetryConfigErrorKind,
}

impl fmt::Display for RetryConfigError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use RetryConfigErrorKind::*;
match &self.kind {
InvalidRetryMode { set_by, .. } => {
write!(f, "invalid configuration set by {set_by}")
}
MaxAttemptsMustNotBeZero { set_by } => {
write!(f, "invalid configuration set by {set_by}: It is invalid to set max attempts to 0. Unset it or set it to an integer greater than or equal to one.")
}
FailedToParseMaxAttempts { set_by, .. } => {
write!(f, "failed to parse max attempts set by {set_by}",)
}
}
}
}

impl std::error::Error for RetryConfigError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use RetryConfigErrorKind::*;
match &self.kind {
InvalidRetryMode { source, .. } => Some(source),
FailedToParseMaxAttempts { source, .. } => Some(source),
MaxAttemptsMustNotBeZero { .. } => None,
}
}
}

impl From<RetryConfigErrorKind> for RetryConfigError {
fn from(kind: RetryConfigErrorKind) -> Self {
Self { kind }
}
}
}
Loading

0 comments on commit e36d346

Please sign in to comment.