docker_pyo3/
network.rs

1use std::collections::HashMap;
2
3use crate::Pyo3Docker;
4use docker_api::opts::{ContainerConnectionOpts, EndpointIpamConfig, NetworkPruneOpts};
5use docker_api::opts::{ContainerDisconnectionOpts, NetworkCreateOpts};
6use docker_api::{models::NetworkPrune200Response, Network, Networks};
7use pyo3::exceptions;
8use pyo3::prelude::*;
9use pyo3::types::{PyDict, PyList};
10use pythonize::pythonize;
11
12#[pymodule]
13pub fn network(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
14    m.add_class::<Pyo3Networks>()?;
15    m.add_class::<Pyo3Network>()?;
16    Ok(())
17}
18
19#[derive(Debug)]
20#[pyclass(name = "Networks")]
21pub struct Pyo3Networks(pub Networks);
22
23#[derive(Debug)]
24#[pyclass(name = "Network")]
25pub struct Pyo3Network(pub Network);
26
27#[pymethods]
28impl Pyo3Networks {
29    #[new]
30    pub fn new(docker: Pyo3Docker) -> Self {
31        Pyo3Networks(Networks::new(docker.0))
32    }
33
34    pub fn get(&self, id: &str) -> Pyo3Network {
35        Pyo3Network(self.0.get(id))
36    }
37
38    pub fn list(&self) -> PyResult<Py<PyAny>> {
39        let rv = __networks_list(&self.0);
40
41        match rv {
42            Ok(rv) => Ok(pythonize_this!(rv)),
43            Err(rv) => Err(py_sys_exception!(rv)),
44        }
45    }
46
47    pub fn prune(&self) -> PyResult<Py<PyAny>> {
48        let rv = __networks_prune(&self.0, &Default::default());
49
50        match rv {
51            Ok(rv) => Ok(pythonize_this!(rv)),
52            Err(rv) => Err(py_sys_exception!(rv)),
53        }
54    }
55
56    #[pyo3(signature = (name, *, check_duplicate=None, driver=None, internal=None, attachable=None, ingress=None, enable_ipv6=None, options=None, labels=None))]
57    pub fn create(
58        &self,
59        name: &str,
60        check_duplicate: Option<bool>,
61        driver: Option<&str>,
62        internal: Option<bool>,
63        attachable: Option<bool>,
64        ingress: Option<bool>,
65        enable_ipv6: Option<bool>,
66        options: Option<&Bound<'_, PyDict>>,
67        labels: Option<&Bound<'_, PyDict>>,
68    ) -> PyResult<Pyo3Network> {
69        let mut network_opts = NetworkCreateOpts::builder(name);
70
71        let options_map: Option<HashMap<String, String>> = if options.is_some() {
72            Some(options.unwrap().extract().unwrap())
73        } else {
74            None
75        };
76        let options: Option<HashMap<&str, &str>> = options_map
77            .as_ref()
78            .map(|m| m.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect());
79
80        let labels_map: Option<HashMap<String, String>> = if labels.is_some() {
81            Some(labels.unwrap().extract().unwrap())
82        } else {
83            None
84        };
85        let labels: Option<HashMap<&str, &str>> = labels_map
86            .as_ref()
87            .map(|m| m.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect());
88
89        bo_setter!(check_duplicate, network_opts);
90        bo_setter!(driver, network_opts);
91        bo_setter!(internal, network_opts);
92        bo_setter!(attachable, network_opts);
93        bo_setter!(ingress, network_opts);
94        bo_setter!(enable_ipv6, network_opts);
95        bo_setter!(options, network_opts);
96        bo_setter!(labels, network_opts);
97
98        let rv = __networks_create(&self.0, &network_opts.build());
99        match rv {
100            Ok(rv) => Ok(Pyo3Network(rv)),
101            Err(rv) => Err(py_sys_exception!(rv)),
102        }
103    }
104}
105
106#[tokio::main]
107async fn __networks_list(
108    networks: &Networks,
109) -> Result<Vec<docker_api::models::Network>, docker_api::Error> {
110    networks.list(&Default::default()).await
111}
112
113#[tokio::main]
114async fn __networks_prune(
115    networks: &Networks,
116    opts: &NetworkPruneOpts,
117) -> Result<NetworkPrune200Response, docker_api::Error> {
118    networks.prune(opts).await
119}
120
121#[tokio::main]
122async fn __networks_create(
123    networks: &Networks,
124    opts: &NetworkCreateOpts,
125) -> Result<Network, docker_api::Error> {
126    networks.create(opts).await
127}
128
129#[pymethods]
130impl Pyo3Network {
131    #[new]
132    pub fn new(docker: Pyo3Docker, id: &str) -> Self {
133        Pyo3Network(Network::new(docker.0, id))
134    }
135
136    pub fn id(&self) -> String {
137        self.0.id().to_string()
138    }
139
140    pub fn inspect(&self) -> PyResult<Py<PyAny>> {
141        let rv = __network_inspect(&self.0);
142
143        match rv {
144            Ok(rv) => Ok(pythonize_this!(rv)),
145            Err(rv) => Err(py_sys_exception!(rv)),
146        }
147    }
148
149    pub fn delete(&self) -> PyResult<()> {
150        let rv = __network_delete(&self.0);
151        match rv {
152            Ok(rv) => Ok(rv),
153            Err(rv) => Err(py_sys_exception!(rv)),
154        }
155    }
156
157    #[pyo3(signature = (container_id, aliases=None, links=None, network_id=None, endpoint_id=None, gateway=None, ipv4=None, prefix_len=None, ipv6_gateway=None, ipv6=None, ipv6_prefix_len=None, mac=None, driver_opts=None, ipam_config=None))]
158    pub fn connect(
159        &self,
160        container_id: &str,
161        aliases: Option<&Bound<'_, PyList>>,
162        links: Option<&Bound<'_, PyList>>,
163        network_id: Option<&str>,
164        endpoint_id: Option<&str>,
165        gateway: Option<&str>,
166        ipv4: Option<&str>,
167        prefix_len: Option<isize>,
168        ipv6_gateway: Option<&str>,
169        ipv6: Option<&str>,
170        ipv6_prefix_len: Option<i64>,
171        mac: Option<&str>,
172        driver_opts: Option<&Bound<'_, PyDict>>,
173        ipam_config: Option<&Bound<'_, PyDict>>,
174    ) -> PyResult<()> {
175        let mut connect_opts = ContainerConnectionOpts::builder(container_id);
176
177        let aliases_strings: Option<Vec<String>> = if aliases.is_some() {
178            aliases.unwrap().extract().unwrap()
179        } else {
180            None
181        };
182        let aliases: Option<Vec<&str>> = aliases_strings
183            .as_ref()
184            .map(|v| v.iter().map(|s| s.as_str()).collect());
185
186        let links_strings: Option<Vec<String>> = if links.is_some() {
187            links.unwrap().extract().unwrap()
188        } else {
189            None
190        };
191        let links: Option<Vec<&str>> = links_strings
192            .as_ref()
193            .map(|v| v.iter().map(|s| s.as_str()).collect());
194
195        let driver_opts_map: Option<HashMap<String, String>> = if driver_opts.is_some() {
196            driver_opts.unwrap().extract().unwrap()
197        } else {
198            None
199        };
200        let driver_opts: Option<HashMap<&str, &str>> = driver_opts_map
201            .as_ref()
202            .map(|m| m.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect());
203
204        bo_setter!(network_id, connect_opts);
205        bo_setter!(endpoint_id, connect_opts);
206        bo_setter!(gateway, connect_opts);
207        bo_setter!(ipv4, connect_opts);
208        bo_setter!(prefix_len, connect_opts);
209        bo_setter!(ipv6_gateway, connect_opts);
210        bo_setter!(ipv6, connect_opts);
211        bo_setter!(ipv6_prefix_len, connect_opts);
212        bo_setter!(mac, connect_opts);
213
214        bo_setter!(aliases, connect_opts);
215        bo_setter!(links, connect_opts);
216        bo_setter!(driver_opts, connect_opts);
217
218        // Handle ipam_config - expects dict with ipv4, ipv6, link_local_ips
219        if let Some(ipam_dict) = ipam_config {
220            let mut config = EndpointIpamConfig::new();
221
222            if let Some(ipv4_addr) = ipam_dict.get_item("ipv4")? {
223                let ipv4_str: String = ipv4_addr.extract()?;
224                config = config.ipv4(ipv4_str);
225            }
226
227            if let Some(ipv6_addr) = ipam_dict.get_item("ipv6")? {
228                let ipv6_str: String = ipv6_addr.extract()?;
229                config = config.ipv6(ipv6_str);
230            }
231
232            if let Some(link_local) = ipam_dict.get_item("link_local_ips")? {
233                let ips: Vec<String> = link_local.extract()?;
234                config = config.link_local_ips(ips);
235            }
236
237            connect_opts = connect_opts.ipam_config(config);
238        }
239
240        let rv = __network_connect(&self.0, &connect_opts.build());
241
242        match rv {
243            Ok(rv) => Ok(rv),
244            Err(rv) => Err(py_sys_exception!(rv)),
245        }
246    }
247
248    #[pyo3(signature = (container_id, force=None))]
249    pub fn disconnect(&self, container_id: &str, force: Option<bool>) -> PyResult<()> {
250        let mut disconnect_opts = ContainerDisconnectionOpts::builder(container_id);
251        bo_setter!(force, disconnect_opts);
252
253        let rv = __network_disconnect(&self.0, &disconnect_opts.build());
254
255        match rv {
256            Ok(rv) => Ok(rv),
257            Err(rv) => Err(py_sys_exception!(rv)),
258        }
259    }
260}
261
262#[tokio::main]
263async fn __network_inspect(
264    network: &Network,
265) -> Result<docker_api::models::Network, docker_api::Error> {
266    network.inspect().await
267}
268
269#[tokio::main]
270async fn __network_delete(network: &Network) -> Result<(), docker_api::Error> {
271    network.delete().await
272}
273
274#[tokio::main]
275async fn __network_connect(
276    network: &Network,
277    opts: &ContainerConnectionOpts,
278) -> Result<(), docker_api::Error> {
279    network.connect(opts).await
280}
281
282#[tokio::main]
283async fn __network_disconnect(
284    network: &Network,
285    opts: &ContainerDisconnectionOpts,
286) -> Result<(), docker_api::Error> {
287    network.disconnect(opts).await
288}