diff --git a/Cargo.lock b/Cargo.lock index 27760b6..b98ddcd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -193,6 +193,8 @@ dependencies = [ "serde_yml", "thiserror", "tokio", + "tracing", + "tracing-subscriber", ] [[package]] @@ -615,6 +617,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.174" @@ -669,6 +677,16 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -699,6 +717,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "percent-encoding" version = "2.3.1" @@ -888,6 +912,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "shlex" version = "1.3.0" @@ -964,6 +997,15 @@ dependencies = [ "syn", ] +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + [[package]] name = "time" version = "0.3.41" @@ -1058,9 +1100,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tracing-core" version = "0.1.34" @@ -1068,6 +1122,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", ] [[package]] @@ -1099,6 +1179,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + [[package]] name = "version_check" version = "0.9.5" diff --git a/Cargo.toml b/Cargo.toml index 31a1032..3b253ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,3 +10,5 @@ serde = "1.0.219" serde_yml = "0.0.12" thiserror = "2.0.12" tokio = { version = "1.45.1", features = ["macros", "rt", "rt-multi-thread"] } +tracing = "0.1.41" +tracing-subscriber = "0.3.19" diff --git a/src/docker.rs b/src/docker.rs index 0f3c031..303bc99 100644 --- a/src/docker.rs +++ b/src/docker.rs @@ -2,6 +2,7 @@ use bollard::models::{ContainerSummary, ContainerSummaryStateEnum, MountPoint}; use serde::de::DeserializeOwned; use serde_yml::Value; use std::collections::HashMap; +use tracing::field::{Field, Visit}; mod labels; diff --git a/src/error.rs b/src/error.rs index 98c455f..fa8d0be 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,4 +1,5 @@ use thiserror::Error; +use tracing::dispatcher::SetGlobalDefaultError; pub type Result = std::result::Result; @@ -6,10 +7,13 @@ pub type Result = std::result::Result; pub enum Error { #[error("Unhandled error: {0}")] Static(&'static str), - + #[error("Unhandled error: {0}")] Generic(String), + #[error(transparent)] + Tracing(#[from] SetGlobalDefaultError), + #[error(transparent)] Docker(#[from] bollard::errors::Error), } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 15a0226..8840bc7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,16 +4,16 @@ use tokio; #[tokio::main] async fn main() -> epoch::Result<()> { + // construct a subscriber that prints formatted traces to stdout + tracing_subscriber::fmt().with_ansi(true).compact().init(); + let docker = Docker::connect_with_local_defaults()?; - let filters: HashMap<&str, Vec<&str>> = HashMap::from( - [ - ("label", vec!["epoch.manage=true"]), - ], - ); + let filters: HashMap<&str, Vec<&str>> = HashMap::from([("label", vec!["epoch.manage=true"])]); let opts = bollard::query_parameters::ListContainersOptionsBuilder::new() - .filters(&filters).build(); + .filters(&filters) + .build(); let containers = docker.list_containers(Some(opts)).await?; diff --git a/src/manager.rs b/src/manager.rs index 3c2f7fe..98d39a5 100644 --- a/src/manager.rs +++ b/src/manager.rs @@ -1,7 +1,10 @@ +use crate::docker::Container; use crate::Error; use bollard::models::ContainerSummary; use bollard::Docker; +use futures::future::try_join_all; use std::collections::HashMap; +use tracing::info; /// Namespace to manage containers together (like compose projects) type ServiceGroup = String; @@ -43,6 +46,7 @@ impl From<&Vec> for Services { } } +#[tracing::instrument(skip(containers))] pub async fn manage(containers: &Vec) -> crate::Result<()> { let services = Services::from(containers); @@ -52,35 +56,35 @@ pub async fn manage(containers: &Vec) -> crate::Result<()> { // 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?; + try_join_all(containers.into_iter().map(|container | stop_container(&docker, container))).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?; + try_join_all(containers.into_iter().map(|container| start_container(&docker, container))).await?; } Ok(()) } + +async fn stop_container(docker: &Docker, container: &crate::docker::Container) -> crate::Result<()> { + info!("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>(()) +} + +async fn start_container(docker: &Docker, container: &crate::docker::Container) -> crate::Result<()> { + info!("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>(()) +}