initial
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
# Lifecycle: pull, ordered start (deps → migrate → app), first admin, health,
|
||||
# plus update/down/logs/status/clean. Wraps `docker compose` with the project's
|
||||
# env file and generated compose file.
|
||||
|
||||
PROJECT="${MCMA_PROJECT:-mcma}"
|
||||
|
||||
dc() {
|
||||
docker compose \
|
||||
--project-name "$PROJECT" \
|
||||
--project-directory "$BOOTSTRAP_DIR" \
|
||||
--env-file "$ENV_FILE" \
|
||||
-f "$COMPOSE_FILE" "$@"
|
||||
}
|
||||
|
||||
# backing_services — the embedded dependencies present in the compose file that
|
||||
# must be healthy/complete before migrations (subset of db redis minio*).
|
||||
backing_services() {
|
||||
local all want s out=""
|
||||
all="$(dc config --services 2>/dev/null)"
|
||||
for want in db redis minio minio-setup; do
|
||||
while IFS= read -r s; do
|
||||
[[ "$s" == "$want" ]] && out+="$want "
|
||||
done <<<"$all"
|
||||
done
|
||||
printf '%s' "${out% }"
|
||||
}
|
||||
|
||||
# app_services — everything that is not a one-shot/backing dependency wait.
|
||||
ensure_media_dir() {
|
||||
# MEDIA_HOST_PATH is read from the generated env file.
|
||||
local p
|
||||
p="$(grep -E '^MEDIA_HOST_PATH=' "$ENV_FILE" | cut -d= -f2-)"
|
||||
[[ -n "$p" ]] || return 0
|
||||
# Resolve relative paths against the project directory (compose does too).
|
||||
[[ "$p" = /* ]] || p="${BOOTSTRAP_DIR}/${p#./}"
|
||||
mkdir -p "$p"
|
||||
}
|
||||
|
||||
lifecycle_pull() {
|
||||
ui_info "$(t pull_images "$(grep -E '^MCMA_IMAGE_TAG=' "$ENV_FILE" | cut -d= -f2-)")"
|
||||
ui_dim "$(t pull_hint)"
|
||||
dc pull
|
||||
}
|
||||
|
||||
# wait_api_healthy — poll the running API's liveness endpoint over the compose
|
||||
# network (no host port / TLS assumptions). Returns non-zero on timeout.
|
||||
wait_api_healthy() {
|
||||
ui_info "$(t checking_health)"
|
||||
dc run --rm --no-deps -T api python -c '
|
||||
import urllib.request, time, sys
|
||||
for _ in range(60):
|
||||
try:
|
||||
if urllib.request.urlopen("http://api:8000/health", timeout=2).status == 200:
|
||||
sys.exit(0)
|
||||
except Exception:
|
||||
pass
|
||||
time.sleep(2)
|
||||
sys.exit(1)
|
||||
'
|
||||
}
|
||||
|
||||
# lifecycle_start CREATE_ADMIN(yes|no)
|
||||
# Ordered, fail-loud startup. Never starts the backend over a broken DB.
|
||||
lifecycle_start() {
|
||||
local create_admin="${1:-no}"
|
||||
ensure_media_dir
|
||||
lifecycle_pull
|
||||
|
||||
local deps; deps="$(backing_services)"
|
||||
if [[ -n "$deps" ]]; then
|
||||
ui_info "$(t starting_deps)"
|
||||
# shellcheck disable=SC2086
|
||||
dc up -d --wait $deps
|
||||
fi
|
||||
|
||||
ui_info "$(t running_migrations)"
|
||||
if ! dc run --rm --no-deps -T api alembic upgrade head; then
|
||||
ui_err "$(t err_migrations_failed)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$create_admin" == "yes" ]]; then
|
||||
ui_info "$(t creating_admin)"
|
||||
# Password passed via --password to avoid interactive prompts; not echoed.
|
||||
dc run --rm --no-deps -T api mcma create-admin "$CFG_ADMIN_USER" --password "$CFG_ADMIN_PASS"
|
||||
fi
|
||||
|
||||
ui_info "$(t starting_app)"
|
||||
dc up -d
|
||||
|
||||
if ! wait_api_healthy; then
|
||||
ui_err "$(t err_health_timeout)"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# -- management commands ---------------------------------------------------
|
||||
lifecycle_update() {
|
||||
lifecycle_pull
|
||||
local deps; deps="$(backing_services)"
|
||||
if [[ -n "$deps" ]]; then
|
||||
# shellcheck disable=SC2086
|
||||
dc up -d --wait $deps
|
||||
fi
|
||||
ui_info "$(t running_migrations)"
|
||||
if ! dc run --rm --no-deps -T api alembic upgrade head; then
|
||||
ui_err "$(t err_migrations_failed)"; exit 1
|
||||
fi
|
||||
dc up -d
|
||||
wait_api_healthy || { ui_err "$(t err_health_timeout)"; exit 1; }
|
||||
ui_ok "$(t done_title)"
|
||||
}
|
||||
|
||||
lifecycle_up() { ensure_media_dir; dc up -d; }
|
||||
lifecycle_down() { dc down; }
|
||||
lifecycle_logs() { dc logs -f --tail=100; }
|
||||
|
||||
lifecycle_status() {
|
||||
dc ps
|
||||
echo
|
||||
if wait_api_healthy >/dev/null 2>&1; then ui_ok "API: ok"; else ui_warn "API: not ready"; fi
|
||||
}
|
||||
|
||||
lifecycle_clean() {
|
||||
dc down
|
||||
if ui_yesno "$(t clean_volumes_confirm)" "no"; then
|
||||
dc down -v
|
||||
fi
|
||||
if ui_yesno "$(t clean_confirm)" "yes"; then
|
||||
rm -f "$COMPOSE_FILE" "$CADDYFILE" "$ENV_FILE"
|
||||
ui_ok "$(t clean_done)"
|
||||
fi
|
||||
}
|
||||
Reference in New Issue
Block a user