Skip to content

Commit

Permalink
Merge pull request #3 from tmknight/develop
Browse files Browse the repository at this point in the history
v0.2.3
  • Loading branch information
tmknight authored Jan 8, 2024
2 parents c7516f5 + 03036ae commit a02c911
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 54 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ target/

# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb

# IDE
.vscode/
83 changes: 82 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

43 changes: 22 additions & 21 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
[package]
name = "docker-autoheal"
version = "0.2.1"
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 = "*"
futures = "*"
tokio = { version = "*", features = ["full"] }

[[bin]]
name = "docker-autoheal"
bench = false
test = false
[package]
name = "docker-autoheal"
version = "0.2.3"
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
23 changes: 17 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,21 @@ The `docker-autoheal` binary may be executed via a native OS or via a Docker con

## ENV Defaults

| Variable | Default | Description |
|:---------------------------------:|:--------:|:---------------------------------------------------------------------------------------------------------------------------------:|
| **AUTOHEAL_CONTAINER_LABEL** | autoheal |This is the label (set to `true`) that `docker-autoheal` will monitor and remediate - or set to `all` to simply monitor all containers on the host|
| **AUTOHEAL_DEFAULT_STOP_TIMEOUT** | 10 | Docker waits `n` seconds for a container to stop before killing it during restarts <!-- (overridable via label; see below) --> |
| **AUTOHEAL_INTERVAL** | 5 | Check container health every`n` seconds** |
| **AUTOHEAL_START_PERIOD** | 0 | Wait `n` seconds before first health check |
| Variable | Default | Description |
|:----------------------------:|:---------------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------:|
| **AUTOHEAL_CONNECTON_TYPE** | local | This determines how `docker-autheal` connects to Docker (One of: local, socket, http |
| **AUTOHEAL_CONTAINER_LABEL** | autoheal | This is the label (set to `true`) that `docker-autoheal` will monitor and remediate - or set to `all` to simply monitor all containers on the host |
| **AUTOHEAL_STOP_TIMEOUT** | 10 | Docker waits `n` seconds for a container to stop before killing it during restarts <!-- (overridable via label; see below) --> |
| **AUTOHEAL_INTERVAL** | 5 | Check container health every`n` seconds** |
| **AUTOHEAL_START_DELAY** | 0 | Wait `n` seconds before first health check |
| **AUTOHEAL_TCP_HOST** | localhost | Address of Docker host |
| **AUTOHEAL_TCP_PORT** | 2375 | Port on which to connect to the Docker host |
| **AUTOHEAL_TCP_TIMEOUT** | 10 | Time in `n` seconds before failing connection attempt |
|
<!-- | **AUTOHEAL_KEY_PATH** | /opt/docker-autoheal/tls/key.pem | Fully qualified path to key.pem |
<!-- | **AUTOHEAL_KEY_PATH** | /opt/docker-autoheal/tls/key.pem | Fully qualified path to key.pem |
| **AUTOHEAL_CERT_PATH** | /opt/docker-autoheal/tls/cert.pem | Fully qualified path to cert.pem |
| **AUTOHEAL_CA_PATH** | /opt/docker-autoheal/tls/ca.pem | Fully qualified path to ca.pem | -->
<!-- |WEBHOOK_URL | |Post messages to the webhook following actions on unhealthy container | -->

<!--
Expand Down Expand Up @@ -41,6 +50,7 @@ export AUTOHEAL_CONTAINER_LABEL=all
docker run -d \
--name autoheal \
--restart=always \
-e AUTOHEAL_CONNECTON_TYPE=socket
-e AUTOHEAL_CONTAINER_LABEL=all \
-v /var/run/docker.sock:/var/run/docker.sock \
tmknight/docker-autoheal
Expand All @@ -52,6 +62,7 @@ docker run -d \
docker run -d \
--name autoheal \
--restart=always \
-e AUTOHEAL_CONNECTON_TYPE=socket
-e AUTOHEAL_CONTAINER_LABEL=all \
-e DOCKER_SOCK=tcp://HOST:PORT \
-v /path/to/certs/:/certs/:ro \
Expand Down
69 changes: 43 additions & 26 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use bollard::container::{ListContainersOptions, RestartContainerOptions};
use bollard::Docker;
use bollard::{Docker, API_DEFAULT_VERSION};
use chrono::prelude::*;
use std::collections::HashMap;
use std::io::{stdout, Write};
Expand All @@ -15,21 +15,29 @@ async fn log_message(msg: &str) {
// Return environment variable
fn get_env(key: &str, default: &str) -> String {
match std::env::var(key) {
Ok(val) => return val,
Err(e) => return default.to_string(),
Ok(val) => return val.to_lowercase(),
Err(_e) => return default.to_string().to_lowercase(),
}
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Autoheal variables
let autoheal_connection_type = get_env("AUTOHEAL_CONNECTION_TYPE", "local");
let autoheal_container_label = get_env("AUTOHEAL_CONTAINER_LABEL", "autoheal");
let autoheal_default_stop_timeout = get_env("AUTOHEAL_DEFAULT_STOP_TIMEOUT", "10")
.parse()
.unwrap();
let autoheal_interval = get_env("AUTOHEAL_INTERVAL", "5").parse().unwrap();
let autoheal_start_period = get_env("AUTOHEAL_START_PERIOD", "0").parse().unwrap();
// Autoheal core variables
let autoheal_connection_type: String = get_env("AUTOHEAL_CONNECTION_TYPE", "local");
let autoheal_container_label: String = get_env("AUTOHEAL_CONTAINER_LABEL", "autoheal");
let autoheal_stop_timeout: isize = get_env("AUTOHEAL_STOP_TIMEOUT", "10").parse().unwrap();
let autoheal_interval: u64 = get_env("AUTOHEAL_INTERVAL", "5").parse().unwrap();
let autoheal_start_delay: u64 = get_env("AUTOHEAL_START_DELAY", "0").parse().unwrap();
// Autoheal tcp variables
let autoheal_tcp_host: String = get_env("AUTOHEAL_TCP_HOST", "localhost");
let autoheal_tcp_port: u64 = get_env("AUTOHEAL_TCP_PORT", "2375").parse().unwrap();
let autoheal_tcp_address: String = autoheal_tcp_host + ":" + &autoheal_tcp_port.to_string();
let autoheal_tcp_timeout: u64 = get_env("AUTOHEAL_TCP_TIMEOUT", "10").parse().unwrap();
let autoheal_key_path: String =
get_env("AUTOHEAL_KEY_PATH", "/opt/docker-autoheal/tls/key.pem");
let autoheal_cert_path: String =
get_env("AUTOHEAL_CERT_PATH", "/opt/docker-autoheal/tls/cert.pem");
let autoheal_ca_path: String = get_env("AUTOHEAL_CA_PATH", "/opt/docker-autoheal/tls/ca.pem");

// todo
// Webhook variables
Expand All @@ -42,18 +50,29 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
match autoheal_connection_type.as_str() {
"socket" => {
docker_tmp = Some(
#[cfg(unix)]
// #[cfg(unix)]
Docker::connect_with_socket_defaults()?,
);
}
"http" => {
docker_tmp = Some(Docker::connect_with_http_defaults()?);
docker_tmp = Some(Docker::connect_with_http(
&autoheal_tcp_address,
autoheal_tcp_timeout,
API_DEFAULT_VERSION,
)?);
}
// todo
// "ssl" => {
// docker_tmp = Some(
// // #[cfg(feature = "ssl")]
// Docker::connect_with_ssl_defaults()?,
// #[cfg(feature = "ssl")]
// Docker::connect_with_ssl(
// autoheal_tcp_address,
// autoheal_tcp_timeout,
// Path::new(autoheal_key_path),
// Path::new(autoheal_cert_path),
// Path::new(autoheal_ca_path),
// API_DEFAULT_VERSION
// )?,
// );
// }
&_ => {
Expand All @@ -66,10 +85,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let docker = docker_tmp.unwrap();

// Delay start of loop if specified
if autoheal_start_period > 0 {
let msg0 = format!("Delaying evaluation {}s on request", autoheal_start_period);
if autoheal_start_delay > 0 {
let msg0 = format!("Delaying evaluation {}s on request", autoheal_start_delay);
log_message(&msg0).await;
std::thread::sleep(Duration::from_secs(autoheal_start_period));
std::thread::sleep(Duration::from_secs(autoheal_start_delay));
}

// Establish loop interval
Expand All @@ -78,7 +97,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Build container assessment criteria
let mut filters = HashMap::new();
filters.insert("health", vec!["unhealthy"]);
if autoheal_container_label != "ALL" {
if autoheal_container_label != "all" {
filters.insert("label", vec![&autoheal_container_label]);
}

Expand Down Expand Up @@ -106,18 +125,16 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
if !matches!(state.as_str(), "paused" | "restarting") {
// Build restart options
let restart_options = Some(RestartContainerOptions {
t: autoheal_default_stop_timeout,
t: autoheal_stop_timeout,
..Default::default()
});

// Report what is transpiring
let msg0 = format!("Container '{}' ({}) unhealthy", name, id);
// todo
// let msg1 = format!(
// "Restarting '{}' with {}s timeout",
// name, autoheal_default_stop_timeout
// );
let msg1 = format!("Restarting '{}' now", name);
let msg1 = format!(
"Restarting '{}' with {}s timeout",
name, autoheal_stop_timeout
);
log_message(&msg0).await;
log_message(&msg1).await;

Expand Down

0 comments on commit a02c911

Please sign in to comment.