add depends_on start order resolution
This commit is contained in:
parent
d22037031a
commit
228e8ff9b9
@ -5,13 +5,14 @@ use bollard::container::{Config, CreateContainerOptions, RemoveContainerOptions}
|
|||||||
use bollard::models::{HostConfig, PortBinding, PortMap, RestartPolicy, RestartPolicyNameEnum};
|
use bollard::models::{HostConfig, PortBinding, PortMap, RestartPolicy, RestartPolicyNameEnum};
|
||||||
use bollard::Docker;
|
use bollard::Docker;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::iter::Map;
|
||||||
|
|
||||||
pub(crate) async fn create_containers(
|
pub(crate) async fn create_containers(
|
||||||
compose: &DockerCompose,
|
compose: &DockerCompose,
|
||||||
docker: &Docker,
|
docker: &Docker,
|
||||||
detach: bool,
|
detach: bool,
|
||||||
) -> anyhow::Result<Vec<String>> {
|
) -> anyhow::Result<HashMap<String, String>> {
|
||||||
let mut container_ids = Vec::new();
|
let mut container_ids = HashMap::new();
|
||||||
let parent_dir = parent_dir_name()?;
|
let parent_dir = parent_dir_name()?;
|
||||||
for (name, service) in &compose.services {
|
for (name, service) in &compose.services {
|
||||||
let env = create_env_vec(&service.environment);
|
let env = create_env_vec(&service.environment);
|
||||||
@ -43,14 +44,62 @@ pub(crate) async fn create_containers(
|
|||||||
conf,
|
conf,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
container_ids.push(create_info.id);
|
container_ids.insert(name.clone(), create_info.id);
|
||||||
}
|
}
|
||||||
Ok(container_ids)
|
Ok(container_ids)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn start_containers(docker: &Docker, ids: Vec<String>) -> anyhow::Result<()> {
|
fn resolve_start_order(compose: &DockerCompose) -> Vec<String> {
|
||||||
for id in ids {
|
let mut start_order = Vec::new();
|
||||||
docker.start_container::<String>(&id, None).await?;
|
let mut visited = HashMap::new();
|
||||||
|
|
||||||
|
for service_name in compose.services.keys() {
|
||||||
|
resolve_service(service_name, compose, &mut visited, &mut start_order);
|
||||||
|
}
|
||||||
|
|
||||||
|
start_order
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_service(
|
||||||
|
service_name: &str,
|
||||||
|
compose: &DockerCompose,
|
||||||
|
visited: &mut HashMap<String, bool>,
|
||||||
|
start_order: &mut Vec<String>,
|
||||||
|
) {
|
||||||
|
if let Some(&true) = visited.get(service_name) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
visited.insert(service_name.to_string(), true);
|
||||||
|
|
||||||
|
if let Some(service) = compose.services.get(service_name) {
|
||||||
|
if let Some(dependencies) = &service.depends_on {
|
||||||
|
for dependency in dependencies {
|
||||||
|
resolve_service(dependency, compose, visited, start_order);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
start_order.push(service_name.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn start_containers(
|
||||||
|
compose: &DockerCompose,
|
||||||
|
docker: &Docker,
|
||||||
|
ids: HashMap<String, String>,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
// resolve dependency resolution
|
||||||
|
let start_order = resolve_start_order(compose);
|
||||||
|
|
||||||
|
for container_name in start_order {
|
||||||
|
docker
|
||||||
|
.start_container::<String>(
|
||||||
|
ids.get(&container_name).ok_or(anyhow!(
|
||||||
|
"no created container found with name {}",
|
||||||
|
container_name
|
||||||
|
))?,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ pub async fn up(compose_file: Option<String>, detach: bool) -> anyhow::Result<()
|
|||||||
pull_images(&compose, &docker).await;
|
pull_images(&compose, &docker).await;
|
||||||
create_volumes(&compose, &docker).await?;
|
create_volumes(&compose, &docker).await?;
|
||||||
let ids = create_containers(&compose, &docker, detach).await?;
|
let ids = create_containers(&compose, &docker, detach).await?;
|
||||||
start_containers(&docker, ids.clone()).await?;
|
start_containers(&compose, &docker, ids.clone()).await?;
|
||||||
|
|
||||||
if !detach {
|
if !detach {
|
||||||
monitor_build_outputs(&docker, ids).await?;
|
monitor_build_outputs(&docker, ids).await?;
|
||||||
|
@ -3,11 +3,17 @@ use bollard::container::{AttachContainerOptions, LogOutput};
|
|||||||
use bollard::Docker;
|
use bollard::Docker;
|
||||||
use futures_util::future::join_all;
|
use futures_util::future::join_all;
|
||||||
use futures_util::StreamExt;
|
use futures_util::StreamExt;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::iter::Map;
|
||||||
|
|
||||||
pub(crate) async fn monitor_build_outputs(docker: &Docker, ids: Vec<String>) -> anyhow::Result<()> {
|
pub(crate) async fn monitor_build_outputs(
|
||||||
|
docker: &Docker,
|
||||||
|
ids: HashMap<String, String>,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
let mut handles = vec![];
|
let mut handles = vec![];
|
||||||
for id in ids.clone() {
|
for id in ids.values() {
|
||||||
let docker = docker.clone();
|
let docker = docker.clone();
|
||||||
|
let id = id.clone();
|
||||||
handles.push(tokio::spawn(async move {
|
handles.push(tokio::spawn(async move {
|
||||||
let r = monitor_logs(&docker, id.clone()).await;
|
let r = monitor_logs(&docker, id.clone()).await;
|
||||||
println!("Container {} exited with {:?}", id, r)
|
println!("Container {} exited with {:?}", id, r)
|
||||||
@ -17,7 +23,7 @@ pub(crate) async fn monitor_build_outputs(docker: &Docker, ids: Vec<String>) ->
|
|||||||
tokio::select! {
|
tokio::select! {
|
||||||
_ = tokio::signal::ctrl_c() => {
|
_ = tokio::signal::ctrl_c() => {
|
||||||
println!("Ctrl-c received, stopping containers");
|
println!("Ctrl-c received, stopping containers");
|
||||||
stop_containers_by_ids(docker, ids.clone()).await?;
|
stop_containers_by_ids(docker, ids.values().map(|v| v.to_string()).collect()).await?;
|
||||||
}
|
}
|
||||||
_ = join_all(handles) => {
|
_ = join_all(handles) => {
|
||||||
println!("All containers exited");
|
println!("All containers exited");
|
||||||
|
Loading…
Reference in New Issue
Block a user