Skip to content

Commit

Permalink
Merge pull request #138 from fussybeaver/ND-tokio-1-named-pipes
Browse files Browse the repository at this point in the history
Windows named pipes
  • Loading branch information
fussybeaver authored Jun 20, 2021
2 parents 3819068 + cbb1bb3 commit f6a9328
Show file tree
Hide file tree
Showing 18 changed files with 152 additions and 80 deletions.
16 changes: 9 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "bollard"
description = "An asynchronous Docker daemon API"
version = "0.10.1"
version = "0.11.0"
authors = [ "Bollard contributors" ]
license = "Apache-2.0"
homepage = "https://github.com/fussybeaver/bollard"
Expand All @@ -19,14 +19,14 @@ test_ssl = ["ssl"]
# Enable tests specifically for macos
test_macos = []
# Enable rustls / ssl
ssl = ["hyper-rustls", "rustls", "rustls-native-certs", "webpki-roots"]
ssl = ["hyper-rustls", "rustls", "rustls-native-certs", "webpki-roots", "ct-logs"]

[dependencies]
base64 = "0.13"
bollard-stubs = { version = "1.41.0" }
bytes = "1"
chrono = { version = "0.4", features = ["serde"] }
ct-logs = "0.8.0"
ct-logs = { version = "0.8.0", optional = true }
dirs-next = "2.0"
futures-core = "0.3"
futures-util = "0.3"
Expand All @@ -42,7 +42,7 @@ serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
serde_urlencoded = "0.7"
tokio = { version = "1.2", features = ["time", "fs", "net", "rt", "rt-multi-thread", "io-util"] }
tokio = { version = "1.7", features = ["time", "fs", "net", "rt", "rt-multi-thread", "io-util"] }
thiserror = "1.0"
tokio-util = { version = "0.6", features = ["codec"] }
url = "2.2"
Expand All @@ -52,11 +52,13 @@ webpki-roots = { version = "0.21", optional = true }
env_logger = "0.8"
flate2 = "1.0"
tar = "0.4"
tokio = { version = "1.2", features = ["time", "fs", "net", "rt", "rt-multi-thread", "macros", "io-std"] }
termion = "1.5"
tokio = { version = "1.7", features = ["time", "fs", "net", "rt", "rt-multi-thread", "macros", "io-std"] }

[target.'cfg(unix)'.dependencies]
hyperlocal = { version = "0.2.2", package = "hyper-unix-connector" }
hyperlocal = { version = "0.8.0" }

[target.'cfg(unix)'.dev-dependencies]
termion = "1.5"

