fix: add proxy health checks from app.json readiness
The caddy, haproxy, openresty, and traefik docs stated that requests are only routed to containers passing healthchecks, but these proxies route to a new container as soon as it starts. The first `web` readiness healthcheck in `app.json` is now also turned into health checks and retries for caddy and openresty, as it already was for traefik, so requests are routed away from containers that are not yet ready, and the docs now describe how each proxy actually behaves.
This commit is contained in:
@@ -180,6 +180,18 @@ A healthcheck entry takes the following properties:
|
||||
|
||||
See the [docker-container-healthchecker](https://github.com/dokku/docker-container-healthchecker) documentation for more details on how healthchecks are interpreted.
|
||||
|
||||
### Healthchecks and label-based proxies
|
||||
|
||||
When using the `docker-local` scheduler, the `nginx` proxy only routes traffic to new containers once healthchecks have passed. The `caddy`, `haproxy`, `openresty`, and `traefik` proxies instead discover containers via docker labels, which are attached when a container is created, and will route requests to a new container as soon as it is running. As Dokku's healthchecks are run from the host, these proxies are not aware of their result.
|
||||
|
||||
To reduce the number of requests routed to a container that is not yet ready, the first `readiness` healthcheck with a `path` for the `web` process is translated into proxy-specific configuration:
|
||||
|
||||
- [Caddy](/docs/networking/proxies/caddy.md#healthchecks): Active healthchecks against the `path`, and retries of failed requests against other containers.
|
||||
- [OpenResty](/docs/networking/proxies/openresty.md#healthchecks): Active healthchecks against the `path`, and retries of failed requests against other containers.
|
||||
- [Traefik](/docs/networking/proxies/traefik.md#healthchecks): Active healthchecks against the `path`.
|
||||
|
||||
Haproxy does not support this configuration. Healthchecks of other types are not translated, as proxy healthchecks run for the lifetime of a container. Translating a `startup` healthcheck would turn it into a `readiness` healthcheck.
|
||||
|
||||
## Manually invoking checks
|
||||
|
||||
Checks can also be manually invoked via the `checks:run` command. This can be used to check the status of an application via cron to provide integration with external healthchecking software.
|
||||
|
||||
@@ -32,7 +32,53 @@ The Caddy plugin has specific rules for routing requests:
|
||||
- If no `http:80` mapping is found, the first `http` port mapping is used for http requests.
|
||||
- If no `https:443` mapping is found, the first `https` port mapping is used for https requests.
|
||||
- If no `https` mapping is found, the container port from `http:80` will be used for https requests.
|
||||
- Requests are routed as soon as the container is running and passing healthchecks.
|
||||
- Requests are routed as soon as the container is running, before Dokku's healthchecks have passed. See the [healthchecks](#healthchecks) section for how Caddy avoids routing to containers that are not yet ready.
|
||||
|
||||
### Healthchecks
|
||||
|
||||
When an app has a readiness healthcheck defined in its `app.json` file with a `path` property, Dokku automatically generates Caddy healthcheck and retry labels. These configure Caddy to periodically check each container, stop routing traffic to containers that fail the check, and retry requests that fail to connect against another container.
|
||||
|
||||
The following `app.json` healthcheck properties are mapped to Caddy labels:
|
||||
|
||||
| app.json Property | Caddy Label | Description |
|
||||
|-------------------|-------------|-------------|
|
||||
| `path` | `caddy.reverse_proxy.health_uri` | The HTTP path to check (required) |
|
||||
| `port` | `caddy.reverse_proxy.health_port` | The port to check |
|
||||
| `timeout` | `caddy.reverse_proxy.health_timeout` | Timeout in seconds (formatted as `Xs`, defaults to `5s`) |
|
||||
| `wait` | `caddy.reverse_proxy.health_interval` | Interval between checks in seconds (formatted as `Xs`, defaults to `5s`) |
|
||||
|
||||
Additionally, the following labels are generated:
|
||||
|
||||
| Caddy Label | Value | Description |
|
||||
|-------------|-------|-------------|
|
||||
| `caddy.reverse_proxy.health_headers.Host` | the first app domain | The `Host` header sent with the healthcheck, matching the header Dokku sends during deploy checks |
|
||||
| `caddy.reverse_proxy.lb_try_duration` | `5s` | How long a request that fails to connect is retried against other containers |
|
||||
| `caddy.reverse_proxy.lb_try_interval` | `250ms` | How long to wait between retries |
|
||||
|
||||
Example `app.json` configuration:
|
||||
|
||||
```json
|
||||
{
|
||||
"healthchecks": {
|
||||
"web": [
|
||||
{
|
||||
"name": "web readiness check",
|
||||
"path": "/health",
|
||||
"timeout": 5,
|
||||
"type": "readiness",
|
||||
"wait": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Caddy considers a new container healthy until its first check fails. The first check runs as soon as Caddy picks up the new container, and requests that reach the container before then and fail to connect are retried against the still-running old container.
|
||||
|
||||
The `scheme` property is not mapped, as Caddy uses the same transport for healthchecks as for proxied requests. Any of the generated labels may be overridden via the `caddy:labels:add` command.
|
||||
|
||||
> [!NOTE]
|
||||
> Only the first readiness healthcheck with a `path` property is used. Apps without one are routed as soon as the container is running. See the [zero downtime deploys documentation](/docs/deployment/zero-downtime-deploys.md#healthchecks-and-label-based-proxies) for more information.
|
||||
|
||||
### Switching to Caddy
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ The Haproxy plugin has specific rules for routing requests:
|
||||
- Haproxy integration is exposed via docker labels attached to containers. Changes in labels require either app deploys or rebuilds.
|
||||
- While Haproxy will respect labels associated with other containers, only `web` containers have Haproxy labels injected by the plugin.
|
||||
- Only `http:80` and `https:443` port mappings are supported at this time.
|
||||
- Requests are routed as soon as the container is running and passing healthchecks.
|
||||
- Requests are routed as soon as the container is running, before Dokku's healthchecks have passed. Haproxy does not support healthcheck configuration via container labels, so `app.json` healthchecks are not used for routing.
|
||||
|
||||
### Switching to Haproxy
|
||||
|
||||
|
||||
@@ -28,7 +28,44 @@ The OpenResty plugin has specific rules for routing requests:
|
||||
- OpenResty integration is exposed via docker labels attached to containers. Changes in labels require either app deploys or rebuilds.
|
||||
- While OpenResty will respect labels associated with other containers, only `web` containers have OpenResty labels injected by the plugin.
|
||||
- Only `http:80` and `https:443` port mappings are supported at this time.
|
||||
- Requests are routed as soon as the container is running and passing healthchecks.
|
||||
- Requests are routed as soon as the container is running, before Dokku's healthchecks have passed. See the [healthchecks](#healthchecks) section for how failed requests to a container that is not yet listening are handled.
|
||||
|
||||
### Healthchecks
|
||||
|
||||
When an app has a readiness healthcheck defined in its `app.json` file with a `path` property, Dokku automatically generates OpenResty healthcheck labels. These configure OpenResty to periodically check each container and stop routing traffic to containers that fail the check until they pass again.
|
||||
|
||||
The following `app.json` healthcheck properties are mapped to OpenResty labels:
|
||||
|
||||
| app.json Property | OpenResty Label | Description |
|
||||
|-------------------|-----------------|-------------|
|
||||
| `path` | `openresty.healthcheck-path` | The HTTP path to check (required) |
|
||||
| `port` | `openresty.healthcheck-port` | The port to check |
|
||||
| `scheme` | `openresty.healthcheck-scheme` | The scheme to use (`http` or `https`) |
|
||||
| `timeout` | `openresty.healthcheck-timeout` | Timeout in seconds (defaults to `5`) |
|
||||
| `wait` | `openresty.healthcheck-interval` | Interval between checks in seconds (defaults to `5`) |
|
||||
| `attempts` | `openresty.healthcheck-fall` | Number of successive failed checks before a container is taken out of rotation (defaults to `3`) |
|
||||
| `httpHeaders` | `openresty.healthcheck-header.<name>` | Headers to send with the check. A `Host` header is set via `openresty.healthcheck-host` instead |
|
||||
|
||||
If no `Host` header is specified, the first app domain is used, matching the header Dokku sends during deploy checks. Headers with invalid names or values containing quotes, backslashes, or control characters are skipped.
|
||||
|
||||
Additionally, the following labels are generated so that a request that fails to connect to a container is retried against another container, and the failing container is immediately taken out of rotation:
|
||||
|
||||
| OpenResty Label | Value | Description |
|
||||
|-----------------|-------|-------------|
|
||||
| `openresty.upstream-max-fails` | `1` | Number of failed requests before a container is taken out of rotation |
|
||||
| `openresty.upstream-fail-timeout` | the healthcheck `wait` value, or `5s` | How long a container is taken out of rotation after a failed request |
|
||||
| `openresty.proxy-next-upstream-timeout` | `5s` | How long a failed request may be retried against other containers |
|
||||
|
||||
OpenResty considers a new container healthy until it fails a check or a request to it fails to connect, and healthcheck state is reset whenever the OpenResty configuration is reloaded. Responses with a `2xx` or `3xx` status are considered healthy, and the `content` property is not supported.
|
||||
|
||||
The status of all checked upstreams can be viewed from within the OpenResty container:
|
||||
|
||||
```shell
|
||||
docker exec openresty-openresty-1 wget -qO- http://127.0.0.1:8999/upstream-healthcheck-status
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> Only the first readiness healthcheck with a `path` property is used. Apps without one are routed as soon as the container is running, though requests that fail to connect to a container are still retried against other containers. See the [zero downtime deploys documentation](/docs/deployment/zero-downtime-deploys.md#healthchecks-and-label-based-proxies) for more information.
|
||||
|
||||
### Switching to OpenResty
|
||||
|
||||
|
||||
@@ -31,12 +31,12 @@ The Traefik plugin has specific rules for routing requests:
|
||||
- If no `http:80` mapping is found, the first `http` port mapping is used for http requests.
|
||||
- If no `https:443` mapping is found, the first `https` port mapping is used for https requests.
|
||||
- If no `https` mapping is found, the container port from `http:80` will be used for https requests.
|
||||
- Requests are routed as soon as the container is running and passing healthchecks.
|
||||
- Requests are routed as soon as the container is running, before Dokku's healthchecks have passed.
|
||||
- Readiness healthchecks defined in `app.json` with a `path` property are automatically transformed into Traefik healthcheck labels.
|
||||
|
||||
### Healthchecks
|
||||
|
||||
When an app has a readiness healthcheck defined in its `app.json` file with a `path` property, Dokku automatically generates Traefik healthcheck labels. These labels configure Traefik to perform health checks on the container before routing traffic to it.
|
||||
When an app has a readiness healthcheck defined in its `app.json` file with a `path` property, Dokku automatically generates Traefik healthcheck labels. These labels configure Traefik to periodically check each container and stop routing traffic to containers that fail the check. Traefik considers a new container healthy until its first check fails, so requests may reach a container before its first check runs.
|
||||
|
||||
The following `app.json` healthcheck properties are mapped to Traefik labels:
|
||||
|
||||
@@ -67,7 +67,7 @@ Example `app.json` configuration:
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> Only the first readiness healthcheck with a `path` property is used. Liveness, startup, and command-based healthchecks are not transformed into Traefik labels.
|
||||
> Only the first readiness healthcheck with a `path` property is used. Liveness, startup, and command-based healthchecks are not transformed into Traefik labels. See the [zero downtime deploys documentation](/docs/deployment/zero-downtime-deploys.md#healthchecks-and-label-based-proxies) for more information.
|
||||
|
||||
### Switching to Traefik
|
||||
|
||||
|
||||
@@ -127,6 +127,10 @@ trigger-caddy-vhosts-docker-args-process-deploy() {
|
||||
|
||||
output="$output --label \"caddy.reverse_proxy={{ upstreams $proxy_container_http_port }}\""
|
||||
fi
|
||||
|
||||
if [[ "$output" == *"caddy.reverse_proxy="* ]]; then
|
||||
output="$output$(fn-caddy-healthcheck-labels "$APP" "$app_domains")"
|
||||
fi
|
||||
fi
|
||||
|
||||
local proxy_labels_file_path=$(fn-proxy-get-labels-file-path "caddy" "$APP")
|
||||
@@ -140,4 +144,43 @@ trigger-caddy-vhosts-docker-args-process-deploy() {
|
||||
echo -n "$STDIN $output"
|
||||
}
|
||||
|
||||
fn-caddy-healthcheck-labels() {
|
||||
declare desc="outputs caddy reverse_proxy health check and retry labels derived from the app's web readiness healthcheck"
|
||||
declare APP="$1" APP_DOMAINS="$2"
|
||||
local healthcheck hc_path hc_port hc_timeout hc_interval hc_host domain
|
||||
local -a domains
|
||||
|
||||
healthcheck="$(fn-proxy-get-readiness-healthcheck "$APP")"
|
||||
if [[ -z "$healthcheck" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
hc_path="$(echo "$healthcheck" | jq -r ".path // empty")"
|
||||
hc_port="$(echo "$healthcheck" | jq -r ".port // empty")"
|
||||
hc_timeout="$(echo "$healthcheck" | jq -r ".timeout // 5")"
|
||||
hc_interval="$(echo "$healthcheck" | jq -r ".wait // 5")"
|
||||
|
||||
if ! fn-proxy-healthcheck-path-is-valid "$hc_path"; then
|
||||
dokku_log_fail "Invalid app.json healthcheck path for caddy: path must start with a / and must not contain whitespace, control characters, quotes, or backslashes"
|
||||
fi
|
||||
|
||||
read -r -d '' -a domains <<<"$APP_DOMAINS" || true
|
||||
for domain in "${domains[@]}"; do
|
||||
if [[ "$domain" == "localhost" ]] || [[ "$domain" == '*' ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
hc_host="$domain"
|
||||
break
|
||||
done
|
||||
|
||||
echo -n " --label \"caddy.reverse_proxy.health_uri=$hc_path\""
|
||||
[[ -n "$hc_port" ]] && echo -n " --label caddy.reverse_proxy.health_port=$hc_port"
|
||||
echo -n " --label caddy.reverse_proxy.health_interval=${hc_interval}s"
|
||||
echo -n " --label caddy.reverse_proxy.health_timeout=${hc_timeout}s"
|
||||
[[ -n "$hc_host" ]] && echo -n " --label caddy.reverse_proxy.health_headers.Host=$hc_host"
|
||||
echo -n " --label caddy.reverse_proxy.lb_try_duration=5s"
|
||||
echo -n " --label caddy.reverse_proxy.lb_try_interval=250ms"
|
||||
}
|
||||
|
||||
trigger-caddy-vhosts-docker-args-process-deploy "$@"
|
||||
|
||||
@@ -206,6 +206,8 @@ trigger-openresty-vhosts-docker-args-process-deploy() {
|
||||
value="$(fn-openresty-computed-x-forwarded-ssl "$APP")"
|
||||
[[ -n "$value" ]] && output="$output '--label=openresty.x-forwarded-ssl=$value'"
|
||||
|
||||
output="$output$(fn-openresty-healthcheck-labels "$APP")"
|
||||
|
||||
local proxy_labels_file_path=$(fn-proxy-get-labels-file-path "openresty" "$APP")
|
||||
if [[ -f "$proxy_labels_file_path" ]]; then
|
||||
while read -r line; do
|
||||
@@ -217,4 +219,76 @@ trigger-openresty-vhosts-docker-args-process-deploy() {
|
||||
echo -n "$STDIN $output"
|
||||
}
|
||||
|
||||
fn-openresty-healthcheck-labels() {
|
||||
declare desc="outputs openresty upstream healthcheck and failover labels derived from the app's web readiness healthcheck"
|
||||
declare APP="$1"
|
||||
local healthcheck hc_path hc_port hc_scheme hc_timeout hc_interval hc_attempts hc_host domain name value
|
||||
local -a domains
|
||||
|
||||
healthcheck="$(fn-proxy-get-readiness-healthcheck "$APP")"
|
||||
if [[ -z "$healthcheck" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
hc_path="$(echo "$healthcheck" | jq -r ".path // empty")"
|
||||
hc_port="$(echo "$healthcheck" | jq -r ".port // empty")"
|
||||
hc_scheme="$(echo "$healthcheck" | jq -r ".scheme // empty")"
|
||||
hc_timeout="$(echo "$healthcheck" | jq -r ".timeout // 5")"
|
||||
hc_interval="$(echo "$healthcheck" | jq -r ".wait // 5")"
|
||||
hc_attempts="$(echo "$healthcheck" | jq -r ".attempts // 3")"
|
||||
|
||||
if ! fn-proxy-healthcheck-path-is-valid "$hc_path"; then
|
||||
dokku_log_fail "Invalid app.json healthcheck path for openresty: path must start with a / and must not contain whitespace, control characters, quotes, or backslashes"
|
||||
fi
|
||||
|
||||
if ! fn-proxy-healthcheck-scheme-is-valid "$hc_scheme"; then
|
||||
dokku_log_fail "Invalid app.json healthcheck scheme for openresty: scheme must be one of http or https"
|
||||
fi
|
||||
|
||||
hc_host="$(echo "$healthcheck" | jq -r '.httpHeaders // [] | map(select((.name | ascii_downcase) == "host")) | .[0].value // empty')"
|
||||
if [[ -z "$hc_host" ]]; then
|
||||
read -r -d '' -a domains <<<"$(plugn trigger domains-list "$APP")" || true
|
||||
for domain in "${domains[@]}"; do
|
||||
if [[ "$domain" == "localhost" ]] || [[ "$domain" == '*' ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
hc_host="$domain"
|
||||
break
|
||||
done
|
||||
fi
|
||||
|
||||
echo -n " '--label=openresty.upstream-max-fails=1'"
|
||||
echo -n " '--label=openresty.upstream-fail-timeout=${hc_interval}s'"
|
||||
echo -n " '--label=openresty.proxy-next-upstream-timeout=5s'"
|
||||
echo -n " '--label=openresty.healthcheck-path=$hc_path'"
|
||||
[[ -n "$hc_port" ]] && echo -n " '--label=openresty.healthcheck-port=$hc_port'"
|
||||
[[ -n "$hc_scheme" ]] && echo -n " '--label=openresty.healthcheck-scheme=${hc_scheme,,}'"
|
||||
echo -n " '--label=openresty.healthcheck-timeout=$hc_timeout'"
|
||||
echo -n " '--label=openresty.healthcheck-interval=$hc_interval'"
|
||||
echo -n " '--label=openresty.healthcheck-fall=$hc_attempts'"
|
||||
if [[ -n "$hc_host" ]] && fn-openresty-healthcheck-header-is-valid "Host" "$hc_host"; then
|
||||
echo -n " '--label=openresty.healthcheck-host=$hc_host'"
|
||||
fi
|
||||
|
||||
while IFS=$'\t' read -r name value; do
|
||||
[[ -z "$name" ]] && continue
|
||||
if ! fn-openresty-healthcheck-header-is-valid "$name" "$value"; then
|
||||
dokku_log_warn "Skipping invalid app.json healthcheck header for openresty: $name"
|
||||
continue
|
||||
fi
|
||||
|
||||
echo -n " '--label=openresty.healthcheck-header.$name=$value'"
|
||||
done < <(echo "$healthcheck" | jq -r '.httpHeaders // [] | map(select((.name | ascii_downcase) != "host")) | .[] | [.name, .value] | @tsv')
|
||||
}
|
||||
|
||||
fn-openresty-healthcheck-header-is-valid() {
|
||||
declare desc="checks that a healthcheck header name is a token and its value is free of control, quote, and backslash characters"
|
||||
declare NAME="$1" VALUE="$2"
|
||||
|
||||
[[ "$NAME" =~ ^[A-Za-z0-9!#$%\&*+.^_\`\|~-]+$ ]] || return 1
|
||||
[[ "$VALUE" =~ [[:cntrl:]\"\'\\] ]] && return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
trigger-openresty-vhosts-docker-args-process-deploy "$@"
|
||||
|
||||
@@ -17,6 +17,32 @@ fn-proxy-get-labels-file-path() {
|
||||
echo "$PROXY_FILE"
|
||||
}
|
||||
|
||||
fn-proxy-get-readiness-healthcheck() {
|
||||
declare desc="outputs the first web readiness healthcheck with a path from the app's app.json as json"
|
||||
declare APP="$1"
|
||||
local app_json
|
||||
|
||||
app_json="$(plugn trigger app-json-get-content "$APP" 2>/dev/null || echo "{}")"
|
||||
echo "$app_json" | jq -c '.healthchecks.web // [] | map(select(.type == "readiness" and .path != null and .path != "")) | .[0] // empty'
|
||||
}
|
||||
|
||||
fn-proxy-healthcheck-path-is-valid() {
|
||||
declare desc="checks that an app.json healthcheck path is absolute and free of whitespace, control, quote, and backslash characters"
|
||||
declare HC_PATH="$1"
|
||||
|
||||
[[ "$HC_PATH" == /* ]] || return 1
|
||||
[[ "$HC_PATH" =~ [[:space:][:cntrl:]\"\'\\] ]] && return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
fn-proxy-healthcheck-scheme-is-valid() {
|
||||
declare desc="checks that an app.json healthcheck scheme is either http or https"
|
||||
declare HC_SCHEME="$1"
|
||||
|
||||
[[ -z "$HC_SCHEME" ]] && return 0
|
||||
[[ "${HC_SCHEME,,}" == "http" ]] || [[ "${HC_SCHEME,,}" == "https" ]]
|
||||
}
|
||||
|
||||
fn-proxy-display-labels() {
|
||||
declare desc="print user-set app container labels for specified proxy"
|
||||
declare PROXY="$1" APP="$2"
|
||||
|
||||
@@ -130,21 +130,20 @@ trigger-traefik-vhosts-docker-args-process-deploy() {
|
||||
fi
|
||||
fi
|
||||
|
||||
local app_json hc_path hc_scheme hc_port hc_timeout hc_interval hc_filter
|
||||
app_json="$(plugn trigger app-json-get-content "$APP" 2>/dev/null || echo "{}")"
|
||||
hc_filter='.healthchecks.web // [] | map(select(.type == "readiness" and .path != null and .path != "")) | .[0]'
|
||||
hc_path=$(echo "$app_json" | jq -r "$hc_filter | .path // empty")
|
||||
if [[ -n "$hc_path" ]]; then
|
||||
hc_scheme=$(echo "$app_json" | jq -r "$hc_filter | .scheme // empty")
|
||||
hc_port=$(echo "$app_json" | jq -r "$hc_filter | .port // empty")
|
||||
hc_timeout=$(echo "$app_json" | jq -r "$hc_filter | .timeout // empty")
|
||||
hc_interval=$(echo "$app_json" | jq -r "$hc_filter | .wait // empty")
|
||||
local healthcheck hc_path hc_scheme hc_port hc_timeout hc_interval
|
||||
healthcheck="$(fn-proxy-get-readiness-healthcheck "$APP")"
|
||||
if [[ -n "$healthcheck" ]]; then
|
||||
hc_path=$(echo "$healthcheck" | jq -r ".path // empty")
|
||||
hc_scheme=$(echo "$healthcheck" | jq -r ".scheme // empty")
|
||||
hc_port=$(echo "$healthcheck" | jq -r ".port // empty")
|
||||
hc_timeout=$(echo "$healthcheck" | jq -r ".timeout // empty")
|
||||
hc_interval=$(echo "$healthcheck" | jq -r ".wait // empty")
|
||||
|
||||
if ! fn-traefik-healthcheck-path-is-valid "$hc_path"; then
|
||||
if ! fn-proxy-healthcheck-path-is-valid "$hc_path"; then
|
||||
dokku_log_fail "Invalid app.json healthcheck path for traefik: path must start with a / and must not contain whitespace, control characters, quotes, or backslashes"
|
||||
fi
|
||||
|
||||
if ! fn-traefik-healthcheck-scheme-is-valid "$hc_scheme"; then
|
||||
if ! fn-proxy-healthcheck-scheme-is-valid "$hc_scheme"; then
|
||||
dokku_log_fail "Invalid app.json healthcheck scheme for traefik: scheme must be one of http or https"
|
||||
fi
|
||||
|
||||
|
||||
@@ -243,20 +243,3 @@ fn-traefik-dns-provider-env-vars() {
|
||||
declare desc="returns all dns-provider-* environment variables"
|
||||
fn-plugin-property-get-all-by-prefix "traefik" "--global" "dns-provider-"
|
||||
}
|
||||
|
||||
fn-traefik-healthcheck-path-is-valid() {
|
||||
declare desc="checks that an app.json healthcheck path is absolute and free of whitespace, control, quote, and backslash characters"
|
||||
declare HC_PATH="$1"
|
||||
|
||||
[[ "$HC_PATH" == /* ]] || return 1
|
||||
[[ "$HC_PATH" =~ [[:space:][:cntrl:]\"\'\\] ]] && return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
fn-traefik-healthcheck-scheme-is-valid() {
|
||||
declare desc="checks that an app.json healthcheck scheme is either http or https"
|
||||
declare HC_SCHEME="$1"
|
||||
|
||||
[[ -z "$HC_SCHEME" ]] && return 0
|
||||
[[ "${HC_SCHEME,,}" == "http" ]] || [[ "${HC_SCHEME,,}" == "https" ]]
|
||||
}
|
||||
|
||||
@@ -6,7 +6,8 @@ load test_helper
|
||||
# Stubs plugn and plugin sources so the trigger can run without a Dokku install.
|
||||
|
||||
setup() {
|
||||
TRIGGER="$(cd "$BATS_TEST_DIRNAME/../.." && pwd)/plugins/caddy-vhosts/docker-args-process-deploy"
|
||||
REPO_ROOT="$(cd "$BATS_TEST_DIRNAME/../.." && pwd)"
|
||||
TRIGGER="$REPO_ROOT/plugins/caddy-vhosts/docker-args-process-deploy"
|
||||
STUB_ROOT="$BATS_TEST_TMPDIR/stub"
|
||||
mkdir -p "$STUB_ROOT/bin" \
|
||||
"$STUB_ROOT/core/common" \
|
||||
@@ -16,10 +17,17 @@ setup() {
|
||||
cat >"$STUB_ROOT/core/common/functions" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
dokku_log_warn() { echo "WARN: $*" >&2; }
|
||||
dokku_log_fail() {
|
||||
echo "FAIL: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
EOF
|
||||
|
||||
cat >"$STUB_ROOT/plugins/proxy/functions" <<'EOF'
|
||||
cat >"$STUB_ROOT/plugins/proxy/functions" <<EOF
|
||||
#!/usr/bin/env bash
|
||||
source "$REPO_ROOT/plugins/proxy/functions"
|
||||
EOF
|
||||
cat >>"$STUB_ROOT/plugins/proxy/functions" <<'EOF'
|
||||
fn-proxy-get-labels-file-path() {
|
||||
echo "${STUB_LABELS_FILE:-/nonexistent}"
|
||||
}
|
||||
@@ -67,6 +75,9 @@ case "$cmd" in
|
||||
printf '%s\n' "$STUB_DOMAINS"
|
||||
fi
|
||||
;;
|
||||
app-json-get-content)
|
||||
echo "${STUB_APP_JSON:-{\}}"
|
||||
;;
|
||||
*)
|
||||
echo "unexpected plugn trigger: $cmd $*" >&2
|
||||
exit 1
|
||||
@@ -89,6 +100,7 @@ invoke_caddy_docker_args() {
|
||||
STUB_PROXY_ENABLED="${STUB_PROXY_ENABLED:-true}" \
|
||||
STUB_VHOST_ENABLED="${STUB_VHOST_ENABLED:-true}" \
|
||||
STUB_LABELS_FILE="${STUB_LABELS_FILE:-/nonexistent}" \
|
||||
STUB_APP_JSON="${STUB_APP_JSON:-}" \
|
||||
bash "$TRIGGER" "${APP_NAME:-testapp}" "dockerfile" "latest" "${PROC_TYPE:-web}" "1" <<<"${STDIN_DATA:-}"
|
||||
}
|
||||
|
||||
@@ -130,3 +142,98 @@ invoke_caddy_docker_args() {
|
||||
assert_success
|
||||
assert_output_contains "caddy.reverse_proxy"
|
||||
}
|
||||
|
||||
@test "(caddy-vhosts) readiness healthcheck emits health and retry labels" {
|
||||
STUB_DOMAINS="example.com"
|
||||
STUB_PORTS="http:80:5000"
|
||||
STUB_APP_JSON='{"healthchecks":{"web":[{"type":"readiness","path":"/health","timeout":3,"wait":2}]}}'
|
||||
|
||||
run invoke_caddy_docker_args
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output_contains '--label "caddy.reverse_proxy.health_uri=/health"'
|
||||
assert_output_contains "--label caddy.reverse_proxy.health_interval=2s"
|
||||
assert_output_contains "--label caddy.reverse_proxy.health_timeout=3s"
|
||||
assert_output_contains "--label caddy.reverse_proxy.health_headers.Host=example.com"
|
||||
assert_output_contains "--label caddy.reverse_proxy.lb_try_duration=5s"
|
||||
assert_output_contains "--label caddy.reverse_proxy.lb_try_interval=250ms"
|
||||
assert_output_contains "health_port" 0
|
||||
}
|
||||
|
||||
@test "(caddy-vhosts) readiness healthcheck defaults and port" {
|
||||
STUB_DOMAINS="example.com"
|
||||
STUB_PORTS="http:80:5000"
|
||||
STUB_APP_JSON='{"healthchecks":{"web":[{"type":"readiness","path":"/","port":5001}]}}'
|
||||
|
||||
run invoke_caddy_docker_args
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output_contains "--label caddy.reverse_proxy.health_port=5001"
|
||||
assert_output_contains "--label caddy.reverse_proxy.health_interval=5s"
|
||||
assert_output_contains "--label caddy.reverse_proxy.health_timeout=5s"
|
||||
}
|
||||
|
||||
@test "(caddy-vhosts) healthcheck host header skips localhost and catch-all domains" {
|
||||
STUB_DOMAINS="localhost * app.example.com other.example.com"
|
||||
STUB_PORTS="http:80:5000"
|
||||
STUB_APP_JSON='{"healthchecks":{"web":[{"type":"readiness","path":"/"}]}}'
|
||||
|
||||
run invoke_caddy_docker_args
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output_contains "--label caddy.reverse_proxy.health_headers.Host=app.example.com"
|
||||
}
|
||||
|
||||
@test "(caddy-vhosts) startup healthcheck emits no health or retry labels" {
|
||||
STUB_DOMAINS="example.com"
|
||||
STUB_PORTS="http:80:5000"
|
||||
STUB_APP_JSON='{"healthchecks":{"web":[{"type":"startup","path":"/"}]}}'
|
||||
|
||||
run invoke_caddy_docker_args
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output_contains "caddy.reverse_proxy="
|
||||
assert_output_contains "health_" 0
|
||||
assert_output_contains "lb_try_" 0
|
||||
}
|
||||
|
||||
@test "(caddy-vhosts) missing app.json emits no health or retry labels" {
|
||||
STUB_DOMAINS="example.com"
|
||||
STUB_PORTS="http:80:5000"
|
||||
|
||||
run invoke_caddy_docker_args
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output_contains "caddy.reverse_proxy="
|
||||
assert_output_contains "health_" 0
|
||||
assert_output_contains "lb_try_" 0
|
||||
}
|
||||
|
||||
@test "(caddy-vhosts) readiness healthcheck without routing labels emits no health labels" {
|
||||
STUB_DOMAINS="example.com"
|
||||
STUB_PORTS=""
|
||||
STUB_APP_JSON='{"healthchecks":{"web":[{"type":"readiness","path":"/"}]}}'
|
||||
|
||||
run invoke_caddy_docker_args
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output_contains "health_" 0
|
||||
}
|
||||
|
||||
@test "(caddy-vhosts) invalid readiness healthcheck path fails" {
|
||||
STUB_DOMAINS="example.com"
|
||||
STUB_PORTS="http:80:5000"
|
||||
STUB_APP_JSON='{"healthchecks":{"web":[{"type":"readiness","path":"/has space"}]}}'
|
||||
|
||||
run invoke_caddy_docker_args
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_failure
|
||||
assert_output_contains "Invalid app.json healthcheck path for caddy"
|
||||
}
|
||||
|
||||
@@ -452,3 +452,142 @@ teardown() {
|
||||
echo "status: $status"
|
||||
assert_output "0"
|
||||
}
|
||||
|
||||
@test "(caddy) healthcheck labels from app.json" {
|
||||
run /bin/bash -c "dokku proxy:set $TEST_APP caddy"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP setup_caddy_readiness_healthcheck
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"caddy.reverse_proxy.health_uri\" }}'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output "/"
|
||||
|
||||
run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"caddy.reverse_proxy.health_interval\" }}'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output "2s"
|
||||
|
||||
run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"caddy.reverse_proxy.health_timeout\" }}'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output "5s"
|
||||
|
||||
run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"caddy.reverse_proxy.health_headers.Host\" }}'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output "$TEST_APP.$DOKKU_DOMAIN"
|
||||
|
||||
run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"caddy.reverse_proxy.lb_try_duration\" }}'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output "5s"
|
||||
|
||||
run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"caddy.reverse_proxy.lb_try_interval\" }}'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output "250ms"
|
||||
|
||||
assert_http_localhost_response "http" "$TEST_APP.dokku.me" "80" "" "python/http.server"
|
||||
|
||||
run /bin/bash -c "dokku ps:rebuild $TEST_APP"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
assert_http_localhost_response "http" "$TEST_APP.dokku.me" "80" "" "python/http.server"
|
||||
}
|
||||
|
||||
@test "(caddy) healthcheck labels can be overridden" {
|
||||
run /bin/bash -c "dokku proxy:set $TEST_APP caddy"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku caddy:labels:add $TEST_APP caddy.reverse_proxy.lb_try_duration 10s"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP setup_caddy_readiness_healthcheck
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"caddy.reverse_proxy.lb_try_duration\" }}'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output "10s"
|
||||
|
||||
assert_http_localhost_response "http" "$TEST_APP.dokku.me" "80" "" "python/http.server"
|
||||
}
|
||||
|
||||
@test "(caddy) no healthcheck labels without readiness check" {
|
||||
run /bin/bash -c "dokku proxy:set $TEST_APP caddy"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP convert_to_dockerfile
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"caddy.reverse_proxy.health_uri\" }}'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output_not_exists
|
||||
|
||||
run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"caddy.reverse_proxy.lb_try_duration\" }}'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output_not_exists
|
||||
}
|
||||
|
||||
@test "(caddy) invalid stored healthcheck path fails restart" {
|
||||
run /bin/bash -c "dokku proxy:set $TEST_APP caddy"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP setup_caddy_readiness_healthcheck
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "jq '.healthchecks.web[0].path = \"/health check\"' /var/lib/dokku/data/app-json/$TEST_APP/app.json > /var/lib/dokku/data/app-json/$TEST_APP/app.json.tmp && mv /var/lib/dokku/data/app-json/$TEST_APP/app.json.tmp /var/lib/dokku/data/app-json/$TEST_APP/app.json"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku ps:restart $TEST_APP"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_failure
|
||||
assert_output_contains "Invalid app.json healthcheck path for caddy" -1
|
||||
}
|
||||
|
||||
setup_caddy_readiness_healthcheck() {
|
||||
local APP="$1"
|
||||
local APP_REPO_DIR="$2"
|
||||
[[ -z "$APP" ]] && local APP="$TEST_APP"
|
||||
APP_REPO_DIR="$(realpath "$APP_REPO_DIR")"
|
||||
|
||||
convert_to_dockerfile "$APP" "$APP_REPO_DIR"
|
||||
mv "$APP_REPO_DIR/app-readiness.json" "$APP_REPO_DIR/app.json"
|
||||
}
|
||||
|
||||
@@ -760,6 +760,175 @@ teardown() {
|
||||
assert_output_not_exists
|
||||
}
|
||||
|
||||
@test "(openresty) healthcheck labels from app.json" {
|
||||
run /bin/bash -c "dokku proxy:set $TEST_APP openresty"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP setup_openresty_readiness_healthcheck
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"openresty.upstream-max-fails\" }}'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output "1"
|
||||
|
||||
run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"openresty.upstream-fail-timeout\" }}'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output "2s"
|
||||
|
||||
run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"openresty.proxy-next-upstream-timeout\" }}'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output "5s"
|
||||
|
||||
run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"openresty.healthcheck-path\" }}'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output "/"
|
||||
|
||||
run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"openresty.healthcheck-interval\" }}'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output "2"
|
||||
|
||||
run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"openresty.healthcheck-timeout\" }}'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output "5"
|
||||
|
||||
run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"openresty.healthcheck-fall\" }}'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output "3"
|
||||
|
||||
run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"openresty.healthcheck-host\" }}'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output "$TEST_APP.dokku.me"
|
||||
|
||||
run /bin/bash -c "docker exec openresty-openresty-1 /usr/local/openresty/nginx/sbin/nginx -t"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "docker exec openresty-openresty-1 cat /etc/nginx/sites-enabled/sites.conf"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output_contains "max_fails=1 fail_timeout=2s;"
|
||||
assert_output_contains "proxy_next_upstream_timeout 5s;"
|
||||
|
||||
sleep 5
|
||||
|
||||
run /bin/bash -c "docker exec openresty-openresty-1 wget -qO- http://127.0.0.1:8999/upstream-healthcheck-status"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output_contains "Upstream $TEST_APP-web-5000"
|
||||
assert_output_contains " UP"
|
||||
assert_output_contains "(NO checkers)" 0
|
||||
|
||||
assert_http_localhost_response "http" "$TEST_APP.dokku.me" "80" "" "python/http.server"
|
||||
}
|
||||
|
||||
@test "(openresty) no healthcheck labels without readiness check" {
|
||||
run /bin/bash -c "dokku proxy:set $TEST_APP openresty"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP convert_to_dockerfile
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"openresty.upstream-max-fails\" }}'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output_not_exists
|
||||
|
||||
run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"openresty.proxy-next-upstream-timeout\" }}'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output_not_exists
|
||||
|
||||
run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"openresty.healthcheck-path\" }}'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output_not_exists
|
||||
}
|
||||
|
||||
@test "(openresty) healthcheck headers from app.json" {
|
||||
run /bin/bash -c "dokku proxy:set $TEST_APP openresty"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP setup_openresty_readiness_healthcheck_headers
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"openresty.healthcheck-header.X-Check\" }}'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output "dokku"
|
||||
|
||||
run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"openresty.healthcheck-host\" }}'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output "check.dokku.me"
|
||||
|
||||
run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"openresty.healthcheck-header.Host\" }}'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output_not_exists
|
||||
|
||||
assert_http_localhost_response "http" "$TEST_APP.dokku.me" "80" "" "python/http.server"
|
||||
}
|
||||
|
||||
@test "(openresty) invalid stored healthcheck path fails restart" {
|
||||
run /bin/bash -c "dokku proxy:set $TEST_APP openresty"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP setup_openresty_readiness_healthcheck
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "jq '.healthchecks.web[0].path = \"/health check\"' /var/lib/dokku/data/app-json/$TEST_APP/app.json > /var/lib/dokku/data/app-json/$TEST_APP/app.json.tmp && mv /var/lib/dokku/data/app-json/$TEST_APP/app.json.tmp /var/lib/dokku/data/app-json/$TEST_APP/app.json"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku ps:restart $TEST_APP"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_failure
|
||||
assert_output_contains "Invalid app.json healthcheck path for openresty" -1
|
||||
}
|
||||
|
||||
add_openresty_include() {
|
||||
local APP="$1"
|
||||
local APP_REPO_DIR="$2"
|
||||
@@ -786,3 +955,23 @@ add_openresty_include_unsafe() {
|
||||
mkdir -p "$APP_REPO_DIR/openresty/http-location-includes"
|
||||
printf '# location\n' >"$APP_REPO_DIR/openresty/http-location-includes/unsafe filename.conf"
|
||||
}
|
||||
|
||||
setup_openresty_readiness_healthcheck() {
|
||||
local APP="$1"
|
||||
local APP_REPO_DIR="$2"
|
||||
[[ -z "$APP" ]] && local APP="$TEST_APP"
|
||||
APP_REPO_DIR="$(realpath "$APP_REPO_DIR")"
|
||||
|
||||
convert_to_dockerfile "$APP" "$APP_REPO_DIR"
|
||||
mv "$APP_REPO_DIR/app-readiness.json" "$APP_REPO_DIR/app.json"
|
||||
}
|
||||
|
||||
setup_openresty_readiness_healthcheck_headers() {
|
||||
local APP="$1"
|
||||
local APP_REPO_DIR="$2"
|
||||
[[ -z "$APP" ]] && local APP="$TEST_APP"
|
||||
APP_REPO_DIR="$(realpath "$APP_REPO_DIR")"
|
||||
|
||||
convert_to_dockerfile "$APP" "$APP_REPO_DIR"
|
||||
jq '.healthchecks.web[0].httpHeaders = [{"name": "X-Check", "value": "dokku"}, {"name": "Host", "value": "check.dokku.me"}]' "$APP_REPO_DIR/app-readiness.json" >"$APP_REPO_DIR/app.json"
|
||||
}
|
||||
|
||||
@@ -943,7 +943,7 @@ setup_traefik_healthcheck() {
|
||||
[[ -z "$APP" ]] && local APP="$TEST_APP"
|
||||
APP_REPO_DIR="$(realpath "$APP_REPO_DIR")"
|
||||
|
||||
mv "$APP_REPO_DIR/app-traefik.json" "$APP_REPO_DIR/app.json"
|
||||
mv "$APP_REPO_DIR/app-readiness.json" "$APP_REPO_DIR/app.json"
|
||||
}
|
||||
|
||||
setup_traefik_healthcheck_whitespace_path() {
|
||||
@@ -952,7 +952,7 @@ setup_traefik_healthcheck_whitespace_path() {
|
||||
[[ -z "$APP" ]] && local APP="$TEST_APP"
|
||||
APP_REPO_DIR="$(realpath "$APP_REPO_DIR")"
|
||||
|
||||
jq '.healthchecks.web[0].path = "/health check"' "$APP_REPO_DIR/app-traefik.json" >"$APP_REPO_DIR/app.json"
|
||||
jq '.healthchecks.web[0].path = "/health check"' "$APP_REPO_DIR/app-readiness.json" >"$APP_REPO_DIR/app.json"
|
||||
}
|
||||
|
||||
setup_traefik_healthcheck_invalid_scheme() {
|
||||
@@ -961,5 +961,5 @@ setup_traefik_healthcheck_invalid_scheme() {
|
||||
[[ -z "$APP" ]] && local APP="$TEST_APP"
|
||||
APP_REPO_DIR="$(realpath "$APP_REPO_DIR")"
|
||||
|
||||
jq '.healthchecks.web[0].scheme = "tcp"' "$APP_REPO_DIR/app-traefik.json" >"$APP_REPO_DIR/app.json"
|
||||
jq '.healthchecks.web[0].scheme = "tcp"' "$APP_REPO_DIR/app-readiness.json" >"$APP_REPO_DIR/app.json"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user