Skip to main content

zlayer_core/
error.rs

1//! Core error types for `ZLayer`
2//!
3//! This module defines the global error hierarchy used across all `ZLayer` crates.
4
5use std::path::PathBuf;
6use thiserror::Error;
7
8/// Global `ZLayer` error type
9#[derive(Debug, Error)]
10pub enum ZLayerError {
11    /// Spec-related errors
12    #[error("spec error: {0}")]
13    Spec(#[from] zlayer_spec::SpecError),
14
15    /// Container runtime errors
16    #[error("container error: {0}")]
17    Container(#[from] ContainerError),
18
19    /// Network-related errors
20    #[error("network error: {0}")]
21    Network(#[from] NetworkError),
22
23    /// Runtime/agent errors
24    #[error("runtime error: {0}")]
25    Runtime(#[from] RuntimeError),
26
27    /// Configuration errors
28    #[error("config error: {0}")]
29    Config(#[from] ConfigError),
30
31    /// Registry/OCI errors
32    #[error("registry error: {0}")]
33    Registry(#[from] RegistryError),
34
35    /// IO errors with context
36    #[error("IO error at {path}: {source}")]
37    Io {
38        path: PathBuf,
39        #[source]
40        source: std::io::Error,
41    },
42}
43
44/// Container runtime errors
45#[derive(Debug, Error)]
46pub enum ContainerError {
47    /// Failed to pull image
48    #[error("failed to pull image {image}: {reason}")]
49    PullFailed { image: String, reason: String },
50
51    /// Failed to create container
52    #[error("failed to create container: {0}")]
53    CreateFailed(String),
54
55    /// Failed to start container
56    #[error("failed to start container {id}: {reason}")]
57    StartFailed { id: String, reason: String },
58
59    /// Container exited unexpectedly
60    #[error("container {id} exited with code {code}")]
61    Exited { id: String, code: i32 },
62
63    /// Container not found
64    #[error("container {id} not found")]
65    NotFound { id: String },
66
67    /// Health check failed
68    #[error("health check failed for {id}: {reason}")]
69    HealthCheckFailed { id: String, reason: String },
70
71    /// Init action failed
72    #[error("init action {action} failed for {id}: {reason}")]
73    InitActionFailed {
74        id: String,
75        action: String,
76        reason: String,
77    },
78}
79
80/// Network-related errors
81#[derive(Debug, Error)]
82pub enum NetworkError {
83    /// Failed to create overlay interface
84    #[error("failed to create overlay interface {name}: {reason}")]
85    OverlayCreateFailed { name: String, reason: String },
86
87    /// Failed to configure overlay peer
88    #[error("failed to configure overlay peer: {0}")]
89    OverlayPeerFailed(String),
90
91    /// DNS resolution failed
92    #[error("DNS resolution failed for {name}: {reason}")]
93    DnsFailed { name: String, reason: String },
94
95    /// Connection timeout
96    #[error("connection timeout to {address}")]
97    ConnectionTimeout { address: String },
98
99    /// Failed to bind port
100    #[error("failed to bind port {port}: {reason}")]
101    BindFailed { port: u16, reason: String },
102}
103
104/// Runtime/agent errors
105#[derive(Debug, Error)]
106pub enum RuntimeError {
107    /// Failed to join deployment
108    #[error("failed to join deployment {name}: {reason}")]
109    JoinFailed { name: String, reason: String },
110
111    /// Scheduler error
112    #[error("scheduler error: {0}")]
113    Scheduler(String),
114
115    /// Service discovery error
116    #[error("service discovery error: {0}")]
117    ServiceDiscovery(String),
118
119    /// Autoscaling error
120    #[error("autoscaling error for {service}: {reason}")]
121    AutoscalingFailed { service: String, reason: String },
122
123    /// Leadership lost
124    #[error("leadership lost for deployment {name}")]
125    LeadershipLost { name: String },
126}
127
128/// Configuration errors
129#[derive(Debug, Error)]
130pub enum ConfigError {
131    /// Missing required configuration
132    #[error("missing required configuration: {0}")]
133    Missing(String),
134
135    /// Invalid configuration value
136    #[error("invalid configuration for {key}: {reason}")]
137    Invalid { key: String, reason: String },
138
139    /// Failed to load configuration file
140    #[error("failed to load config from {path}: {reason}")]
141    LoadFailed { path: PathBuf, reason: String },
142
143    /// Generic configuration error
144    #[error("{0}")]
145    Other(String),
146}
147
148impl ConfigError {
149    /// Create a generic configuration error
150    pub fn other(msg: impl Into<String>) -> ZLayerError {
151        ZLayerError::Config(ConfigError::Other(msg.into()))
152    }
153}
154
155/// Registry/OCI errors
156#[derive(Debug, Error)]
157pub enum RegistryError {
158    /// Failed to pull manifest
159    #[error("failed to pull manifest for {image}: {reason}")]
160    ManifestFailed { image: String, reason: String },
161
162    /// Failed to pull blob
163    #[error("failed to pull blob {digest}: {reason}")]
164    BlobFailed { digest: String, reason: String },
165
166    /// Authentication failed
167    #[error("authentication failed for registry {registry}")]
168    AuthFailed { registry: String },
169
170    /// Image not found
171    #[error("image {image} not found")]
172    NotFound { image: String },
173}
174
175/// Result type alias for `ZLayer` operations
176pub type Result<T, E = ZLayerError> = std::result::Result<T, E>;
177
178/// Convenience alias for core Error type
179pub use ZLayerError as Error;
180
181impl Error {
182    /// Create a configuration error
183    pub fn config(msg: impl Into<String>) -> Self {
184        ZLayerError::Config(ConfigError::Other(msg.into()))
185    }
186}
187
188#[cfg(test)]
189mod tests {
190    use super::*;
191
192    #[test]
193    fn test_error_display() {
194        let err = ContainerError::NotFound {
195            id: "test-id".to_string(),
196        };
197        assert!(err.to_string().contains("test-id"));
198    }
199}