docker_client_async/
volume.rs1use crate::error::*;
21use crate::types::client::{VolumeCreateBody, VolumeListOKBody, VolumesPruneReport};
22use crate::types::filters::Args;
23use crate::types::volume::Volume;
24use crate::{read_response_body, version, DockerEngineClient};
25use hyper::client::connect::Connect;
26use hyper::{Body, Method, Request};
27use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
28use snafu::{ensure, ResultExt};
29use std::collections::HashMap;
30use tokio::time::timeout;
31
32impl<C: Connect + Clone + Send + Sync + 'static> DockerEngineClient<C> {
33 pub async fn volume_list(&self, filter: Option<Args>) -> Result<VolumeListOKBody, Error> {
35 let mut query_params: HashMap<String, String> = HashMap::new();
36 if let Some(filter) = filter {
37 query_params.insert(
38 "filters".into(),
39 serde_json::to_string(&filter.fields).context(JsonSerializationError {})?,
40 );
41 }
42 let query_params = if !query_params.is_empty() {
43 Some(query_params)
44 } else {
45 None
46 };
47
48 let request = Request::builder()
49 .method(Method::GET)
50 .uri(self.request_uri("/volumes", query_params)?)
51 .header("Accept", "application/json")
52 .body(Body::empty())
53 .context(HttpClientRequestBuilderError {})?;
54
55 let client = self.client.as_ref().unwrap();
56 let response = timeout(self.timeout, client.request(request))
57 .await
58 .context(HttpClientTimeoutError {})?
59 .context(HttpClientError {})?;
60 ensure!(
61 response.status().is_success(),
62 HttpClientResponseError {
63 status: response.status().as_u16()
64 }
65 );
66 let response_body = read_response_body(response, self.timeout).await?;
67 Ok(serde_json::from_str(&response_body).context(JsonDeserializationError {})?)
68 }
69
70 pub async fn volume_create(&self, options: VolumeCreateBody) -> Result<Volume, Error> {
72 let request = Request::builder()
73 .method(Method::POST)
74 .uri(self.request_uri("/volumes/create", None)?)
75 .header("Content-Type", "application/json")
76 .header("Accept", "application/json")
77 .body(Body::from(
78 serde_json::to_string(&options).context(JsonSerializationError {})?,
79 ))
80 .context(HttpClientRequestBuilderError {})?;
81
82 let client = self.client.as_ref().unwrap();
83 let response = timeout(self.timeout, client.request(request))
84 .await
85 .context(HttpClientTimeoutError {})?
86 .context(HttpClientError {})?;
87 ensure!(
88 response.status().is_success(),
89 HttpClientResponseError {
90 status: response.status().as_u16()
91 }
92 );
93 let response_body = read_response_body(response, self.timeout).await?;
94 Ok(serde_json::from_str(&response_body).context(JsonDeserializationError {})?)
95 }
96
97 pub async fn volume_inspect(&self, volume_id: &str) -> Result<Volume, Error> {
99 let request = Request::builder()
100 .method(Method::GET)
101 .uri(self.request_uri(
102 &format!(
103 "/volumes/{}",
104 utf8_percent_encode(volume_id, NON_ALPHANUMERIC).to_string()
105 ),
106 None,
107 )?)
108 .header("Accept", "application/json")
109 .body(Body::empty())
110 .context(HttpClientRequestBuilderError {})?;
111
112 let client = self.client.as_ref().unwrap();
113 let response = timeout(self.timeout, client.request(request))
114 .await
115 .context(HttpClientTimeoutError {})?
116 .context(HttpClientError {})?;
117 ensure!(
118 response.status().is_success(),
119 HttpClientResponseError {
120 status: response.status().as_u16()
121 }
122 );
123 let response_body = read_response_body(response, self.timeout).await?;
124 Ok(serde_json::from_str(&response_body).context(JsonDeserializationError {})?)
125 }
126
127 pub async fn volume_remove(&self, volume_id: &str, force: bool) -> Result<(), Error> {
129 let mut query_params: HashMap<String, String> = HashMap::new();
130 if version::greater_than_or_equal_to(&self.version, "1.25") && force {
131 query_params.insert("force".into(), "1".into());
132 }
133 let query_params = if !query_params.is_empty() {
134 Some(query_params)
135 } else {
136 None
137 };
138
139 let request = Request::builder()
140 .method(Method::DELETE)
141 .uri(self.request_uri(
142 &format!(
143 "/volumes/{}",
144 utf8_percent_encode(volume_id, NON_ALPHANUMERIC).to_string()
145 ),
146 query_params,
147 )?)
148 .header("Accept", "application/json")
149 .body(Body::empty())
150 .context(HttpClientRequestBuilderError {})?;
151
152 let client = self.client.as_ref().unwrap();
153 let response = timeout(self.timeout, client.request(request))
154 .await
155 .context(HttpClientTimeoutError {})?
156 .context(HttpClientError {})?;
157 ensure!(
158 response.status().is_success(),
159 HttpClientResponseError {
160 status: response.status().as_u16()
161 }
162 );
163
164 Ok(())
165 }
166
167 pub async fn volumes_prune(
169 &self,
170 prune_filters: Option<Args>,
171 ) -> Result<VolumesPruneReport, Error> {
172 let mut query_params: HashMap<String, String> = HashMap::new();
173 if let Some(prune_filters) = prune_filters {
174 query_params.insert(
175 "filters".into(),
176 serde_json::to_string(&prune_filters.fields).context(JsonSerializationError {})?,
177 );
178 }
179 let query_params = if !query_params.is_empty() {
180 Some(query_params)
181 } else {
182 None
183 };
184
185 let request = Request::builder()
186 .method(Method::POST)
187 .uri(self.request_uri("/volumes/prune", query_params)?)
188 .header("Accept", "application/json")
189 .body(Body::empty())
190 .context(HttpClientRequestBuilderError {})?;
191
192 let client = self.client.as_ref().unwrap();
193 let response = timeout(self.timeout, client.request(request))
194 .await
195 .context(HttpClientTimeoutError {})?
196 .context(HttpClientError {})?;
197 ensure!(
198 response.status().is_success(),
199 HttpClientResponseError {
200 status: response.status().as_u16()
201 }
202 );
203 let response_body = read_response_body(response, self.timeout).await?;
204 Ok(serde_json::from_str(&response_body).context(JsonDeserializationError {})?)
205 }
206}
207
208#[cfg(test)]
209mod tests {
210 use crate::types::client::*;
211 use crate::types::filters::*;
212 use crate::{opts, LocalDockerEngineClient};
213 use maplit::hashmap;
214
215 #[tokio::test]
216 async fn test_volume_api() {
217 let docker_client =
218 LocalDockerEngineClient::new_client_with_opts(Some(vec![Box::new(opts::from_env)]))
219 .unwrap();
220
221 let name = "test_volume_api_volume";
223 let volume_create_response = docker_client
224 .volume_create(
225 VolumeCreateBodyBuilder::default()
226 .name(Some(name.into()))
227 .build()
228 .unwrap(),
229 )
230 .await
231 .unwrap();
232
233 assert_eq!(volume_create_response.name.as_ref().unwrap(), name);
234 assert_eq!(volume_create_response.driver.as_ref().unwrap(), "local");
235
236 let volume_list_response = docker_client
238 .volume_list(Some(
239 ArgsBuilder::default()
240 .fields(hashmap! {
241 "name".into() => vec![name.into()],
242 })
243 .build()
244 .unwrap(),
245 ))
246 .await
247 .unwrap();
248
249 let volumes = volume_list_response.volumes.unwrap();
250
251 assert_eq!(volumes.len(), 1);
252 assert_eq!(volumes[0].name.as_ref().unwrap(), name);
253
254 let volume_inspect_response = docker_client.volume_inspect(name).await.unwrap();
256
257 assert_eq!(volume_inspect_response.name.as_ref().unwrap(), name);
258
259 docker_client.volume_remove(name, true).await.unwrap();
261
262 let response = docker_client.volume_inspect(name).await;
264
265 assert!(response.is_err());
266 }
267}