diff --git a/Cargo.lock b/Cargo.lock index dd37df4..0779d8d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -881,9 +881,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.17" +version = "1.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" +checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c" dependencies = [ "jobserver", "libc", @@ -1172,9 +1172,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.4.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cfac68e08048ae1883171632c2aef3ebc555621ae56fbccce1cbf22dd7f058" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" dependencies = [ "powerfmt", "serde", @@ -1294,9 +1294,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", "windows-sys 0.59.0", @@ -1513,7 +1513,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.8.0", + "indexmap 2.9.0", "slab", "tokio", "tokio-util", @@ -1532,7 +1532,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.3.1", - "indexmap 2.8.0", + "indexmap 2.9.0", "slab", "tokio", "tokio-util", @@ -1976,9 +1976,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", "hashbrown 0.15.2", @@ -2226,9 +2226,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.5" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" +checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430" dependencies = [ "adler2", ] @@ -2272,7 +2272,7 @@ dependencies = [ [[package]] name = "multitool" -version = "0.2.0" +version = "0.2.1" dependencies = [ "async-stream", "async-trait", @@ -2292,7 +2292,7 @@ dependencies = [ "directories", "futures-core", "futures-util", - "indexmap 2.8.0", + "indexmap 2.9.0", "miette", "mockall", "multitool-sdk", @@ -2437,9 +2437,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "openssl" -version = "0.10.71" +version = "0.10.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd" +checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" dependencies = [ "bitflags 2.9.0", "cfg-if", @@ -2478,9 +2478,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.106" +version = "0.9.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd" +checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07" dependencies = [ "cc", "libc", @@ -2875,9 +2875,9 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.31" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5316f57387668042f561aae71480de936257848f9c43ce528e311d89a07cadeb" +checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6" dependencies = [ "proc-macro2", "syn 2.0.100", @@ -3014,9 +3014,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" +checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" dependencies = [ "bitflags 2.9.0", ] @@ -3627,7 +3627,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.8.0", + "indexmap 2.9.0", "serde", "serde_derive", "serde_json", @@ -3666,7 +3666,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcb06c0da8bc20b8e9f0349d655d1d29ce732b919c13c8d0ed7a14a8fcb9c90f" dependencies = [ "base64 0.22.1", - "indexmap 2.8.0", + "indexmap 2.9.0", "ref-cast", ] @@ -3722,9 +3722,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" [[package]] name = "socket2" @@ -4049,9 +4049,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.44.1" +version = "1.44.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a" +checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" dependencies = [ "backtrace", "bytes", @@ -4177,7 +4177,7 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" dependencies = [ - "indexmap 2.8.0", + "indexmap 2.9.0", "serde", "serde_spanned", "toml_datetime", @@ -4199,7 +4199,7 @@ version = "0.22.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ - "indexmap 2.8.0", + "indexmap 2.9.0", "serde", "serde_spanned", "toml_datetime", @@ -4912,9 +4912,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" +checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index aa88373..67a6d40 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ directories = "6.0" futures-core = "0.3.31" futures-util = "0.3.31" indexmap = { version = "2.1.0", features = ["serde"] } -miette = { version = "7", features = ["fancy"] } +miette = { version = "7.5", features = ["fancy"] } mockall = "0.13.1" multitool-sdk = { git = "https://github.com/wack/multitool-rust-sdk.git", branch = "trunk" } pingora = { version = "0.3", features = ["lb", "proxy"], optional = true } diff --git a/src/adapters/ingresses/apig.rs b/src/adapters/ingresses/apig.rs index c819134..ec7a93c 100644 --- a/src/adapters/ingresses/apig.rs +++ b/src/adapters/ingresses/apig.rs @@ -1,10 +1,12 @@ use async_trait::async_trait; use bon::bon; -use miette::{Result, miette}; +use miette::{Result, WrapErr, miette}; use tracing::{debug, info}; use crate::{ - Shutdownable, WholePercent, subsystems::ShutdownResult, utils::load_default_aws_config, + Shutdownable, WholePercent, + subsystems::ShutdownResult, + utils::{load_default_aws_config, map_aws_error}, }; use aws_sdk_apigateway::{ @@ -201,26 +203,8 @@ impl Ingress for AwsApiGateway { .principal("apigateway.amazonaws.com") .send() .await - .map_err(|err| { - let error_message = match err { - SdkError::ServiceError(service_err) => { - // Extract the specific service error details - format!( - "{}", - service_err - .err() - .meta() - .message() - .unwrap_or("No error message found") - ) - } - _ => format!("{:?}", err), - }; - miette!( - "Failed to add invoke permission to Lambda: {}", - error_message - ) - })?; + .map_err(map_aws_error) + .wrap_err_with(|| "Failed to add invoke permission to Lambda")?; // Update our API Gateway to point at our new lambda version let patch_op = PatchOperation::builder() diff --git a/src/adapters/platforms/lambda.rs b/src/adapters/platforms/lambda.rs index c819090..c7ce694 100644 --- a/src/adapters/platforms/lambda.rs +++ b/src/adapters/platforms/lambda.rs @@ -1,10 +1,13 @@ use async_trait::async_trait; use bon::bon; -use miette::{Result, miette}; +use miette::{Result, WrapErr, miette}; use tracing::info; use crate::{ - Shutdownable, artifacts::LambdaZip, subsystems::ShutdownResult, utils::load_default_aws_config, + Shutdownable, + artifacts::LambdaZip, + subsystems::ShutdownResult, + utils::{load_default_aws_config, map_aws_error}, }; use aws_sdk_lambda::{client::Client, error::SdkError, primitives::Blob, types::FunctionCode}; @@ -58,23 +61,8 @@ impl Platform for LambdaPlatform { .zip_file(zip_file.clone()) .send() .await - .map_err(|err| { - let error_message = match err { - SdkError::ServiceError(service_err) => { - // Extract the specific service error details - format!( - "{}", - service_err - .err() - .meta() - .message() - .unwrap_or("No error message found") - ) - } - _ => format!("{:?}", err), - }; - miette!("Failed to deploy Lambda: {}", error_message) - })?; + .map_err(map_aws_error) + .wrap_err("Failed to deploy lambda")?; let function_arn = res .function_arn() diff --git a/src/cmd/run.rs b/src/cmd/run.rs index abb6089..4cd6cc9 100644 --- a/src/cmd/run.rs +++ b/src/cmd/run.rs @@ -9,9 +9,13 @@ use crate::subsystems::CONTROLLER_SUBSYSTEM_NAME; use crate::{ ControllerSubsystem, adapters::BackendClient, artifacts::LambdaZip, config::RunSubcommand, }; -use miette::Result; +use miette::{Diagnostic, Result}; +use thiserror::Error; use tokio::runtime::Runtime; use tokio::time::Duration; +use tokio_graceful_shutdown::errors::GracefulShutdownError::ShutdownTimeout; +use tokio_graceful_shutdown::errors::GracefulShutdownError::SubsystemsFailed; +use tokio_graceful_shutdown::errors::SubsystemError; use tokio_graceful_shutdown::{IntoSubsystem as _, SubsystemBuilder, Toplevel}; use tracing::{debug, info}; @@ -30,6 +34,21 @@ pub struct Run { backend: BackendClient, } +#[derive(Debug, Error, Diagnostic)] +#[error("Rollout failed to complete successfully.")] +pub struct RunError { + #[related] + subsystem_errors: Vec, +} + +impl> From for RunError { + fn from(subsystem_errors: T) -> Self { + Self { + subsystem_errors: subsystem_errors.into_iter().collect(), + } + } +} + impl Run { pub fn new(terminal: Terminal, args: RunSubcommand) -> Result { let fs = FileSystem::new().unwrap(); @@ -105,7 +124,12 @@ impl Run { .catch_signals() .handle_shutdown_requests(Duration::from_millis(DEFAULT_SHUTDOWN_TIMEOUT)) .await - .map_err(Into::into) + .map_err(|err| match err { + SubsystemsFailed(errs) => RunError::from(errs), + ShutdownTimeout(errs) => RunError::from(errs), + })?; + + Ok(()) }) } diff --git a/src/terminal/mod.rs b/src/terminal/mod.rs index d01fc20..f719ef4 100644 --- a/src/terminal/mod.rs +++ b/src/terminal/mod.rs @@ -38,7 +38,7 @@ impl Terminal { miette::set_hook(Box::new(move |_| { if allow_color { // TODO: Add brand colors using ``::new_themed()` - Box::new(GraphicalReportHandler::new()) + Box::new(GraphicalReportHandler::new().with_cause_chain()) } else { Box::new(DebugReportHandler) } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 5f60d07..8d7470e 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,4 +1,7 @@ use aws_config::{BehaviorVersion, SdkConfig}; +use aws_sdk_lambda::error::ProvideErrorMetadata; +use aws_smithy_runtime_api::client::result::SdkError; +use miette::miette; use tokio::sync::OnceCell; /// Load AWS configuration using their standard rules. e.g. AWS_ACCESS_KEY_ID, @@ -21,3 +24,22 @@ async fn load_config() -> SdkConfig { } static AWS_CONFIG_CELL: OnceCell = OnceCell::const_new(); + +pub fn map_aws_error( + err: SdkError, +) -> miette::Report { + match err { + SdkError::ServiceError(service_err) => { + // Extract the specific service error details + miette!( + "{:?}", + service_err + .err() + .meta() + .message() + .unwrap_or("No error message found") + ) + } + _ => miette!("{:?}", err), + } +}