summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Kirillov <saratovsource@gmail.com>2017-04-03 22:52:18 +0400
committerAlexander Kirillov <saratovsource@gmail.com>2017-04-03 22:52:18 +0400
commitad1153421117b7c92785623b43c44bedda15f369 (patch)
tree857611c0984c1491254b64c2cb0dbfeee82d4772
parent6653b0c4bb79dfa6b11aa786dcc6a2f7ed767452 (diff)
Add support for docker networks
commit 55008eea85dace74acc625914e11d87d15a46b1e Author: Alexander Kirillov <saratovsource@gmail.com> Date: Mon Apr 3 22:47:34 2017 +0400 Some DRY commit c9173593eb9827b30071cb6e42d439ec3d4c3bb1 Author: Alexander Kirillov <saratovsource@gmail.com> Date: Mon Apr 3 22:42:35 2017 +0400 Connect container to network commit 8d68406ef4c69c98e43b7b28923a78e1e9672955 Author: Alexander Kirillov <saratovsource@gmail.com> Date: Mon Apr 3 22:09:58 2017 +0400 Create docker network commit 868e2076988c0b16f6d5a200cf12e77f5bffaeab Author: Alexander Kirillov <saratovsource@gmail.com> Date: Mon Apr 3 18:49:12 2017 +0400 Delete network commit 58a08e77e5984847589eeb35bc097c8949752619 Author: Alexander Kirillov <saratovsource@gmail.com> Date: Mon Apr 3 18:42:28 2017 +0400 Add inspect docker network commit 9fa4143013aa43aaf73645b19565d6e606489952 Author: Alexander Kirillov <saratovsource@gmail.com> Date: Mon Apr 3 18:03:02 2017 +0400 Add list networks
-rw-r--r--examples/networkconnect.rs16
-rw-r--r--examples/networkcreate.rs17
-rw-r--r--examples/networkdelete.rs15
-rw-r--r--examples/networkdisconnect.rs16
-rw-r--r--examples/networkinspect.rs15
-rw-r--r--examples/networks.rs13
-rw-r--r--src/builder.rs161
-rw-r--r--src/lib.rs100
-rw-r--r--src/rep.rs40
9 files changed, 391 insertions, 2 deletions
diff --git a/examples/networkconnect.rs b/examples/networkconnect.rs
new file mode 100644
index 0000000..165510b
--- /dev/null
+++ b/examples/networkconnect.rs
@@ -0,0 +1,16 @@
+extern crate shiplift;
+
+use shiplift::{ContainerConnectionOptions, Docker};
+use std::env;
+
+fn main() {
+ let docker = Docker::new();
+ let networks = docker.networks();
+ let container_id = env::args().nth(1).unwrap();
+ let network_id = env::args().nth(2).unwrap();
+ let info = networks
+ .get(&network_id)
+ .connect(&ContainerConnectionOptions::new(&container_id))
+ .unwrap();
+ println!("{:?}", info);
+}
diff --git a/examples/networkcreate.rs b/examples/networkcreate.rs
new file mode 100644
index 0000000..b78ddd0
--- /dev/null
+++ b/examples/networkcreate.rs
@@ -0,0 +1,17 @@
+extern crate shiplift;
+
+use shiplift::{NetworkCreateOptions, Docker};
+use std::env;
+
+fn main() {
+ let docker = Docker::new();
+ let networks = docker.networks();
+ if let Some(network_name) = env::args().nth(1) {
+ let info = networks.create(
+ &NetworkCreateOptions::builder(network_name.as_ref())
+ .driver("bridge")
+ .build()
+ ).unwrap();
+ println!("{:?}", info);
+ }
+}
diff --git a/examples/networkdelete.rs b/examples/networkdelete.rs
new file mode 100644
index 0000000..e67b798
--- /dev/null
+++ b/examples/networkdelete.rs
@@ -0,0 +1,15 @@
+extern crate shiplift;
+
+use shiplift::Docker;
+use std::env;
+
+fn main() {
+ let docker = Docker::new();
+ if let Some(id) = env::args().nth(1) {
+ let status = docker.networks()
+ .get(&id)
+ .delete()
+ .unwrap();
+ println!("{:?}", status);
+ }
+}
diff --git a/examples/networkdisconnect.rs b/examples/networkdisconnect.rs
new file mode 100644
index 0000000..b3e0721
--- /dev/null
+++ b/examples/networkdisconnect.rs
@@ -0,0 +1,16 @@
+extern crate shiplift;
+
+use shiplift::{ContainerConnectionOptions, Docker};
+use std::env;
+
+fn main() {
+ let docker = Docker::new();
+ let networks = docker.networks();
+ let container_id = env::args().nth(1).unwrap();
+ let network_id = env::args().nth(2).unwrap();
+ let info = networks
+ .get(&network_id)
+ .disconnect(&ContainerConnectionOptions::new(&container_id))
+ .unwrap();
+ println!("{:?}", info);
+}
diff --git a/examples/networkinspect.rs b/examples/networkinspect.rs
new file mode 100644
index 0000000..f290f93
--- /dev/null
+++ b/examples/networkinspect.rs
@@ -0,0 +1,15 @@
+extern crate shiplift;
+
+use shiplift::Docker;
+use std::env;
+
+fn main() {
+ let docker = Docker::new();
+ if let Some(id) = env::args().nth(1) {
+ let network = docker.networks()
+ .get(&id)
+ .inspect()
+ .unwrap();
+ println!("{:?}", network);
+ }
+}
diff --git a/examples/networks.rs b/examples/networks.rs
new file mode 100644
index 0000000..18767d1
--- /dev/null
+++ b/examples/networks.rs
@@ -0,0 +1,13 @@
+extern crate shiplift;
+extern crate env_logger;
+
+use shiplift::Docker;
+
+fn main() {
+ env_logger::init().unwrap();
+ let docker = Docker::new();
+ for c in docker.networks().
+ list(&Default::default()).unwrap() {
+ println!("network -> {:?}", c)
+ }
+}
diff --git a/src/builder.rs b/src/builder.rs
index c13dca6..244f93d 100644
--- a/src/builder.rs
+++ b/src/builder.rs
@@ -767,3 +767,164 @@ impl RmContainerOptionsBuilder {
RmContainerOptions { params: self.params.clone() }
}
}
+
+/// Options for filtering networks list results
+#[derive(Default)]
+pub struct NetworkListOptions {
+ params: HashMap<&'static str, String>,
+}
+
+impl NetworkListOptions {
+
+ /// serialize options as a string. returns None if no options are defined
+ pub fn serialize(&self) -> Option<String> {
+ if self.params.is_empty() {
+ None
+ } else {
+ Some(form_urlencoded::serialize(&self.params))
+ }
+ }
+}
+
+/// Interface for creating new docker network
+pub struct NetworkCreateOptions {
+ pub name: Option<String>,
+ params: HashMap<&'static str, String>,
+ params_hash: HashMap<String, Vec<HashMap<String, String>>>
+}
+
+impl ToJson for NetworkCreateOptions {
+ fn to_json(&self) -> Json {
+ let mut body: BTreeMap<String, Json> = BTreeMap::new();
+
+ self.parse_from(&self.params, &mut body);
+ self.parse_from(&self.params_hash, &mut body);
+
+ body.to_json()
+ }
+}
+
+impl NetworkCreateOptions {
+ /// return a new instance of a builder for options
+ pub fn builder(name: &str) -> NetworkCreateOptionsBuilder {
+ NetworkCreateOptionsBuilder::new(name)
+ }
+
+ /// serialize options as a string. returns None if no options are defined
+ pub fn serialize(&self) -> Result<String> {
+ Ok(try!(json::encode(&self.to_json())))
+ }
+
+ pub fn parse_from<'a, K, V>(&self,
+ params: &'a HashMap<K, V>,
+ body: &mut BTreeMap<String, Json>)
+ where &'a HashMap<K, V>: IntoIterator,
+ K: ToString + Eq + Hash,
+ V: ToJson
+ {
+ for (k, v) in params.iter() {
+ let key = k.to_string();
+ let value = v.to_json();
+
+ body.insert(key, value);
+ }
+ }
+
+}
+
+#[derive(Default)]
+pub struct NetworkCreateOptionsBuilder {
+ name: Option<String>,
+ params: HashMap<&'static str, String>,
+ params_hash: HashMap<String, Vec<HashMap<String, String>>>
+}
+
+impl NetworkCreateOptionsBuilder {
+ pub fn new(name: &str) -> NetworkCreateOptionsBuilder {
+ let mut params = HashMap::new();
+ let params_hash = HashMap::new();
+
+ params.insert("Name", name.to_owned());
+ NetworkCreateOptionsBuilder {
+ name: None,
+ params: params,
+ params_hash: params_hash,
+ }
+ }
+
+ pub fn driver(&mut self, name: &str) -> &mut NetworkCreateOptionsBuilder {
+ if !name.is_empty() {
+ self.params.insert("Driver", name.to_owned());
+ }
+ self
+ }
+
+ pub fn label(&mut self, labels: Vec<HashMap<String, String>>) -> &mut NetworkCreateOptionsBuilder {
+ for l in labels {
+ self.params_hash.entry("Labels".to_string()).or_insert(Vec::new()).push(l)
+ }
+ self
+ }
+
+ pub fn build(&self) -> NetworkCreateOptions {
+ NetworkCreateOptions {
+ name: self.name.clone(),
+ params: self.params.clone(),
+ params_hash: self.params_hash.clone(),
+ }
+ }
+}
+
+/// Interface for connect container to network
+pub struct ContainerConnectionOptions {
+ pub Container: Option<String>,
+ params: HashMap<&'static str, String>
+}
+
+impl ToJson for ContainerConnectionOptions {
+ fn to_json(&self) -> Json {
+ let mut body: BTreeMap<String, Json> = BTreeMap::new();
+ self.parse_from(&self.params, &mut body);
+ body.to_json()
+ }
+}
+
+
+impl ContainerConnectionOptions {
+ /// serialize options as a string. returns None if no options are defined
+ pub fn serialize(&self) -> Result<String> {
+ Ok(try!(json::encode(&self.to_json())))
+ }
+
+ pub fn parse_from<'a, K, V>(&self,
+ params: &'a HashMap<K, V>,
+ body: &mut BTreeMap<String, Json>)
+ where &'a HashMap<K, V>: IntoIterator,
+ K: ToString + Eq + Hash,
+ V: ToJson
+ {
+ for (k, v) in params.iter() {
+ let key = k.to_string();
+ let value = v.to_json();
+
+ body.insert(key, value);
+ }
+ }
+
+ pub fn new(container_id: &str) -> ContainerConnectionOptions {
+ let mut params = HashMap::new();
+ params.insert("Container", container_id.to_owned());
+ ContainerConnectionOptions {
+ Container: None,
+ params: params.clone(),
+ }
+ }
+
+ pub fn force(&mut self) -> ContainerConnectionOptions {
+ self.params.insert("Force", "true".to_owned());
+ ContainerConnectionOptions {
+ Container: None,
+ params: self.params.clone()
+ }
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 42f2686..d2fc334 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -37,8 +37,8 @@ mod tarball;
pub use errors::Error;
pub use builder::{BuildOptions, ContainerOptions, ContainerListOptions, ContainerFilter,
EventsOptions, ImageFilter, ImageListOptions, LogsOptions,
- PullOptions, RmContainerOptions, ExecContainerOptions
- };
+ PullOptions, RmContainerOptions, ExecContainerOptions,
+ NetworkListOptions, NetworkCreateOptions, ContainerConnectionOptions};
use hyper::{Client, Url};
use hyper::header::ContentType;
use hyper::net::{HttpsConnector};
@@ -48,6 +48,7 @@ use hyperlocal::UnixSocketConnector;
use openssl::x509::X509_FILETYPE_PEM;
use openssl::ssl::{SslMethod, SslConnectorBuilder};
use rep::Image as ImageRep;
+use rep::{NetworkDetails as NetworkInfo, NetworkCreateInfo};
use rep::{Output, PullInfo, Change, ContainerCreateInfo, ContainerDetails,
Container as ContainerRep, Event, Exit, History, ImageDetails, Info, SearchResult,
Stats, Status, Top, Version};
@@ -488,6 +489,97 @@ impl<'a> Containers<'a> {
}
}
+/// Interface for docker network
+pub struct Networks<'a> {
+ docker: &'a Docker,
+}
+
+impl<'a> Networks<'a> {
+ /// Exports an interface for interacting with docker Networks
+ pub fn new(docker: &'a Docker) -> Networks<'a> {
+ Networks { docker: docker }
+ }
+
+ /// List the docker networks on the current docker host
+ pub fn list(&self, opts: &NetworkListOptions) -> Result<Vec<NetworkInfo>> {
+ let mut path = vec!["/networks".to_owned()];
+ if let Some(query) = opts.serialize() {
+ path.push(query);
+ }
+ let raw = try!(self.docker.get(&path.join("?")));
+ Ok(try!(json::decode::<Vec<NetworkInfo>>(&raw)))
+ }
+
+ /// Returns a reference to a set of operations available to a specific network instance
+ pub fn get(&'a self, id: &'a str) -> Network {
+ Network::new(self.docker, id)
+ }
+
+ pub fn create(&'a self, opts: &NetworkCreateOptions) -> Result<NetworkCreateInfo> {
+ let data = try!(opts.serialize());
+ let mut bytes = data.as_bytes();
+ let path = vec!["/networks/create".to_owned()];
+
+ let raw = try!(self.docker.post(&path.join("?"),
+ Some((&mut bytes, ContentType::json()))));
+ Ok(try!(json::decode::<NetworkCreateInfo>(&raw)))
+ }
+
+}
+
+/// Interface for accessing and manipulating a docker network
+pub struct Network<'a, 'b> {
+ docker: &'a Docker,
+ id: Cow<'b, str>,
+}
+
+impl<'a, 'b> Network<'a, 'b> {
+ /// Exports an interface exposing operations against a network instance
+ pub fn new<S>(docker: &'a Docker, id: S) -> Network<'a, 'b>
+ where S: Into<Cow<'b, str>>
+ {
+ Network {
+ docker: docker,
+ id: id.into(),
+ }
+ }
+
+ /// a getter for the Network id
+ pub fn id(&self) -> &str { &self.id }
+
+ /// Inspects the current docker network instance's details
+ pub fn inspect(&self) -> Result<NetworkInfo> {
+ let raw = try!(self.docker.get(&format!("/networks/{}", self.id)[..]));
+ Ok(try!(json::decode::<NetworkInfo>(&raw)))
+ }
+
+ /// Delete the network instance
+ pub fn delete(&self) -> Result<()> {
+ self.docker.delete(&format!("/networks/{}", self.id)[..]).map(|_| ())
+ }
+
+ /// Connect container to network
+ pub fn connect(&self, opts: &ContainerConnectionOptions) -> Result<()> {
+ self.do_connection("connect", opts)
+ }
+
+ /// Disconnect container to network
+ pub fn disconnect(&self, opts: &ContainerConnectionOptions) -> Result<()> {
+ self.do_connection("disconnect", opts)
+ }
+
+ fn do_connection(&self, segment: &str, opts: &ContainerConnectionOptions) -> Result<()> {
+ let data = try!(opts.serialize());
+ let mut bytes = data.as_bytes();
+
+ self.docker
+ .post(&format!("/networks/{}/{}", self.id, segment)[..],
+ Some((&mut bytes, ContentType::json())))
+ .map(|_| ())
+ }
+
+}
+
// https://docs.docker.com/reference/api/docker_remote_api_v1.17/
impl Docker {
/// constructs a new Docker instance for a docker host listening at a url specified by an env var `DOCKER_HOST`,
@@ -557,6 +649,10 @@ impl Docker {
Containers::new(self)
}
+ pub fn networks<'a>(&'a self) -> Networks {
+ Networks::new(self)
+ }
+
/// Returns version information associated with the docker daemon
pub fn version(&self) -> Result<Version> {
let raw = try!(self.get("/version"));
diff --git a/src/rep.rs b/src/rep.rs
index 5bf92ff..1d2c392 100644
--- a/src/rep.rs
+++ b/src/rep.rs
@@ -204,6 +204,46 @@ pub struct Network {
}
#[derive(Debug, RustcEncodable, RustcDecodable)]
+#[allow(non_snake_case)]
+pub struct IPAM {
+ pub Driver: String,
+ pub Config: Vec<HashMap<String, String>>,
+ pub Options: Option<HashMap<String, String>>,
+}
+
+#[derive(Debug, RustcEncodable, RustcDecodable)]
+#[allow(non_snake_case)]
+pub struct NetworkDetails {
+ pub Name: String,
+ pub Id: String,
+ pub Scope: String,
+ pub Driver: String,
+ pub EnableIPv6: bool,
+ pub IPAM: IPAM,
+ pub Internal: bool,
+ pub Attachable: bool,
+ pub Containers: HashMap<String, NetworkContainerDetails>,
+ pub Options: Option<HashMap<String, String>>,
+ pub Labels: Option<HashMap<String, String>>,
+}
+
+#[derive(Debug, RustcEncodable, RustcDecodable)]
+#[allow(non_snake_case)]
+pub struct NetworkContainerDetails {
+ pub EndpointID: String,
+ pub MacAddress: String,
+ pub IPv4Address: String,
+ pub IPv6Address: String,
+}
+
+#[derive(Debug, RustcEncodable, RustcDecodable)]
+#[allow(non_snake_case)]
+pub struct NetworkCreateInfo {
+ pub Id: String,
+ pub Warning: String,
+}
+
+#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct MemoryStats {
pub max_usage: u64,
pub usage: u64,