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    /// Container operation failed
38    #[error("Container operation failed: {0}")]
39    Container(String),
40
41    /// Volume operation failed
42    #[error("Volume operation failed: {0}")]
43    Volume(String),
44
45    /// Operation timed out
46    #[error("Docker operation timed out")]
47    Timeout,
48}
49
50impl From<bollard::errors::Error> for DockerError {
51    fn from(err: bollard::errors::Error) -> Self {
52        let msg = err.to_string();
53
54        // Detect common error patterns and provide better messages
55        if msg.contains("No such file or directory") {
56            DockerError::SocketNotFound
57        } else if msg.contains("Cannot connect to the Docker daemon")
58            || msg.contains("connection refused")
59        {
60            DockerError::NotRunning
61        } else if msg.contains("permission denied") || msg.contains("Permission denied") {
62            DockerError::PermissionDenied
63        } else {
64            DockerError::Connection(msg)
65        }
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72
73    #[test]
74    fn docker_error_displays_correctly() {
75        let err = DockerError::NotRunning;
76        assert!(err.to_string().contains("Docker daemon not running"));
77
78        let err = DockerError::SocketNotFound;
79        assert!(err.to_string().contains("Docker socket not found"));
80
81        let err = DockerError::PermissionDenied;
82        assert!(err.to_string().contains("Permission denied"));
83
84        let err = DockerError::Build("layer failed".to_string());
85        assert!(err.to_string().contains("layer failed"));
86    }
87}