Skip to main content

libcontainer/
error.rs

1use crate::container::ContainerStatus;
2
3#[derive(Debug, thiserror::Error)]
4pub enum MissingSpecError {
5    #[error("missing process in spec")]
6    Process,
7    #[error("missing linux in spec")]
8    Linux,
9    #[error("missing args in the process spec")]
10    Args,
11    #[error("missing root in the spec")]
12    Root,
13}
14
15#[derive(Debug, thiserror::Error)]
16pub enum LibcontainerError {
17    #[error("failed operation due to incompatible container status: `{0}`")]
18    IncorrectStatus(ContainerStatus),
19    #[error("container already exists")]
20    Exist,
21    #[error("container state directory does not exist")]
22    NoDirectory,
23    #[error("invalid input")]
24    InvalidInput(String),
25    #[error("requires at least one executors")]
26    NoExecutors,
27    #[error("rootless container requires valid user namespace definition")]
28    NoUserNamespace,
29
30    // Invalid inputs
31    #[error(transparent)]
32    InvalidID(#[from] ErrInvalidID),
33    #[error(transparent)]
34    MissingSpec(#[from] MissingSpecError),
35    #[error("invalid runtime spec")]
36    InvalidSpec(#[from] ErrInvalidSpec),
37
38    // Errors from submodules and other errors
39    #[error(transparent)]
40    Tty(#[from] crate::tty::TTYError),
41    #[error(transparent)]
42    UserNamespace(#[from] crate::user_ns::UserNamespaceError),
43    #[error(transparent)]
44    NotifyListener(#[from] crate::notify_socket::NotifyListenerError),
45    #[error(transparent)]
46    Config(#[from] crate::config::ConfigError),
47    #[error(transparent)]
48    Hook(#[from] crate::hooks::HookError),
49    #[error(transparent)]
50    State(#[from] crate::container::state::StateError),
51    #[error("oci spec error")]
52    Spec(#[from] oci_spec::OciSpecError),
53    #[error(transparent)]
54    MainProcess(#[from] crate::process::container_main_process::ProcessError),
55    #[error(transparent)]
56    Procfs(#[from] procfs::ProcError),
57    #[error(transparent)]
58    Capabilities(#[from] caps::errors::CapsError),
59    #[error(transparent)]
60    CgroupManager(#[from] libcgroups::common::AnyManagerError),
61    #[error(transparent)]
62    CgroupCreate(#[from] libcgroups::common::CreateCgroupSetupError),
63    #[error(transparent)]
64    CgroupGet(#[from] libcgroups::common::GetCgroupSetupError),
65    #[error[transparent]]
66    Checkpoint(#[from] crate::container::CheckpointError),
67    #[error[transparent]]
68    CreateContainerError(#[from] CreateContainerError),
69    #[error(transparent)]
70    NetDevicesError(#[from] crate::utils::NetDevicesError),
71    #[error(transparent)]
72    NetworkError(#[from] crate::network::NetworkError),
73
74    // Catch all errors that are not covered by the above
75    #[error("syscall error")]
76    OtherSyscall(#[source] nix::Error),
77    #[error("io error")]
78    OtherIO(#[source] std::io::Error),
79    #[error("serialization error")]
80    OtherSerialization(#[source] serde_json::Error),
81    #[error("{0}")]
82    OtherCgroup(String),
83    #[error("{0}")]
84    Other(String),
85}
86
87#[derive(Debug, thiserror::Error)]
88pub enum ErrInvalidID {
89    #[error("container id can't be empty")]
90    Empty,
91    #[error("container id contains invalid characters: {0}")]
92    InvalidChars(char),
93    #[error("container id can't be used to represent a file name (such as . or ..)")]
94    FileName,
95}
96
97#[derive(Debug, thiserror::Error)]
98pub enum ErrInvalidSpec {
99    #[error("runtime spec has incompatible version. Only 1.X.Y is supported")]
100    UnsupportedVersion,
101    #[error("apparmor is specified but not enabled on this system")]
102    AppArmorNotEnabled,
103    #[error("invalid io priority or class.")]
104    IoPriority,
105    #[error("invalid scheduler config for process")]
106    Scheduler,
107}
108
109#[derive(Debug, thiserror::Error)]
110pub struct CreateContainerError(Box<LibcontainerError>, Option<Box<LibcontainerError>>);
111
112impl CreateContainerError {
113    pub(crate) fn new(
114        run_error: LibcontainerError,
115        cleanup_error: Option<LibcontainerError>,
116    ) -> Self {
117        Self(Box::new(run_error), cleanup_error.map(Box::new))
118    }
119}
120
121impl std::fmt::Display for CreateContainerError {
122    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
123        write!(f, "failed to create container: {}", self.0)?;
124        if let Some(cleanup_err) = &self.1 {
125            write!(f, ". error during cleanup: {}", cleanup_err)?;
126        }
127        Ok(())
128    }
129}
130
131#[cfg(test)]
132mod tests {
133    use libcgroups::common::CreateCgroupSetupError;
134
135    use super::{CreateContainerError, ErrInvalidID};
136
137    #[test]
138    fn test_create_container() {
139        let create_container_err =
140            CreateContainerError::new(CreateCgroupSetupError::NonDefault.into(), None);
141        let msg = format!("{}", create_container_err);
142        assert_eq!(
143            "failed to create container: non default cgroup root not supported",
144            msg
145        );
146
147        let create_container_err = CreateContainerError::new(
148            CreateCgroupSetupError::NonDefault.into(),
149            Some(ErrInvalidID::Empty.into()),
150        );
151        let msg = format!("{}", create_container_err);
152        assert_eq!(
153            "failed to create container: non default cgroup root not supported. \
154         error during cleanup: container id can't be empty",
155            msg
156        );
157    }
158    #[test]
159    fn test_libcontainer_error_msg() {
160        use crate::container::ContainerStatus::*;
161        use crate::error::LibcontainerError::IncorrectStatus;
162
163        assert_eq!(
164            "failed operation due to incompatible container status: `Creating`",
165            format!("{}", IncorrectStatus(Creating))
166        );
167        assert_eq!(
168            "failed operation due to incompatible container status: `Created`",
169            format!("{}", IncorrectStatus(Created))
170        );
171        assert_eq!(
172            "failed operation due to incompatible container status: `Stopped`",
173            format!("{}", IncorrectStatus(Stopped))
174        );
175        assert_eq!(
176            "failed operation due to incompatible container status: `Running`",
177            format!("{}", IncorrectStatus(Running))
178        );
179        assert_eq!(
180            "failed operation due to incompatible container status: `Paused`",
181            format!("{}", IncorrectStatus(Paused))
182        );
183    }
184}