1use microsandbox_utils::MicrosandboxUtilsError;
2use sqlx::migrate::MigrateError;
3use std::{
4 error::Error,
5 fmt::{self, Display},
6 path::{PathBuf, StripPrefixError},
7 time::SystemTimeError,
8};
9use thiserror::Error;
10
11use crate::oci::DockerRegistryResponseError;
12
13pub type MicrosandboxResult<T> = Result<T, MicrosandboxError>;
19
20#[derive(pretty_error_debug::Debug, Error)]
22pub enum MicrosandboxError {
23 #[error("io error: {0}")]
25 Io(#[from] std::io::Error),
26
27 #[error(transparent)]
29 Custom(#[from] AnyError),
30
31 #[error("oci distribution error: {0}")]
33 OciDistribution(#[from] anyhow::Error),
34
35 #[error("http request error: {0}")]
37 HttpRequest(#[from] reqwest::Error),
38
39 #[error("http middleware error: {0}")]
41 HttpMiddleware(#[from] reqwest_middleware::Error),
42
43 #[error("database error: {0}")]
45 Database(#[from] sqlx::Error),
46
47 #[error("manifest not found")]
49 ManifestNotFound,
50
51 #[error("join error: {0}")]
53 JoinError(#[from] tokio::task::JoinError),
54
55 #[error("unsupported image hash algorithm: {0}")]
57 UnsupportedImageHashAlgorithm(String),
58
59 #[error("image layer download failed: {0}")]
61 ImageLayerDownloadFailed(String),
62
63 #[error("invalid path pair: {0}")]
65 InvalidPathPair(String),
66
67 #[error("invalid port pair: {0}")]
69 InvalidPortPair(String),
70
71 #[error("invalid environment variable pair: {0}")]
73 InvalidEnvPair(String),
74
75 #[error("invalid MicroVm configuration: {0}")]
77 InvalidMicroVMConfig(InvalidMicroVMConfigError),
78
79 #[error("invalid resource limit format: {0}")]
81 InvalidRLimitFormat(String),
82
83 #[error("invalid resource limit value: {0}")]
85 InvalidRLimitValue(String),
86
87 #[error("invalid resource limit resource: {0}")]
89 InvalidRLimitResource(String),
90
91 #[error("serde json error: {0}")]
93 SerdeJson(#[from] serde_json::Error),
94
95 #[error("serde yaml error: {0}")]
97 SerdeYaml(#[from] serde_yaml::Error),
98
99 #[error("toml error: {0}")]
101 Toml(#[from] toml::de::Error),
102
103 #[error("configuration validation error: {0}")]
105 ConfigValidation(String),
106
107 #[error("configuration validation errors: {0:?}")]
109 ConfigValidationErrors(Vec<String>),
110
111 #[error("service '{0}' belongs to no group")]
113 ServiceBelongsToNoGroup(String),
114
115 #[error("service '{0}' belongs to wrong group: '{1}'")]
118 ServiceBelongsToWrongGroup(String, String),
119
120 #[error("failed to get shutdown eventfd: {0}")]
122 FailedToGetShutdownEventFd(i32),
123
124 #[error("failed to write to shutdown eventfd: {0}")]
126 FailedToShutdown(String),
127
128 #[error("failed to start VM: {0}")]
130 FailedToStartVM(i32),
131
132 #[error("path does not exist: {0}")]
134 PathNotFound(String),
135
136 #[error("rootfs path does not exist: {0}")]
138 RootFsPathNotFound(String),
139
140 #[error("supervisor binary not found: {0}")]
142 SupervisorBinaryNotFound(String),
143
144 #[error("failed to start VM: {0}")]
146 StartVmFailed(i32),
147
148 #[error("process wait error: {0}")]
150 ProcessWaitError(String),
151
152 #[error("supervisor error: {0}")]
154 SupervisorError(String),
155
156 #[error("failed to kill process: {0}")]
158 ProcessKillError(String),
159
160 #[error("configuration merge error: {0}")]
162 ConfigMerge(String),
163
164 #[error("no available IP addresses in the pool")]
166 NoAvailableIPs,
167
168 #[error("walkdir error: {0}")]
170 WalkDir(#[from] walkdir::Error),
171
172 #[error("strip prefix error: {0}")]
174 StripPrefix(#[from] StripPrefixError),
175
176 #[error("nix error: {0}")]
178 NixError(#[from] nix::Error),
179
180 #[error("system time error: {0}")]
182 SystemTime(#[from] SystemTimeError),
183
184 #[error("layer extraction error: {0}")]
187 LayerExtraction(String),
188
189 #[error("layer handling error: {source}")]
192 LayerHandling {
193 source: std::io::Error,
195 layer: String,
197 },
198
199 #[error("configuration file not found: {0}")]
201 ConfigNotFound(String),
202
203 #[error("Service rootfs not found: {0}")]
205 RootfsNotFound(String),
206
207 #[error("invalid image reference: {0}")]
209 ImageReferenceError(String),
210
211 #[error("Cannot remove running services: {0}")]
213 ServiceStillRunning(String),
214
215 #[error("{0}")]
217 InvalidArgument(String),
218
219 #[error("path validation error: {0}")]
221 PathValidation(String),
222
223 #[error("microsandbox config file not found at: {0}")]
225 MicrosandboxConfigNotFound(String),
226
227 #[error("failed to parse configuration file: {0}")]
229 ConfigParseError(String),
230
231 #[error("log not found: {0}")]
233 LogNotFound(String),
234
235 #[error("pager error: {0}")]
237 PagerError(String),
238
239 #[error("microsandbox-utils error: {0}")]
241 MicrosandboxUtilsError(#[from] MicrosandboxUtilsError),
242
243 #[error("migration error: {0}")]
245 MigrationError(#[from] MigrateError),
246
247 #[error("docker registry response error: {0}")]
249 DockerRegistryResponseError(#[from] DockerRegistryResponseError),
250
251 #[error("invalid image reference selector format: {0}")]
253 InvalidReferenceSelectorFormat(String),
254
255 #[error("invalid image reference selector digest: {0}")]
257 InvalidReferenceSelectorDigest(String),
258
259 #[error("feature not yet implemented: {0}")]
261 NotImplemented(String),
262
263 #[error("cannot find sandbox: '{0}' in '{1}'")]
265 SandboxNotFoundInConfig(String, PathBuf),
266
267 #[error("invalid log level: {0}")]
269 InvalidLogLevel(u8),
270
271 #[error("empty path segment")]
273 EmptyPathSegment,
274
275 #[error("invalid path component: {0}")]
277 InvalidPathComponent(String),
278
279 #[error("script '{0}' not found in sandbox configuration '{1}'")]
281 ScriptNotFoundInSandbox(String, String),
282
283 #[error("sandbox server error: {0}")]
285 SandboxServerError(String),
286
287 #[error("invalid network scope: {0}")]
289 InvalidNetworkScope(String),
290
291 #[error("missing start script or exec command or shell")]
293 MissingStartOrExecOrShell,
294
295 #[error("command already exists: {0}")]
297 CommandExists(String),
298
299 #[error("command not found: {0}")]
301 CommandNotFound(String),
302}
303
304#[derive(Debug, Error)]
306pub enum InvalidMicroVMConfigError {
307 #[error("root path does not exist: {0}")]
309 RootPathDoesNotExist(String),
310
311 #[error("host path does not exist: {0}")]
313 HostPathDoesNotExist(String),
314
315 #[error("number of vCPUs is zero")]
317 NumVCPUsIsZero,
318
319 #[error("amount of memory is zero")]
321 MemoryIsZero,
322
323 #[error("command line contains invalid characters (only ASCII characters between space and tilde are allowed): {0}")]
325 InvalidCommandLineString(String),
326
327 #[error("Conflicting guest paths: '{0}' and '{1}' overlap")]
329 ConflictingGuestPaths(String, String),
330}
331
332#[derive(Debug)]
334pub struct AnyError {
335 error: anyhow::Error,
336}
337
338impl MicrosandboxError {
343 pub fn custom(error: impl Into<anyhow::Error>) -> MicrosandboxError {
345 MicrosandboxError::Custom(AnyError {
346 error: error.into(),
347 })
348 }
349}
350
351impl AnyError {
352 pub fn downcast<T>(&self) -> Option<&T>
354 where
355 T: Display + fmt::Debug + Send + Sync + 'static,
356 {
357 self.error.downcast_ref::<T>()
358 }
359}
360
361#[allow(non_snake_case)]
367pub fn Ok<T>(value: T) -> MicrosandboxResult<T> {
368 Result::Ok(value)
369}
370
371impl PartialEq for AnyError {
376 fn eq(&self, other: &Self) -> bool {
377 self.error.to_string() == other.error.to_string()
378 }
379}
380
381impl Display for AnyError {
382 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
383 write!(f, "{}", self.error)
384 }
385}
386
387impl Error for AnyError {}