use crate::DockerTestError;
use access_queue::AccessQueue;
use bollard::{
container::{ListContainersOptions, RemoveContainerOptions},
errors::Error,
image::RemoveImageOptions,
Docker,
};
use futures::future::FutureExt;
use once_cell::sync::Lazy;
use std::collections::HashMap;
pub(crate) static CONCURRENT_IMAGE_ACCESS_QUEUE: Lazy<AccessQueue<&str>> =
Lazy::new(|| AccessQueue::new("williamyeh/dummy", 1));
pub(crate) async fn delete_image_if_present(
client: &Docker,
repository: &str,
tag: &str,
) -> Result<(), DockerTestError> {
if image_exists_locally(client, repository, tag).await? {
let id = image_id(client, repository, tag).await?;
delete_image(client, id).await?;
}
Ok(())
}
pub(crate) async fn image_exists_locally(
client: &Docker,
repository: &str,
tag: &str,
) -> Result<bool, DockerTestError> {
client
.inspect_image(&format!("{}:{}", repository, tag))
.map(|result| match result {
Ok(_) => Ok(true),
Err(e) => match e {
Error::DockerResponseServerError {
message: _,
status_code,
} => {
if status_code == 404 {
Ok(false)
} else {
Err(DockerTestError::Daemon(e.to_string()))
}
}
_ => Err(DockerTestError::Daemon(e.to_string())),
},
})
.await
}
pub(crate) async fn delete_image(client: &Docker, image_id: String) -> Result<(), DockerTestError> {
let _ = remove_containers(client, image_id.clone()).await;
let options = RemoveImageOptions {
force: true,
..Default::default()
};
client
.remove_image(&image_id, Some(options), None)
.await
.map_err(|e| DockerTestError::Daemon(e.to_string()))?;
Ok(())
}
pub(crate) async fn remove_containers(
client: &Docker,
image_id: String,
) -> Result<(), DockerTestError> {
let mut filters = HashMap::new();
filters.insert("ancestor", vec![image_id.as_str()]);
let options = ListContainersOptions {
all: true,
filters: filters,
..Default::default()
};
let containers = client
.list_containers(Some(options))
.await
.map_err(|e| DockerTestError::Daemon(e.to_string()))?;
for container in containers {
let options = RemoveContainerOptions {
force: true,
..Default::default()
};
client
.remove_container(&container.id.unwrap(), Some(options))
.await
.map_err(|e| DockerTestError::Daemon(e.to_string()))?;
}
Ok(())
}
pub(crate) async fn image_id(
client: &Docker,
repository: &str,
tag: &str,
) -> Result<String, DockerTestError> {
client
.inspect_image(&format!("{}:{}", repository, tag))
.await
.map_err(|e| DockerTestError::Processing(format!("failed to get image id {}", e)))
.map(|res| res.id.unwrap())
}