summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/builder.rs24
-rw-r--r--src/errors.rs18
-rw-r--r--src/lib.rs458
-rw-r--r--src/transport.rs282
4 files changed, 422 insertions, 360 deletions
diff --git a/src/builder.rs b/src/builder.rs
index c69a155..ffc0cf1 100644
--- a/src/builder.rs
+++ b/src/builder.rs
@@ -25,7 +25,8 @@ impl PullOptions {
if self.params.is_empty() {
None
} else {
- Some(form_urlencoded::serialize(&self.params))
+ Some(form_urlencoded::Serializer::new(String::new())
+ .extend_pairs(&self.params).finish())
}
}
}
@@ -99,7 +100,8 @@ impl BuildOptions {
if self.params.is_empty() {
None
} else {
- Some(form_urlencoded::serialize(&self.params))
+ Some(form_urlencoded::Serializer::new(String::new())
+ .extend_pairs(&self.params).finish())
}
}
}
@@ -207,7 +209,8 @@ impl ContainerListOptions {
if self.params.is_empty() {
None
} else {
- Some(form_urlencoded::serialize(&self.params))
+ Some(form_urlencoded::Serializer::new(String::new())
+ .extend_pairs(&self.params).finish())
}
}
}
@@ -680,7 +683,8 @@ impl EventsOptions {
if self.params.is_empty() {
None
} else {
- Some(form_urlencoded::serialize(&self.params))
+ Some(form_urlencoded::Serializer::new(String::new())
+ .extend_pairs(&self.params).finish())
}
}
}
@@ -817,7 +821,8 @@ impl LogsOptions {
if self.params.is_empty() {
None
} else {
- Some(form_urlencoded::serialize(&self.params))
+ Some(form_urlencoded::Serializer::new(String::new())
+ .extend_pairs(&self.params).finish())
}
}
}
@@ -886,7 +891,8 @@ impl ImageListOptions {
if self.params.is_empty() {
None
} else {
- Some(form_urlencoded::serialize(&self.params))
+ Some(form_urlencoded::Serializer::new(String::new())
+ .extend_pairs(&self.params).finish())
}
}
}
@@ -963,7 +969,8 @@ impl RmContainerOptions {
if self.params.is_empty() {
None
} else {
- Some(form_urlencoded::serialize(&self.params))
+ Some(form_urlencoded::Serializer::new(String::new())
+ .extend_pairs(&self.params).finish())
}
}
}
@@ -1006,7 +1013,8 @@ impl NetworkListOptions {
if self.params.is_empty() {
None
} else {
- Some(form_urlencoded::serialize(&self.params))
+ Some(form_urlencoded::Serializer::new(String::new())
+ .extend_pairs(&self.params).finish())
}
}
}
diff --git a/src/errors.rs b/src/errors.rs
index 856a010..d4905a1 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -1,7 +1,7 @@
//! Representations of various client errors
-use hyper::Error as HttpError;
-use hyper::status::StatusCode;
+use http;
+use hyper::{self, StatusCode};
use rustc_serialize::json::{DecoderError, EncoderError, ParserError};
use std::error::Error as ErrorTrait;
use std::fmt;
@@ -12,7 +12,8 @@ pub enum Error {
Decoding(DecoderError),
Encoding(EncoderError),
Parse(ParserError),
- Http(HttpError),
+ Hyper(hyper::Error),
+ Http(http::Error),
IO(IoError),
Fault { code: StatusCode, message: String },
}
@@ -35,8 +36,14 @@ impl From<EncoderError> for Error {
}
}
-impl From<HttpError> for Error {
- fn from(error: HttpError) -> Error {
+impl From<hyper::Error> for Error {
+ fn from(error: hyper::Error) -> Error {
+ Error::Hyper(error)
+ }
+}
+
+impl From<http::Error> for Error {
+ fn from(error: http::Error) -> Error {
Error::Http(error)
}
}
@@ -55,6 +62,7 @@ impl fmt::Display for Error {
&Error::Encoding(ref err) => return err.fmt(f),
&Error::Parse(ref err) => return err.fmt(f),
&Error::Http(ref err) => return err.fmt(f),
+ &Error::Hyper(ref err) => return err.fmt(f),
&Error::IO(ref err) => return err.fmt(f),
&Error::Fault { code, .. } => return write!(f, "{}", code),
};
diff --git a/src/lib.rs b/src/lib.rs
index 787b469..c2f7807 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -15,56 +15,63 @@
#[macro_use]
extern crate log;
+extern crate byteorder;
+extern crate flate2;
+extern crate http;
extern crate hyper;
extern crate hyper_openssl;
#[cfg(feature = "unix-socket")]
extern crate hyperlocal;
-extern crate flate2;
extern crate jed;
+extern crate mime;
extern crate openssl;
extern crate rustc_serialize;
-extern crate url;
extern crate tar;
-extern crate byteorder;
+extern crate url;
#[macro_use]
extern crate serde_derive;
extern crate serde;
+extern crate tokio;
pub mod builder;
+pub mod errors;
pub mod rep;
pub mod transport;
-pub mod errors;
pub mod tty;
mod tarball;
-pub use builder::{BuildOptions, ContainerConnectionOptions, ContainerFilter,
- ContainerListOptions, ContainerOptions, EventsOptions,
- ExecContainerOptions, ImageFilter, ImageListOptions,
- LogsOptions, NetworkCreateOptions, NetworkListOptions,
- PullOptions, RmContainerOptions};
+pub use builder::{
+ BuildOptions, ContainerConnectionOptions, ContainerFilter,
+ ContainerListOptions, ContainerOptions, EventsOptions,
+ ExecContainerOptions, ImageFilter, ImageListOptions, LogsOptions,
+ NetworkCreateOptions, NetworkListOptions, PullOptions, RmContainerOptions,
+};
pub use errors::Error;
-use hyper::{Client, Url};
-use hyper::client::Body;
-use hyper::header::ContentType;
-use hyper::method::Method;
-use hyper::net::HttpsConnector;
-use hyper_openssl::OpensslClient;
-use openssl::ssl::{SslConnectorBuilder, SslMethod};
-use openssl::x509::X509_FILETYPE_PEM;
-use rep::{Change, Container as ContainerRep, ContainerCreateInfo,
- ContainerDetails, Event, Exit, History, ImageDetails, Info,
- SearchResult, Stats, Status, Top, Version};
-use rep::{NetworkCreateInfo, NetworkDetails as NetworkInfo};
+use hyper::client::HttpConnector;
+use hyper::Body;
+use hyper::{Client, Method, Uri};
+use hyper_openssl::HttpsConnector;
+#[cfg(feature = "unix-socket")]
+use hyperlocal::UnixConnector;
+use mime::Mime;
+use openssl::ssl::{SslConnector, SslFiletype, SslMethod};
use rep::Image as ImageRep;
+use rep::{
+ Change, Container as ContainerRep, ContainerCreateInfo, ContainerDetails,
+ Event, Exit, History, ImageDetails, Info, SearchResult, Stats, Status, Top,
+ Version,
+};
+use rep::{NetworkCreateInfo, NetworkDetails as NetworkInfo};
use rustc_serialize::json::{self, Json};
use std::borrow::Cow;
-use std::env::{self, VarError};
-use std::io::Read;
+use std::cell::RefCell;
+use std::env;
+use std::io::prelude::*;
use std::iter::IntoIterator;
use std::path::Path;
use std::time::Duration;
-use transport::{Transport, tar};
+use transport::{tar, Transport};
use tty::Tty;
use url::form_urlencoded;
@@ -96,58 +103,49 @@ impl<'a, 'b> Image<'a, 'b> {
/// Inspects a named image's details
pub fn inspect(&self) -> Result<ImageDetails> {
- let raw = self.docker.get(&format!("/images/{}/json", self.name)[..])?;
+ let raw = self
+ .docker
+ .get(&format!("/images/{}/json", self.name)[..])?;
Ok(json::decode::<ImageDetails>(&raw)?)
}
/// Lists the history of the images set of changes
pub fn history(&self) -> Result<Vec<History>> {
- let raw = self.docker.get(
- &format!("/images/{}/history", self.name)[..],
- )?;
+ let raw = self
+ .docker
+ .get(&format!("/images/{}/history", self.name)[..])?;
Ok(json::decode::<Vec<History>>(&raw)?)
}
/// Delete's an image
pub fn delete(&self) -> Result<Vec<Status>> {
let raw = self.docker.delete(&format!("/images/{}", self.name)[..])?;
- Ok(
- match Json::from_str(&raw)? {
- Json::Array(ref xs) => {
- xs.iter().map(|j| {
- let obj = j.as_object().expect("expected json object");
- obj.get("Untagged")
- .map(|sha| {
- Status::Untagged(
- sha.as_string()
- .expect(
- "expected Untagged to be a string",
- )
- .to_owned(),
- )
- })
- .or(obj.get("Deleted").map(|sha| {
- Status::Deleted(
- sha.as_string()
- .expect(
- "expected Deleted to be a string",
- )
- .to_owned(),
- )
- }))
- .expect("expected Untagged or Deleted")
- })
- }
- _ => unreachable!(),
- }.collect(),
- )
+ Ok(match Json::from_str(&raw)? {
+ Json::Array(ref xs) => xs.iter().map(|j| {
+ let obj = j.as_object().expect("expected json object");
+ obj.get("Untagged")
+ .map(|sha| {
+ Status::Untagged(
+ sha.as_string()
+ .expect("expected Untagged to be a string")
+ .to_owned(),
+ )
+ }).or(obj.get("Deleted").map(|sha| {
+ Status::Deleted(
+ sha.as_string()
+ .expect("expected Deleted to be a string")
+ .to_owned(),
+ )
+ })).expect("expected Untagged or Deleted")
+ }),
+ _ => unreachable!(),
+ }.collect())
}
/// Export this image to a tarball
pub fn export(&self) -> Result<Box<Read>> {
- self.docker.stream_get(
- &format!("/images/{}/get", self.name)[..],
- )
+ self.docker
+ .stream_get(&format!("/images/{}/get", self.name)[..])
}
}
@@ -176,12 +174,9 @@ impl<'a> Images<'a> {
tarball::dir(&mut bytes, &opts.path[..])?;
- let raw = self.docker.stream_post(
- &path.join("?"),
- Some(
- (Body::BufBody(&bytes[..], bytes.len()), tar()),
- ),
- )?;
+ let raw = self
+ .docker
+ .stream_post(&path.join("?"), Some((Body::from(bytes), tar())))?;
let it = jed::Iter::new(raw).into_iter();
Ok(Box::new(it))
}
@@ -203,7 +198,9 @@ impl<'a> Images<'a> {
/// Search for docker images by term
pub fn search(&self, term: &str) -> Result<Vec<SearchResult>> {
- let query = form_urlencoded::serialize(vec![("term", term)]);
+ let query = form_urlencoded::Serializer::new(String::new())
+ .append_pair("term", term)
+ .finish();
let raw = self.docker.get(&format!("/images/search?{}", query)[..])?;
Ok(json::decode::<Vec<SearchResult>>(&raw)?)
}
@@ -217,10 +214,7 @@ impl<'a> Images<'a> {
if let Some(query) = opts.serialize() {
path.push(query);
}
- let raw = self.docker.stream_post(
- &path.join("?"),
- None as Option<(&'a str, ContentType)>,
- )?;
+ let raw = self.docker.stream_post::<Body>(&path.join("?"), None)?;
let it = jed::Iter::new(raw).into_iter();
Ok(Box::new(it))
}
@@ -228,14 +222,12 @@ impl<'a> Images<'a> {
/// exports a collection of named images,
/// either by name, name:tag, or image id, into a tarball
pub fn export(&self, names: Vec<&str>) -> Result<Box<Read>> {
- let params = names
- .iter()
- .map(|n| ("names", *n))
- .collect::<Vec<(&str, &str)>>();
- let query = form_urlencoded::serialize(params);
- self.docker.stream_get(
- &format!("/images/get?{}", query)[..],
- )
+ let params = names.iter().map(|n| ("names", *n));
+ let query = form_urlencoded::Serializer::new(String::new())
+ .extend_pairs(params)
+ .finish();
+ self.docker
+ .stream_get(&format!("/images/get?{}", query)[..])
}
// pub fn import(self, tarball: Box<Read>) -> Result<()> {
@@ -268,9 +260,9 @@ impl<'a, 'b> Container<'a, 'b> {
/// Inspects the current docker container instance's details
pub fn inspect(&self) -> Result<ContainerDetails> {
- let raw = self.docker.get(
- &format!("/containers/{}/json", self.id)[..],
- )?;
+ let raw = self
+ .docker
+ .get(&format!("/containers/{}/json", self.id)[..])?;
Ok(json::decode::<ContainerDetails>(&raw)?)
}
@@ -278,7 +270,9 @@ impl<'a, 'b> Container<'a, 'b> {
pub fn top(&self, psargs: Option<&str>) -> Result<Top> {
let mut path = vec![format!("/containers/{}/top", self.id)];
if let Some(ref args) = psargs {
- let encoded = form_urlencoded::serialize(vec![("ps_args", args)]);
+ let encoded = form_urlencoded::Serializer::new(String::new())
+ .append_pair("ps_args", args)
+ .finish();
path.push(encoded)
}
let raw = self.docker.get(&path.join("?"))?;
@@ -297,24 +291,23 @@ impl<'a, 'b> Container<'a, 'b> {
/// Returns a set of changes made to the container instance
pub fn changes(&self) -> Result<Vec<Change>> {
- let raw = self.docker.get(
- &format!("/containers/{}/changes", self.id)[..],
- )?;
+ let raw = self
+ .docker
+ .get(&format!("/containers/{}/changes", self.id)[..])?;
Ok(json::decode::<Vec<Change>>(&raw)?)
}
/// Exports the current docker container into a tarball
pub fn export(&self) -> Result<Box<Read>> {
- self.docker.stream_get(
- &format!("/containers/{}/export", self.id)[..],
- )
+ self.docker
+ .stream_get(&format!("/containers/{}/export", self.id)[..])
}
/// Returns a stream of stats specific to this container instance
pub fn stats(&self) -> Result<Box<Iterator<Item = Stats>>> {
- let raw = self.docker.stream_get(
- &format!("/containers/{}/stats", self.id)[..],
- )?;
+ let raw = self
+ .docker
+ .stream_get(&format!("/containers/{}/stats", self.id)[..])?;
let it = jed::Iter::new(raw).into_iter().map(|j| {
// fixme: better error handling
debug!("{:?}", j);
@@ -327,10 +320,7 @@ impl<'a, 'b> Container<'a, 'b> {
/// Start the container instance
pub fn start(&'a self) -> Result<()> {
self.docker
- .post(
- &format!("/containers/{}/start", self.id)[..],
- None as Option<(&'a str, ContentType)>,
- )
+ .post::<Body>(&format!("/containers/{}/start", self.id)[..], None)
.map(|_| ())
}
@@ -338,80 +328,70 @@ impl<'a, 'b> Container<'a, 'b> {
pub fn stop(&self, wait: Option<Duration>) -> Result<()> {
let mut path = vec![format!("/containers/{}/stop", self.id)];
if let Some(w) = wait {
- let encoded = form_urlencoded::serialize(
- vec![("t", w.as_secs().to_string())],
- );
+ let encoded = form_urlencoded::Serializer::new(String::new())
+ .append_pair("t", &w.as_secs().to_string())
+ .finish();
+
path.push(encoded)
}
- self.docker
- .post(&path.join("?"), None as Option<(&'a str, ContentType)>)
- .map(|_| ())
+ self.docker.post::<Body>(&path.join("?"), None).map(|_| ())
}
/// Restart the container instance
pub fn restart(&self, wait: Option<Duration>) -> Result<()> {
let mut path = vec![format!("/containers/{}/restart", self.id)];
if let Some(w) = wait {
- let encoded = form_urlencoded::serialize(
- vec![("t", w.as_secs().to_string())],
- );
+ let encoded = form_urlencoded::Serializer::new(String::new())
+ .append_pair("t", &w.as_secs().to_string())
+ .finish();
path.push(encoded)
}
- self.docker
- .post(&path.join("?"), None as Option<(&'a str, ContentType)>)
- .map(|_| ())
+ self.docker.post::<Body>(&path.join("?"), None).map(|_| ())
}
/// Kill the container instance
pub fn kill(&self, signal: Option<&str>) -> Result<()> {
let mut path = vec![format!("/containers/{}/kill", self.id)];
if let Some(sig) = signal {
- let encoded =
- form_urlencoded::serialize(vec![("signal", sig.to_owned())]);
+ let encoded = form_urlencoded::Serializer::new(String::new())
+ .append_pair("signal", &sig.to_owned())
+ .finish();
path.push(encoded)
}
- self.docker
- .post(&path.join("?"), None as Option<(&'a str, ContentType)>)
- .map(|_| ())
+ self.docker.post::<Body>(&path.join("?"), None).map(|_| ())
}
/// Rename the container instance
pub fn rename(&self, name: &str) -> Result<()> {
- let query = form_urlencoded::serialize(vec![("name", name)]);
+ let query = form_urlencoded::Serializer::new(String::new())
+ .append_pair("name", name)
+ .finish();
self.docker
- .post(
+ .post::<Body>(
&format!("/containers/{}/rename?{}", self.id, query)[..],
- None as Option<(&'a str, ContentType)>,
- )
- .map(|_| ())
+ None,
+ ).map(|_| ())
}
/// Pause the container instance
pub fn pause(&self) -> Result<()> {
self.docker
- .post(
- &format!("/containers/{}/pause", self.id)[..],
- None as Option<(&'a str, ContentType)>,
- )
+ .post::<Body>(&format!("/containers/{}/pause", self.id)[..], None)
.map(|_| ())
}
/// Unpause the container instance
pub fn unpause(&self) -> Result<()> {
self.docker
- .post(
- &format!("/containers/{}/unpause", self.id)[..],
- None as Option<(&'a str, ContentType)>,
- )
+ .post::<Body>(&format!("/containers/{}/unpause", self.id)[..], None)
.map(|_| ())
}
/// Wait until the container stops
pub fn wait(&self) -> Result<Exit> {
- let raw = self.docker.post(
- &format!("/containers/{}/wait", self.id)[..],
- None as Option<(&'a str, ContentType)>,
- )?;
+ let raw = self
+ .docker
+ .post::<Body>(&format!("/containers/{}/wait", self.id)[..], None)?;
Ok(json::decode::<Exit>(&raw)?)
}
@@ -437,10 +417,10 @@ impl<'a, 'b> Container<'a, 'b> {
/// Exec the specified command in the container
pub fn exec(&self, opts: &ExecContainerOptions) -> Result<Tty> {
let data = opts.serialize()?;
- let mut bytes = data.as_bytes();
+ let bytes = data.into_bytes();
match self.docker.post(
&format!("/containers/{}/exec", self.id)[..],
- Some((&mut bytes, ContentType::json())),
+ Some((bytes, mime::APPLICATION_JSON)),
) {
Err(e) => Err(e),
Ok(res) => {
@@ -456,11 +436,9 @@ impl<'a, 'b> Container<'a, 'b> {
.unwrap()
.as_string()
.unwrap()
- )
- [..],
- Some((&mut bytes, ContentType::json())),
- )
- .map(|stream| Tty::new(stream))
+ )[..],
+ Some((bytes, mime::APPLICATION_JSON)),
+ ).map(|stream| Tty::new(stream))
}
}
}
@@ -503,17 +481,20 @@ impl<'a> Containers<'a> {
opts: &ContainerOptions,
) -> Result<ContainerCreateInfo> {
let data = opts.serialize()?;
- let mut bytes = data.as_bytes();
+ let bytes = data.into_bytes();
let mut path = vec!["/containers/create".to_owned()];
if let Some(ref name) = opts.name {
- path.push(form_urlencoded::serialize(vec![("name", name)]));
+ path.push(
+ form_urlencoded::Serializer::new(String::new())
+ .append_pair("name", name)
+ .finish(),
+ );
}
- let raw = self.docker.post(
- &path.join("?"),
- Some((&mut bytes, ContentType::json())),
- )?;
+ let raw = self
+ .docker
+ .post(&path.join("?"), Some((bytes, mime::APPLICATION_JSON)))?;
Ok(json::decode::<ContainerCreateInfo>(&raw)?)
}
}
@@ -549,13 +530,12 @@ impl<'a> Networks<'a> {
opts: &NetworkCreateOptions,
) -> Result<NetworkCreateInfo> {
let data = opts.serialize()?;
- let mut bytes = data.as_bytes();
+ let bytes = data.into_bytes();
let path = vec!["/networks/create".to_owned()];
- let raw = self.docker.post(
- &path.join("?"),
- Some((&mut bytes, ContentType::json())),
- )?;
+ let raw = self
+ .docker
+ .post(&path.join("?"), Some((bytes, mime::APPLICATION_JSON)))?;
Ok(json::decode::<NetworkCreateInfo>(&raw)?)
}
}
@@ -612,14 +592,13 @@ impl<'a, 'b> Network<'a, 'b> {
opts: &ContainerConnectionOptions,
) -> Result<()> {
let data = opts.serialize()?;
- let mut bytes = data.as_bytes();
+ let bytes = data.into_bytes();
self.docker
.post(
&format!("/networks/{}/{}", self.id, segment)[..],
- Some((&mut bytes, ContentType::json())),
- )
- .map(|_| ())
+ Some((bytes, mime::APPLICATION_JSON)),
+ ).map(|_| ())
}
}
@@ -628,80 +607,106 @@ impl Docker {
/// constructs a new Docker instance for a docker host listening at a url specified by an env var `DOCKER_HOST`,
/// falling back on unix:///var/run/docker.sock
pub fn new() -> Docker {
- let fallback: std::result::Result<String, VarError> =
- Ok("unix:///var/run/docker.sock".to_owned());
- let host = env::var("DOCKER_HOST")
- .or(fallback)
- .map(|h| Url::parse(&h).ok().expect("invalid url"))
- .ok()
- .expect("expected host");
- Docker::host(host)
+ match env::var("DOCKER_HOST").ok() {
+ Some(host) => {
+ let host = host.parse().expect("invalid url");
+ Docker::host(host)
+ }
+ #[cfg(feature = "unix-socket")]
+ None => Docker::unix("/var/run/docker.sock"),
+ #[cfg(not(feature = "unix-socket"))]
+ None => panic!("Unix socket support is disabled"),
+ }
+ }
+
+ /// Creates a new docker instance for a docker host
+ /// listening on a given Unix socket.
+ #[cfg(feature = "unix-socket")]
+ pub fn unix<S>(socket_path: S) -> Docker
+ where
+ S: Into<String>,
+ {
+ Docker {
+ transport: Transport::Unix {
+ client: Client::builder()
+ .keep_alive(false)
+ .build(UnixConnector),
+ runtime: RefCell::new(tokio::runtime::Runtime::new().unwrap()),
+ path: socket_path.into(),
+ },
+ }
}
/// constructs a new Docker instance for docker host listening at the given host url
- pub fn host(host: Url) -> Docker {
- match host.scheme() {
+ pub fn host(host: Uri) -> Docker {
+ let tcp_host_str = format!(
+ "{}://{}:{}",
+ host.scheme_part().map(|s| s.as_str()).unwrap(),
+ host.host().unwrap().to_owned(),
+ host.port().unwrap_or(80)
+ );
+
+ match host.scheme_part().map(|s| s.as_str()) {
#[cfg(feature = "unix-socket")]
- "unix" => {
- Docker {
- transport: Transport::Unix {
- client: Client::with_connector(hyperlocal::UnixSocketConnector),
- path: host.path().to_owned(),
- },
- }
- }
+ Some("unix") => Docker {
+ transport: Transport::Unix {
+ client: Client::builder().build(UnixConnector),
+ runtime: RefCell::new(
+ tokio::runtime::Runtime::new().unwrap(),
+ ),
+ path: host.path().to_owned(),
+ },
+ },
#[cfg(not(feature = "unix-socket"))]
- "unix" => panic!("Unix socket support is disabled"),
+ Some("unix") => panic!("Unix socket support is disabled"),
_ => {
- let client = if let Some(ref certs) = env::var(
- "DOCKER_CERT_PATH",
- ).ok()
- {
+ if let Some(ref certs) = env::var("DOCKER_CERT_PATH").ok() {
// fixme: don't unwrap before you know what's in the box
// https://github.com/hyperium/hyper/blob/master/src/net.rs#L427-L428
let mut connector =
- SslConnectorBuilder::new(SslMethod::tls()).unwrap();
- connector.builder_mut().set_cipher_list("DEFAULT").unwrap();
+ SslConnector::builder(SslMethod::tls()).unwrap();
+ connector.set_cipher_list("DEFAULT").unwrap();
let cert = &format!("{}/cert.pem", certs);
let key = &format!("{}/key.pem", certs);
connector
- .builder_mut()
.set_certificate_file(
&Path::new(cert),
- X509_FILETYPE_PEM,
- )
- .unwrap();
+ SslFiletype::PEM,
+ ).unwrap();
connector
- .builder_mut()
- .set_private_key_file(
- &Path::new(key),
- X509_FILETYPE_PEM,
- )
+ .set_private_key_file(&Path::new(key), SslFiletype::PEM)
.unwrap();
if let Some(_) = env::var("DOCKER_TLS_VERIFY").ok() {
let ca = &format!("{}/ca.pem", certs);
- connector
- .builder_mut()
- .set_ca_file(&Path::new(ca))
+ connector.set_ca_file(&Path::new(ca)).unwrap();
+ }
+
+ let http = HttpConnector::new(1);
+ let connector =
+ HttpsConnector::with_connector(http, connector)
.unwrap();
+
+ Docker {
+ transport: Transport::EncryptedTcp {
+ client: Client::builder().build(connector),
+ runtime: RefCell::new(
+ tokio::runtime::Runtime::new().unwrap(),
+ ),
+ host: tcp_host_str,
+ },
}
- let ssl = OpensslClient::from(connector.build());
- Client::with_connector(HttpsConnector::new(ssl))
} else {
- Client::new()
- };
- Docker {
- transport: Transport::Tcp {
- client: client,
- host: format!(
- "{}://{}:{}",
- host.scheme(),
- host.host_str().unwrap().to_owned(),
- host.port_or_known_default().unwrap()
- ),
- },
+ Docker {
+ transport: Transport::Tcp {
+ client: Client::new(),
+ runtime: RefCell::new(
+ tokio::runtime::Runtime::new().unwrap(),
+ ),
+ host: tcp_host_str,
+ },
+ }
}
}
}
@@ -757,49 +762,34 @@ impl Docker {
Ok(Box::new(it))
}
- fn get<'a>(&self, endpoint: &str) -> Result<String> {
- self.transport.request(
- Method::Get,
- endpoint,
- None as Option<(&'a str, ContentType)>,
- )
+ fn get(&self, endpoint: &str) -> Result<String> {
+ self.transport.request::<Body>(Method::GET, endpoint, None)
}
- fn post<'a, B>(
- &'a self,
- endpoint: &str,
- body: Option<(B, ContentType)>,
- ) -> Result<String>
+ fn post<B>(&self, endpoint: &str, body: Option<(B, Mime)>) -> Result<String>
where
- B: Into<Body<'a>>,
+ B: Into<Body>,
{
- self.transport.request(Method::Post, endpoint, body)
+ self.transport.request(Method::POST, endpoint, body)
}
- fn delete<'a>(&self, endpoint: &str) -> Result<String> {
- self.transport.request(
- Method::Delete,
- endpoint,
- None as Option<(&'a str, ContentType)>,
- )
+ fn delete(&self, endpoint: &str) -> Result<String> {
+ self.transport
+ .request::<Body>(Method::DELETE, endpoint, None)
}
- fn stream_post<'a, B>(
- &'a self,
+ fn stream_post<B>(
+ &self,
endpoint: &str,
- body: Option<(B, ContentType)>,
+ body: Option<(B, Mime)>,
) -> Result<Box<Read>>
where
- B: Into<Body<'a>>,
+ B: Into<Body>,
{
- self.transport.stream(Method::Post, endpoint, body)
+ self.transport.stream(Method::POST, endpoint, body)
}
- fn stream_get<'a>(&self, endpoint: &str) -> Result<Box<Read>> {
- self.transport.stream(
- Method::Get,
- endpoint,
- None as Option<(&'a str, ContentType)>,
- )
+ fn stream_get(&self, endpoint: &str) -> Result<Box<Read>> {
+ self.transport.stream::<Body>(Method::GET, endpoint, None)
}
}
diff --git a/src/transport.rs b/src/transport.rs
index 69c2eab..4cd0a96 100644
--- a/src/transport.rs
+++ b/src/transport.rs
@@ -4,42 +4,60 @@ extern crate hyper;
#[cfg(feature = "unix-socket")]
extern crate hyperlocal;
-use self::hyper::buffer::BufReader;
-use self::hyper::header::ContentType;
-use self::hyper::status::StatusCode;
use self::super::{Error, Result};
-use hyper::Client;
-use hyper::client::Body;
-use hyper::client::response::Response;
+use hyper::client::{Client, HttpConnector};
use hyper::header;
-use hyper::method::Method;
-use hyper::mime;
+use hyper::rt::Stream;
+use hyper::Body;
+use hyper::{Method, Request, Response, StatusCode};
+use hyper_openssl::HttpsConnector;
+#[cfg(feature = "unix-socket")]
+use hyperlocal::UnixConnector;
+#[cfg(feature = "unix-socket")]
+use hyperlocal::Uri as DomainUri;
+use mime::Mime;
use rustc_serialize::json;
+use std::cell::{RefCell, RefMut};
use std::fmt;
use std::io::Read;
+use std::io::{BufReader, Cursor};
+use tokio::runtime::Runtime;
-pub fn tar() -> ContentType {
- ContentType(mime::Mime(
- mime::TopLevel::Application,
- mime::SubLevel::Ext(String::from("tar")),
- vec![],
- ))
+pub fn tar() -> Mime {
+ "application/tar".parse().unwrap()
}
/// Transports are types which define the means of communication
/// with the docker daemon
pub enum Transport {
/// A network tcp interface
- Tcp { client: Client, host: String },
+ Tcp {
+ client: Client<HttpConnector>,
+ runtime: RefCell<Runtime>,
+ host: String,
+ },
+ /// TCP/TLS
+ EncryptedTcp {
+ client: Client<HttpsConnector<HttpConnector>>,
+ runtime: RefCell<Runtime>,
+ host: String,
+ },
/// A Unix domain socket
#[cfg(feature = "unix-socket")]
- Unix { client: Client, path: String },
+ Unix {
+ client: Client<UnixConnector>,
+ runtime: RefCell<Runtime>,
+ path: String,
+ },
}
impl fmt::Debug for Transport {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Transport::Tcp { ref host, .. } => write!(f, "Tcp({})", host),
+ Transport::EncryptedTcp { ref host, .. } => {
+ write!(f, "EncryptedTcp({})", host)
+ }
#[cfg(feature = "unix-socket")]
Transport::Unix { ref path, .. } => write!(f, "Unix({})", path),
}
@@ -47,14 +65,14 @@ impl fmt::Debug for Transport {
}
impl Transport {
- pub fn request<'a, B>(
- &'a self,
+ pub fn request<B>(
+ &self,
method: Method,
endpoint: &str,
- body: Option<(B, ContentType)>,
+ body: Option<(B, Mime)>,
) -> Result<String>
where
- B: Into<Body<'a>>,
+ B: Into<Body>,
{
let mut res = self.stream(method, endpoint, body)?;
let mut body = String::new();
@@ -63,112 +81,150 @@ impl Transport {
Ok(body)
}
- pub fn stream<'c, B>(
- &'c self,
+ /// Builds an HTTP request.
+ fn build_request<B>(
+ &self,
method: Method,
endpoint: &str,
- body: Option<(B, ContentType)>,
- ) -> Result<Box<Read>>
+ body: Option<(B, Mime)>,
+ ) -> Result<Request<Body>>
where
- B: Into<Body<'c>>,
+ B: Into<Body>,
{
- let headers = {
- let mut headers = header::Headers::new();
- headers.set(header::Host