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}