diff --git a/maintenance/delete-orphan-services.sh b/maintenance/delete-orphan-services.sh new file mode 100755 index 0000000..b511449 --- /dev/null +++ b/maintenance/delete-orphan-services.sh @@ -0,0 +1,121 @@ +#!/usr/bin/env bash +set -euo pipefail + +APPFACTORY_ROOT="/opt/appfactory" +DB_FILE="$APPFACTORY_ROOT/data/appfactory/appfactory.db" +WORKSPACE_DIR="$APPFACTORY_ROOT/workspace" +DELETE_SCRIPT="$WORKSPACE_DIR/appfactory-tools/scripts/delete-app.sh" + +# Výchozí režim pouze vypisuje kandidáty. +DRY_RUN="${DRY_RUN:-1}" + +# Čerstvé adresáře nemažeme. Selhávající provisioning může ještě dobíhat. +MIN_AGE_HOURS="${MIN_AGE_HOURS:-24}" +MIN_AGE_MINUTES=$((MIN_AGE_HOURS * 60)) + +CORE_SERVICES=( + appfactory-tools + appfactory-portal + appfactory-worker + appfactory-monitor + appfactory-webhook + appfactory-infrastructure +) + +log() { + printf '%s %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" +} + +is_core_service() { + local candidate="$1" + local core + + for core in "${CORE_SERVICES[@]}"; do + if [ "$candidate" = "$core" ]; then + return 0 + fi + done + + return 1 +} + +if [ ! -f "$DB_FILE" ]; then + log "ERROR: Databáze neexistuje: $DB_FILE" + exit 1 +fi + +if [ ! -x "$DELETE_SCRIPT" ]; then + log "ERROR: Mazací skript není spustitelný: $DELETE_SCRIPT" + exit 1 +fi + +# Bez důvěryhodného zdroje pravdy nic nemažeme. +if ! sqlite3 "$DB_FILE" \ + "SELECT 1 FROM sqlite_master WHERE type='table' AND name='apps';" | + grep -qx 1; then + log "ERROR: Tabulka apps nebyla nalezena. Automatické mazání zastaveno." + exit 1 +fi + +mapfile -t REGISTERED_APPS < <( + sqlite3 "$DB_FILE" \ + "SELECT id FROM apps WHERE id IS NOT NULL AND trim(id) <> '' ORDER BY id;" +) + +is_registered_app() { + local candidate="$1" + local registered + + for registered in "${REGISTERED_APPS[@]}"; do + if [ "$candidate" = "$registered" ]; then + return 0 + fi + done + + return 1 +} + +found=0 + +while IFS= read -r app_dir; do + app_id="$(basename "$app_dir")" + + if is_core_service "$app_id"; then + continue + fi + + if is_registered_app "$app_id"; then + continue + fi + + # Nedotýkat se čerstvého workspace. + if ! find "$app_dir" -maxdepth 0 -mmin "+$MIN_AGE_MINUTES" | + grep -q .; then + continue + fi + + found=$((found + 1)) + log "ORPHAN candidate: $app_id" + + if [ "$DRY_RUN" = "1" ]; then + log "DRY-RUN: byl by spuštěn delete-app.sh $app_id" + continue + fi + + log "Deleting orphan: $app_id" + + if "$DELETE_SCRIPT" "$app_id"; then + log "Deleted: $app_id" + else + log "ERROR: Mazání selhalo: $app_id" + fi +done < <( + find "$WORKSPACE_DIR" \ + -mindepth 1 \ + -maxdepth 1 \ + -type d \ + -print | + sort +) + +log "Finished. Orphan candidates: $found; DRY_RUN=$DRY_RUN" \ No newline at end of file