116 lines
3.6 KiB
Bash
116 lines
3.6 KiB
Bash
# shellcheck shell=bash
|
|
# Shared helpers for Castopod ops on koopa — fail fast, never hang forever.
|
|
|
|
set -euo pipefail
|
|
|
|
# --- defaults (override via env) ---
|
|
: "${CP_BASEURL:=https://castopod.hacktivism.ch}"
|
|
: "${CP_COMPOSE_DIR:=/home/hernani/koopa-castopod}"
|
|
: "${CP_CONNECT_TIMEOUT:=10}" # seconds — TCP connect
|
|
: "${CP_MAX_TIME:=120}" # seconds — whole HTTP transfer
|
|
: "${CP_PULL_TIMEOUT:=600}" # seconds — image pull
|
|
: "${CP_HEALTH_TRIES:=30}" # health poll attempts
|
|
: "${CP_HEALTH_SLEEP:=5}" # seconds between polls
|
|
|
|
# curl that cannot hang forever
|
|
cp_curl() {
|
|
curl -sS \
|
|
--connect-timeout "${CP_CONNECT_TIMEOUT}" \
|
|
--max-time "${CP_MAX_TIME}" \
|
|
--retry 2 \
|
|
--retry-delay 2 \
|
|
--retry-connrefused \
|
|
"$@"
|
|
}
|
|
|
|
# HTTP status only (no hang)
|
|
cp_http_code() {
|
|
local url=$1
|
|
cp_curl -o /dev/null -w '%{http_code}' "$url" || echo "000"
|
|
}
|
|
|
|
# Run command with hard wall-clock limit (GNU coreutils timeout)
|
|
cp_timeout() {
|
|
local secs=$1
|
|
shift
|
|
if command -v timeout >/dev/null 2>&1; then
|
|
timeout --signal=TERM --kill-after=15s "${secs}" "$@"
|
|
else
|
|
# fallback: no timeout binary — still run, but warn
|
|
echo "WARN: timeout(1) missing; running without wall limit: $*" >&2
|
|
"$@"
|
|
fi
|
|
}
|
|
|
|
# Non-interactive answer stream for spark / CLI that prompts [y,n] or passwords.
|
|
# Usage: cp_yes | podman exec -i … php spark …
|
|
# Prefer SQL for activate when possible (spark prompts hang without TTY).
|
|
cp_yes() {
|
|
# enough y's for a few prompts; never block waiting for input
|
|
yes y 2>/dev/null | head -n 20
|
|
}
|
|
|
|
# Poll until URL returns expected code or give up
|
|
cp_wait_http() {
|
|
local url=$1
|
|
local want=${2:-200}
|
|
local i code
|
|
for ((i = 1; i <= CP_HEALTH_TRIES; i++)); do
|
|
code=$(cp_http_code "$url")
|
|
echo "health try $i/${CP_HEALTH_TRIES}: $url → $code"
|
|
if [[ "$code" == "$want" || "$code" =~ ^[23] ]]; then
|
|
return 0
|
|
fi
|
|
sleep "${CP_HEALTH_SLEEP}"
|
|
done
|
|
echo "ERROR: $url still not healthy after ${CP_HEALTH_TRIES} tries (last=$code)" >&2
|
|
return 1
|
|
}
|
|
|
|
# MariaDB password from compose .env (no hang if missing)
|
|
cp_mysql_password() {
|
|
local envf="${CP_COMPOSE_DIR}/.env"
|
|
[[ -f "$envf" ]] || { echo "ERROR: missing $envf" >&2; return 1; }
|
|
# shellcheck disable=SC1090
|
|
grep -E '^MYSQL_PASSWORD=' "$envf" | head -1 | cut -d= -f2-
|
|
}
|
|
|
|
cp_mysql() {
|
|
local pw
|
|
pw=$(cp_mysql_password)
|
|
podman exec koopa-castopod-mariadb \
|
|
mariadb -ucastopod -p"$pw" castopod "$@"
|
|
}
|
|
|
|
# Activate shield users without spark interactive prompt
|
|
cp_activate_users() {
|
|
cp_mysql -e "UPDATE cp_users SET active=1 WHERE username IN ('admin','ngi');"
|
|
}
|
|
|
|
# Session login for admin UI automation (uses users.env)
|
|
cp_admin_login() {
|
|
local cookie=${1:-/tmp/cp-cj}
|
|
local envf="${CP_COMPOSE_DIR}/users.env"
|
|
[[ -f "$envf" ]] || { echo "ERROR: missing $envf" >&2; return 1; }
|
|
# shellcheck disable=SC1090
|
|
source "$envf"
|
|
[[ -n "${ADMIN_PW:-}" ]] || { echo "ERROR: ADMIN_PW empty" >&2; return 1; }
|
|
|
|
rm -f "$cookie"
|
|
cp_curl -c "$cookie" -b "$cookie" "${CP_BASEURL}/cp-auth/login" -o /tmp/cp-login.html
|
|
local csrf
|
|
csrf=$(sed -n 's/.*name="csrf_test_name" value="\([^"]*\)".*/\1/p' /tmp/cp-login.html | head -1)
|
|
[[ -n "$csrf" ]] || { echo "ERROR: no CSRF on login page" >&2; return 1; }
|
|
|
|
local code
|
|
code=$(cp_curl -c "$cookie" -b "$cookie" -o /dev/null -w '%{http_code}' \
|
|
-X POST "${CP_BASEURL}/cp-auth/login" \
|
|
--data-urlencode "csrf_test_name=${csrf}" \
|
|
--data-urlencode "email=admin@castopod.hacktivism.ch" \
|
|
--data-urlencode "password=${ADMIN_PW}")
|
|
# 303 see other is success
|
|
if [[ "$code" != "303" && "$code" != "302" && "$code" != "200" ]]; then
|
|
echo "ERROR: login HTTP $code" >&2
|
|
return 1
|
|
fi
|
|
}
|