Skip to main content

opencode_cloud_core/docker/
error.rs

1//! Docker-specific error types
2//!
3//! This module defines errors that can occur during Docker operations,
4//! providing clear, actionable messages for common issues.
5
6use thiserror::Error;
7
8/// Errors that can occur during Docker operations
9#[derive(Error, Debug)]
10pub enum DockerError {
11    /// Failed to connect to the Docker daemon
12    #[error("Docker connection failed: {0}")]
13    Connection(String),
14
15    /// Docker daemon is not running
16    #[error("Docker daemon not running. Start Docker Desktop or the Docker service.")]
17    NotRunning,
18
19    /// Docker socket not found
20    #[error("Docker socket not found. Is Docker installed and running?")]
21    SocketNotFound,
22
23    /// Permission denied accessing Docker socket
24    #[error(
25        "Permission denied accessing Docker socket. You may need to add your user to the 'docker' group."
26    )]
27    PermissionDenied,
28
29    /// Failed to build Docker image
30    #[error("Docker build failed: {0}")]
31    Build(String),
32
33    /// Failed to pull Docker image
34    #[error("Docker pull failed: {0}")]
35    Pull(String),
36
37    /// Image operation failed
38    #[error("Docker image operation failed: {0}")]
39    Image(String),
40
41    /// Container operation failed
42    #[error("Container operation failed: {0}")]
43    Container(String),
44
45    /// Volume operation failed
46    #[error("Volume operation failed: {0}")]
47    Volume(String),
48
49    /// Operation timed out
50    #[error("Docker operation timed out")]
51    Timeout,
52}
53
54impl From<bollard::errors::Error> for DockerError {
55    fn from(err: bollard::errors::Error) -> Self {
56        let msg = err.to_string();
57
58        // Detect common error patterns and provide better messages
59        if msg.contains("No such file or directory") {
60            DockerError::SocketNotFound
61        } else if msg.contains("Cannot connect to the Docker daemon")
62            || msg.contains("connection refused")
63        {
64            DockerError::NotRunning
65        } else if msg.contains("permission denied") || msg.contains("Permission denied") {
66            DockerError::PermissionDenied
67        } else {
68            DockerError::Connection(msg)
69        }
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76
77    #[test]
78    fn docker_error_displays_correctly() {
79        let err = DockerError::NotRunning;
80        assert!(err.to_string().contains("Docker daemon not running"));
81
82        let err = DockerError::SocketNotFound;
83        assert!(err.to_string().contains("Docker socket not found"));
84
85        let err = DockerError::PermissionDenied;
86        assert!(err.to_string().contains("Permission denied"));
87
88        let err = DockerError::Build("layer failed".to_string());
89        assert!(err.to_string().contains("layer failed"));
90    }
91}