86 lines
2.7 KiB
Rust
86 lines
2.7 KiB
Rust
use crate::Error;
|
|
use bollard::models::ContainerSummary;
|
|
use bollard::Docker;
|
|
use std::collections::HashMap;
|
|
|
|
/// Namespace to manage containers together (like compose projects)
|
|
type ServiceGroup = String;
|
|
|
|
const DEFAULT_GROUP: &str = "NONE";
|
|
|
|
#[derive(Debug)]
|
|
struct Services(HashMap<ServiceGroup, Vec<crate::docker::Container>>);
|
|
|
|
impl From<&Vec<ContainerSummary>> for Services {
|
|
fn from(value: &Vec<ContainerSummary>) -> Self {
|
|
let mut services = HashMap::new();
|
|
|
|
for summary in value.iter().cloned() {
|
|
let container = crate::docker::Container::from(summary);
|
|
|
|
if container.mounts.is_empty() {
|
|
continue;
|
|
}
|
|
|
|
let group = match &container.labels.service.group {
|
|
// Doesn't have a group defined by the user,
|
|
// try to use the compose hash or throw it with the default group
|
|
None => container
|
|
.labels
|
|
.service
|
|
.compose_hash
|
|
.as_ref()
|
|
.map(|s| s.to_string())
|
|
.unwrap_or_else(|| DEFAULT_GROUP.to_owned()),
|
|
Some(group) => group.to_owned(),
|
|
};
|
|
|
|
let list: &mut Vec<crate::docker::Container> = services.entry(group).or_default();
|
|
list.push(container);
|
|
}
|
|
|
|
Self(services)
|
|
}
|
|
}
|
|
|
|
pub async fn manage(containers: &Vec<ContainerSummary>) -> crate::Result<()> {
|
|
let services = Services::from(containers);
|
|
|
|
// TODO: reuse main instance
|
|
let docker = Docker::connect_with_local_defaults()?;
|
|
|
|
// TODO: iterate over groups in parallel
|
|
for (group, containers) in services.0.iter() {
|
|
// stop containers of service group
|
|
let stop_tasks = containers.into_iter().map(async |container| {
|
|
eprintln!("Stoping container: {:#?}", container.id);
|
|
|
|
let stop_opts = bollard::query_parameters::StopContainerOptionsBuilder::new().build();
|
|
|
|
docker.stop_container(&container.id, Some(stop_opts)).await?;
|
|
|
|
Ok::<(), crate::Error>(())
|
|
});
|
|
|
|
futures::future::try_join_all(stop_tasks).await?;
|
|
|
|
// create container with the same mounts as each container in the group
|
|
|
|
// run the new container
|
|
|
|
// restart the containers
|
|
let start_tasks = containers.into_iter().map(async |container| {
|
|
eprintln!("Starting container: {:#?}", container.id);
|
|
|
|
let start_opts = bollard::query_parameters::StartContainerOptionsBuilder::new().build();
|
|
|
|
docker.start_container(&container.id, Some(start_opts)).await?;
|
|
|
|
Ok::<(), crate::Error>(())
|
|
});
|
|
|
|
futures::future::try_join_all(start_tasks).await?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|