Skip to content

Commit

Permalink
Merge pull request #52 from ufoscout/feature/wait_for_path
Browse files Browse the repository at this point in the history
Feature/wait for path
  • Loading branch information
ufoscout authored May 11, 2021
2 parents 198d1c2 + c3f1b37 commit 5098f22
Show file tree
Hide file tree
Showing 7 changed files with 411 additions and 88 deletions.
84 changes: 54 additions & 30 deletions Cargo.lock

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

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "wait"
version = "2.8.0"
version = "2.9.0"
authors = ["ufoscout <[email protected]>"]
edition = "2018"

Expand All @@ -12,7 +12,7 @@ env_logger = { version = "0.8", default-features = false }
[dev-dependencies]
atomic-counter = "1.0"
lazy_static = "1.4"
time = "0.1.40"
rand = "0.8"

[profile.release]
opt-level = 'z' # Optimize for size.
Expand Down
25 changes: 15 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/e9c2359ba5534f58a4b178191acb836a)](https://www.codacy.com/manual/edumco/docker-compose-wait?utm_source=github.com&utm_medium=referral&utm_content=edumco/docker-compose-wait&utm_campaign=Badge_Grade)
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fedumco%2Fdocker-compose-wait.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fedumco%2Fdocker-compose-wait?ref=badge_shield)

A small command line utility to wait for other docker images to be started while using docker-compose.
It permits to wait for a fixed amount of seconds and/or to wait until a TCP port is open on a target image.
A small command-line utility to wait for other docker images to be started while using docker-compose.

It permits waiting for:
- a fixed amount of seconds
- until a TCP port is open on a target image
- until a file or directory is present on the local filesystem

## Usage

