lmrc_docker/volumes/
mod.rs

1//! Volume management operations.
2
3use crate::DockerClient;
4use crate::error::{DockerError, Result};
5use bollard::models::*;
6use bollard::volume::*;
7use tracing::{debug, info};
8
9/// Volume operations manager.
10pub struct Volumes<'a> {
11    client: &'a DockerClient,
12}
13
14impl<'a> Volumes<'a> {
15    pub(crate) fn new(client: &'a DockerClient) -> Self {
16        Self { client }
17    }
18
19    /// Create a new volume.
20    ///
21    /// # Example
22    ///
23    /// ```no_run
24    /// use lmrc_docker::DockerClient;
25    ///
26    /// #[tokio::main]
27    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
28    ///     let client = DockerClient::new()?;
29    ///     let volume = client.volumes()
30    ///         .create("my-volume")
31    ///         .await?;
32    ///     println!("Created volume: {}", volume.name);
33    ///     Ok(())
34    /// }
35    /// ```
36    pub async fn create(&self, name: impl Into<String>) -> Result<Volume> {
37        let name = name.into();
38        info!("Creating volume: {}", name);
39
40        let config = CreateVolumeOptions {
41            name: name.clone(),
42            ..Default::default()
43        };
44
45        self.client
46            .docker
47            .create_volume(config)
48            .await
49            .map_err(|e| DockerError::Other(format!("Failed to create volume: {}", e)))
50    }
51
52    /// List all volumes.
53    ///
54    /// # Example
55    ///
56    /// ```no_run
57    /// use lmrc_docker::DockerClient;
58    ///
59    /// #[tokio::main]
60    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
61    ///     let client = DockerClient::new()?;
62    ///     let volumes = client.volumes().list().await?;
63    ///     for volume in volumes {
64    ///         println!("{}", volume.name);
65    ///     }
66    ///     Ok(())
67    /// }
68    /// ```
69    pub async fn list(&self) -> Result<Vec<Volume>> {
70        let response = self
71            .client
72            .docker
73            .list_volumes(Some(
74                bollard::query_parameters::ListVolumesOptions::default(),
75            ))
76            .await
77            .map_err(|e| DockerError::Other(format!("Failed to list volumes: {}", e)))?;
78
79        Ok(response.volumes.unwrap_or_default())
80    }
81
82    /// Get a reference to a specific volume.
83    pub fn get(&self, name: impl Into<String>) -> VolumeRef<'a> {
84        VolumeRef::new(self.client, name.into())
85    }
86
87    /// Prune unused volumes.
88    pub async fn prune(&self) -> Result<VolumePruneResponse> {
89        info!("Pruning unused volumes...");
90        self.client
91            .docker
92            .prune_volumes(Some(
93                bollard::query_parameters::PruneVolumesOptions::default(),
94            ))
95            .await
96            .map_err(|e| DockerError::Other(format!("Failed to prune volumes: {}", e)))
97    }
98}
99
100/// Reference to a specific volume.
101pub struct VolumeRef<'a> {
102    client: &'a DockerClient,
103    name: String,
104}
105
106impl<'a> VolumeRef<'a> {
107    pub(crate) fn new(client: &'a DockerClient, name: String) -> Self {
108        Self { client, name }
109    }
110
111    /// Get the volume name.
112    pub fn name(&self) -> &str {
113        &self.name
114    }
115
116    /// Inspect the volume to get detailed information.
117    ///
118    /// # Example
119    ///
120    /// ```no_run
121    /// use lmrc_docker::DockerClient;
122    ///
123    /// #[tokio::main]
124    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
125    ///     let client = DockerClient::new()?;
126    ///     let info = client.volumes().get("my-volume").inspect().await?;
127    ///     println!("Mountpoint: {}", info.mountpoint);
128    ///     Ok(())
129    /// }
130    /// ```
131    pub async fn inspect(&self) -> Result<Volume> {
132        debug!("Inspecting volume: {}", self.name);
133        self.client
134            .docker
135            .inspect_volume(&self.name)
136            .await
137            .map_err(|e| DockerError::VolumeNotFound(format!("{}: {}", self.name, e)))
138    }
139
140    /// Remove the volume.
141    ///
142    /// # Arguments
143    ///
144    /// * `force` - Force removal even if volume is in use
145    pub async fn remove(&self, force: bool) -> Result<()> {
146        info!("Removing volume: {}", self.name);
147
148        let options = if force {
149            Some(RemoveVolumeOptions { force })
150        } else {
151            None
152        };
153
154        self.client
155            .docker
156            .remove_volume(&self.name, options)
157            .await
158            .map_err(|e| DockerError::Other(format!("Failed to remove volume: {}", e)))
159    }
160}
161
162impl DockerClient {
163    /// Access volume operations.
164    ///
165    /// # Example
166    ///
167    /// ```no_run
168    /// use lmrc_docker::DockerClient;
169    ///
170    /// #[tokio::main]
171    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
172    ///     let client = DockerClient::new()?;
173    ///     let volumes = client.volumes().list().await?;
174    ///     Ok(())
175    /// }
176    /// ```
177    pub fn volumes(&self) -> Volumes<'_> {
178        Volumes::new(self)
179    }
180}