use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[non_exhaustive]
pub enum SsmErrorCode {
ParameterNotFound,
ParameterAlreadyExists,
ParameterMaxVersionLimitExceeded,
ParameterVersionNotFound,
ParameterVersionLabelLimitExceeded,
HierarchyLevelLimitExceeded,
HierarchyTypeMismatch,
InvalidAllowedPatternException,
ParameterPatternMismatchException,
InvalidFilterKey,
InvalidFilterOption,
InvalidFilterValue,
InvalidNextToken,
InvalidResourceId,
InvalidResourceType,
UnsupportedParameterType,
TooManyTagsError,
InternalServerError,
InvalidSecurity,
InvalidAction,
MissingAction,
#[default]
ValidationException,
}
impl SsmErrorCode {
#[must_use]
pub fn error_type(&self) -> &'static str {
self.as_str()
}
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::ParameterNotFound => "ParameterNotFound",
Self::ParameterAlreadyExists => "ParameterAlreadyExists",
Self::ParameterMaxVersionLimitExceeded => "ParameterMaxVersionLimitExceeded",
Self::ParameterVersionNotFound => "ParameterVersionNotFound",
Self::ParameterVersionLabelLimitExceeded => "ParameterVersionLabelLimitExceeded",
Self::HierarchyLevelLimitExceeded => "HierarchyLevelLimitExceeded",
Self::HierarchyTypeMismatch => "HierarchyTypeMismatch",
Self::InvalidAllowedPatternException => "InvalidAllowedPatternException",
Self::ParameterPatternMismatchException => "ParameterPatternMismatchException",
Self::InvalidFilterKey => "InvalidFilterKey",
Self::InvalidFilterOption => "InvalidFilterOption",
Self::InvalidFilterValue => "InvalidFilterValue",
Self::InvalidNextToken => "InvalidNextToken",
Self::InvalidResourceId => "InvalidResourceId",
Self::InvalidResourceType => "InvalidResourceType",
Self::UnsupportedParameterType => "UnsupportedParameterType",
Self::TooManyTagsError => "TooManyTagsError",
Self::InternalServerError => "InternalServerError",
Self::InvalidSecurity => "InvalidSecurity",
Self::InvalidAction => "InvalidAction",
Self::MissingAction => "MissingAction",
Self::ValidationException => "ValidationException",
}
}
#[must_use]
pub fn default_status_code(&self) -> http::StatusCode {
match self {
Self::InternalServerError => http::StatusCode::INTERNAL_SERVER_ERROR,
_ => http::StatusCode::BAD_REQUEST,
}
}
}
impl fmt::Display for SsmErrorCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug)]
pub struct SsmError {
pub code: SsmErrorCode,
pub message: String,
pub status_code: http::StatusCode,
pub source: Option<Box<dyn std::error::Error + Send + Sync>>,
}
impl fmt::Display for SsmError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "SsmError({}): {}", self.code, self.message)
}
}
impl std::error::Error for SsmError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.source
.as_ref()
.map(|e| e.as_ref() as &(dyn std::error::Error + 'static))
}
}
impl SsmError {
#[must_use]
pub fn new(code: SsmErrorCode) -> Self {
Self {
status_code: code.default_status_code(),
message: code.as_str().to_owned(),
code,
source: None,
}
}
#[must_use]
pub fn with_message(code: SsmErrorCode, message: impl Into<String>) -> Self {
Self {
status_code: code.default_status_code(),
message: message.into(),
code,
source: None,
}
}
#[must_use]
pub fn with_source(mut self, source: impl std::error::Error + Send + Sync + 'static) -> Self {
self.source = Some(Box::new(source));
self
}
#[must_use]
pub fn error_type(&self) -> &'static str {
self.code.error_type()
}
#[must_use]
pub fn parameter_not_found(name: &str) -> Self {
Self::with_message(SsmErrorCode::ParameterNotFound, name.to_owned())
}
#[must_use]
pub fn parameter_already_exists(name: &str) -> Self {
Self::with_message(
SsmErrorCode::ParameterAlreadyExists,
format!(
"The parameter {name} already exists. To overwrite this value, set the overwrite \
option in the request to true."
),
)
}
#[must_use]
pub fn validation(message: impl Into<String>) -> Self {
Self::with_message(SsmErrorCode::ValidationException, message)
}
#[must_use]
pub fn internal_error(message: impl Into<String>) -> Self {
Self::with_message(SsmErrorCode::InternalServerError, message)
}
#[must_use]
pub fn missing_action() -> Self {
Self::with_message(
SsmErrorCode::MissingAction,
"Missing required header: X-Amz-Target",
)
}
#[must_use]
pub fn unknown_operation(target: &str) -> Self {
Self::with_message(
SsmErrorCode::InvalidAction,
format!(
"Operation {target} is not supported. Only Parameter Store operations are \
implemented."
),
)
}
#[must_use]
pub fn not_implemented(operation: &str) -> Self {
Self::with_message(
SsmErrorCode::InternalServerError,
format!("Operation {operation} is not yet implemented"),
)
}
}
#[macro_export]
macro_rules! ssm_error {
($code:ident) => {
$crate::error::SsmError::new($crate::error::SsmErrorCode::$code)
};
($code:ident, $msg:expr) => {
$crate::error::SsmError::with_message($crate::error::SsmErrorCode::$code, $msg)
};
}