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 #[error(transparent)]
32 InvalidID(#[from] ErrInvalidID),
33 #[error(transparent)]
34 MissingSpec(#[from] MissingSpecError),
35 #[error("invalid runtime spec")]
36 InvalidSpec(#[from] ErrInvalidSpec),
37
38 #[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 #[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}