Skip to content

Commit 5098f22

Browse files
authored
Merge pull request #52 from ufoscout/feature/wait_for_path
Feature/wait for path
2 parents 198d1c2 + c3f1b37 commit 5098f22

File tree

7 files changed

+411
-88
lines changed

7 files changed

+411
-88
lines changed

Cargo.lock

+54-30
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "wait"
3-
version = "2.8.0"
3+
version = "2.9.0"
44
authors = ["ufoscout <[email protected]>"]
55
edition = "2018"
66

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

1717
[profile.release]
1818
opt-level = 'z' # Optimize for size.

README.md

+15-10
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@
55
[![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)
66
[![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)
77

8-
A small command line utility to wait for other docker images to be started while using docker-compose.
9-
It permits to wait for a fixed amount of seconds and/or to wait until a TCP port is open on a target image.
8+
A small command-line utility to wait for other docker images to be started while using docker-compose.
9+
10+
It permits waiting for:
11+
- a fixed amount of seconds
12+
- until a TCP port is open on a target image
13+
- until a file or directory is present on the local filesystem
1014

1115
## Usage
1216

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

21-
## Add your application to the docker image
22-
ADD MySuperApp.sh /MySuperApp.sh
23-
2425
## Add the wait script to the image
25-
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.8.0/wait /wait
26+
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.9.0/wait /wait
2627
RUN chmod +x /wait
2728

29+
## Add your application to the docker image
30+
ADD MySuperApp.sh /MySuperApp.sh
31+
2832
## Launch the wait tool and then your application
2933
CMD /wait && /MySuperApp.sh
3034
```
@@ -82,11 +86,12 @@ Instead the recommendation for base Docker images are ones offering a shell like
8286
The behaviour of the wait utility can be configured with the following environment variables:
8387

8488
- _WAIT_LOGGER_LEVEL_ : the output logger level. Valid values are: _debug_, _info_, _error_, _off_. the default is _debug_.
85-
- _WAIT_HOSTS_: comma separated list of pairs host:port for which you want to wait.
86-
- _WAIT_HOSTS_TIMEOUT_: max number of seconds to wait for all the hosts to be available before failure. The default is 30 seconds.
89+
- _WAIT_HOSTS_: comma-separated list of pairs host:port for which you want to wait.
90+
- _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.
91+
- _WAIT_TIMEOUT_: max number of seconds to wait for all the hosts/paths to be available before failure. The default is 30 seconds.
8792
- _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.
88-
- _WAIT_BEFORE_HOSTS_: number of seconds to wait (sleep) before start checking for the hosts availability
89-
- _WAIT_AFTER_HOSTS_: number of seconds to wait (sleep) once all the hosts are available
93+
- _WAIT_BEFORE_: number of seconds to wait (sleep) before start checking for the hosts/paths availability
94+
- _WAIT_AFTER_: number of seconds to wait (sleep) once all the hosts/paths are available
9095
- _WAIT_SLEEP_INTERVAL_: number of seconds to sleep between retries. The default is 1 second.
9196

9297
## Using on non-linux systems

src/env_reader/mod.rs

+11-6
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ pub fn env_var(key: &str, default: String) -> String {
77
}
88
}
99

10+
pub fn env_var_exists(key: &str) -> bool {
11+
env::var(key).is_ok()
12+
}
13+
1014
#[cfg(test)]
1115
mod test {
1216

13-
extern crate time;
14-
1517
use super::*;
1618
use std::env;
1719

@@ -30,15 +32,18 @@ mod test {
3032

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

35+
assert!(env_var_exists(&env_key));
3336
assert_ne!(env_value, String::from(""));
3437
assert_eq!(env_value, env_var(&env_key, String::from("")));
3538
}
3639

3740
#[test]
3841
fn should_return_the_default_value_if_env_variable_not_present() {
39-
let mut nanosec = time::get_time().nsec;
40-
let env_key = nanosec.to_string();
41-
nanosec = nanosec + 10;
42-
assert_eq!(nanosec.to_string(), env_var(&env_key, nanosec.to_string()));
42+
let mut random: i64 = rand::random();
43+
let env_key = random.to_string();
44+
random = random + 10;
45+
46+
assert!(!env_var_exists(&env_key));
47+
assert_eq!(random.to_string(), env_var(&env_key, random.to_string()));
4348
}
4449
}

src/lib.rs

+53-23
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1+
use crate::env_reader::env_var_exists;
12
use log::*;
3+
use std::path::Path;
24
use std::time::Duration;
35

46
pub mod env_reader;
57
pub mod sleeper;
68

79
pub struct Config {
810
pub hosts: String,
11+
pub paths: String,
912
pub global_timeout: u64,
1013
pub tcp_connection_timeout: u64,
1114
pub wait_before: u64,
@@ -25,6 +28,7 @@ pub fn wait(
2528
info!("---------------------------");
2629
debug!("Starting with configuration:");
2730
debug!(" - Hosts to be waiting for: [{}]", config.hosts);
31+
debug!(" - Paths to be waiting for: [{}]", config.paths);
2832
debug!(
2933
" - Timeout before failure: {} seconds ",
3034
config.global_timeout
@@ -34,11 +38,11 @@ pub fn wait(
3438
config.tcp_connection_timeout
3539
);
3640
debug!(
37-
" - Sleeping time before checking for hosts availability: {} seconds",
41+
" - Sleeping time before checking for hosts/paths availability: {} seconds",
3842
config.wait_before
3943
);
4044
debug!(
41-
" - Sleeping time once all hosts are available: {} seconds",
45+
" - Sleeping time once all hosts/paths are available: {} seconds",
4246
config.wait_after
4347
);
4448
debug!(
@@ -49,22 +53,23 @@ pub fn wait(
4953

5054
if config.wait_before > 0 {
5155
info!(
52-
"Waiting {} seconds before checking for hosts availability",
56+
"Waiting {} seconds before checking for hosts/paths availability",
5357
config.wait_before
5458
);
5559
info!("{}", LINE_SEPARATOR);
5660
sleep.sleep(config.wait_before);
5761
}
5862

63+
sleep.reset();
64+
5965
if !config.hosts.trim().is_empty() {
60-
sleep.reset();
6166
for host in config.hosts.trim().split(',') {
62-
info!("Checking availability of {}", host);
67+
info!("Checking availability of host [{}]", host);
6368
while !port_check::is_port_reachable_with_timeout(
6469
&host.trim().to_string(),
6570
Duration::from_secs(config.tcp_connection_timeout),
6671
) {
67-
info!("Host {} not yet available...", host);
72+
info!("Host [{}] not yet available...", host);
6873
if sleep.elapsed(config.global_timeout) {
6974
error!(
7075
"Timeout! After {} seconds some hosts are still not reachable",
@@ -75,14 +80,34 @@ pub fn wait(
7580
}
7681
sleep.sleep(config.wait_sleep_interval);
7782
}
78-
info!("Host {} is now available!", host);
83+
info!("Host [{}] is now available!", host);
84+
info!("{}", LINE_SEPARATOR);
85+
}
86+
}
87+
88+
if !config.paths.trim().is_empty() {
89+
for path in config.paths.trim().split(',') {
90+
info!("Checking availability of path [{}]", path);
91+
while !Path::new(path.trim()).exists() {
92+
info!("Path {} not yet available...", path);
93+
if sleep.elapsed(config.global_timeout) {
94+
error!(
95+
"Timeout! After [{}] seconds some paths are still not reachable",
96+
config.global_timeout
97+
);
98+
on_timeout();
99+
return;
100+
}
101+
sleep.sleep(config.wait_sleep_interval);
102+
}
103+
info!("Path [{}] is now available!", path);
79104
info!("{}", LINE_SEPARATOR);
80105
}
81106
}
82107

83108
if config.wait_after > 0 {
84109
info!(
85-
"Waiting {} seconds after hosts availability",
110+
"Waiting {} seconds after hosts/paths availability",
86111
config.wait_after
87112
);
88113
info!("{}", LINE_SEPARATOR);
@@ -95,30 +120,35 @@ pub fn wait(
95120

96121
pub fn config_from_env() -> Config {
97122
Config {
98-
hosts: crate::env_reader::env_var(&"WAIT_HOSTS".to_string(), "".to_string()),
99-
global_timeout: to_int(
100-
&crate::env_reader::env_var(&"WAIT_HOSTS_TIMEOUT".to_string(), "".to_string()),
101-
30,
102-
),
123+
hosts: crate::env_reader::env_var("WAIT_HOSTS", "".to_string()),
124+
paths: crate::env_reader::env_var("WAIT_PATHS", "".to_string()),
125+
global_timeout: to_int(&legacy_or_new("WAIT_HOSTS_TIMEOUT", "WAIT_TIMEOUT", ""), 30),
103126
tcp_connection_timeout: to_int(
104-
&crate::env_reader::env_var(&"WAIT_HOST_CONNECT_TIMEOUT".to_string(), "".to_string()),
127+
&crate::env_reader::env_var("WAIT_HOST_CONNECT_TIMEOUT", "".to_string()),
105128
5,
106129
),
107-
wait_before: to_int(
108-
&crate::env_reader::env_var(&"WAIT_BEFORE_HOSTS".to_string(), "".to_string()),
109-
0,
110-
),
111-
wait_after: to_int(
112-
&crate::env_reader::env_var(&"WAIT_AFTER_HOSTS".to_string(), "".to_string()),
113-
0,
114-
),
130+
wait_before: to_int(&legacy_or_new("WAIT_BEFORE_HOSTS", "WAIT_BEFORE", ""), 0),
131+
wait_after: to_int(&legacy_or_new("WAIT_AFTER_HOSTS", "WAIT_AFTER", ""), 0),
115132
wait_sleep_interval: to_int(
116-
&crate::env_reader::env_var(&"WAIT_SLEEP_INTERVAL".to_string(), "".to_string()),
133+
&crate::env_reader::env_var("WAIT_SLEEP_INTERVAL", "".to_string()),
117134
1,
118135
),
119136
}
120137
}
121138

139+
fn legacy_or_new(legacy_var_name: &str, var_name: &str, default: &str) -> String {
140+
let mut temp_value = default.to_string();
141+
if env_var_exists(legacy_var_name) {
142+
warn!(
143+
"Environment variable [{}] is deprecated. Use [{}] instead.",
144+
legacy_var_name, var_name
145+
);
146+
temp_value = crate::env_reader::env_var(legacy_var_name, temp_value);
147+
}
148+
temp_value = crate::env_reader::env_var(var_name, temp_value);
149+
temp_value
150+
}
151+
122152
fn to_int(number: &str, default: u64) -> u64 {
123153
match number.parse::<u64>() {
124154
Ok(value) => value,

test.sh

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
#!/bin/bash
22

33
export WAIT_HOSTS=localhost:4748
4-
export WAIT_HOSTS_TIMEOUT=10
5-
export WAIT_BEFORE_HOSTS=1
6-
export WAIT_AFTER_HOSTS=2
4+
#export WAIT_PATHS=./target/one
5+
export WAIT_TIMEOUT=10
6+
export WAIT_BEFORE=1
7+
export WAIT_AFTER=2
78

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

0 commit comments

Comments
 (0)