use derive_more::Display;
use foundation_errstacks::ErrorTrace;
pub type DockerResult<T> = Result<T, ErrorTrace<DockerError>>;
#[derive(Debug, Display)]
pub enum DockerError {
#[display("Docker daemon not reachable: {_0}")]
Connection(String),
#[display("Docker API error during {operation} (status {status}): {message}")]
Api {
operation: String,
status: u16,
message: String,
},
#[display("Docker daemon is incompatible with this client: {_0}")]
IncompatibleDaemon(String),
#[display("Image pull failed for '{image}': {reason}")]
ImagePull { image: String, reason: String },
#[display("Image push failed: {_0}")]
ImagePush(String),
#[display("Image load failed: {_0}")]
ImageLoad(String),
#[display("Image build failed: {_0}")]
ImageBuild(String),
#[display("Container creation failed: {_0}")]
ContainerCreate(String),
#[display("Container start failed: {_0}")]
ContainerStart(String),
#[display("Container exited with code {code} before becoming ready")]
ContainerExited { code: i64 },
#[display("Wait strategy '{strategy}' timed out after {elapsed:?}")]
WaitTimeout {
strategy: String,
elapsed: std::time::Duration,
},
#[display("Network operation failed: {_0}")]
Network(String),
#[display("Invalid configuration: {_0}")]
InvalidConfig(String),
}
impl std::error::Error for DockerError {}
impl DockerError {
#[must_use]
pub fn is_connection_error(&self) -> bool {
matches!(self, Self::Connection(_))
}
}
#[must_use]
pub fn docker_err(e: DockerError) -> ErrorTrace<DockerError> {
ErrorTrace::new(e)
}
#[must_use]
pub fn classify_docker_client_err(
operation: &str,
e: foundation_deployment_docker::DockerError,
) -> DockerError {
use foundation_deployment_docker::DockerError as De;
match e {
De::Transport(m) | De::Unavailable(m) => DockerError::Connection(format!("{operation}: {m}")),
De::Api { status, message } => DockerError::Api {
operation: operation.to_string(),
status,
message,
},
e @ De::UnsupportedApiVersion { .. } => {
DockerError::IncompatibleDaemon(format!("{operation}: {e}"))
}
De::JsonParse(m) => DockerError::InvalidConfig(format!("{operation}: {m}")),
De::BuildFailed(m) => DockerError::ImageBuild(m),
De::PullFailed(m) => DockerError::ImagePull { image: operation.to_string(), reason: m },
De::PushFailed(m) => DockerError::ImagePush(format!("{operation}: {m}")),
De::LoadFailed(m) => DockerError::ImageLoad(format!("{operation}: {m}")),
}
}
#[must_use]
pub fn map_docker_client_err(e: foundation_deployment_docker::DockerError) -> ErrorTrace<DockerError> {
docker_err(classify_docker_client_err("docker request", e))
}