mirror of
https://github.com/dokku/dokku.git
synced 2026-05-18 05:05:46 +02:00
fix: deflake haproxy bats tests
The byjg/easy-haproxy image polls Docker for label changes every 10 seconds by default, which races with the haproxy bats suite and intermittently produces curl exit 7. Expose `refresh-conf` as a global-only haproxy property that maps to `EASYHAPROXY_REFRESH_CONF`, lower it to 2 seconds in the bats setup, and wrap the localhost HTTP assertions in a retry loop so checks wait for haproxy to converge rather than failing on the first attempt.
This commit is contained in:
@@ -113,6 +113,16 @@ dokku haproxy:set --global log-level DEBUG
|
||||
|
||||
After modifying, the Haproxy container will need to be restarted.
|
||||
|
||||
### Changing the Haproxy refresh interval
|
||||
|
||||
Haproxy polls the Docker API for label changes every `10` seconds by default. The interval may be changed by setting the `refresh-conf` property with the `--global` flag:
|
||||
|
||||
```shell
|
||||
dokku haproxy:set --global refresh-conf 5
|
||||
```
|
||||
|
||||
The `refresh-conf` property is global-only and cannot be set on a per-app basis. Setting an empty value will reset it to the default. After modifying, the Haproxy container will need to be restarted.
|
||||
|
||||
### Label Management
|
||||
|
||||
The Haproxy plugin allows you to add custom container labels to apps. These labels are injected into containers during deployment and can be used to configure Haproxy behavior beyond what the plugin provides by default.
|
||||
|
||||
@@ -72,6 +72,7 @@ cmd-haproxy-report-single() {
|
||||
"--haproxy-letsencrypt-email: $(fn-haproxy-letsencrypt-email)"
|
||||
"--haproxy-letsencrypt-server: $(fn-haproxy-letsencrypt-server)"
|
||||
"--haproxy-log-level: $(fn-haproxy-log-level)"
|
||||
"--haproxy-refresh-conf: $(fn-haproxy-refresh-conf)"
|
||||
)
|
||||
|
||||
fn-report-validate-format "$FORMAT" "$INFO_FLAG"
|
||||
|
||||
@@ -38,7 +38,8 @@ fn-haproxy-template-compose-file() {
|
||||
local SIGIL_PARAMS=(HAPROXY_IMAGE="$(fn-haproxy-image)"
|
||||
HAPROXY_LOG_LEVEL="$(fn-haproxy-log-level)"
|
||||
HAPROXY_LETSENCRYPT_EMAIL="$(fn-haproxy-letsencrypt-email)"
|
||||
HAPROXY_LETSENCRYPT_SERVER="$(fn-haproxy-letsencrypt-server)")
|
||||
HAPROXY_LETSENCRYPT_SERVER="$(fn-haproxy-letsencrypt-server)"
|
||||
HAPROXY_REFRESH_CONF="$(fn-haproxy-refresh-conf)")
|
||||
|
||||
sigil -f "$COMPOSE_TEMPLATE" "${SIGIL_PARAMS[@]}" | cat -s >"$OUTPUT_PATH"
|
||||
}
|
||||
@@ -60,3 +61,7 @@ fn-haproxy-letsencrypt-email() {
|
||||
fn-haproxy-letsencrypt-server() {
|
||||
fn-plugin-property-get-default "haproxy" "--global" "letsencrypt-server" "https://acme-v02.api.letsencrypt.org/directory"
|
||||
}
|
||||
|
||||
fn-haproxy-refresh-conf() {
|
||||
fn-plugin-property-get-default "haproxy" "--global" "refresh-conf" "10"
|
||||
}
|
||||
|
||||
@@ -9,13 +9,14 @@ cmd-haproxy-set() {
|
||||
declare cmd="haproxy:set"
|
||||
[[ "$1" == "$cmd" ]] && shift 1
|
||||
declare APP="$1" KEY="$2" VALUE="$3"
|
||||
local VALID_KEYS=("image" "log-level" "letsencrypt-email" "letsencrypt-server")
|
||||
local GLOBAL_KEYS=("image" "log-level" "letsencrypt-email" "letsencrypt-server")
|
||||
local VALID_KEYS=("image" "log-level" "letsencrypt-email" "letsencrypt-server" "refresh-conf")
|
||||
local GLOBAL_KEYS=("image" "log-level" "letsencrypt-email" "letsencrypt-server" "refresh-conf")
|
||||
local GLOBAL_ONLY_KEYS=("refresh-conf")
|
||||
|
||||
[[ -z "$KEY" ]] && dokku_log_fail "No key specified"
|
||||
|
||||
if ! fn-in-array "$KEY" "${VALID_KEYS[@]}"; then
|
||||
dokku_log_fail "Invalid key specified, valid keys include: image log-level letsencrypt-email letsencrypt-server"
|
||||
dokku_log_fail "Invalid key specified, valid keys include: image log-level letsencrypt-email letsencrypt-server refresh-conf"
|
||||
fi
|
||||
|
||||
if ! fn-in-array "$KEY" "${GLOBAL_KEYS[@]}"; then
|
||||
@@ -25,6 +26,10 @@ cmd-haproxy-set() {
|
||||
verify_app_name "$APP"
|
||||
fi
|
||||
|
||||
if fn-in-array "$KEY" "${GLOBAL_ONLY_KEYS[@]}" && [[ "$APP" != "--global" ]]; then
|
||||
dokku_log_fail "The key '$KEY' can only be set globally"
|
||||
fi
|
||||
|
||||
if [[ -n "$VALUE" ]]; then
|
||||
dokku_log_info2_quiet "Setting ${KEY} to ${VALUE}"
|
||||
fn-plugin-property-write "haproxy" "$APP" "$KEY" "$VALUE"
|
||||
|
||||
@@ -7,6 +7,7 @@ services:
|
||||
- EASYHAPROXY_DISCOVER=docker
|
||||
- EASYHAPROXY_LABEL_PREFIX=haproxy
|
||||
- EASYHAPROXY_LOG_LEVEL={{ $.HAPROXY_LOG_LEVEL }}
|
||||
- EASYHAPROXY_REFRESH_CONF={{ $.HAPROXY_REFRESH_CONF }}
|
||||
- CERTBOT_LOG_LEVEL={{ $.HAPROXY_LOG_LEVEL }}
|
||||
- HAPROXY_LOG_LEVEL={{ $.HAPROXY_LOG_LEVEL }}
|
||||
{{ if $.HAPROXY_LETSENCRYPT_EMAIL }}
|
||||
|
||||
@@ -7,6 +7,7 @@ setup() {
|
||||
dokku nginx:stop
|
||||
dokku haproxy:set --global letsencrypt-server https://acme-staging-v02.api.letsencrypt.org/directory
|
||||
dokku haproxy:set --global letsencrypt-email
|
||||
dokku haproxy:set --global refresh-conf 2
|
||||
dokku haproxy:start
|
||||
create_app
|
||||
}
|
||||
@@ -15,6 +16,7 @@ teardown() {
|
||||
global_teardown
|
||||
destroy_app
|
||||
dokku haproxy:stop
|
||||
dokku haproxy:set --global refresh-conf
|
||||
dokku nginx:start
|
||||
}
|
||||
|
||||
@@ -32,6 +34,42 @@ teardown() {
|
||||
assert_output "$help_output"
|
||||
}
|
||||
|
||||
@test "(haproxy) refresh-conf" {
|
||||
run /bin/bash -c "dokku haproxy:set $TEST_APP refresh-conf 2"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_failure
|
||||
assert_output_contains "can only be set globally"
|
||||
|
||||
run /bin/bash -c "dokku haproxy:set --global refresh-conf 5"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku haproxy:report --global --haproxy-refresh-conf"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output "5"
|
||||
|
||||
run /bin/bash -c "dokku haproxy:show-config"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output_contains "EASYHAPROXY_REFRESH_CONF=5"
|
||||
|
||||
run /bin/bash -c "dokku haproxy:set --global refresh-conf"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku haproxy:report --global --haproxy-refresh-conf"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output "10"
|
||||
}
|
||||
|
||||
@test "(haproxy) log-level" {
|
||||
run /bin/bash -c "dokku haproxy:set --global log-level DEBUG"
|
||||
echo "output: $output"
|
||||
@@ -60,11 +98,7 @@ teardown() {
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "curl --silent $(dokku url $TEST_APP)"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output_contains "python/http.server"
|
||||
assert_http_localhost_response_contains "http" "$TEST_APP.$DOKKU_DOMAIN" "80" "/" "python/http.server"
|
||||
}
|
||||
|
||||
@test "(haproxy) multiple domains" {
|
||||
@@ -88,8 +122,6 @@ teardown() {
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
sleep 5
|
||||
|
||||
run /bin/bash -c "dokku logs $TEST_APP"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
|
||||
@@ -249,10 +249,17 @@ assert_http_success() {
|
||||
|
||||
assert_http_localhost_response() {
|
||||
local scheme="$1" domain="$2" port="${3:-80}" path="${4:-}" content="${5:-}" status_code="${6:-200}"
|
||||
run curl --connect-to "$domain:$port:localhost:$port" -kSso /dev/null -w "%{http_code}" "$scheme://$domain:$port$path"
|
||||
local retries="${HTTP_ASSERT_RETRIES:-30}" attempt=1
|
||||
while [[ "$attempt" -lt "$retries" ]]; do
|
||||
run curl --connect-to "$domain:$port:localhost:$port" -kSso /dev/null -w "%{http_code}" "$scheme://$domain:$port$path"
|
||||
[[ "$output" == "$status_code" ]] && break
|
||||
sleep 1
|
||||
attempt=$((attempt + 1))
|
||||
done
|
||||
echo "curl: curl --connect-to $domain:$port:localhost:$port -kSso /dev/null -w %{http_code} $scheme://$domain:$port$path"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
echo "attempts: $attempt"
|
||||
assert_output "$status_code"
|
||||
|
||||
if [[ -n "$content" ]]; then
|
||||
@@ -265,10 +272,17 @@ assert_http_localhost_response() {
|
||||
|
||||
assert_http_localhost_response_contains() {
|
||||
local scheme="$1" domain="$2" port="${3:-80}" path="${4:-}" content="${5:-}" status_code="${6:-200}"
|
||||
run curl --connect-to "$domain:$port:localhost:$port" -kSso /dev/null -w "%{http_code}" "$scheme://$domain:$port$path"
|
||||
local retries="${HTTP_ASSERT_RETRIES:-30}" attempt=1
|
||||
while [[ "$attempt" -lt "$retries" ]]; do
|
||||
run curl --connect-to "$domain:$port:localhost:$port" -kSso /dev/null -w "%{http_code}" "$scheme://$domain:$port$path"
|
||||
[[ "$output" == "$status_code" ]] && break
|
||||
sleep 1
|
||||
attempt=$((attempt + 1))
|
||||
done
|
||||
echo "curl: curl --connect-to $domain:$port:localhost:$port -kSso /dev/null -w %{http_code} $scheme://$domain:$port$path"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
echo "attempts: $attempt"
|
||||
assert_output "$status_code"
|
||||
|
||||
if [[ -n "$content" ]]; then
|
||||
|
||||
Reference in New Issue
Block a user