docker_sdk/
network.rs

1//! Create and manage user-defined networks that containers can be attached to.
2//!
3//! API Reference: <https://docs.docker.com/engine/api/v1.41/#tag/Network>
4
5use std::{
6    collections::{BTreeMap, HashMap},
7    hash::Hash,
8};
9
10use hyper::Body;
11use serde::{Deserialize, Serialize};
12use serde_json::{json, Value};
13use url::form_urlencoded;
14
15use crate::{
16    docker::Docker,
17    errors::{Error, Result},
18};
19
20/// Interface for docker network
21///
22/// API Reference: <https://docs.docker.com/engine/api/v1.41/#tag/Network>
23pub struct Networks<'docker> {
24    docker: &'docker Docker,
25}
26
27impl<'docker> Networks<'docker> {
28    /// Exports an interface for interacting with docker Networks
29    pub fn new(docker: &'docker Docker) -> Self {
30        Networks { docker }
31    }
32
33    /// List the docker networks on the current docker host
34    ///
35    /// API Reference: <https://docs.docker.com/engine/api/v1.41/#operation/NetworkList>
36    pub async fn list(
37        &self,
38        opts: &NetworkListOptions,
39    ) -> Result<Vec<NetworkDetails>> {
40        let mut path = vec!["/networks".to_owned()];
41        if let Some(query) = opts.serialize() {
42            path.push(query);
43        }
44        self.docker.get_json(&path.join("?")).await
45    }
46
47    /// Returns a reference to a set of operations available to a specific network instance
48    pub fn get<S>(
49        &self,
50        id: S,
51    ) -> Network<'docker>
52    where
53        S: Into<String>,
54    {
55        Network::new(self.docker, id)
56    }
57
58    /// Create a new Network instance
59    ///
60    /// API Reference: <https://docs.docker.com/engine/api/v1.41/#operation/NetworkCreate>
61    pub async fn create(
62        &self,
63        opts: &NetworkCreateOptions,
64    ) -> Result<NetworkCreateInfo> {
65        let body: Body = opts.serialize()?.into();
66        let path = vec!["/networks/create".to_owned()];
67
68        self.docker
69            .post_json(&path.join("?"), Some((body, mime::APPLICATION_JSON)))
70            .await
71    }
72}
73
74/// Interface for accessing and manipulating a docker network
75pub struct Network<'docker> {
76    docker: &'docker Docker,
77    id: String,
78}
79
80impl<'docker> Network<'docker> {
81    /// Exports an interface exposing operations against a network instance
82    pub fn new<S>(
83        docker: &'docker Docker,
84        id: S,
85    ) -> Self
86    where
87        S: Into<String>,
88    {
89        Network {
90            docker,
91            id: id.into(),
92        }
93    }
94
95    /// a getter for the Network id
96    pub fn id(&self) -> &str {
97        &self.id
98    }
99
100    /// Inspects the current docker network instance's details
101    ///
102    /// API Reference: <https://docs.docker.com/engine/api/v1.41/#operation/NetworkInspect>
103    pub async fn inspect(&self) -> Result<NetworkDetails> {
104        self.docker
105            .get_json(&format!("/networks/{}", self.id)[..])
106            .await
107    }
108
109    /// Delete the network instance
110    ///
111    /// API Reference: <https://docs.docker.com/engine/api/v1.41/#operation/NetworkDelete>
112    pub async fn delete(&self) -> Result<()> {
113        self.docker
114            .delete(&format!("/networks/{}", self.id)[..])
115            .await?;
116        Ok(())
117    }
118
119    /// Connect container to network
120    ///
121    /// API Reference: <https://docs.docker.com/engine/api/v1.41/#operation/NetworkConnect>
122    pub async fn connect(
123        &self,
124        opts: &ContainerConnectionOptions,
125    ) -> Result<()> {
126        self.do_connection("connect", opts).await
127    }
128
129    /// Disconnect container to network
130    ///
131    /// API Reference: <https://docs.docker.com/engine/api/v1.41/#operation/NetworkDisconnect>
132    pub async fn disconnect(
133        &self,
134        opts: &ContainerConnectionOptions,
135    ) -> Result<()> {
136        self.do_connection("disconnect", opts).await
137    }
138
139    async fn do_connection(
140        &self,
141        segment: &str,
142        opts: &ContainerConnectionOptions,
143    ) -> Result<()> {
144        let body: Body = opts.serialize()?.into();
145
146        self.docker
147            .post(
148                &format!("/networks/{}/{}", self.id, segment)[..],
149                Some((body, mime::APPLICATION_JSON)),
150            )
151            .await?;
152        Ok(())
153    }
154}
155
156/// Options for filtering networks list results
157#[derive(Default, Debug)]
158pub struct NetworkListOptions {
159    params: HashMap<&'static str, String>,
160}
161
162impl NetworkListOptions {
163    /// serialize options as a string. returns None if no options are defined
164    pub fn serialize(&self) -> Option<String> {
165        if self.params.is_empty() {
166            None
167        } else {
168            Some(
169                form_urlencoded::Serializer::new(String::new())
170                    .extend_pairs(&self.params)
171                    .finish(),
172            )
173        }
174    }
175}
176
177/// Interface for creating new docker network
178#[derive(Serialize, Debug)]
179pub struct NetworkCreateOptions {
180    params: HashMap<&'static str, Value>,
181}
182
183impl NetworkCreateOptions {
184    /// return a new instance of a builder for options
185    pub fn builder(name: &str) -> NetworkCreateOptionsBuilder {
186        NetworkCreateOptionsBuilder::new(name)
187    }
188
189    /// serialize options as a string. returns None if no options are defined
190    pub fn serialize(&self) -> Result<String> {
191        serde_json::to_string(&self.params).map_err(Error::from)
192    }
193
194    pub fn parse_from<'a, K, V>(
195        &self,
196        params: &'a HashMap<K, V>,
197        body: &mut serde_json::Map<String, Value>,
198    ) where
199        &'a HashMap<K, V>: IntoIterator,
200        K: ToString + Eq + Hash,
201        V: Serialize,
202    {
203        for (k, v) in params.iter() {
204            let key = k.to_string();
205            let value = serde_json::to_value(v).unwrap();
206
207            body.insert(key, value);
208        }
209    }
210}
211
212#[derive(Default)]
213pub struct NetworkCreateOptionsBuilder {
214    params: HashMap<&'static str, Value>,
215}
216
217impl NetworkCreateOptionsBuilder {
218    pub(crate) fn new(name: &str) -> Self {
219        let mut params = HashMap::new();
220        params.insert("Name", json!(name));
221        NetworkCreateOptionsBuilder { params }
222    }
223
224    pub fn driver(
225        &mut self,
226        name: &str,
227    ) -> &mut Self {
228        if !name.is_empty() {
229            self.params.insert("Driver", json!(name));
230        }
231        self
232    }
233
234    pub fn label(
235        &mut self,
236        labels: HashMap<String, String>,
237    ) -> &mut Self {
238        self.params.insert("Labels", json!(labels));
239        self
240    }
241
242    pub fn build(&self) -> NetworkCreateOptions {
243        NetworkCreateOptions {
244            params: self.params.clone(),
245        }
246    }
247}
248
249/// Interface for connect container to network
250#[derive(Serialize, Debug)]
251pub struct ContainerConnectionOptions {
252    params: HashMap<&'static str, Value>,
253}
254
255impl ContainerConnectionOptions {
256    /// serialize options as a string. returns None if no options are defined
257    pub fn serialize(&self) -> Result<String> {
258        serde_json::to_string(&self.params).map_err(Error::from)
259    }
260
261    pub fn parse_from<'a, K, V>(
262        &self,
263        params: &'a HashMap<K, V>,
264        body: &mut BTreeMap<String, Value>,
265    ) where
266        &'a HashMap<K, V>: IntoIterator,
267        K: ToString + Eq + Hash,
268        V: Serialize,
269    {
270        for (k, v) in params.iter() {
271            let key = k.to_string();
272            let value = serde_json::to_value(v).unwrap();
273
274            body.insert(key, value);
275        }
276    }
277
278    /// return a new instance of a builder for options
279    pub fn builder(container_id: &str) -> ContainerConnectionOptionsBuilder {
280        ContainerConnectionOptionsBuilder::new(container_id)
281    }
282}
283
284#[derive(Default)]
285pub struct ContainerConnectionOptionsBuilder {
286    params: HashMap<&'static str, Value>,
287}
288
289impl ContainerConnectionOptionsBuilder {
290    pub(crate) fn new(container_id: &str) -> Self {
291        let mut params = HashMap::new();
292        params.insert("Container", json!(container_id));
293        ContainerConnectionOptionsBuilder { params }
294    }
295
296    pub fn aliases(
297        &mut self,
298        aliases: Vec<&str>,
299    ) -> &mut Self {
300        self.params
301            .insert("EndpointConfig", json!({ "Aliases": json!(aliases) }));
302        self
303    }
304
305    pub fn force(&mut self) -> &mut Self {
306        self.params.insert("Force", json!(true));
307        self
308    }
309
310    pub fn build(&self) -> ContainerConnectionOptions {
311        ContainerConnectionOptions {
312            params: self.params.clone(),
313        }
314    }
315}
316
317type PortDescription = HashMap<String, Option<Vec<HashMap<String, String>>>>;
318
319#[derive(Clone, Debug, Serialize, Deserialize)]
320#[serde(rename_all = "PascalCase")]
321pub struct NetworkSettings {
322    pub bridge: String,
323    pub gateway: String,
324    #[serde(rename = "IPAddress")]
325    pub ip_address: String,
326    #[serde(rename = "IPPrefixLen")]
327    pub ip_prefix_len: u64,
328    pub mac_address: String,
329    pub ports: Option<PortDescription>,
330    pub networks: HashMap<String, NetworkEntry>,
331}
332
333#[derive(Clone, Debug, Serialize, Deserialize)]
334#[serde(rename_all = "PascalCase")]
335pub struct NetworkEntry {
336    #[serde(rename = "NetworkID")]
337    pub network_id: String,
338    #[serde(rename = "EndpointID")]
339    pub endpoint_id: String,
340    pub gateway: String,
341    #[serde(rename = "IPAddress")]
342    pub ip_address: String,
343    #[serde(rename = "IPPrefixLen")]
344    pub ip_prefix_len: u64,
345    #[serde(rename = "IPv6Gateway")]
346    pub ipv6_gateway: String,
347    #[serde(rename = "GlobalIPv6Address")]
348    pub global_ipv6_address: String,
349    #[serde(rename = "GlobalIPv6PrefixLen")]
350    pub global_ipv6_prefix_len: u64,
351    pub mac_address: String,
352    pub links: Option<Vec<String>>,
353    pub aliases: Option<Vec<String>>,
354    #[serde(rename = "IPAMConfig")]
355    pub ipam_config: Option<EndpointIPAMConfig>,
356}
357
358#[derive(Clone, Debug, Serialize, Deserialize)]
359#[allow(clippy::upper_case_acronyms)]
360pub struct EndpointIPAMConfig {
361    #[serde(rename = "IPv4Address")]
362    pub ipv4_address: String,
363    #[serde(rename = "IPv6Address")]
364    pub ipv6_address: String,
365    #[serde(rename = "LinkLocalIPs")]
366    pub link_local_ips: Vec<String>,
367}
368
369#[derive(Clone, Debug, Serialize, Deserialize)]
370#[serde(rename_all = "PascalCase")]
371pub struct Ipam {
372    pub driver: String,
373    pub config: Vec<HashMap<String, String>>,
374    pub options: Option<HashMap<String, String>>,
375}
376
377#[derive(Clone, Debug, Serialize, Deserialize)]
378#[serde(rename_all = "PascalCase")]
379pub struct NetworkDetails {
380    pub name: String,
381    pub id: String,
382    pub scope: String,
383    pub driver: String,
384    #[serde(rename = "EnableIPv6")]
385    pub enable_ipv6: bool,
386    #[serde(rename = "IPAM")]
387    pub ipam: Ipam,
388    pub internal: bool,
389    pub attachable: bool,
390    pub containers: HashMap<String, NetworkContainerDetails>,
391    pub options: Option<HashMap<String, String>>,
392    pub labels: Option<HashMap<String, String>>,
393}
394
395#[derive(Clone, Debug, Serialize, Deserialize)]
396#[serde(rename_all = "PascalCase")]
397pub struct NetworkContainerDetails {
398    #[serde(rename = "EndpointID")]
399    pub endpoint_id: String,
400    pub mac_address: String,
401    #[serde(rename = "IPv4Address")]
402    pub ipv4_address: String,
403    #[serde(rename = "IPv6Address")]
404    pub ipv6_address: String,
405}
406
407#[derive(Clone, Debug, Serialize, Deserialize)]
408#[serde(rename_all = "PascalCase")]
409pub struct NetworkCreateInfo {
410    pub id: String,
411    pub warning: String,
412}