use crate::error::*;
use crate::types::client::{
NetworkConnect, NetworkCreateResponse, NetworkDisconnect, NetworkInspectOptions,
NetworkListOptions, NetworksPruneReport,
};
use crate::types::filters::Args;
use crate::types::network::{
EndpointSettings, NetworkCreate, NetworkCreateBuilder, NetworkResource,
};
use crate::{read_response_body, 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 network_list(
&self,
options: Option<NetworkListOptions>,
) -> Result<Vec<NetworkResource>, Error> {
let mut query_params: HashMap<String, String> = HashMap::new();
if let Some(options) = options {
if let Some(filter) = options.filters {
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("/networks", 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 network_inspect(
&self,
network_id: &str,
options: Option<NetworkInspectOptions>,
) -> Result<NetworkResource, Error> {
let mut query_params: HashMap<String, String> = HashMap::new();
if let Some(options) = options {
if options.verbose {
query_params.insert("verbose".into(), "true".into());
}
if let Some(scope) = options.scope {
query_params.insert("scope".into(), scope);
}
}
let query_params = if !query_params.is_empty() {
Some(query_params)
} else {
None
};
let request = Request::builder()
.method(Method::GET)
.uri(self.request_uri(
&format!(
"/networks/{}",
utf8_percent_encode(network_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()
}
);
let response_body = read_response_body(response, self.timeout).await?;
Ok(serde_json::from_str(&response_body).context(JsonDeserializationError {})?)
}
pub async fn network_remove(&self, network_id: &str) -> Result<(), Error> {
let request = Request::builder()
.method(Method::DELETE)
.uri(self.request_uri(
&format!(
"/networks/{}",
utf8_percent_encode(network_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()
}
);
Ok(())
}
pub async fn network_create(
&self,
name: &str,
options: Option<NetworkCreate>,
) -> Result<NetworkCreateResponse, Error> {
let mut network_create_request =
options.unwrap_or_else(|| NetworkCreateBuilder::default().build().unwrap());
network_create_request.name = Some(name.into());
let request = Request::builder()
.method(Method::POST)
.uri(self.request_uri("/networks/create", None)?)
.header("Content-Type", "application/json")
.header("Accept", "application/json")
.body(Body::from(
serde_json::to_string(&network_create_request)
.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 network_connect(
&self,
network_id: &str,
container_id: &str,
config: Option<EndpointSettings>,
) -> Result<(), Error> {
let network_connect_request = NetworkConnect {
container: container_id.into(),
endpoint_config: config,
};
let request = Request::builder()
.method(Method::POST)
.uri(self.request_uri(
&format!(
"/networks/{}/connect",
utf8_percent_encode(network_id, NON_ALPHANUMERIC).to_string()
),
None,
)?)
.header("Content-Type", "application/json")
.header("Accept", "application/json")
.body(Body::from(
serde_json::to_string(&network_connect_request)
.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()
}
);
Ok(())
}
pub async fn network_disconnect(
&self,
network_id: &str,
container_id: &str,
force: bool,
) -> Result<(), Error> {
let network_disconnect_request = NetworkDisconnect {
container: container_id.into(),
force: if force { Some(true) } else { None },
};
let request = Request::builder()
.method(Method::POST)
.uri(self.request_uri(
&format!(
"/networks/{}/disconnect",
utf8_percent_encode(network_id, NON_ALPHANUMERIC).to_string()
),
None,
)?)
.header("Content-Type", "application/json")
.header("Accept", "application/json")
.body(Body::from(
serde_json::to_string(&network_disconnect_request)
.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()
}
);
Ok(())
}
pub async fn networks_prune(
&self,
prune_filters: Option<Args>,
) -> Result<NetworksPruneReport, 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("/networks/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::container::ContainerConfigBuilder;
use crate::types::filters::*;
use crate::{opts, LocalDockerEngineClient};
use maplit::hashmap;
#[tokio::test]
async fn test_network_api() {
let docker_client =
LocalDockerEngineClient::new_client_with_opts(Some(vec![Box::new(opts::from_env)]))
.unwrap();
let name = "test_network";
let network_create_response = docker_client.network_create(name, None).await.unwrap();
let networks_response = docker_client
.network_list(Some(
NetworkListOptionsBuilder::default()
.filters(Some(
ArgsBuilder::default()
.fields(hashmap! {
"id".into() => vec![network_create_response.id.clone()],
})
.build()
.unwrap(),
))
.build()
.unwrap(),
))
.await
.unwrap();
assert_eq!(networks_response.len(), 1);
assert_eq!(networks_response[0].name.as_ref().unwrap(), name);
let network_inspect_response = docker_client
.network_inspect(
&network_create_response.id,
Some(
NetworkInspectOptionsBuilder::default()
.verbose(true)
.build()
.unwrap(),
),
)
.await
.unwrap();
assert_eq!(network_inspect_response.name.as_ref().unwrap(), name);
let container_create_response = docker_client
.container_create(
ContainerConfigBuilder::default()
.image(Some("busybox".into()))
.cmd(Some(vec!["sleep".into(), "60".into()]))
.build()
.unwrap(),
Some("test_network_api_container".into()),
)
.await
.unwrap();
docker_client
.network_connect(
&network_create_response.id,
&container_create_response.id,
None,
)
.await
.unwrap();
let container_inspect_response = docker_client
.container_inspect(&container_create_response.id)
.await
.unwrap();
assert!(container_inspect_response
.network_settings
.as_ref()
.unwrap()
.networks
.as_ref()
.unwrap()
.contains_key(name));
docker_client
.network_disconnect(
&network_create_response.id,
&container_create_response.id,
true,
)
.await
.unwrap();
let container_inspect_response = docker_client
.container_inspect(&container_create_response.id)
.await
.unwrap();
assert!(!container_inspect_response
.network_settings
.as_ref()
.unwrap()
.networks
.as_ref()
.unwrap()
.contains_key(name));
docker_client
.container_remove(
&container_create_response.id,
Some(
ContainerRemoveOptionsBuilder::default()
.force(true)
.build()
.unwrap(),
),
)
.await
.unwrap();
docker_client
.network_remove(&network_create_response.id)
.await
.unwrap();
let response = docker_client
.network_inspect(
&network_create_response.id,
Some(
NetworkInspectOptionsBuilder::default()
.verbose(true)
.build()
.unwrap(),
),
)
.await;
assert!(response.is_err());
}
}