95 lines
3.2 KiB
Bash
Executable File
95 lines
3.2 KiB
Bash
Executable File
#!/bin/sh
|
|
set -eu
|
|
|
|
ROOT=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)
|
|
ENV_FILE=${WNH_LOAD_ENV_FILE:-"$ROOT/output/runtime/load.env"}
|
|
LOAD_TOOLS_IMAGE=${WNH_LOAD_TOOLS_IMAGE:-who-need-help:load-tools}
|
|
PYTHON_RUNTIME_IMAGE=${WNH_PYTHON_RUNTIME_IMAGE:-who-need-help:python-runtime}
|
|
|
|
if [ ! -f "$ENV_FILE" ]; then
|
|
echo "Missing $ENV_FILE; no load-profile project was selected." >&2
|
|
exit 1
|
|
fi
|
|
|
|
set -a
|
|
# shellcheck source=/dev/null
|
|
. "$ENV_FILE"
|
|
set +a
|
|
|
|
: "${LOAD_PROJECT:?LOAD_PROJECT is missing from the generated load runtime environment}"
|
|
|
|
if [ "$LOAD_PROJECT" = who_need_help ]; then
|
|
echo "Refusing to stop the staging Compose project." >&2
|
|
exit 1
|
|
fi
|
|
|
|
case "$LOAD_PROJECT" in
|
|
*[!a-z0-9_-]* | '')
|
|
echo "LOAD_PROJECT contains unsupported characters." >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
cd "$ROOT"
|
|
docker compose \
|
|
--env-file "$ENV_FILE" \
|
|
-p "$LOAD_PROJECT" \
|
|
-f compose.yaml \
|
|
-f compose.load.yaml \
|
|
down --remove-orphans
|
|
|
|
# Optional observability and backup overlays create additional networks which
|
|
# are not present in the base load Compose file. Remove only unattached
|
|
# networks carrying this exact isolated project label.
|
|
for network_id in $(docker network ls -q \
|
|
--filter "label=com.docker.compose.project=$LOAD_PROJECT"); do
|
|
observed_project=$(docker network inspect --format \
|
|
'{{index .Labels "com.docker.compose.project"}}' "$network_id")
|
|
endpoints=$(docker network inspect --format '{{len .Containers}}' "$network_id")
|
|
|
|
if [ "$observed_project" != "$LOAD_PROJECT" ] || [ "$endpoints" != 0 ]; then
|
|
echo "Refusing unexpected or connected load-profile network: $network_id" >&2
|
|
exit 1
|
|
fi
|
|
|
|
docker network rm "$network_id" >/dev/null
|
|
done
|
|
|
|
if image_id=$(docker image inspect --format '{{.Id}}' "$LOAD_TOOLS_IMAGE" 2>/dev/null); then
|
|
if [ -z "$(docker ps -aq --filter "ancestor=$image_id")" ]; then
|
|
docker image rm "$LOAD_TOOLS_IMAGE" >/dev/null
|
|
fi
|
|
fi
|
|
|
|
# Prometheus and Grafana read run-scoped files under their container UIDs. Once
|
|
# every container and network for this exact isolated project is gone, restore
|
|
# the host owner and remove only that project's generated runtime directory.
|
|
# Without this step, an otherwise successful cleanup can leave empty UID-owned
|
|
# directories that the invoking user cannot remove.
|
|
observability_runtime="$ROOT/tmp/observability/$LOAD_PROJECT"
|
|
if [ -d "$observability_runtime" ]; then
|
|
if [ -n "$(docker ps -aq --filter "label=com.docker.compose.project=$LOAD_PROJECT")" ] ||
|
|
[ -n "$(docker network ls -q --filter "label=com.docker.compose.project=$LOAD_PROJECT")" ]; then
|
|
echo "Refusing to remove observability runtime while project resources remain." >&2
|
|
exit 1
|
|
fi
|
|
|
|
docker run --rm \
|
|
--user 0:0 \
|
|
--volume "$observability_runtime:/runtime" \
|
|
--entrypoint /bin/sh \
|
|
"$PYTHON_RUNTIME_IMAGE" \
|
|
-euc "chown -R $(id -u):$(id -g) /runtime; chmod -R u+rwX /runtime"
|
|
|
|
find "$observability_runtime" -xdev -depth -delete
|
|
fi
|
|
|
|
|
|
if image_id=$(docker image inspect --format '{{.Id}}' "$PYTHON_RUNTIME_IMAGE" 2>/dev/null); then
|
|
if [ -z "$(docker ps -aq --filter "ancestor=$image_id")" ]; then
|
|
docker image rm "$PYTHON_RUNTIME_IMAGE" >/dev/null
|
|
fi
|
|
fi
|
|
|
|
echo "Removed the isolated load-profile containers, networks, and generated observability runtime; its named volumes remain."
|