Expand All @@ -18,13 +22,13 @@ For example, your application "MySuperApp" uses MongoDB, Postgres and MySql (wow
## Use whatever base image
FROM alpine

## Add your application to the docker image
ADD MySuperApp.sh /MySuperApp.sh

## Add the wait script to the image
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.8.0/wait /wait
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.9.0/wait /wait
RUN chmod +x /wait

## Add your application to the docker image
ADD MySuperApp.sh /MySuperApp.sh

## Launch the wait tool and then your application
CMD /wait && /MySuperApp.sh
```
Expand Down Expand Up @@ -82,11 +86,12 @@ Instead the recommendation for base Docker images are ones offering a shell like
The behaviour of the wait utility can be configured with the following environment variables:

- _WAIT_LOGGER_LEVEL_ : the output logger level. Valid values are: _debug_, _info_, _error_, _off_. the default is _debug_.
- _WAIT_HOSTS_: comma separated list of pairs host:port for which you want to wait.
- _WAIT_HOSTS_TIMEOUT_: max number of seconds to wait for all the hosts to be available before failure. The default is 30 seconds.
- _WAIT_HOSTS_: comma-separated list of pairs host:port for which you want to wait.
- _WAIT_PATHS_: comma-separated list of paths (i.e. files or directories) on the local filesystem for which you want to wait until they exist.
- _WAIT_TIMEOUT_: max number of seconds to wait for all the hosts/paths to be available before failure. The default is 30 seconds.
- _WAIT_HOST_CONNECT_TIMEOUT_: The timeout of a single TCP connection to a remote host before attempting a new connection. The default is 5 seconds.
- _WAIT_BEFORE_HOSTS_: number of seconds to wait (sleep) before start checking for the hosts availability
- _WAIT_AFTER_HOSTS_: number of seconds to wait (sleep) once all the hosts are available
- _WAIT_BEFORE_: number of seconds to wait (sleep) before start checking for the hosts/paths availability
- _WAIT_AFTER_: number of seconds to wait (sleep) once all the hosts/paths are available
- _WAIT_SLEEP_INTERVAL_: number of seconds to sleep between retries. The default is 1 second.

## Using on non-linux systems
Expand Down
17 changes: 11 additions & 6 deletions src/env_reader/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ pub fn env_var(key: &str, default: String) -> String {
}
}

pub fn env_var_exists(key: &str) -> bool {
env::var(key).is_ok()
}

#[cfg(test)]
mod test {

extern crate time;

use super::*;
use std::env;

Expand All @@ -30,15 +32,18 @@ mod test {

println!("Result Variable [{}]: [{}]", env_key, env_value);

assert!(env_var_exists(&env_key));
assert_ne!(env_value, String::from(""));
assert_eq!(env_value, env_var(&env_key, String::from("")));
}

#[test]
fn should_return_the_default_value_if_env_variable_not_present() {
let mut nanosec = time::get_time().nsec;
let env_key = nanosec.to_string();
nanosec = nanosec + 10;
assert_eq!(nanosec.to_string(), env_var(&env_key, nanosec.to_string()));
let mut random: i64 = rand::random();
let env_key = random.to_string();
random = random + 10;

assert!(!env_var_exists(&env_key));
assert_eq!(random.to_string(), env_var(&env_key, random.to_string()));
}
}
76 changes: 53 additions & 23 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
use crate::env_reader::env_var_exists;
use log::*;
use std::path::Path;
use std::time::Duration;

pub mod env_reader;
pub mod sleeper;

pub struct Config {
pub hosts: String,
pub paths: String,
pub global_timeout: u64,
pub tcp_connection_timeout: u64,
pub wait_before: u64,
Expand All @@ -25,6 +28,7 @@ pub fn wait(
info!("---------------------------");
debug!("Starting with configuration:");
debug!(" - Hosts to be waiting for: [{}]", config.hosts);
debug!(" - Paths to be waiting for: [{}]", config.paths);
debug!(
" - Timeout before failure: {} seconds ",
config.global_timeout
Expand All @@ -34,11 +38,11 @@ pub fn wait(
config.tcp_connection_timeout
);
debug!(
" - Sleeping time before checking for hosts availability: {} seconds",
" - Sleeping time before checking for hosts/paths availability: {} seconds",
config.wait_before
);
debug!(
" - Sleeping time once all hosts are available: {} seconds",
" - Sleeping time once all hosts/paths are available: {} seconds",
config.wait_after
);
debug!(
Expand All @@ -49,22 +53,23 @@ pub fn wait(

if config.wait_before > 0 {
info!(
"Waiting {} seconds before checking for hosts availability",
"Waiting {} seconds before checking for hosts/paths availability",
config.wait_before
);
info!("{}", LINE_SEPARATOR);
sleep.sleep(config.wait_before);
}

sleep.reset();

if !config.hosts.trim().is_empty() {
sleep.reset();
for host in config.hosts.trim().split(',') {
info!("Checking availability of {}", host);
info!("Checking availability of host [{}]", host);
while !port_check::is_port_reachable_with_timeout(
&host.trim().to_string(),
Duration::from_secs(config.tcp_connection_timeout),
) {
info!("Host {} not yet available...", host);
info!("Host [{}] not yet available...", host);
if sleep.elapsed(config.global_timeout) {
error!(
"Timeout! After {} seconds some hosts are still not reachable",
Expand All @@ -75,14 +80,34 @@ pub fn wait(
}
sleep.sleep(config.wait_sleep_interval);
}
info!("Host {} is now available!", host);
info!("Host [{}] is now available!", host);
info!("{}", LINE_SEPARATOR);
}
}

if !config.paths.trim().is_empty() {
for path in config.paths.trim().split(',') {
info!("Checking availability of path [{}]", path);
while !Path::new(path.trim()).exists() {
info!("Path {} not yet available...", path);
if sleep.elapsed(config.global_timeout) {
error!(
"Timeout! After [{}] seconds some paths are still not reachable",
config.global_timeout
);
on_timeout();
return;
}
sleep.sleep(config.wait_sleep_interval);
}
info!("Path [{}] is now available!", path);
info!("{}", LINE_SEPARATOR);
}
}

if config.wait_after > 0 {
info!(
"Waiting {} seconds after hosts availability",
"Waiting {} seconds after hosts/paths availability",
config.wait_after
);
info!("{}", LINE_SEPARATOR);
Expand All @@ -95,30 +120,35 @@ pub fn wait(

pub fn config_from_env() -> Config {
Config {
hosts: crate::env_reader::env_var(&"WAIT_HOSTS".to_string(), "".to_string()),
global_timeout: to_int(
&crate::env_reader::env_var(&"WAIT_HOSTS_TIMEOUT".to_string(), "".to_string()),
30,
),
hosts: crate::env_reader::env_var("WAIT_HOSTS", "".to_string()),
paths: crate::env_reader::env_var("WAIT_PATHS", "".to_string()),
global_timeout: to_int(&legacy_or_new("WAIT_HOSTS_TIMEOUT", "WAIT_TIMEOUT", ""), 30),
tcp_connection_timeout: to_int(
&crate::env_reader::env_var(&"WAIT_HOST_CONNECT_TIMEOUT".to_string(), "".to_string()),
&crate::env_reader::env_var("WAIT_HOST_CONNECT_TIMEOUT", "".to_string()),
5,
),
wait_before: to_int(
&crate::env_reader::env_var(&"WAIT_BEFORE_HOSTS".to_string(), "".to_string()),
0,
),
wait_after: to_int(
&crate::env_reader::env_var(&"WAIT_AFTER_HOSTS".to_string(), "".to_string()),
0,
),
wait_before: to_int(&legacy_or_new("WAIT_BEFORE_HOSTS", "WAIT_BEFORE", ""), 0),
wait_after: to_int(&legacy_or_new("WAIT_AFTER_HOSTS", "WAIT_AFTER", ""), 0),
wait_sleep_interval: to_int(
&crate::env_reader::env_var(&"WAIT_SLEEP_INTERVAL".to_string(), "".to_string()),
&crate::env_reader::env_var("WAIT_SLEEP_INTERVAL", "".to_string()),
1,
),
}
}

fn legacy_or_new(legacy_var_name: &str, var_name: &str, default: &str) -> String {
let mut temp_value = default.to_string();
if env_var_exists(legacy_var_name) {
warn!(
"Environment variable [{}] is deprecated. Use [{}] instead.",
legacy_var_name, var_name
);
temp_value = crate::env_reader::env_var(legacy_var_name, temp_value);
}
temp_value = crate::env_reader::env_var(var_name, temp_value);
temp_value
}

fn to_int(number: &str, default: u64) -> u64 {
match number.parse::<u64>() {
Ok(value) => value,
Expand Down
7 changes: 4 additions & 3 deletions test.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#!/bin/bash

export WAIT_HOSTS=localhost:4748
export WAIT_HOSTS_TIMEOUT=10
export WAIT_BEFORE_HOSTS=1
export WAIT_AFTER_HOSTS=2
#export WAIT_PATHS=./target/one
export WAIT_TIMEOUT=10
export WAIT_BEFORE=1
export WAIT_AFTER=2

./target/x86_64-unknown-linux-musl/release/wait && echo 'DOOOOOOONEEEEEE'
Loading

0 comments on commit 5098f22

Please sign in to comment.