Files

135 lines
4.2 KiB
Bash

#!/usr/bin/env bash
# Gemeinsame Konstanten und Hilfsfunktionen der deploy-Skripte (wird gesourced).
APP_USER=checkbot
APP_GROUP=checkbot
APP_DIR=/opt/checkbot
CONF_DIR=/etc/checkbot
DATA_DIR=/var/lib/checkbot
BACKUP_DIR=/var/backups/checkbot
ENV_FILE=$CONF_DIR/checkbot.env
VENV_DIR=$APP_DIR/.venv
SERVICE_NAME=checkbot
SYSTEMD_DIR=/etc/systemd/system
UNIT_FILES=(checkbot.service checkbot-backup.service checkbot-backup.timer)
DEFAULT_DB_FILE=$DATA_DIR/checkbot.db
DEFAULT_BIND_HOST=127.0.0.1
DEFAULT_BIND_PORT=8080
MIN_PYTHON="3.11"
HEALTH_WAIT_SECONDS=60
HEALTH_CURL_TIMEOUT=15
DEPLOYED_REV_FILE=$DATA_DIR/deployed-rev
COMMON_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
DEPLOY_DIR=$(dirname "$COMMON_DIR")
REPO_DIR=$(dirname "$DEPLOY_DIR")
shopt -u patsub_replacement 2>/dev/null || true
log() { printf '[checkbot] %s\n' "$*"; }
warn() { printf '[checkbot] WARNUNG: %s\n' "$*" >&2; }
die() { printf '[checkbot] FEHLER: %s\n' "$*" >&2; exit 1; }
require_root() {
[[ $EUID -eq 0 ]] || die "Bitte als root ausführen."
}
env_value() {
local key=$1 default=$2 line value=""
if [[ -r $ENV_FILE ]]; then
while IFS= read -r line || [[ -n $line ]]; do
if [[ $line == "$key="* ]]; then value=${line#*=}; fi
done < "$ENV_FILE"
fi
value=${value%\"}
value=${value#\"}
printf '%s' "${value:-$default}"
}
db_file() { env_value CHECKBOT_DB "$DEFAULT_DB_FILE"; }
health_url() {
local host port
host=$(env_value CHECKBOT_BIND_HOST "$DEFAULT_BIND_HOST")
port=$(env_value CHECKBOT_BIND_PORT "$DEFAULT_BIND_PORT")
case $host in 0.0.0.0|::|"") host=127.0.0.1 ;; esac
[[ $host == *:* ]] && host="[$host]"
printf 'http://%s:%s/health' "$host" "$port"
}
check_python_version() {
python3 -c "import sys; sys.exit(0 if sys.version_info >= tuple(map(int, '$MIN_PYTHON'.split('.'))) else 1)" \
|| die "Python $MIN_PYTHON oder neuer wird benötigt (Debian 12 oder 13)."
}
sync_code() {
[[ -f $REPO_DIR/requirements.txt && -d $REPO_DIR/app ]] \
|| die "Kein checkbot-Checkout unter $REPO_DIR (requirements.txt oder app/ fehlt)."
[[ $(realpath "$REPO_DIR") != "$(realpath -m "$APP_DIR")" ]] \
|| die "Das Skript läuft bereits aus $APP_DIR. Bitte aus dem Git-Checkout starten."
install -d -m 0755 -o root -g root "$APP_DIR"
rsync -a --delete --chown=root:root --chmod='u=rwX,go=rX' \
--exclude='.git' --exclude='/tests' --exclude='/.venv' --exclude='__pycache__' \
--exclude='*.pyc' --exclude='.pytest_cache' \
"$REPO_DIR/" "$APP_DIR/"
chmod 0755 "$APP_DIR"/deploy/*.sh "$APP_DIR/deploy/checkbot-cli" "$APP_DIR/deploy/checkmk/checkbot-local-check"
}
ensure_venv() {
if [[ ! -x $VENV_DIR/bin/python ]]; then
log "Lege virtuelle Umgebung an."
python3 -m venv "$VENV_DIR"
fi
log "Installiere Python-Abhängigkeiten."
PYTHONDONTWRITEBYTECODE=1 "$VENV_DIR/bin/pip" install --disable-pip-version-check --quiet \
-r "$APP_DIR/requirements.txt"
}
install_units() {
local unit changed=0
for unit in "${UNIT_FILES[@]}"; do
if ! cmp -s "$DEPLOY_DIR/systemd/$unit" "$SYSTEMD_DIR/$unit"; then
install -m 0644 -o root -g root "$DEPLOY_DIR/systemd/$unit" "$SYSTEMD_DIR/$unit"
changed=1
fi
done
if (( changed )); then
systemctl daemon-reload
log "systemd-Units aktualisiert."
fi
}
HEALTH_EVAL='
import json, sys
try:
checks = json.load(sys.stdin)["checks"]
db_ok = bool(checks["db"]["ok"])
except Exception:
sys.exit(2)
print(" ".join(sorted(n for n, c in checks.items() if not c.get("ok"))))
sys.exit(0 if db_ok else 1)
'
# /health liefert 503, solange nicht alles konfiguriert ist; der Start gilt als gelungen, wenn die DB-Prüfung ok ist.
wait_health() {
local url body bad deadline=$((SECONDS + HEALTH_WAIT_SECONDS))
url=$(health_url)
while (( SECONDS < deadline )); do
if body=$(curl -sS --max-time "$HEALTH_CURL_TIMEOUT" "$url" 2>/dev/null) \
&& bad=$(printf '%s' "$body" | python3 -I -c "$HEALTH_EVAL"); then
if [[ -z $bad ]]; then
log "Health-Check ok ($url)."
else
log "Bot läuft, DB ok. Teilchecks nicht ok: $bad (vor der Einrichtung normal, Details in der UI oder per curl $url)."
fi
return 0
fi
sleep 2
done
return 1
}
latest_backup() {
find "$BACKUP_DIR" -maxdepth 1 -type f -name 'checkbot-*.db' 2>/dev/null | sort | tail -n 1
}