1 //! Errors for this module. 2 use std::cmp; 3 use std::fmt::{Display, Formatter, Result}; 4 5 use failure::Context; 6 7 #[derive(Debug)] 8 /// Generic Error type over all errors in the bollard library 9 pub struct Error { 10 inner: Context<ErrorKind>, 11 } 12 13 /// The type of error embedded in an Error. 14 #[derive(Debug, Fail)] 15 pub enum ErrorKind { 16 #[fail(display = "could not find DOCKER_CERT_PATH")] 17 /// Error emitted during client instantiation when the `DOCKER_CERT_PATH` environment variable 18 /// is invalid. 19 NoCertPathError, 20 #[fail(display = "API responded with a 404 not found: {}", message)] 21 /// Error emitted by the docker server, when it responds with a 404. 22 DockerResponseNotFoundError { 23 /// Message returned by the docker server. 24 message: String, 25 }, 26 #[fail( 27 display = "Docker responded with status code {}: {}", 28 status_code, message 29 )] 30 /// Generic error emitted by the docker server. 31 DockerResponseServerError { 32 /// Status code returned by the docker server. 33 status_code: u16, 34 /// Message returned by the docker server. 35 message: String, 36 }, 37 #[fail(display = "API queried with a bad parameter: {}", message)] 38 /// Error emitted by the docker server, when it responds with a 400. 39 DockerResponseBadParameterError { 40 /// Message returned by the docker server. 41 message: String, 42 }, 43 #[fail(display = "API responded with a 409 conflict: {}", message)] 44 /// Error emitted by the docker server, when it responds with a 409. 45 DockerResponseConflictError { 46 /// Message returned by the docker server. 47 message: String, 48 }, 49 #[fail( 50 display = "API responded with a 304, resource was not modified: {}", 51 message 52 )] 53 /// Error emitted by the docker server, when it responds with a 304. 54 DockerResponseNotModifiedError { 55 /// Message returned by the docker server. 56 message: String, 57 }, 58 #[fail(display = "Failed to deserialize JSON: {}", message)] 59 /// Error facilitating debugging failed JSON parsing. 60 JsonDataError { 61 /// Short section of the json close to the error. 62 message: String, 63 /// Entire JSON payload. 64 contents: String, 65 /// Character sequence at error location. 66 column: usize, 67 }, 68 #[fail(display = "Failed to parse API version: {}", api_version)] 69 /// Error emitted when the server version cannot be parsed when negotiating a version 70 APIVersionParseError { 71 /// The api version returned by the server. 72 api_version: String, 73 }, 74 #[fail(display = "Failed to serialize JSON: {:?}", err)] 75 /// Error emitted when JSON fails to serialize. 76 JsonSerializeError { 77 /// The original error emitted by serde. 78 err: serde_json::Error, 79 }, 80 #[fail(display = "Failed to deserialize JSON: {}: {:?}", content, err)] 81 /// Error emitted when JSON fails to deserialize. 82 JsonDeserializeError { 83 /// The original string that was being deserialized. 84 content: String, 85 /// The original error emitted by serde. 86 err: serde_json::Error, 87 }, 88 #[fail(display = "UTF8 error: {}: {:?}", content, err)] 89 /// Error emitted when log output generates an I/O error. 90 StrParseError { 91 /// the bytes that failed 92 content: String, 93 /// The original error emitted. 94 err: std::str::Utf8Error, 95 }, 96 #[fail(display = "I/O error: {:?}", err)] 97 /// Error emitted from an I/O error. 98 IOError { 99 /// The original error emitted. 100 err: std::io::Error, 101 }, 102 #[fail(display = "Format error: {}: {:?}", content, err)] 103 /// Error emitted from a formatting error. 104 StrFmtError { 105 /// The original string that failed to format. 106 content: String, 107 /// The original error emitted. 108 err: std::fmt::Error, 109 }, 110 #[fail(display = "HTTP error: {}: {:?}", builder, err)] 111 /// Error emitted from an HTTP error. 112 HttpClientError { 113 /// The client builder, formatted as a debug string. 114 builder: String, 115 /// The original error emitted. 116 err: http::Error, 117 }, 118 #[fail(display = "Hyper error: {:?}", err)] 119 /// Error emitted from an HTTP error. 120 HyperResponseError { 121 /// The original error emitted. 122 err: hyper::Error, 123 }, 124 /// Error emitted when a request times out. 125 #[fail(display = "Timeout error")] 126 RequestTimeoutError, 127 /// Error emitted when an SSL context fails to configure. 128 #[cfg(feature = "openssl")] 129 #[fail(display = "SSL error: {:?}", err)] 130 SSLError { 131 /// The original error emitted. 132 err: openssl::error::ErrorStack, 133 }, 134 /// Error emitted when a TLS context fails to configure. 135 #[cfg(feature = "tls")] 136 #[fail(display = "TLS error: {:?}", err)] 137 TLSError { 138 /// The original error emitted. 139 err: native_tls::Error, 140 }, 141 } 142 143 impl Display for Error { fmt(&self, f: &mut Formatter<'_>) -> Result144 fn fmt(&self, f: &mut Formatter<'_>) -> Result { 145 match self.inner.get_context() { 146 ErrorKind::JsonDataError { 147 message, 148 contents, 149 column, 150 } => { 151 let backtrack_len: usize = 24; 152 let peek_len: usize = 32; 153 let description = "Failed to deserialize near ..."; 154 let from_start_length = column.checked_sub(backtrack_len).unwrap_or(0); 155 write!( 156 f, 157 "{}{}...\n{}", 158 description, 159 &contents[from_start_length..cmp::min(contents.len(), column + peek_len)], 160 message 161 ) 162 } 163 _ => Display::fmt(&self.inner, f), 164 } 165 } 166 } 167 168 impl std::error::Error for Error { source(&self) -> Option<&(dyn std::error::Error + 'static)>169 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 170 match self.inner.get_context() { 171 ErrorKind::JsonSerializeError { err, .. } => Some(err), 172 ErrorKind::JsonDeserializeError { err, .. } => Some(err), 173 ErrorKind::StrParseError { err, .. } => Some(err), 174 ErrorKind::IOError { err, .. } => Some(err), 175 ErrorKind::StrFmtError { err, .. } => Some(err), 176 ErrorKind::HttpClientError { err, .. } => Some(err), 177 ErrorKind::HyperResponseError { err, .. } => Some(err), 178 _ => None, 179 } 180 } 181 } 182 183 impl Error { 184 /// yield the underlying error kind of this error. kind(&self) -> &ErrorKind185 pub fn kind(&self) -> &ErrorKind { 186 self.inner.get_context() 187 } 188 } 189 190 impl From<ErrorKind> for Error { from(kind: ErrorKind) -> Error191 fn from(kind: ErrorKind) -> Error { 192 Error { 193 inner: Context::new(kind), 194 } 195 } 196 } 197 198 impl From<Context<ErrorKind>> for Error { from(inner: Context<ErrorKind>) -> Error199 fn from(inner: Context<ErrorKind>) -> Error { 200 Error { inner: inner } 201 } 202 } 203 204 /// Needed due to tokio's Decoder implementation 205 impl From<std::io::Error> for Error { from(err: std::io::Error) -> Error206 fn from(err: std::io::Error) -> Error { 207 Error { 208 inner: ErrorKind::IOError { err: err }.into(), 209 } 210 } 211 } 212