docker_pyo3/
plugin.rs

1//! Docker Plugin management support.
2//!
3//! This module provides types and functions for managing Docker plugins.
4
5use crate::Pyo3Docker;
6use docker_api::opts::PluginListOpts;
7use docker_api::plugin::{Plugin, Plugins};
8use pyo3::exceptions;
9use pyo3::prelude::*;
10use pythonize::pythonize;
11
12#[pymodule]
13pub fn plugin(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
14    m.add_class::<Pyo3Plugins>()?;
15    m.add_class::<Pyo3Plugin>()?;
16    Ok(())
17}
18
19/// Interface for managing Docker plugins collection.
20///
21/// Docker plugins extend the capabilities of the Docker daemon.
22/// Swarm mode must be enabled for some plugin operations.
23#[derive(Debug)]
24#[pyclass(name = "Plugins")]
25pub struct Pyo3Plugins {
26    plugins: Plugins,
27}
28
29/// Represents an individual Docker plugin.
30///
31/// Provides methods to inspect, enable, disable, and manage plugins.
32#[derive(Debug)]
33#[pyclass(name = "Plugin")]
34pub struct Pyo3Plugin {
35    plugin: Plugin,
36}
37
38#[pymethods]
39impl Pyo3Plugins {
40    #[new]
41    pub fn new(docker: Pyo3Docker) -> Self {
42        Pyo3Plugins {
43            plugins: Plugins::new(docker.0),
44        }
45    }
46
47    /// Get a specific plugin by name.
48    ///
49    /// Args:
50    ///     name: Plugin name (e.g., "vieux/sshfs:latest")
51    ///
52    /// Returns:
53    ///     Plugin: Plugin instance for further operations
54    pub fn get(&self, name: &str) -> Pyo3Plugin {
55        Pyo3Plugin {
56            plugin: self.plugins.get(name),
57        }
58    }
59
60    /// List all installed plugins.
61    ///
62    /// Returns:
63    ///     list[dict]: List of plugin information dictionaries including:
64    ///         - id: Plugin ID
65    ///         - name: Plugin name
66    ///         - enabled: Whether the plugin is enabled
67    ///         - config: Plugin configuration
68    ///
69    /// Raises:
70    ///     SystemError: If the operation fails
71    pub fn list(&self) -> PyResult<Py<PyAny>> {
72        let rv = __plugins_list(&self.plugins, &Default::default());
73
74        match rv {
75            Ok(rv) => Ok(pythonize_this!(rv)),
76            Err(rv) => Err(py_sys_exception!(rv)),
77        }
78    }
79
80    /// List plugins filtered by capability.
81    ///
82    /// Args:
83    ///     capability: Filter plugins by capability (e.g., "volumedriver", "networkdriver")
84    ///
85    /// Returns:
86    ///     list[dict]: List of matching plugin information dictionaries
87    ///
88    /// Raises:
89    ///     SystemError: If the operation fails
90    pub fn list_by_capability(&self, capability: &str) -> PyResult<Py<PyAny>> {
91        let opts = PluginListOpts::builder()
92            .filter([docker_api::opts::PluginFilter::Capability(
93                capability.to_string(),
94            )])
95            .build();
96        let rv = __plugins_list(&self.plugins, &opts);
97
98        match rv {
99            Ok(rv) => Ok(pythonize_this!(rv)),
100            Err(rv) => Err(py_sys_exception!(rv)),
101        }
102    }
103
104    /// List only enabled plugins.
105    ///
106    /// Returns:
107    ///     list[dict]: List of enabled plugin information dictionaries
108    ///
109    /// Raises:
110    ///     SystemError: If the operation fails
111    pub fn list_enabled(&self) -> PyResult<Py<PyAny>> {
112        let opts = PluginListOpts::builder()
113            .filter([docker_api::opts::PluginFilter::Enable])
114            .build();
115        let rv = __plugins_list(&self.plugins, &opts);
116
117        match rv {
118            Ok(rv) => Ok(pythonize_this!(rv)),
119            Err(rv) => Err(py_sys_exception!(rv)),
120        }
121    }
122
123    /// List only disabled plugins.
124    ///
125    /// Returns:
126    ///     list[dict]: List of disabled plugin information dictionaries
127    ///
128    /// Raises:
129    ///     SystemError: If the operation fails
130    pub fn list_disabled(&self) -> PyResult<Py<PyAny>> {
131        let opts = PluginListOpts::builder()
132            .filter([docker_api::opts::PluginFilter::Disable])
133            .build();
134        let rv = __plugins_list(&self.plugins, &opts);
135
136        match rv {
137            Ok(rv) => Ok(pythonize_this!(rv)),
138            Err(rv) => Err(py_sys_exception!(rv)),
139        }
140    }
141}
142
143#[tokio::main]
144async fn __plugins_list(
145    plugins: &Plugins,
146    opts: &PluginListOpts,
147) -> Result<Vec<docker_api::models::Plugin>, docker_api::Error> {
148    plugins.list(opts).await
149}
150
151#[pymethods]
152impl Pyo3Plugin {
153    #[new]
154    pub fn new(docker: Pyo3Docker, name: &str) -> Self {
155        Pyo3Plugin {
156            plugin: Plugin::new(docker.0, name),
157        }
158    }
159
160    /// Get the plugin name.
161    ///
162    /// Returns:
163    ///     str: Plugin name
164    pub fn name(&self) -> String {
165        self.plugin.name().to_string()
166    }
167
168    /// Inspect the plugin to get detailed information.
169    ///
170    /// Returns:
171    ///     dict: Detailed plugin information including:
172    ///         - id: Plugin ID
173    ///         - name: Plugin name
174    ///         - enabled: Whether the plugin is enabled
175    ///         - settings: Plugin settings (mounts, env, args, devices)
176    ///         - plugin_reference: Plugin reference
177    ///         - config: Full plugin configuration
178    ///
179    /// Raises:
180    ///     SystemError: If the operation fails
181    pub fn inspect(&self) -> PyResult<Py<PyAny>> {
182        let rv = __plugin_inspect(&self.plugin);
183
184        match rv {
185            Ok(rv) => Ok(pythonize_this!(rv)),
186            Err(rv) => Err(py_sys_exception!(rv)),
187        }
188    }
189
190    /// Enable the plugin.
191    ///
192    /// Enables a previously disabled plugin so it can be used by Docker.
193    ///
194    /// Args:
195    ///     timeout: Timeout in seconds to wait for enable (optional)
196    ///
197    /// Returns:
198    ///     None
199    ///
200    /// Raises:
201    ///     SystemError: If the plugin cannot be enabled
202    #[pyo3(signature = (timeout=None))]
203    pub fn enable(&self, timeout: Option<u64>) -> PyResult<()> {
204        let rv = __plugin_enable(&self.plugin, timeout);
205        match rv {
206            Ok(rv) => Ok(rv),
207            Err(rv) => Err(py_sys_exception!(rv)),
208        }
209    }
210
211    /// Disable the plugin.
212    ///
213    /// Disables a running plugin. The plugin must be disabled before it can be removed.
214    ///
215    /// Returns:
216    ///     None
217    ///
218    /// Raises:
219    ///     SystemError: If the plugin cannot be disabled
220    pub fn disable(&self) -> PyResult<()> {
221        let rv = __plugin_disable(&self.plugin);
222        match rv {
223            Ok(rv) => Ok(rv),
224            Err(rv) => Err(py_sys_exception!(rv)),
225        }
226    }
227
228    /// Remove (delete) the plugin.
229    ///
230    /// Removes the plugin from Docker. The plugin must be disabled first.
231    /// Use force_remove() to remove an enabled plugin.
232    ///
233    /// Returns:
234    ///     dict: Information about the removed plugin
235    ///
236    /// Raises:
237    ///     SystemError: If the plugin cannot be removed (e.g., still enabled)
238    pub fn remove(&self) -> PyResult<Py<PyAny>> {
239        let rv = __plugin_delete(&self.plugin);
240        match rv {
241            Ok(rv) => Ok(pythonize_this!(rv)),
242            Err(rv) => Err(py_sys_exception!(rv)),
243        }
244    }
245
246    /// Forcefully remove the plugin.
247    ///
248    /// Removes the plugin from Docker, even if it's currently enabled.
249    ///
250    /// Returns:
251    ///     dict: Information about the removed plugin
252    ///
253    /// Raises:
254    ///     SystemError: If the plugin cannot be removed
255    pub fn force_remove(&self) -> PyResult<Py<PyAny>> {
256        let rv = __plugin_force_delete(&self.plugin);
257        match rv {
258            Ok(rv) => Ok(pythonize_this!(rv)),
259            Err(rv) => Err(py_sys_exception!(rv)),
260        }
261    }
262
263    /// Push the plugin to a registry.
264    ///
265    /// Pushes the plugin to the registry specified in the plugin name.
266    ///
267    /// Returns:
268    ///     None
269    ///
270    /// Raises:
271    ///     SystemError: If the push fails
272    pub fn push(&self) -> PyResult<()> {
273        let rv = __plugin_push(&self.plugin);
274        match rv {
275            Ok(rv) => Ok(rv),
276            Err(rv) => Err(py_sys_exception!(rv)),
277        }
278    }
279
280    /// Create a plugin from a tar archive.
281    ///
282    /// Creates a new plugin from a tar archive containing the plugin's
283    /// rootfs directory and config.json manifest.
284    ///
285    /// Args:
286    ///     path: Path to the tar archive containing plugin rootfs and manifest
287    ///
288    /// Returns:
289    ///     None
290    ///
291    /// Raises:
292    ///     SystemError: If plugin creation fails
293    pub fn create(&self, path: &str) -> PyResult<()> {
294        let rv = __plugin_create(&self.plugin, path);
295        match rv {
296            Ok(rv) => Ok(rv),
297            Err(rv) => Err(py_sys_exception!(rv)),
298        }
299    }
300}
301
302#[tokio::main]
303async fn __plugin_inspect(
304    plugin: &Plugin,
305) -> Result<docker_api::models::Plugin, docker_api::Error> {
306    plugin.inspect().await
307}
308
309#[tokio::main]
310async fn __plugin_enable(plugin: &Plugin, timeout: Option<u64>) -> Result<(), docker_api::Error> {
311    plugin.enable(timeout).await
312}
313
314#[tokio::main]
315async fn __plugin_disable(plugin: &Plugin) -> Result<(), docker_api::Error> {
316    plugin.disable().await
317}
318
319#[tokio::main]
320async fn __plugin_delete(plugin: &Plugin) -> Result<docker_api::models::Plugin, docker_api::Error> {
321    plugin.delete().await
322}
323
324#[tokio::main]
325async fn __plugin_force_delete(
326    plugin: &Plugin,
327) -> Result<docker_api::models::Plugin, docker_api::Error> {
328    plugin.force_delete().await
329}
330
331#[tokio::main]
332async fn __plugin_push(plugin: &Plugin) -> Result<(), docker_api::Error> {
333    plugin.push().await
334}
335
336#[tokio::main]
337async fn __plugin_create(plugin: &Plugin, path: &str) -> Result<(), docker_api::Error> {
338    plugin.create(path).await
339}