systemg/
error.rs

1//! Error handling for systemg.
2use thiserror::Error;
3
4/// Defines all possible errors that can occur in the process manager.
5#[derive(Debug, Error)]
6pub enum ProcessManagerError {
7    /// Error reading or accessing a configuration file.
8    #[error("Failed to read config file: {0}")]
9    ConfigReadError(#[from] std::io::Error),
10
11    /// Error parsing YAML configuration.
12    #[error("Invalid YAML format: {0}")]
13    ConfigParseError(#[from] serde_yaml::Error),
14
15    /// Error spawning a service process.
16    #[error("Failed to start service '{service}': {source}")]
17    ServiceStartError {
18        /// The service name that failed to start.
19        service: String,
20        /// The underlying error that occurred.
21        #[source]
22        source: std::io::Error,
23    },
24
25    /// Error stopping a service process.
26    #[error("Failed to stop service '{service}': {source}")]
27    ServiceStopError {
28        /// The service name that failed to stop.
29        service: String,
30        /// The underlying error that occurred.
31        #[source]
32        source: std::io::Error,
33    },
34
35    /// Error executing a lifecycle hook (e.g., on_start, on_error).
36    #[error("Failed to execute hook for service '{service}': {source}")]
37    HookExecutionError {
38        /// The service name whose hook execution failed.
39        service: String,
40        /// The underlying error that occurred.
41        #[source]
42        source: std::io::Error,
43    },
44
45    /// Error when a required dependency service is not running.
46    #[error(
47        "Service '{service}' is waiting for an unavailable dependency: '{dependency}'"
48    )]
49    DependencyError {
50        /// The service that is waiting.
51        service: String,
52        /// The missing dependency.
53        dependency: String,
54    },
55
56    /// Error when a dependency has failed during startup.
57    #[error("Service '{service}' cannot start because dependency '{dependency}' failed")]
58    DependencyFailed {
59        /// The service that cannot be started.
60        service: String,
61        /// The dependency that failed.
62        dependency: String,
63    },
64
65    /// Error when a dependency reference is undefined in the configuration.
66    #[error("Service '{service}' declares unknown dependency '{dependency}'")]
67    UnknownDependency {
68        /// The service with an invalid dependency reference.
69        service: String,
70        /// The missing dependency name.
71        dependency: String,
72    },
73
74    /// Error when dependency graph contains a cycle.
75    #[error("Detected dependency cycle: {cycle}")]
76    DependencyCycle {
77        /// Human-readable cycle description (e.g. `a -> b -> a`).
78        cycle: String,
79    },
80
81    /// Error for poisoned mutex.
82    #[error("Mutex is poisoned: {0}")]
83    MutexPoisonError(String),
84
85    /// Error for PID file.
86    #[error("PID file error: {0}")]
87    PidFileError(#[from] PidFileError),
88
89    /// Error for service state file.
90    #[error("Service state error: {0}")]
91    ServiceStateError(#[from] ServiceStateError),
92
93    /// Error for logs manager.
94    #[error("Service not found in PID file")]
95    ErrNo(#[from] nix::errno::Errno),
96
97    /// Error when privilege setup fails before spawning a service.
98    #[error("Failed to configure privileges for service '{service}': {source}")]
99    PrivilegeSetupFailed {
100        /// Service requesting privilege changes.
101        service: String,
102        /// Underlying IO error.
103        #[source]
104        source: std::io::Error,
105    },
106
107    /// Error when services fail to remain running after a restart completes.
108    #[error("Service(s) failed to remain running after restart: {services:?}")]
109    ServicesNotRunning {
110        /// List of services that were expected to be running but were not.
111        services: Vec<String>,
112    },
113}
114
115/// Implement the `From` trait to convert a `std::sync::PoisonError` into a `ProcessManagerError`.
116impl<T> From<std::sync::PoisonError<T>> for ProcessManagerError {
117    /// Converts a `std::sync::PoisonError` into a `ProcessManagerError`.
118    fn from(err: std::sync::PoisonError<T>) -> Self {
119        ProcessManagerError::MutexPoisonError(err.to_string())
120    }
121}
122
123/// Error type for PID file operations.
124#[derive(Debug, Error)]
125pub enum PidFileError {
126    /// Error writing to a PID file.
127    #[error("Failed to read PID file: {0}")]
128    ReadError(#[from] std::io::Error),
129
130    /// Error writing to a PID file.
131    #[error("Failed to parse PID file: {0}")]
132    ParseError(#[from] serde_json::Error),
133
134    /// Error writing to a PID file.
135    #[error("Service not found in PID file")]
136    ServiceNotFound,
137}
138
139/// Error type for persistent service state file operations.
140#[derive(Debug, Error)]
141pub enum ServiceStateError {
142    /// Error reading the state file from disk.
143    #[error("Failed to read service state file: {0}")]
144    ReadError(#[from] std::io::Error),
145
146    /// Error parsing JSON contents of the state file.
147    #[error("Failed to parse service state file: {0}")]
148    ParseError(#[from] serde_json::Error),
149
150    /// Attempted to update or remove a non-existent service entry.
151    #[error("Service not found in state file")]
152    ServiceNotFound,
153}
154
155/// Error type for logs manager operations.
156#[derive(Debug, Error)]
157pub enum LogsManagerError {
158    /// Error parsing YAML configuration.
159    #[error("Service '{0}' not found in PID file")]
160    ServiceNotFound(String),
161
162    /// Error executing the tail command for logs.
163    #[error("Log file unavailable for PID {0}")]
164    LogUnavailable(u32),
165
166    /// Error while tailing logs, such as command failure.
167    #[error("Log tailing failed: {0}")]
168    LogProcessError(#[from] std::io::Error),
169
170    /// Error when the tail command exits with a non-zero status.
171    #[error("Log tail command exited with status {0:?}")]
172    TailCommandFailed(Option<i32>),
173
174    /// Error when the log file is unavailable.
175    #[error("Unsupported platform for log tailing")]
176    UnsupportedPlatform,
177}