[target.'cfg(windows)'.dependencies]
winapi = "0.3.9"
Expand Down
23 changes: 11 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,35 +10,33 @@ Bollard leverages the latest [Hyper](https://github.com/hyperium/hyper) and
[Tokio](https://github.com/tokio-rs/tokio) improvements for an asynchronous API containing
futures, streams and the async/await paradigm.

The library also features Windows support through Named Pipes (disabled in 0.10, see below) and
HTTPS support through optional rustls bindings.
The library also features Windows support through Named Pipes and HTTPS support through
optional rustls bindings.

## Install

Add the following to your `Cargo.toml` file

```nocompile
[dependencies]
bollard = "0.9"
bollard = "0.11"
```

## API
### Documentation

[API docs](crate).

Version 0.10 disables Named Pipe Windows support until the upstream Tokio project re-adds
support for Named Pipes. Please follow the [tracking
issue](https://github.com/tokio-rs/tokio/issues/3511) for updates on this.
Version 0.11 re-enables Windows Named Pipe support.

As of version 0.6, this project now generates API stubs from the upstream Docker-maintained
[Swagger OpenAPI specification](https://docs.docker.com/engine/api/v1.40.yaml). The generated
[Swagger OpenAPI specification](https://docs.docker.com/engine/api/v1.41.yaml). The generated
models are committed to this repository, but packaged in a separate crate
[bollard-stubs](https://crates.io/crates/bollard-stubs).

### Version

The [Docker API](https://docs.docker.com/engine/api/v1.40/) is pegged at version `1.40`. The
The [Docker API](https://docs.docker.com/engine/api/v1.41/) is pegged at version `1.41`. The
library also supports [version
negotiation](https://docs.rs/bollard/latest/bollard/struct.Docker.html#method.negotiate_version),
to allow downgrading to an older API version.
Expand All @@ -49,15 +47,16 @@ to allow downgrading to an older API version.

Connect to the docker server according to your architecture and security remit.

#### Unix socket
#### Socket

The client will connect to the standard unix socket location `/var/run/docker.sock`. Use the
`Docker::connect_with_unix` method API to parameterise the interface.
The client will connect to the standard unix socket location `/var/run/docker.sock` or windows
named pipe location `//./pipe/docker_engine`. Use the `Docker::connect_with_socket` method API
to parameterise the interface.

```rust
use bollard::Docker;
#[cfg(unix)]
Docker::connect_with_unix_defaults();
Docker::connect_with_socket_defaults();
```

#### Local
Expand Down
2 changes: 1 addition & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@ test_script:
- ps: Set-Item -path env:RUST_BACKTRACE -value 1
- ps: Set-Item -path env:RUST_LOG -value "hyper=trace,bollard=debug"
- ps: Set-Item -path env:REGISTRY_HTTP_ADDR -value localhost:5000
# - cargo test --verbose -- --nocapture --test-threads 1
- cargo test --verbose -- --nocapture --test-threads 1
2 changes: 1 addition & 1 deletion examples/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use futures_util::stream::StreamExt;

#[tokio::main]
async fn main() {
let docker = Docker::connect_with_unix_defaults().unwrap();
let docker = Docker::connect_with_socket_defaults().unwrap();

let mut build_image_args = HashMap::new();
build_image_args.insert("dummy", "value");
Expand Down
2 changes: 1 addition & 1 deletion examples/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ extern crate bollard;
use bollard::Docker;

fn run() -> Result<(), Box<dyn std::error::Error>> {
let _docker1 = Docker::connect_with_unix_defaults()?;
let _docker = Docker::connect_with_socket_defaults().unwrap();

let _env_var = std::env::var("ZOOKEEPER_ADDR")?;

Expand Down
2 changes: 1 addition & 1 deletion examples/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const IMAGE: &'static str = "alpine:3";

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + 'static>> {
let docker = Docker::connect_with_unix_defaults().unwrap();
let docker = Docker::connect_with_socket_defaults().unwrap();

docker
.create_image(
Expand Down
7 changes: 6 additions & 1 deletion examples/exec_term.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ use bollard::image::CreateImageOptions;
use futures_util::{StreamExt, TryStreamExt};
use std::io::{stdout, Read, Write};
use std::time::Duration;
#[cfg(not(windows))]
use termion::raw::IntoRawMode;
#[cfg(not(windows))]
use termion::{async_stdin, terminal_size};
use tokio::io::AsyncWriteExt;
use tokio::task::spawn;
Expand All @@ -19,7 +21,9 @@ const IMAGE: &'static str = "alpine:3";

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + 'static>> {
let docker = Docker::connect_with_unix_defaults().unwrap();
let docker = Docker::connect_with_socket_defaults().unwrap();

#[cfg(not(windows))]
let tty_size = terminal_size()?;

docker
Expand Down Expand Up @@ -60,6 +64,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + 'static>> {
)
.await?
.id;
#[cfg(not(windows))]
if let StartExecResults::Attached {
mut output,
mut input,
Expand Down
2 changes: 1 addition & 1 deletion examples/hoover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const THRESHOLD_DAYS: i64 = 90;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + 'static>> {
let docker = Docker::connect_with_unix_defaults()?;
let docker = Docker::connect_with_socket_defaults().unwrap();

let date = Utc::now() - Duration::days(THRESHOLD_DAYS);
let timestamp = &date.timestamp().to_string()[..];
Expand Down
2 changes: 1 addition & 1 deletion examples/image_from_scratch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + 'static>> {

let file = File::open(&arguments[1]).expect("Could not find archive.");

let docker = Docker::connect_with_unix_defaults().unwrap();
let docker = Docker::connect_with_socket_defaults().unwrap();

let options = CreateImageOptions {
from_src: "-", // from_src must be "-" when sending the archive in the request body
Expand Down
2 changes: 1 addition & 1 deletion examples/info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ async fn conc(arg: (Docker, &ContainerSummary)) -> () {

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + 'static>> {
let docker = Docker::connect_with_unix_defaults().unwrap();
let docker = Docker::connect_with_socket_defaults().unwrap();

let mut list_container_filters = HashMap::new();
list_container_filters.insert("status", vec!["running"]);
Expand Down
2 changes: 1 addition & 1 deletion examples/kafka.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const ZOOKEEPER_IMAGE: &'static str = "confluentinc/cp-zookeeper:5.0.1";

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + 'static>> {
let docker = Docker::connect_with_unix_defaults().unwrap();
let docker = Docker::connect_with_socket_defaults().unwrap();

let sd1 = docker.clone();
let sd2 = docker.clone();
Expand Down
2 changes: 1 addition & 1 deletion examples/post_dockerfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use std::env::args;

#[tokio::main]
async fn main() {
let docker = Docker::connect_with_unix_defaults().unwrap();
let docker = Docker::connect_with_socket_defaults().unwrap();

let image_options = BuildImageOptions {
dockerfile: "Dockerfile",
Expand Down
2 changes: 1 addition & 1 deletion examples/stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use std::collections::HashMap;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let docker = Docker::connect_with_unix_defaults().unwrap();
let docker = Docker::connect_with_socket_defaults().unwrap();

loop {
let mut filter = HashMap::new();
Expand Down
2 changes: 1 addition & 1 deletion examples/top.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use futures_util::stream::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + 'static>> {
let docker = Docker::connect_with_unix_defaults()?;
let docker = Docker::connect_with_socket_defaults().unwrap();

let mut list_container_filters = HashMap::new();
list_container_filters.insert("status", vec!["running"]);
Expand Down
75 changes: 65 additions & 10 deletions src/docker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use hyper::{self, body::Bytes, Body, Method, Request, Response, StatusCode};
#[cfg(feature = "ssl")]
use hyper_rustls::HttpsConnector;
#[cfg(unix)]
use hyperlocal::UnixClient as UnixConnector;
use hyperlocal::UnixConnector;
#[cfg(feature = "ssl")]
use rustls::internal::pemfile;
#[cfg(feature = "ssl")]
Expand Down Expand Up @@ -525,12 +525,67 @@ impl Docker {

Ok(docker)
}

/// Connect using to either a Unix socket or a Windows named pipe using defaults common to the
/// standard docker configuration.
///
/// # Defaults
///
/// - The unix socket location defaults to `/var/run/docker.sock`. The windows named pipe
/// location defaults to `//./pipe/docker_engine`.
/// - The request timeout defaults to 2 minutes.
///
/// # Examples
///
/// ```rust,no_run
/// use bollard::Docker;
///
/// use futures_util::future::TryFutureExt;
///
/// let connection = Docker::connect_with_socket_defaults().unwrap();
/// connection.ping().map_ok(|_| Ok::<_, ()>(println!("Connected!")));
/// ```
pub fn connect_with_socket_defaults() -> Result<Docker, Error> {
#[cfg(unix)]
let path = DEFAULT_SOCKET;
#[cfg(windows)]
let path = DEFAULT_NAMED_PIPE;

Docker::connect_with_socket(path, DEFAULT_TIMEOUT, API_DEFAULT_VERSION)
}

/// Connect using a Unix socket or a Windows named pipe.
///
/// # Arguments
///
/// - `path`: connection unix socket path or windows named pipe path.
/// - `timeout`: the read/write timeout (seconds) to use for every hyper connection
/// - `client_version`: the client version to communicate with the server.
///
/// # Examples
///
/// ```rust,no_run
/// use bollard::{API_DEFAULT_VERSION, Docker};
///
/// use futures_util::future::TryFutureExt;
///
/// let connection = Docker::connect_with_socket("/var/run/docker.sock", 120, API_DEFAULT_VERSION).unwrap();
/// connection.ping().map_ok(|_| Ok::<_, ()>(println!("Connected!")));
/// ```
pub fn connect_with_socket(path: &str, timeout: u64, client_version: &ClientVersion) -> Result<Docker, Error> {
#[cfg(unix)]
let docker = Docker::connect_with_unix(path, timeout, client_version);
#[cfg(windows)]
let docker = Docker::connect_with_named_pipe(path, timeout, client_version);

docker
}
}

#[cfg(unix)]
/// A Docker implementation typed to connect to a Unix socket.
impl Docker {
/// Connect using a Unix socket using defaults that are signalled by environment variables.
/// Connect using a Unix socket using defaults common to the standard docker configuration.
///
/// # Defaults
///
Expand Down Expand Up @@ -570,11 +625,11 @@ impl Docker {
/// connection.ping().map_ok(|_| Ok::<_, ()>(println!("Connected!")));
/// ```
pub fn connect_with_unix(
addr: &str,
path: &str,
timeout: u64,
client_version: &ClientVersion,
) -> Result<Docker, Error> {
let client_addr = addr.replacen("unix://", "", 1);
let client_addr = path.replacen("unix://", "", 1);

let unix_connector = UnixConnector;

Expand Down Expand Up @@ -602,8 +657,8 @@ impl Docker {
/// A Docker implementation typed to connect to a Windows Named Pipe, exclusive to the windows
/// target.
impl Docker {
/// Connect using a Windows Named Pipe using defaults that are signalled by environment
/// variables.
/// Connect using a Windows Named Pipe using defaults that are common to the standard docker
/// configuration.
///
/// # Defaults
///
Expand Down Expand Up @@ -646,11 +701,11 @@ impl Docker {
///
/// ```
pub fn connect_with_named_pipe(
addr: &str,
path: &str,
timeout: u64,
client_version: &ClientVersion,
) -> Result<Docker, Error> {
let client_addr = addr.replacen("npipe://", "", 1);
let client_addr = path.replacen("npipe://", "", 1);

let named_pipe_connector = NamedPipeConnector;

Expand All @@ -659,7 +714,7 @@ impl Docker {
client_builder.http1_title_case_headers(true);
let client = client_builder.build(named_pipe_connector);
let transport = Transport::NamedPipe { client };
let _docker = Docker {
let docker = Docker {
transport: Arc::new(transport),
client_type: ClientType::NamedPipe,
client_addr,
Expand All @@ -670,7 +725,7 @@ impl Docker {
)),
};

Err(NamedPipeDisabled {}.into())
Ok(docker)
}
}

Expand Down
3 changes: 0 additions & 3 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,4 @@ pub enum Error {
#[from]
err: serde_urlencoded::ser::Error,
},
/// Disable NamedPipe support until tokio#3511 is resolved
#[error("Named Pipe support is disabled until tokio#3511 is resolved")]
NamedPipeDisabled {},
}
Loading

0 comments on commit f6a9328

Please sign in to comment.