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)]
21#[pyclass(name = "Networks")]
22pub struct Pyo3Networks(pub Networks);
23
24#[derive(Debug)]
26#[pyclass(name = "Network")]
27pub struct Pyo3Network(pub Network);
28
29#[pymethods]
30impl Pyo3Networks {
31 #[new]
32 pub fn new(docker: Pyo3Docker) -> Self {
33 Pyo3Networks(Networks::new(docker.0))
34 }
35
36 pub fn get(&self, id: &str) -> Pyo3Network {
44 Pyo3Network(self.0.get(id))
45 }
46
47 pub fn list(&self) -> PyResult<Py<PyAny>> {
52 let rv = __networks_list(&self.0);
53
54 match rv {
55 Ok(rv) => Ok(pythonize_this!(rv)),
56 Err(rv) => Err(py_sys_exception!(rv)),
57 }
58 }
59
60 pub fn prune(&self) -> PyResult<Py<PyAny>> {
65 let rv = __networks_prune(&self.0, &Default::default());
66
67 match rv {
68 Ok(rv) => Ok(pythonize_this!(rv)),
69 Err(rv) => Err(py_sys_exception!(rv)),
70 }
71 }
72
73 #[pyo3(signature = (name, *, check_duplicate=None, driver=None, internal=None, attachable=None, ingress=None, enable_ipv6=None, options=None, labels=None))]
89 pub fn create(
90 &self,
91 name: &str,
92 check_duplicate: Option<bool>,
93 driver: Option<&str>,
94 internal: Option<bool>,
95 attachable: Option<bool>,
96 ingress: Option<bool>,
97 enable_ipv6: Option<bool>,
98 options: Option<&Bound<'_, PyDict>>,
99 labels: Option<&Bound<'_, PyDict>>,
100 ) -> PyResult<Pyo3Network> {
101 let mut network_opts = NetworkCreateOpts::builder(name);
102
103 let options_map: Option<HashMap<String, String>> = if options.is_some() {
104 Some(options.unwrap().extract().unwrap())
105 } else {
106 None
107 };
108 let options: Option<HashMap<&str, &str>> = options_map
109 .as_ref()
110 .map(|m| m.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect());
111
112 let labels_map: Option<HashMap<String, String>> = if labels.is_some() {
113 Some(labels.unwrap().extract().unwrap())
114 } else {
115 None
116 };
117 let labels: Option<HashMap<&str, &str>> = labels_map
118 .as_ref()
119 .map(|m| m.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect());
120
121 bo_setter!(check_duplicate, network_opts);
122 bo_setter!(driver, network_opts);
123 bo_setter!(internal, network_opts);
124 bo_setter!(attachable, network_opts);
125 bo_setter!(ingress, network_opts);
126 bo_setter!(enable_ipv6, network_opts);
127 bo_setter!(options, network_opts);
128 bo_setter!(labels, network_opts);
129
130 let rv = __networks_create(&self.0, &network_opts.build());
131 match rv {
132 Ok(rv) => Ok(Pyo3Network(rv)),
133 Err(rv) => Err(py_sys_exception!(rv)),
134 }
135 }
136}
137
138#[tokio::main]
139async fn __networks_list(
140 networks: &Networks,
141) -> Result<Vec<docker_api::models::Network>, docker_api::Error> {
142 networks.list(&Default::default()).await
143}
144
145#[tokio::main]
146async fn __networks_prune(
147 networks: &Networks,
148 opts: &NetworkPruneOpts,
149) -> Result<NetworkPrune200Response, docker_api::Error> {
150 networks.prune(opts).await
151}
152
153#[tokio::main]
154async fn __networks_create(
155 networks: &Networks,
156 opts: &NetworkCreateOpts,
157) -> Result<Network, docker_api::Error> {
158 networks.create(opts).await
159}
160
161#[pymethods]
162impl Pyo3Network {
163 #[new]
164 pub fn new(docker: Pyo3Docker, id: &str) -> Self {
165 Pyo3Network(Network::new(docker.0, id))
166 }
167
168 pub fn id(&self) -> String {
173 self.0.id().to_string()
174 }
175
176 pub fn inspect(&self) -> PyResult<Py<PyAny>> {
181 let rv = __network_inspect(&self.0);
182
183 match rv {
184 Ok(rv) => Ok(pythonize_this!(rv)),
185 Err(rv) => Err(py_sys_exception!(rv)),
186 }
187 }
188
189 pub fn delete(&self) -> PyResult<()> {
194 let rv = __network_delete(&self.0);
195 match rv {
196 Ok(rv) => Ok(rv),
197 Err(rv) => Err(py_sys_exception!(rv)),
198 }
199 }
200
201 #[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))]
222 pub fn connect(
223 &self,
224 container_id: &str,
225 aliases: Option<&Bound<'_, PyList>>,
226 links: Option<&Bound<'_, PyList>>,
227 network_id: Option<&str>,
228 endpoint_id: Option<&str>,
229 gateway: Option<&str>,
230 ipv4: Option<&str>,
231 prefix_len: Option<isize>,
232 ipv6_gateway: Option<&str>,
233 ipv6: Option<&str>,
234 ipv6_prefix_len: Option<i64>,
235 mac: Option<&str>,
236 driver_opts: Option<&Bound<'_, PyDict>>,
237 ipam_config: Option<&Bound<'_, PyDict>>,
238 ) -> PyResult<()> {
239 let mut connect_opts = ContainerConnectionOpts::builder(container_id);
240
241 let aliases_strings: Option<Vec<String>> = if aliases.is_some() {
242 aliases.unwrap().extract().unwrap()
243 } else {
244 None
245 };
246 let aliases: Option<Vec<&str>> = aliases_strings
247 .as_ref()
248 .map(|v| v.iter().map(|s| s.as_str()).collect());
249
250 let links_strings: Option<Vec<String>> = if links.is_some() {
251 links.unwrap().extract().unwrap()
252 } else {
253 None
254 };
255 let links: Option<Vec<&str>> = links_strings
256 .as_ref()
257 .map(|v| v.iter().map(|s| s.as_str()).collect());
258
259 let driver_opts_map: Option<HashMap<String, String>> = if driver_opts.is_some() {
260 driver_opts.unwrap().extract().unwrap()
261 } else {
262 None
263 };
264 let driver_opts: Option<HashMap<&str, &str>> = driver_opts_map
265 .as_ref()
266 .map(|m| m.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect());
267
268 bo_setter!(network_id, connect_opts);
269 bo_setter!(endpoint_id, connect_opts);
270 bo_setter!(gateway, connect_opts);
271 bo_setter!(ipv4, connect_opts);
272 bo_setter!(prefix_len, connect_opts);
273 bo_setter!(ipv6_gateway, connect_opts);
274 bo_setter!(ipv6, connect_opts);
275 bo_setter!(ipv6_prefix_len, connect_opts);
276 bo_setter!(mac, connect_opts);
277
278 bo_setter!(aliases, connect_opts);
279 bo_setter!(links, connect_opts);
280 bo_setter!(driver_opts, connect_opts);
281
282 if let Some(ipam_dict) = ipam_config {
284 let mut config = EndpointIpamConfig::new();
285
286 if let Some(ipv4_addr) = ipam_dict.get_item("ipv4")? {
287 let ipv4_str: String = ipv4_addr.extract()?;
288 config = config.ipv4(ipv4_str);
289 }
290
291 if let Some(ipv6_addr) = ipam_dict.get_item("ipv6")? {
292 let ipv6_str: String = ipv6_addr.extract()?;
293 config = config.ipv6(ipv6_str);
294 }
295
296 if let Some(link_local) = ipam_dict.get_item("link_local_ips")? {
297 let ips: Vec<String> = link_local.extract()?;
298 config = config.link_local_ips(ips);
299 }
300
301 connect_opts = connect_opts.ipam_config(config);
302 }
303
304 let rv = __network_connect(&self.0, &connect_opts.build());
305
306 match rv {
307 Ok(rv) => Ok(rv),
308 Err(rv) => Err(py_sys_exception!(rv)),
309 }
310 }
311
312 #[pyo3(signature = (container_id, force=None))]
321 pub fn disconnect(&self, container_id: &str, force: Option<bool>) -> PyResult<()> {
322 let mut disconnect_opts = ContainerDisconnectionOpts::builder(container_id);
323 bo_setter!(force, disconnect_opts);
324
325 let rv = __network_disconnect(&self.0, &disconnect_opts.build());
326
327 match rv {
328 Ok(rv) => Ok(rv),
329 Err(rv) => Err(py_sys_exception!(rv)),
330 }
331 }
332}
333
334#[tokio::main]
335async fn __network_inspect(
336 network: &Network,
337) -> Result<docker_api::models::Network, docker_api::Error> {
338 network.inspect().await
339}
340
341#[tokio::main]
342async fn __network_delete(network: &Network) -> Result<(), docker_api::Error> {
343 network.delete().await
344}
345
346#[tokio::main]
347async fn __network_connect(
348 network: &Network,
349 opts: &ContainerConnectionOpts,
350) -> Result<(), docker_api::Error> {
351 network.connect(opts).await
352}
353
354#[tokio::main]
355async fn __network_disconnect(
356 network: &Network,
357 opts: &ContainerDisconnectionOpts,
358) -> Result<(), docker_api::Error> {
359 network.disconnect(opts).await
360}