diff --git a/crates/libcontainer/src/container/builder_impl.rs b/crates/libcontainer/src/container/builder_impl.rs index 0a9e43f52..b330f4503 100644 --- a/crates/libcontainer/src/container/builder_impl.rs +++ b/crates/libcontainer/src/container/builder_impl.rs @@ -60,11 +60,14 @@ impl ContainerBuilderImpl { Err(outer) => { // Only the init container should be cleaned up in the case of // an error. + let mut errors = vec![outer]; if matches!(self.container_type, ContainerType::InitContainer) { - self.cleanup_container()?; + if let Err(e) = self.cleanup_container() { + errors.push(e); + } } - Err(outer) + Err(LibcontainerError::MultiError(errors.into())) } } } diff --git a/crates/libcontainer/src/error.rs b/crates/libcontainer/src/error.rs index f6efed7db..d5659b504 100644 --- a/crates/libcontainer/src/error.rs +++ b/crates/libcontainer/src/error.rs @@ -62,6 +62,8 @@ pub enum LibcontainerError { CgroupGet(#[from] libcgroups::common::GetCgroupSetupError), #[error[transparent]] Checkpoint(#[from] crate::container::CheckpointError), + #[error[transparent]] + MultiError(#[from] MultiError), // Catch all errors that are not covered by the above #[error("syscall error")] @@ -97,3 +99,59 @@ pub enum ErrInvalidSpec { #[error("invalid scheduler config for process")] Scheduler, } + +#[derive(Debug, thiserror::Error)] +pub struct MultiError(Vec); + +impl std::fmt::Display for MultiError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.0.len() { + 0 => write!(f, ""), + 1 => std::fmt::Display::fmt(&self.0[0], f), + _ => { + writeln!(f, "multiple errors occurred while processing the request:")?; + for (index, error) in self.0.iter().enumerate() { + writeln!(f, "{}: {}", index + 1, error)?; + } + Ok(()) + } + } + } +} + +impl From> for MultiError { + fn from(value: Vec) -> Self { + Self(value) + } +} + +#[cfg(test)] +mod tests { + use super::{LibcontainerError, MultiError}; + use libcgroups::common::CreateCgroupSetupError; + + #[test] + fn test_multi_error() { + let errs = Vec::::new(); + let multi_err: MultiError = errs.into(); + let msg = format!("{}", multi_err); + assert_eq!("", msg); + + let err1 = LibcontainerError::CgroupCreate(CreateCgroupSetupError::NonDefault); + let errs = vec![err1]; + let multi_err: MultiError = errs.into(); + let msg = format!("{:#}", multi_err); + assert_eq!("non default cgroup root not supported", msg); + + let err1 = LibcontainerError::CgroupCreate(CreateCgroupSetupError::NonDefault); + let err2 = LibcontainerError::InvalidID(super::ErrInvalidID::Empty); + let errs = vec![err1, err2]; + let multi_err: MultiError = errs.into(); + let msg = format!("{:#}", multi_err); + let expect = r#"multiple errors occurred while processing the request: +1: non default cgroup root not supported +2: container id can't be empty +"#; + assert_eq!(expect, msg); + } +}