Skip to content

Commit

Permalink
fix(libcontainer): combine multi error when create container failed
Browse files Browse the repository at this point in the history
When container creation fails and triggers a cleanup process that also
fails, the original creation error is overwritten by the cleanup error.
This change ensures that both the primary creation error and the
subsequent cleanup error are captured and reported, providing better
visibility into the failure sequence.

Signed-off-by: xujihui1985 <xujihui1985@gmail.com>
  • Loading branch information
xujihui1985 committed Nov 20, 2024
1 parent fad458f commit 074fa17
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 2 deletions.
7 changes: 5 additions & 2 deletions crates/libcontainer/src/container/builder_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()))
}
}
}
Expand Down
58 changes: 58 additions & 0 deletions crates/libcontainer/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down Expand Up @@ -97,3 +99,59 @@ pub enum ErrInvalidSpec {
#[error("invalid scheduler config for process")]
Scheduler,
}

#[derive(Debug, thiserror::Error)]
pub struct MultiError(Vec<LibcontainerError>);

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<Vec<LibcontainerError>> for MultiError {
fn from(value: Vec<LibcontainerError>) -> Self {
Self(value)
}
}

#[cfg(test)]
mod tests {
use super::{LibcontainerError, MultiError};
use libcgroups::common::CreateCgroupSetupError;

#[test]
fn test_multi_error() {
let errs = Vec::<LibcontainerError>::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);
}
}

0 comments on commit 074fa17

Please sign in to comment.