-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #17 from tmknight/dev/v0.3.0
v0.3.0
- Loading branch information
Showing
7 changed files
with
411 additions
and
202 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,23 @@ | ||
[package] | ||
name = "docker-autoheal" | ||
version = "0.2.7" | ||
authors = ["Travis M Knight <[email protected]>"] | ||
license = "MIT" | ||
description = "Monitor and restart unhealthy docker containers" | ||
readme = "README.md" | ||
homepage = "https://github.com/tmknight/docker-autoheal" | ||
edition = "2021" | ||
rust-version = "1.74.1" | ||
|
||
[dependencies] | ||
bollard = "*" | ||
chrono = "0.4.*" | ||
futures = "0.3.*" | ||
rustls = "0.22.*" | ||
tokio = { version = "1.*", features = ["full"] } | ||
|
||
[[bin]] | ||
name = "docker-autoheal" | ||
bench = true | ||
test = true | ||
[package] | ||
name = "docker-autoheal" | ||
version = "0.3.0" | ||
authors = ["Travis M Knight <[email protected]>"] | ||
license = "MIT" | ||
description = "Monitor and restart unhealthy docker containers" | ||
readme = "README.md" | ||
homepage = "https://github.com/tmknight/docker-autoheal" | ||
edition = "2021" | ||
rust-version = "1.74.1" | ||
|
||
[dependencies] | ||
bollard = "*" | ||
chrono = "0.4.*" | ||
futures = "0.3.*" | ||
rustls = "0.22.*" | ||
tokio = { version = "1.*", features = ["full"] } | ||
getopts = "0.2.*" | ||
|
||
[[bin]] | ||
name = "docker-autoheal" | ||
bench = true | ||
test = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
// Get environment variable | ||
pub fn get_env(key: &str, default: &str) -> String { | ||
match std::env::var(key) { | ||
Ok(val) => val.to_lowercase(), | ||
Err(_e) => default.to_string().to_lowercase(), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
use chrono::Local; | ||
use std::io::{stdout, Write}; | ||
|
||
// Return binary information | ||
pub const NAME: &str = env!("CARGO_PKG_NAME"); | ||
pub const VERSION: &str = env!("CARGO_PKG_VERSION"); | ||
pub const AUTHORS: &str = env!("CARGO_PKG_AUTHORS"); | ||
pub const LICENSE: &str = env!("CARGO_PKG_LICENSE"); | ||
pub const DESCRIPTION: &str = env!("CARGO_PKG_DESCRIPTION"); | ||
pub const HOMEPAGE: &str = env!("CARGO_PKG_HOMEPAGE"); | ||
|
||
pub fn print_version() { | ||
println!("Name: {}", NAME); | ||
println!("Version: {}", VERSION); | ||
println!("Authors: {}", AUTHORS); | ||
println!("License: {}", LICENSE); | ||
println!("Description: {}", DESCRIPTION); | ||
println!("Homepage: {}", HOMEPAGE); | ||
println!(); | ||
println!("This is free software; you are free to change and redistribute it."); | ||
println!("There is NO WARRANTY, to the extent permitted by law."); | ||
} | ||
|
||
// Logging | ||
pub async fn log_message(msg: &str) { | ||
let date = Local::now().format("%Y-%m-%d %H:%M:%S%z").to_string(); | ||
let mut lock = stdout().lock(); | ||
writeln!(lock, "{} {}", date, msg).unwrap(); | ||
} | ||
|
||
// todo | ||
// Webhook | ||
// pub async fn webhook (msg: &str) { | ||
// let date = Local::now().format("%Y-%m-%d %H:%M:%S%z").to_string(); | ||
// msg; | ||
// } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
use bollard::container::{ListContainersOptions, RestartContainerOptions}; | ||
use bollard::Docker; | ||
use std::collections::HashMap; | ||
use std::time::Duration; | ||
|
||
use crate::logging::log_message; | ||
|
||
pub async fn start_loop( | ||
autoheal_interval: u64, | ||
autoheal_container_label: String, | ||
autoheal_stop_timeout: isize, | ||
docker: Docker, | ||
) -> Result<(), Box<dyn std::error::Error>> { | ||
// Establish loop interval | ||
let mut interval = tokio::time::interval(Duration::from_secs(autoheal_interval)); | ||
loop { | ||
// Build container assessment criteria | ||
let mut filters = HashMap::new(); | ||
filters.insert("health", vec!["unhealthy"]); | ||
filters.insert("status", vec!["running", "exited", "dead"]); | ||
if autoheal_container_label != "all" { | ||
filters.insert("label", vec![&autoheal_container_label]); | ||
} | ||
|
||
// Gather all containers that are unhealthy | ||
let container_options = Some(ListContainersOptions { | ||
all: true, | ||
filters, | ||
..Default::default() | ||
}); | ||
let containers = docker.list_containers(container_options).await?; | ||
for container in containers { | ||
// Execute concurrently | ||
let docker_clone = docker.clone(); | ||
let join = tokio::task::spawn(async move { | ||
// Get name of container | ||
let name_tmp = match &container.names { | ||
Some(names) => &names[0], | ||
None => { | ||
let msg0 = | ||
String::from("[ERROR] Could not reliably determine container name"); | ||
log_message(&msg0).await; | ||
"" | ||
} | ||
}; | ||
let name = name_tmp.trim_matches('/').trim(); | ||
|
||
// Get id of container | ||
let id: String = match container.id { | ||
Some(id) => id.chars().take(12).collect(), | ||
None => { | ||
let msg0 = | ||
String::from("[ERROR] Could not reliably determine container id"); | ||
log_message(&msg0).await; | ||
"".to_string() | ||
} | ||
}; | ||
|
||
if !(name.is_empty() && id.is_empty()) { | ||
// Report unhealthy container | ||
let msg0 = format!("[WARNING] [{}] Container ({}) unhealthy", name, id); | ||
log_message(&msg0).await; | ||
|
||
// Build restart options | ||
let restart_options = Some(RestartContainerOptions { | ||
t: autoheal_stop_timeout, | ||
}); | ||
|
||
// Report container restart | ||
let msg1 = format!( | ||
"[WARNING] [{}] Restarting container ({}) with {}s timeout", | ||
name, id, autoheal_stop_timeout | ||
); | ||
log_message(&msg1).await; | ||
|
||
// Restart unhealthy container | ||
let rslt = docker_clone.restart_container(&id, restart_options).await; | ||
match rslt { | ||
Ok(()) => { | ||
let msg0 = format!( | ||
"[INFO] [{}] Restart of container ({}) was successful", | ||
name, id | ||
); | ||
log_message(&msg0).await; | ||
} | ||
Err(e) => { | ||
let msg0 = format!( | ||
"[ERROR] [{}] Restart of container ({}) failed: {}", | ||
name, id, e | ||
); | ||
log_message(&msg0).await; | ||
} | ||
} | ||
} else { | ||
let msg0 = String::from("[ERROR] Could not reliably identify the container"); | ||
log_message(&msg0).await; | ||
} | ||
}); | ||
join.await?; | ||
} | ||
// Loop interval | ||
interval.tick().await; | ||
} | ||
} |
Oops, something went wrong.