use crate::error::*;
use crate::types::client::{VolumeCreateBody, VolumeListOKBody, VolumesPruneReport};
use crate::types::filters::Args;
use crate::types::volume::Volume;
use crate::{read_response_body, version, DockerEngineClient};
use hyper::client::connect::Connect;
use hyper::{Body, Method, Request};
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
use snafu::{ensure, ResultExt};
use std::collections::HashMap;
use tokio::time::timeout;
impl<C: Connect + Clone + Send + Sync + 'static> DockerEngineClient<C> {
pub async fn volume_list(&self, filter: Option<Args>) -> Result<VolumeListOKBody, Error> {
let mut query_params: HashMap<String, String> = HashMap::new();
if let Some(filter) = filter {
query_params.insert(
"filters".into(),
serde_json::to_string(&filter.fields).context(JsonSerializationError {})?,
);
}
let query_params = if !query_params.is_empty() {
Some(query_params)
} else {
None
};
let request = Request::builder()
.method(Method::GET)
.uri(self.request_uri("/volumes", query_params)?)
.header("Accept", "application/json")
.body(Body::empty())
.context(HttpClientRequestBuilderError {})?;
let client = self.client.as_ref().unwrap();
let response = timeout(self.timeout, client.request(request))
.await
.context(HttpClientTimeoutError {})?
.context(HttpClientError {})?;
ensure!(
response.status().is_success(),
HttpClientResponseError {
status: response.status().as_u16()
}
);
let response_body = read_response_body(response, self.timeout).await?;
Ok(serde_json::from_str(&response_body).context(JsonDeserializationError {})?)
}
pub async fn volume_create(&self, options: VolumeCreateBody) -> Result<Volume, Error> {
let request = Request::builder()
.method(Method::POST)
.uri(self.request_uri("/volumes/create", None)?)
.header("Content-Type", "application/json")
.header("Accept", "application/json")
.body(Body::from(
serde_json::to_string(&options).context(JsonSerializationError {})?,
))
.context(HttpClientRequestBuilderError {})?;
let client = self.client.as_ref().unwrap();
let response = timeout(self.timeout, client.request(request))
.await
.context(HttpClientTimeoutError {})?
.context(HttpClientError {})?;
ensure!(
response.status().is_success(),
HttpClientResponseError {
status: response.status().as_u16()
}
);
let response_body = read_response_body(response, self.timeout).await?;
Ok(serde_json::from_str(&response_body).context(JsonDeserializationError {})?)
}
pub async fn volume_inspect(&self, volume_id: &str) -> Result<Volume, Error> {
let request = Request::builder()
.method(Method::GET)
.uri(self.request_uri(
&format!(
"/volumes/{}",
utf8_percent_encode(volume_id, NON_ALPHANUMERIC).to_string()
),
None,
)?)
.header("Accept", "application/json")
.body(Body::empty())
.context(HttpClientRequestBuilderError {})?;
let client = self.client.as_ref().unwrap();
let response = timeout(self.timeout, client.request(request))
.await
.context(HttpClientTimeoutError {})?
.context(HttpClientError {})?;
ensure!(
response.status().is_success(),
HttpClientResponseError {
status: response.status().as_u16()
}
);
let response_body = read_response_body(response, self.timeout).await?;
Ok(serde_json::from_str(&response_body).context(JsonDeserializationError {})?)
}
pub async fn volume_remove(&self, volume_id: &str, force: bool) -> Result<(), Error> {
let mut query_params: HashMap<String, String> = HashMap::new();
if version::greater_than_or_equal_to(&self.version, "1.25") && force {
query_params.insert("force".into(), "1".into());
}
let query_params = if !query_params.is_empty() {
Some(query_params)
} else {
None
};
let request = Request::builder()
.method(Method::DELETE)
.uri(self.request_uri(
&format!(
"/volumes/{}",
utf8_percent_encode(volume_id, NON_ALPHANUMERIC).to_string()
),
query_params,
)?)
.header("Accept", "application/json")
.body(Body::empty())
.context(HttpClientRequestBuilderError {})?;
let client = self.client.as_ref().unwrap();
let response = timeout(self.timeout, client.request(request))
.await
.context(HttpClientTimeoutError {})?
.context(HttpClientError {})?;
ensure!(
response.status().is_success(),
HttpClientResponseError {
status: response.status().as_u16()
}
);
Ok(())
}
pub async fn volumes_prune(
&self,
prune_filters: Option<Args>,
) -> Result<VolumesPruneReport, Error> {
let mut query_params: HashMap<String, String> = HashMap::new();
if let Some(prune_filters) = prune_filters {
query_params.insert(
"filters".into(),
serde_json::to_string(&prune_filters.fields).context(JsonSerializationError {})?,
);
}
let query_params = if !query_params.is_empty() {
Some(query_params)
} else {
None
};
let request = Request::builder()
.method(Method::POST)
.uri(self.request_uri("/volumes/prune", query_params)?)
.header("Accept", "application/json")
.body(Body::empty())
.context(HttpClientRequestBuilderError {})?;
let client = self.client.as_ref().unwrap();
let response = timeout(self.timeout, client.request(request))
.await
.context(HttpClientTimeoutError {})?
.context(HttpClientError {})?;
ensure!(
response.status().is_success(),
HttpClientResponseError {
status: response.status().as_u16()
}
);
let response_body = read_response_body(response, self.timeout).await?;
Ok(serde_json::from_str(&response_body).context(JsonDeserializationError {})?)
}
}
#[cfg(test)]
mod tests {
use crate::types::client::*;
use crate::types::filters::*;
use crate::{opts, LocalDockerEngineClient};
use maplit::hashmap;
#[tokio::test]
async fn test_volume_api() {
let docker_client =
LocalDockerEngineClient::new_client_with_opts(Some(vec![Box::new(opts::from_env)]))
.unwrap();
let name = "test_volume_api_volume";
let volume_create_response = docker_client
.volume_create(
VolumeCreateBodyBuilder::default()
.name(Some(name.into()))
.build()
.unwrap(),
)
.await
.unwrap();
assert_eq!(volume_create_response.name.as_ref().unwrap(), name);
assert_eq!(volume_create_response.driver.as_ref().unwrap(), "local");
let volume_list_response = docker_client
.volume_list(Some(
ArgsBuilder::default()
.fields(hashmap! {
"name".into() => vec![name.into()],
})
.build()
.unwrap(),
))
.await
.unwrap();
let volumes = volume_list_response.volumes.unwrap();
assert_eq!(volumes.len(), 1);
assert_eq!(volumes[0].name.as_ref().unwrap(), name);
let volume_inspect_response = docker_client.volume_inspect(name).await.unwrap();
assert_eq!(volume_inspect_response.name.as_ref().unwrap(), name);
docker_client.volume_remove(name, true).await.unwrap();
let response = docker_client.volume_inspect(name).await;
assert!(response.is_err());
}
}