135 lines
4.2 KiB
Bash
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
|
|
}
|