Entrypoint steps are functions called from main (closes #163)
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
bin/entrypoint.sh was top-level code with one helper; the shell section of the code style guide asks for every step in a function and a main called at the end. The PORT and TRUSTED_PROXIES checks, the data directory, starting each process, the wait loop, stopping both and the exit are now functions, which main calls in order, setting the stop trap before either process starts. It stays POSIX sh with no set -e. Messages and exit codes are unchanged; the 8081 message is passed to echo as two arguments so its line fits in 80 columns. Model: opus-5-5
This commit was merged in pull request #180.
This commit is contained in:
@@ -21,6 +21,13 @@ Run `make frontend-viewport-test` in CI as its own step; it is not part of
|
|||||||
|
|
||||||
# Completed Steps
|
# Completed Steps
|
||||||
|
|
||||||
|
- 2026-10-19: `bin/entrypoint.sh` has each of its steps in a function, and a
|
||||||
|
`main` at the end calls them in order, as the shell section of the code style
|
||||||
|
guide asks ([#163](https://git.eeqj.de/sneak/netwatch/issues/163)). It is
|
||||||
|
still POSIX sh with no `set -e`, and does what it did, with the same messages
|
||||||
|
and exit codes. Checked by running the image with each script: a normal start,
|
||||||
|
bad `PORT`, `TRUSTED_PROXIES` and `DATA_DIR` values, `docker stop`, INT, and
|
||||||
|
nginx exiting on its own
|
||||||
- 2026-10-19: while report files cannot be written, the health check answers 503
|
- 2026-10-19: while report files cannot be written, the health check answers 503
|
||||||
with `"status":"error"` and the same fields, so the image's `HEALTHCHECK`
|
with `"status":"error"` and the same fields, so the image's `HEALTHCHECK`
|
||||||
reports the container `unhealthy`
|
reports the container `unhealthy`
|
||||||
|
|||||||
+35
-7
@@ -13,6 +13,7 @@ set -u
|
|||||||
# address and start anyway, and reports a bad port without naming
|
# address and start anyway, and reports a bad port without naming
|
||||||
# PORT, so a value that is not a usable port stops the container here,
|
# PORT, so a value that is not a usable port stops the container here,
|
||||||
# before either process starts.
|
# before either process starts.
|
||||||
|
check_port() {
|
||||||
export PORT="${PORT:-8080}"
|
export PORT="${PORT:-8080}"
|
||||||
case "$PORT" in
|
case "$PORT" in
|
||||||
*[!0-9]*)
|
*[!0-9]*)
|
||||||
@@ -28,9 +29,11 @@ if [ "${#PORT}" -gt 5 ] || [ "$PORT" -lt 1 ] || [ "$PORT" -gt 65535 ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
if [ "$PORT" -eq 8081 ]; then
|
if [ "$PORT" -eq 8081 ]; then
|
||||||
echo "entrypoint: PORT cannot be 8081, netwatch-server listens there" >&2
|
echo "entrypoint: PORT cannot be 8081, netwatch-server" \
|
||||||
|
"listens there" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# TRUSTED_PROXIES names the reverse proxies in front of the container,
|
# TRUSTED_PROXIES names the reverse proxies in front of the container,
|
||||||
# as IP addresses or CIDRs separated by commas. nginx takes the client
|
# as IP addresses or CIDRs separated by commas. nginx takes the client
|
||||||
@@ -47,6 +50,7 @@ fi
|
|||||||
# TRUSTED_PROXIES. Its error, naming the CIDR, is dropped for the one
|
# TRUSTED_PROXIES. Its error, naming the CIDR, is dropped for the one
|
||||||
# below, naming the entry as written. set -f keeps a * in an entry from
|
# below, naming the entry as written. set -f keeps a * in an entry from
|
||||||
# becoming a list of file names.
|
# becoming a list of file names.
|
||||||
|
write_trusted_proxies() {
|
||||||
TRUSTED_PROXIES="${TRUSTED_PROXIES-10.0.0.0/8,172.16.0.0/12,192.168.0.0/16}"
|
TRUSTED_PROXIES="${TRUSTED_PROXIES-10.0.0.0/8,172.16.0.0/12,192.168.0.0/16}"
|
||||||
set -f
|
set -f
|
||||||
for proxy in $(printf '%s' "$TRUSTED_PROXIES" | tr ',' ' '); do
|
for proxy in $(printf '%s' "$TRUSTED_PROXIES" | tr ',' ' '); do
|
||||||
@@ -62,6 +66,7 @@ for proxy in $(printf '%s' "$TRUSTED_PROXIES" | tr ',' ' '); do
|
|||||||
fi
|
fi
|
||||||
echo "set_real_ip_from $cidr;"
|
echo "set_real_ip_from $cidr;"
|
||||||
done > /etc/nginx/trusted-proxies.conf
|
done > /etc/nginx/trusted-proxies.conf
|
||||||
|
}
|
||||||
|
|
||||||
# netwatch-server keeps its report files in DATA_DIR, on the /data
|
# netwatch-server keeps its report files in DATA_DIR, on the /data
|
||||||
# volume, which may be a host directory owned by root or by another
|
# volume, which may be a host directory owned by root or by another
|
||||||
@@ -73,12 +78,10 @@ done > /etc/nginx/trusted-proxies.conf
|
|||||||
# naming DATA_DIR, unless DATA_DIR is /data or a path below it, and it
|
# naming DATA_DIR, unless DATA_DIR is /data or a path below it, and it
|
||||||
# acts on nothing outside /data, whatever symbolic or hard links it
|
# acts on nothing outside /data, whatever symbolic or hard links it
|
||||||
# meets there.
|
# meets there.
|
||||||
|
prepare_data_dir() {
|
||||||
export DATA_DIR="${DATA_DIR:-/data/reports}"
|
export DATA_DIR="${DATA_DIR:-/data/reports}"
|
||||||
netwatch-server prepare-data-dir "$DATA_DIR" || exit 1
|
netwatch-server prepare-data-dir "$DATA_DIR" || exit 1
|
||||||
|
}
|
||||||
# A stop signal is only noted here; the loop below acts on it.
|
|
||||||
stop_requested=""
|
|
||||||
trap 'stop_requested=yes' TERM INT
|
|
||||||
|
|
||||||
# netwatch-server runs as the netwatch user and listens on loopback
|
# netwatch-server runs as the netwatch user and listens on loopback
|
||||||
# only, on a port other than the public one; configs/nginx.conf proxies
|
# only, on a port other than the public one; configs/nginx.conf proxies
|
||||||
@@ -87,9 +90,11 @@ trap 'stop_requested=yes' TERM INT
|
|||||||
# the container has. The netwatch user has no login shell, hence -s
|
# the container has. The netwatch user has no login shell, hence -s
|
||||||
# /bin/sh. busybox su replaces itself with the command instead of
|
# /bin/sh. busybox su replaces itself with the command instead of
|
||||||
# staying on as its parent, so $! is the server's own PID.
|
# staying on as its parent, so $! is the server's own PID.
|
||||||
|
start_backend() {
|
||||||
BIND_ADDRESS=127.0.0.1 PORT=8081 TRUSTED_PROXIES=127.0.0.1/32 \
|
BIND_ADDRESS=127.0.0.1 PORT=8081 TRUSTED_PROXIES=127.0.0.1/32 \
|
||||||
su -s /bin/sh netwatch -c 'exec netwatch-server' &
|
su -s /bin/sh netwatch -c 'exec netwatch-server' &
|
||||||
backend=$!
|
backend=$!
|
||||||
|
}
|
||||||
|
|
||||||
# nginx starts through the nginx image's own entrypoint, which applies
|
# nginx starts through the nginx image's own entrypoint, which applies
|
||||||
# the image's start-up configuration and then replaces itself with
|
# the image's start-up configuration and then replaces itself with
|
||||||
@@ -98,9 +103,11 @@ backend=$!
|
|||||||
# that rendering to PORT: a variable nginx itself uses, such as $uri,
|
# that rendering to PORT: a variable nginx itself uses, such as $uri,
|
||||||
# would otherwise be replaced by an environment variable of the same
|
# would otherwise be replaced by an environment variable of the same
|
||||||
# name.
|
# name.
|
||||||
|
start_nginx() {
|
||||||
NGINX_ENVSUBST_FILTER='^PORT$' \
|
NGINX_ENVSUBST_FILTER='^PORT$' \
|
||||||
/docker-entrypoint.sh nginx -g 'daemon off;' &
|
/docker-entrypoint.sh nginx -g 'daemon off;' &
|
||||||
nginx=$!
|
nginx=$!
|
||||||
|
}
|
||||||
|
|
||||||
running() {
|
running() {
|
||||||
kill -0 "$1" 2>/dev/null
|
kill -0 "$1" 2>/dev/null
|
||||||
@@ -109,26 +116,47 @@ running() {
|
|||||||
# POSIX sh cannot wait for whichever of two children exits first, so
|
# POSIX sh cannot wait for whichever of two children exits first, so
|
||||||
# look once a second. The shell collects a child that has exited while
|
# look once a second. The shell collects a child that has exited while
|
||||||
# it runs sleep, and running() is false for that child from then on.
|
# it runs sleep, and running() is false for that child from then on.
|
||||||
|
wait_for_stop_or_exit() {
|
||||||
while [ -z "$stop_requested" ] && running "$backend" && running "$nginx"; do
|
while [ -z "$stop_requested" ] && running "$backend" && running "$nginx"; do
|
||||||
sleep 1
|
sleep 1
|
||||||
done
|
done
|
||||||
|
}
|
||||||
|
|
||||||
# Stop both, then wait until neither is left.
|
# Stop both, then wait until neither is left.
|
||||||
|
stop_both() {
|
||||||
kill -TERM "$backend" "$nginx" 2>/dev/null
|
kill -TERM "$backend" "$nginx" 2>/dev/null
|
||||||
while running "$backend" || running "$nginx"; do
|
while running "$backend" || running "$nginx"; do
|
||||||
sleep 1
|
sleep 1
|
||||||
done
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Success is a requested stop that both processes exited cleanly from.
|
||||||
|
exit_with_status() {
|
||||||
wait "$backend"
|
wait "$backend"
|
||||||
backend_status=$?
|
backend_status=$?
|
||||||
wait "$nginx"
|
wait "$nginx"
|
||||||
nginx_status=$?
|
nginx_status=$?
|
||||||
echo "entrypoint: netwatch-server exited $backend_status," \
|
echo "entrypoint: netwatch-server exited $backend_status," \
|
||||||
"nginx exited $nginx_status"
|
"nginx exited $nginx_status"
|
||||||
|
|
||||||
# Success is a requested stop that both processes exited cleanly from.
|
|
||||||
if [ -n "$stop_requested" ] && [ "$backend_status" -eq 0 ] &&
|
if [ -n "$stop_requested" ] && [ "$backend_status" -eq 0 ] &&
|
||||||
[ "$nginx_status" -eq 0 ]; then
|
[ "$nginx_status" -eq 0 ]; then
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
exit 1
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
check_port
|
||||||
|
write_trusted_proxies
|
||||||
|
prepare_data_dir
|
||||||
|
# A stop signal is only noted here; wait_for_stop_or_exit acts on it.
|
||||||
|
stop_requested=""
|
||||||
|
trap 'stop_requested=yes' TERM INT
|
||||||
|
start_backend
|
||||||
|
start_nginx
|
||||||
|
wait_for_stop_or_exit
|
||||||
|
stop_both
|
||||||
|
exit_with_status
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
|
|||||||
Reference in New Issue
Block a user