docker_client_async/
opts.rs1use crate::error::*;
21use crate::{parse_host_url, DockerEngineClient, UnixConnector};
22use hyper::client::connect::Connect;
23use hyper::client::HttpConnector;
24use hyper::Client;
25use hyper_tls::HttpsConnector;
26use native_tls::{Certificate, Identity};
27use openssl::pkcs12::Pkcs12;
28use openssl::pkey::PKey;
29use openssl::x509::X509;
30use snafu::ResultExt;
31use std::collections::HashMap;
32use std::path::Path;
33use std::time::Duration;
34use std::{env, fs};
35use tokio_tls::TlsConnector;
36
37pub type DockerEngineClientOption<C> = Box<dyn Fn(&mut DockerEngineClient<C>) -> Result<(), Error>>;
39
40pub fn from_env_remote_tls(
47 client: &mut DockerEngineClient<HttpsConnector<HttpConnector>>,
48) -> Result<(), Error> {
49 if let Ok(docker_cert_path) = env::var("DOCKER_CERT_PATH") {
50 let insecure_skip_verify = if let Ok(tls_verify) = env::var("DOCKER_TLS_VERIFY") {
51 tls_verify.is_empty()
52 } else {
53 false
54 };
55
56 let docker_cert_path = Path::new(&docker_cert_path);
57 let ca_certificate_pem =
58 fs::read_to_string(docker_cert_path.join("ca.pem")).context(IoError {})?;
59 let client_certificate_pem =
60 fs::read_to_string(docker_cert_path.join("cert.pem")).context(IoError {})?;
61 let client_key_pem =
62 fs::read_to_string(docker_cert_path.join("key.pem")).context(IoError {})?;
63
64 let pcks12_encoded_client_key = pem_to_pkcs12(&client_certificate_pem, &client_key_pem)?;
65
66 let ca_certificate = Certificate::from_pem(ca_certificate_pem.as_bytes())
67 .context(CertificateParseError {})?;
68 let client_identity = Identity::from_pkcs12(&pcks12_encoded_client_key, "")
69 .context(CertificateParseError {})?;
70
71 let mut http_connector = HttpConnector::new();
72 http_connector.enforce_http(false);
73 let tls_connector = TlsConnector::from(
74 native_tls::TlsConnector::builder()
75 .identity(client_identity)
76 .add_root_certificate(ca_certificate)
77 .danger_accept_invalid_hostnames(insecure_skip_verify)
78 .build()
79 .unwrap(),
80 );
81 let https_connector = HttpsConnector::from((http_connector, tls_connector));
82 client.client = Some(Client::builder().build(https_connector));
83 }
84 if let Ok(host) = env::var("DOCKER_HOST") {
85 with_host(host)(client)?;
86 }
87 if let Ok(version) = env::var("DOCKER_API_VERSION") {
88 with_version(version)(client)?;
89 }
90 Ok(())
91}
92
93pub fn from_env_remote(client: &mut DockerEngineClient<HttpConnector>) -> Result<(), Error> {
98 let mut http_connector = HttpConnector::new();
99 http_connector.enforce_http(false);
100 client.client = Some(Client::builder().build(http_connector));
101
102 if let Ok(host) = env::var("DOCKER_HOST") {
103 with_host(host)(client)?;
104 }
105 if let Ok(version) = env::var("DOCKER_API_VERSION") {
106 with_version(version)(client)?;
107 }
108 Ok(())
109}
110
111pub fn from_env(client: &mut DockerEngineClient<UnixConnector>) -> Result<(), Error> {
116 let unix_connector = UnixConnector;
117 client.client = Some(Client::builder().build(unix_connector));
118
119 if let Ok(host) = env::var("DOCKER_HOST") {
120 with_host(host)(client)?;
121 }
122 if let Ok(version) = env::var("DOCKER_API_VERSION") {
123 with_version(version)(client)?;
124 }
125 Ok(())
126}
127
128pub fn with_host<C: Connect + Clone + Send + Sync + 'static>(
130 host: String,
131) -> DockerEngineClientOption<C> {
132 Box::new(
133 move |client: &mut DockerEngineClient<C>| -> Result<(), Error> {
134 let host_url = parse_host_url(&host)?;
135 client.host = host_url.host().map(String::from);
136 client.proto = host_url.scheme_str().map(String::from);
137 client.addr = host_url.host().map(String::from);
138
139 let path = host_url.path();
140 client.base_path = if !path.is_empty() {
141 Some(path.into())
142 } else {
143 None
144 };
145 Ok(())
146 },
147 )
148}
149
150pub fn with_timeout<C: Connect + Clone + Send + Sync + 'static>(
152 timeout: Duration,
153) -> DockerEngineClientOption<C> {
154 Box::new(
155 move |client: &mut DockerEngineClient<C>| -> Result<(), Error> {
156 client.timeout = timeout;
157 Ok(())
158 },
159 )
160}
161
162#[allow(clippy::implicit_hasher)]
164pub fn with_http_headers<C: Connect + Clone + Send + Sync + 'static>(
165 headers: HashMap<String, String>,
166) -> DockerEngineClientOption<C> {
167 Box::new(
168 move |client: &mut DockerEngineClient<C>| -> Result<(), Error> {
169 if !headers.is_empty() {
170 client.custom_http_headers = Some(headers.clone());
171 }
172 Ok(())
173 },
174 )
175}
176
177pub fn with_scheme<C: Connect + Clone + Send + Sync + 'static>(
179 scheme: String,
180) -> DockerEngineClientOption<C> {
181 Box::new(
182 move |client: &mut DockerEngineClient<C>| -> Result<(), Error> {
183 client.scheme = Some(scheme.clone());
184 Ok(())
185 },
186 )
187}
188
189pub fn with_tls_client_config(
191 cacert_path: String,
192 cert_path: String,
193 key_path: String,
194) -> DockerEngineClientOption<HttpsConnector<HttpConnector>> {
195 Box::new(
196 move |client: &mut DockerEngineClient<HttpsConnector<HttpConnector>>| -> Result<(), Error> {
197 let ca_certificate_pem = fs::read_to_string(&cacert_path).context(IoError {})?;
198 let client_certificate_pem = fs::read_to_string(&cert_path).context(IoError {})?;
199 let client_key_pem = fs::read_to_string(&key_path).context(IoError {})?;
200
201 let pcks12_encoded_client_key =
202 pem_to_pkcs12(&client_certificate_pem, &client_key_pem)?;
203
204 let ca_certificate = Certificate::from_pem(ca_certificate_pem.as_bytes())
205 .context(CertificateParseError {})?;
206 let client_identity = Identity::from_pkcs12(&pcks12_encoded_client_key, "")
207 .context(CertificateParseError {})?;
208
209 let mut http_connector = HttpConnector::new();
210 http_connector.enforce_http(false);
211 let tls_connector = TlsConnector::from(
212 native_tls::TlsConnector::builder()
213 .identity(client_identity)
214 .add_root_certificate(ca_certificate)
215 .build()
216 .unwrap(),
217 );
218 let https_connector = HttpsConnector::from((http_connector, tls_connector));
219 client.client = Some(Client::builder().build(https_connector));
220 Ok(())
221 },
222 )
223}
224
225pub fn with_version<C: Connect + Clone + Send + Sync + 'static>(
228 version: String,
229) -> DockerEngineClientOption<C> {
230 Box::new(
231 move |client: &mut DockerEngineClient<C>| -> Result<(), Error> {
232 if !version.is_empty() {
233 client.version = version.clone();
234 client.manual_override = true;
235 }
236 Ok(())
237 },
238 )
239}
240
241pub fn with_api_version_negotiation<C: Connect + Clone + Send + Sync + 'static>(
246) -> DockerEngineClientOption<C> {
247 Box::new(
248 move |client: &mut DockerEngineClient<C>| -> Result<(), Error> {
249 client.negotiate_version = true;
250 Ok(())
251 },
252 )
253}
254
255fn pem_to_pkcs12(client_certificate_pem: &str, client_key_pem: &str) -> Result<Vec<u8>, Error> {
258 let client_certificate =
259 X509::from_pem(client_certificate_pem.as_bytes()).context(CryptoError {})?;
260 let client_private_key =
261 PKey::private_key_from_pem(client_key_pem.as_bytes()).context(CryptoError {})?;
262 Pkcs12::builder()
263 .build("", "", &client_private_key, &client_certificate)
264 .context(CryptoError {})?
265 .to_der()
266 .context(CryptoError {})
267}