From 57d19c7df3d779066df8dfe699880a35f71d13ec Mon Sep 17 00:00:00 2001 From: Till Tomczak Date: Sun, 1 Jun 2025 13:11:59 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=89=20Improved=20backend=20functionali?= =?UTF-8?q?ty=20with=20new=20watchdog=20services=20and=20manager=20script?= =?UTF-8?q?=20=F0=9F=93=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/combined.sh | 251 ++++++++++- backend/kiosk-watchdog-python.service | 53 +++ backend/kiosk-watchdog.service | 233 +++++++--- backend/utils/watchdog_manager.py | 590 ++++++++++++++++++++++++++ 4 files changed, 1052 insertions(+), 75 deletions(-) create mode 100644 backend/kiosk-watchdog-python.service create mode 100644 backend/utils/watchdog_manager.py diff --git a/backend/combined.sh b/backend/combined.sh index a7d6d894..20b3f2b5 100644 --- a/backend/combined.sh +++ b/backend/combined.sh @@ -758,6 +758,84 @@ install_system_dependencies() { log "✅ System-Abhängigkeiten vollständig installiert" } +# =========================== WATCHDOG-SERVICES =========================== +create_watchdog_service() { + log "=== WATCHDOG-SERVICE KONFIGURATION ===" + + progress "Erstelle intelligenten Watchdog-Service..." + + # Prüfe Python-Dependencies für erweiterten Watchdog + local python_watchdog_available=false + if python3 -c "import psutil, requests" 2>/dev/null; then + python_watchdog_available=true + log "✅ Python-Dependencies für erweiterten Watchdog verfügbar" + else + warning "⚠️ Python-Dependencies fehlen - verwende Bash-Watchdog" + fi + + # Kopiere Watchdog-Service-Dateien + if [ -f "$CURRENT_DIR/kiosk-watchdog.service" ]; then + cp "$CURRENT_DIR/kiosk-watchdog.service" "/etc/systemd/system/kiosk-watchdog.service" + log "✅ Bash-Watchdog-Service installiert" + fi + + if [ "$python_watchdog_available" = true ] && [ -f "$CURRENT_DIR/kiosk-watchdog-python.service" ]; then + cp "$CURRENT_DIR/kiosk-watchdog-python.service" "/etc/systemd/system/kiosk-watchdog-python.service" + log "✅ Python-Watchdog-Service installiert" + + # Installiere Python-Dependencies falls nicht vorhanden + local pip_opts="--break-system-packages --trusted-host pypi.org --trusted-host pypi.python.org --trusted-host files.pythonhosted.org" + pip3 install $pip_opts psutil requests 2>/dev/null || warning "Python-Watchdog-Dependencies Installation fehlgeschlagen" + fi + + # Aktiviere bevorzugten Watchdog-Service + if [ "$python_watchdog_available" = true ]; then + progress "Aktiviere Python-Watchdog-Service..." + systemctl enable kiosk-watchdog-python.service || warning "Python-Watchdog Enable fehlgeschlagen" + systemctl disable kiosk-watchdog.service 2>/dev/null || true + log "✅ Python-Watchdog als primärer Service konfiguriert" + else + progress "Aktiviere Bash-Watchdog-Service..." + systemctl enable kiosk-watchdog.service || warning "Bash-Watchdog Enable fehlgeschlagen" + systemctl disable kiosk-watchdog-python.service 2>/dev/null || true + log "✅ Bash-Watchdog als primärer Service konfiguriert" + fi + + log "✅ Watchdog-Service erfolgreich konfiguriert" +} + +start_watchdog_service() { + log "=== WATCHDOG-SERVICE START ===" + + # Prüfe welcher Watchdog-Service aktiviert ist + if systemctl is-enabled --quiet kiosk-watchdog-python.service 2>/dev/null; then + progress "Starte Python-Watchdog-Service..." + systemctl start kiosk-watchdog-python.service || warning "Python-Watchdog Start fehlgeschlagen" + + sleep 5 + if systemctl is-active --quiet kiosk-watchdog-python.service; then + log "✅ Python-Watchdog-Service läuft erfolgreich" + else + warning "⚠️ Python-Watchdog-Service läuft nicht - prüfen Sie: journalctl -u kiosk-watchdog-python -f" + fi + elif systemctl is-enabled --quiet kiosk-watchdog.service 2>/dev/null; then + progress "Starte Bash-Watchdog-Service..." + systemctl start kiosk-watchdog.service || warning "Bash-Watchdog Start fehlgeschlagen" + + sleep 5 + if systemctl is-active --quiet kiosk-watchdog.service; then + log "✅ Bash-Watchdog-Service läuft erfolgreich" + else + warning "⚠️ Bash-Watchdog-Service läuft nicht - prüfen Sie: journalctl -u kiosk-watchdog -f" + fi + else + warning "⚠️ Kein Watchdog-Service aktiviert" + fi + + log "✅ Watchdog-Service-Start abgeschlossen" +} + +# =========================== AKTUALISIERTE HAUPTFUNKTIONEN =========================== setup_production_kiosk() { log "=== PRODUKTIONS-KIOSK SETUP ===" @@ -771,8 +849,10 @@ setup_production_kiosk() { install_npm_dependencies create_https_service create_kiosk_service + create_watchdog_service configure_kiosk_environment enable_and_start_services + start_watchdog_service run_system_tests log "✅ PRODUKTIONS-KIOSK ERFOLGREICH EINGERICHTET" @@ -791,6 +871,17 @@ show_main_menu() { echo -e "${YELLOW}HTTPS-URL:${NC} $HTTPS_URL" echo -e "${YELLOW}Kiosk-Benutzer:${NC} $KIOSK_USER" echo -e "${YELLOW}System:${NC} $(uname -m) - $(cat /etc/debian_version 2>/dev/null || echo 'Unbekannt')" + echo "" + + # Watchdog-Status anzeigen + if systemctl is-active --quiet kiosk-watchdog-python.service 2>/dev/null; then + echo -e "${GREEN}🔍 Watchdog:${NC} Python-Watchdog aktiv" + elif systemctl is-active --quiet kiosk-watchdog.service 2>/dev/null; then + echo -e "${GREEN}🔍 Watchdog:${NC} Bash-Watchdog aktiv" + else + echo -e "${RED}🔍 Watchdog:${NC} Nicht aktiv" + fi + echo "" echo -e "${PURPLE}Installationsoptionen:${NC}" echo "" @@ -804,6 +895,7 @@ show_main_menu() { echo -e " → Installiert minimale X11-Umgebung" echo -e " → Erstellt SSL-Zertifikate automatisch" echo -e " → Konfiguriert Autologin und Chromium-Kiosk" + echo -e " → ${CYAN}Intelligenter Watchdog-Service${NC}" echo -e " → ${YELLOW}NEUSTART ERFORDERLICH!${NC}" echo "" echo -e "${GREEN}3)${NC} Nur SSL-Zertifikate generieren" @@ -811,17 +903,20 @@ show_main_menu() { echo -e " → Fügt Zertifikate zum System CA-Store hinzu" echo "" echo -e "${GREEN}4)${NC} Services verwalten" - echo -e " → Start/Stop/Restart HTTPS und Kiosk Services" + echo -e " → Start/Stop/Restart HTTPS, Kiosk und Watchdog Services" echo -e " → Service-Status anzeigen" + echo -e " → ${CYAN}Erweiterte Watchdog-Verwaltung${NC}" echo "" echo -e "${GREEN}5)${NC} System-Tests ausführen" echo -e " → Prüft Installation und Konfiguration" echo -e " → Testet HTTPS-Erreichbarkeit" + echo -e " → Watchdog-Funktionalität testen" echo "" echo -e "${RED}0)${NC} Beenden" echo "" echo -e "${RED}⚠️ WARNUNG: Option 2 macht das System zu einem reinen Kiosk!${NC}" echo -e "${GREEN}🔐 HTTPS: Automatische SSL-Zertifikat-Generierung${NC}" + echo -e "${CYAN}🔍 WATCHDOG: Intelligente Python/Bash-basierte Überwachung${NC}" echo -e "${BLUE}=================================================================${NC}" echo -n "Ihre Wahl [0-5]: " } @@ -836,11 +931,12 @@ manage_services_menu() { echo -e "${GREEN}3)${NC} HTTPS-Service neustarten" echo -e "${GREEN}4)${NC} Kiosk-Service starten" echo -e "${GREEN}5)${NC} Kiosk-Service stoppen" - echo -e "${GREEN}6)${NC} Service-Status anzeigen" - echo -e "${GREEN}7)${NC} Service-Logs anzeigen" + echo -e "${GREEN}6)${NC} Watchdog-Service verwalten" + echo -e "${GREEN}7)${NC} Service-Status anzeigen" + echo -e "${GREEN}8)${NC} Service-Logs anzeigen" echo -e "${RED}0)${NC} Zurück zum Hauptmenü" echo "" - echo -n "Ihre Wahl [0-7]: " + echo -n "Ihre Wahl [0-8]: " read -r choice @@ -866,18 +962,163 @@ manage_services_menu() { echo -e "${YELLOW}Kiosk-Service gestoppt${NC}" ;; 6) + manage_watchdog_services + ;; + 7) echo -e "${BLUE}=== SERVICE-STATUS ===${NC}" systemctl status "${HTTPS_SERVICE_NAME}.service" --no-pager || true echo "" systemctl status "${KIOSK_SERVICE_NAME}.service" --no-pager || true + echo "" + # Watchdog-Status + if systemctl is-enabled --quiet kiosk-watchdog-python.service 2>/dev/null; then + systemctl status kiosk-watchdog-python.service --no-pager || true + elif systemctl is-enabled --quiet kiosk-watchdog.service 2>/dev/null; then + systemctl status kiosk-watchdog.service --no-pager || true + fi ;; - 7) + 8) echo -e "${BLUE}=== SERVICE-LOGS (letzte 20 Zeilen) ===${NC}" echo -e "${CYAN}HTTPS-Service:${NC}" journalctl -u "${HTTPS_SERVICE_NAME}.service" -n 20 --no-pager || true echo "" echo -e "${CYAN}Kiosk-Service:${NC}" journalctl -u "${KIOSK_SERVICE_NAME}.service" -n 20 --no-pager || true + echo "" + echo -e "${CYAN}Watchdog-Service:${NC}" + if systemctl is-active --quiet kiosk-watchdog-python.service 2>/dev/null; then + journalctl -u kiosk-watchdog-python.service -n 20 --no-pager || true + elif systemctl is-active --quiet kiosk-watchdog.service 2>/dev/null; then + journalctl -u kiosk-watchdog.service -n 20 --no-pager || true + fi + ;; + 0) + break + ;; + *) + echo -e "${RED}Ungültige Eingabe${NC}" + ;; + esac + + echo "" + echo -e "${YELLOW}Drücken Sie Enter, um fortzufahren...${NC}" + read -r + done +} + +manage_watchdog_services() { + while true; do + clear + echo -e "${BLUE}=== WATCHDOG-SERVICE MANAGEMENT ===${NC}" + echo "" + + # Status anzeigen + if systemctl is-active --quiet kiosk-watchdog-python.service 2>/dev/null; then + echo -e "${GREEN}✅ Python-Watchdog aktiv${NC}" + elif systemctl is-enabled --quiet kiosk-watchdog-python.service 2>/dev/null; then + echo -e "${YELLOW}⚠️ Python-Watchdog aktiviert aber nicht laufend${NC}" + else + echo -e "${RED}❌ Python-Watchdog nicht aktiviert${NC}" + fi + + if systemctl is-active --quiet kiosk-watchdog.service 2>/dev/null; then + echo -e "${GREEN}✅ Bash-Watchdog aktiv${NC}" + elif systemctl is-enabled --quiet kiosk-watchdog.service 2>/dev/null; then + echo -e "${YELLOW}⚠️ Bash-Watchdog aktiviert aber nicht laufend${NC}" + else + echo -e "${RED}❌ Bash-Watchdog nicht aktiviert${NC}" + fi + + echo "" + echo -e "${GREEN}1)${NC} Python-Watchdog aktivieren und starten" + echo -e "${GREEN}2)${NC} Bash-Watchdog aktivieren und starten" + echo -e "${GREEN}3)${NC} Aktiven Watchdog stoppen" + echo -e "${GREEN}4)${NC} Aktiven Watchdog neustarten" + echo -e "${GREEN}5)${NC} Watchdog-Logs anzeigen" + echo -e "${GREEN}6)${NC} Watchdog-Konfiguration testen" + echo -e "${RED}0)${NC} Zurück" + echo "" + echo -n "Ihre Wahl [0-6]: " + + read -r choice + + case $choice in + 1) + # Python-Watchdog aktivieren + systemctl stop kiosk-watchdog.service 2>/dev/null || true + systemctl disable kiosk-watchdog.service 2>/dev/null || true + systemctl enable kiosk-watchdog-python.service + systemctl start kiosk-watchdog-python.service + echo -e "${GREEN}Python-Watchdog aktiviert und gestartet${NC}" + ;; + 2) + # Bash-Watchdog aktivieren + systemctl stop kiosk-watchdog-python.service 2>/dev/null || true + systemctl disable kiosk-watchdog-python.service 2>/dev/null || true + systemctl enable kiosk-watchdog.service + systemctl start kiosk-watchdog.service + echo -e "${GREEN}Bash-Watchdog aktiviert und gestartet${NC}" + ;; + 3) + # Aktiven Watchdog stoppen + systemctl stop kiosk-watchdog-python.service 2>/dev/null || true + systemctl stop kiosk-watchdog.service 2>/dev/null || true + echo -e "${YELLOW}Watchdog-Services gestoppt${NC}" + ;; + 4) + # Aktiven Watchdog neustarten + if systemctl is-enabled --quiet kiosk-watchdog-python.service 2>/dev/null; then + systemctl restart kiosk-watchdog-python.service + echo -e "${GREEN}Python-Watchdog neugestartet${NC}" + elif systemctl is-enabled --quiet kiosk-watchdog.service 2>/dev/null; then + systemctl restart kiosk-watchdog.service + echo -e "${GREEN}Bash-Watchdog neugestartet${NC}" + else + echo -e "${RED}Kein Watchdog-Service aktiviert${NC}" + fi + ;; + 5) + # Watchdog-Logs anzeigen + echo -e "${BLUE}=== WATCHDOG-LOGS ===${NC}" + if systemctl is-active --quiet kiosk-watchdog-python.service 2>/dev/null; then + echo -e "${CYAN}Python-Watchdog (systemd):${NC}" + journalctl -u kiosk-watchdog-python.service -n 30 --no-pager || true + echo "" + echo -e "${CYAN}Python-Watchdog (Datei):${NC}" + tail -n 20 /var/log/kiosk-watchdog-python.log 2>/dev/null || echo "Log-Datei nicht gefunden" + elif systemctl is-active --quiet kiosk-watchdog.service 2>/dev/null; then + echo -e "${CYAN}Bash-Watchdog:${NC}" + journalctl -u kiosk-watchdog.service -n 30 --no-pager || true + echo "" + tail -n 20 /var/log/kiosk-watchdog.log 2>/dev/null || echo "Log-Datei nicht gefunden" + else + echo -e "${RED}Kein aktiver Watchdog-Service${NC}" + fi + ;; + 6) + # Watchdog-Konfiguration testen + echo -e "${BLUE}=== WATCHDOG-KONFIGURATION TEST ===${NC}" + + # Teste Python-Watchdog + if python3 -c "import sys; sys.path.insert(0, '$APP_DIR'); from utils.watchdog_manager import WatchdogManager; print('✅ Python-Watchdog importierbar')" 2>/dev/null; then + echo -e "${GREEN}✅ Python-Watchdog-Konfiguration OK${NC}" + else + echo -e "${RED}❌ Python-Watchdog-Konfiguration fehlerhaft${NC}" + fi + + # Teste SSL-Zertifikate + if [ -f "$APP_DIR/certs/localhost/localhost.crt" ]; then + echo -e "${GREEN}✅ SSL-Zertifikat vorhanden${NC}" + else + echo -e "${RED}❌ SSL-Zertifikat fehlt${NC}" + fi + + # Teste HTTPS-Erreichbarkeit + if curl -k -s --connect-timeout 5 "$HTTPS_URL" >/dev/null 2>&1; then + echo -e "${GREEN}✅ HTTPS Backend erreichbar${NC}" + else + echo -e "${RED}❌ HTTPS Backend nicht erreichbar${NC}" + fi ;; 0) break diff --git a/backend/kiosk-watchdog-python.service b/backend/kiosk-watchdog-python.service new file mode 100644 index 00000000..8208c853 --- /dev/null +++ b/backend/kiosk-watchdog-python.service @@ -0,0 +1,53 @@ +[Unit] +Description=MYP Kiosk Watchdog Service - Python-basierte intelligente Überwachung +Documentation=https://github.com/MYP-Druckerverwaltung +After=multi-user.target myp-https.service +Wants=myp-https.service + +[Service] +Type=simple +User=root +Restart=always +RestartSec=30 +TimeoutStartSec=60 +TimeoutStopSec=30 + +# Python-basierter Watchdog mit erweiterten Features +WorkingDirectory=/opt/myp +ExecStartPre=/usr/bin/python3 -c "import psutil, requests; print('Python-Dependencies verfügbar')" +ExecStart=/usr/bin/python3 /opt/myp/utils/watchdog_manager.py --app-dir /opt/myp --daemon + +# Umgebungsvariablen für Python-Watchdog +Environment=PYTHONPATH=/opt/myp +Environment=PYTHONUNBUFFERED=1 +Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +Environment=DISPLAY=:0 +Environment=SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt +Environment=LC_ALL=C.UTF-8 +Environment=LANG=C.UTF-8 + +# Logging-Konfiguration +StandardOutput=journal +StandardError=journal +SyslogIdentifier=myp-watchdog-python + +# Sicherheitseinstellungen +NoNewPrivileges=false +PrivateTmp=false +ProtectSystem=strict +ReadWritePaths=/var/log +ReadWritePaths=/opt/myp +ReadWritePaths=/home/kiosk +ReadWritePaths=/proc/sys/vm +ReadWritePaths=/tmp + +# Resource-Limits für Python-Prozess +MemoryMax=512M +CPUQuota=50% + +# Restart-Verhalten bei Fehlern +StartLimitBurst=5 +StartLimitInterval=300 + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/backend/kiosk-watchdog.service b/backend/kiosk-watchdog.service index 40693121..e618d9e9 100644 --- a/backend/kiosk-watchdog.service +++ b/backend/kiosk-watchdog.service @@ -1,5 +1,5 @@ [Unit] -Description=MYP Kiosk Watchdog Service - Überwacht HTTPS Backend und Kiosk-Browser +Description=MYP Kiosk Watchdog Service - Intelligente Überwachung für HTTPS Backend und Kiosk-Browser Documentation=https://github.com/MYP-Druckerverwaltung After=multi-user.target myp-https.service Wants=myp-https.service @@ -9,104 +9,197 @@ Type=simple User=root Restart=always RestartSec=30 +TimeoutStartSec=60 +TimeoutStopSec=30 + +# Intelligentes Watchdog-Skript mit modularer Struktur ExecStart=/bin/bash -c '\ - while true; do \ - # Prüfe HTTPS Backend-Service (Port 443) \ - if ! systemctl is-active --quiet myp-https; then \ - echo "$(date): HTTPS Backend-Service nicht aktiv - starte neu" >> /var/log/kiosk-watchdog.log; \ - systemctl start myp-https; \ - sleep 10; \ - fi; \ - \ - # Prüfe HTTPS Backend-Erreichbarkeit (Port 443) \ - if ! curl -k -s --connect-timeout 5 https://localhost:443 >/dev/null 2>&1; then \ - echo "$(date): HTTPS Backend nicht erreichbar - starte Service neu" >> /var/log/kiosk-watchdog.log; \ - systemctl restart myp-https; \ - sleep 15; \ - fi; \ - \ - # Prüfe SSL-Zertifikat-Gültigkeit \ - if [ -f /opt/myp/certs/localhost/localhost.crt ]; then \ - if ! openssl x509 -in /opt/myp/certs/localhost/localhost.crt -noout -checkend 86400 >/dev/null 2>&1; then \ - echo "$(date): SSL-Zertifikat läuft ab - regeneriere Zertifikat" >> /var/log/kiosk-watchdog.log; \ - python3 -c "import sys; sys.path.insert(0, \"/opt/myp\"); from utils.ssl_config import ensure_ssl_certificates; ensure_ssl_certificates(\"/opt/myp\", True)" || true; \ - systemctl restart myp-https; \ - sleep 10; \ - fi; \ + # === KONFIGURATION === \ + readonly HTTPS_SERVICE="myp-https" \ + readonly KIOSK_SERVICE="myp-kiosk" \ + readonly KIOSK_USER="kiosk" \ + readonly HTTPS_URL="https://localhost:443" \ + readonly APP_DIR="/opt/myp" \ + readonly LOG_FILE="/var/log/kiosk-watchdog.log" \ + readonly CHECK_INTERVAL=30 \ + readonly HTTPS_TIMEOUT=10 \ + readonly RESTART_DELAY=15 \ + readonly MAX_MEMORY_PERCENT=85 \ + readonly CERT_EXPIRE_DAYS=7 \ + \ + # === LOGGING-FUNKTIONEN === \ + log_info() { echo "$(date "+%Y-%m-%d %H:%M:%S") [INFO] $1" >> "$LOG_FILE"; } \ + log_warn() { echo "$(date "+%Y-%m-%d %H:%M:%S") [WARN] $1" >> "$LOG_FILE"; } \ + log_error() { echo "$(date "+%Y-%m-%d %H:%M:%S") [ERROR] $1" >> "$LOG_FILE"; } \ + \ + # === HILFSFUNKTIONEN === \ + is_service_active() { systemctl is-active --quiet "$1"; } \ + is_service_enabled() { systemctl is-enabled --quiet "$1"; } \ + restart_service() { \ + log_info "Starte Service neu: $1"; \ + systemctl restart "$1" && sleep "$RESTART_DELAY" || log_error "Service-Neustart fehlgeschlagen: $1"; \ + } \ + \ + check_https_connectivity() { \ + curl -k -s --connect-timeout "$HTTPS_TIMEOUT" --max-time "$HTTPS_TIMEOUT" "$HTTPS_URL" >/dev/null 2>&1; \ + } \ + \ + check_ssl_certificate() { \ + local cert_file="$APP_DIR/certs/localhost/localhost.crt" \ + [ -f "$cert_file" ] && openssl x509 -in "$cert_file" -noout -checkend $((86400 * CERT_EXPIRE_DAYS)) >/dev/null 2>&1; \ + } \ + \ + regenerate_ssl_certificate() { \ + log_warn "Regeneriere SSL-Zertifikat..."; \ + if python3 -c "import sys; sys.path.insert(0, \"$APP_DIR\"); from utils.ssl_config import ensure_ssl_certificates; ensure_ssl_certificates(\"$APP_DIR\", True)" 2>/dev/null; then \ + log_info "SSL-Zertifikat erfolgreich regeneriert"; \ + restart_service "$HTTPS_SERVICE"; \ else \ - echo "$(date): SSL-Zertifikat fehlt - generiere neues Zertifikat" >> /var/log/kiosk-watchdog.log; \ - python3 -c "import sys; sys.path.insert(0, \"/opt/myp\"); from utils.ssl_config import ensure_ssl_certificates; ensure_ssl_certificates(\"/opt/myp\")" || true; \ - systemctl restart myp-https; \ - sleep 10; \ + log_error "SSL-Zertifikat-Regenerierung fehlgeschlagen"; \ + fi \ + } \ + \ + check_kiosk_user_session() { \ + pgrep -u "$KIOSK_USER" >/dev/null 2>&1; \ + } \ + \ + check_chromium_process() { \ + pgrep -u "$KIOSK_USER" -f "chromium.*kiosk" >/dev/null 2>&1; \ + } \ + \ + check_x_server() { \ + pgrep -f "X.*:0" >/dev/null 2>&1; \ + } \ + \ + check_display_availability() { \ + [ -n "$(DISPLAY=:0 xdpyinfo 2>/dev/null)" ]; \ + } \ + \ + get_memory_usage() { \ + free | awk "/^Mem:/ {printf \"%.1f\", \$3/\$2 * 100.0}"; \ + } \ + \ + cleanup_system_resources() { \ + log_info "Bereinige Systemressourcen (Speichernutzung: $(get_memory_usage)%)"; \ + \ + # Browser-Cache bereinigen \ + rm -rf "/home/$KIOSK_USER/.chromium-kiosk/Default/Cache"/* 2>/dev/null || true; \ + rm -rf "/home/$KIOSK_USER/.cache"/* 2>/dev/null || true; \ + \ + # Temporäre Dateien bereinigen \ + find "/tmp" -type f -atime +1 -delete 2>/dev/null || true; \ + find "$APP_DIR/uploads/temp" -type f -mtime +1 -delete 2>/dev/null || true; \ + \ + # System-Cache leeren \ + sync; \ + echo 3 > /proc/sys/vm/drop_caches 2>/dev/null || true; \ + \ + log_info "Systemressourcen bereinigt - neue Speichernutzung: $(get_memory_usage)%"; \ + } \ + \ + restart_kiosk_session() { \ + log_warn "Starte Kiosk-Session neu..."; \ + \ + # Beende alle Kiosk-Prozesse sanft \ + pkill -u "$KIOSK_USER" -TERM 2>/dev/null || true; \ + sleep 5; \ + \ + # Erzwinge Beendigung falls nötig \ + pkill -u "$KIOSK_USER" -KILL 2>/dev/null || true; \ + sleep 2; \ + \ + # Starte Getty-Service neu für Autologin \ + systemctl restart getty@tty1.service; \ + sleep "$RESTART_DELAY"; \ + \ + log_info "Kiosk-Session neugestartet"; \ + } \ + \ + # === HAUPTÜBERWACHUNGSSCHLEIFE === \ + log_info "Kiosk-Watchdog gestartet (PID: $$)"; \ + \ + while true; do \ + # === HTTPS BACKEND ÜBERWACHUNG === \ + if ! is_service_active "$HTTPS_SERVICE"; then \ + log_error "HTTPS-Service nicht aktiv"; \ + restart_service "$HTTPS_SERVICE"; \ + elif ! check_https_connectivity; then \ + log_error "HTTPS Backend nicht erreichbar"; \ + restart_service "$HTTPS_SERVICE"; \ fi; \ \ - # Prüfe Kiosk-Benutzer Session \ - if ! pgrep -u kiosk > /dev/null; then \ - echo "$(date): Kiosk-Benutzer nicht angemeldet - prüfe Autologin" >> /var/log/kiosk-watchdog.log; \ - # Versuche getty@tty1 Service zu restarten für Autologin \ - systemctl restart getty@tty1.service; \ - sleep 15; \ + # === SSL-ZERTIFIKAT ÜBERWACHUNG === \ + if ! check_ssl_certificate; then \ + if [ -f "$APP_DIR/certs/localhost/localhost.crt" ]; then \ + log_warn "SSL-Zertifikat läuft in $CERT_EXPIRE_DAYS Tagen ab"; \ + else \ + log_error "SSL-Zertifikat fehlt"; \ + fi; \ + regenerate_ssl_certificate; \ fi; \ \ - # Prüfe Chromium Kiosk-Prozess \ - if pgrep -u kiosk > /dev/null && ! pgrep -u kiosk -f "chromium.*kiosk" > /dev/null; then \ - echo "$(date): Chromium-Kiosk nicht gefunden aber Kiosk-User aktiv - starte Browser" >> /var/log/kiosk-watchdog.log; \ - # Versuche Kiosk-Service zu starten \ - systemctl --user start myp-kiosk 2>/dev/null || true; \ - sleep 10; \ + # === KIOSK-SESSION ÜBERWACHUNG === \ + if ! check_kiosk_user_session; then \ + log_error "Kiosk-Benutzer-Session nicht aktiv"; \ + restart_kiosk_session; \ + elif ! check_x_server; then \ + log_error "X-Server nicht verfügbar"; \ + restart_kiosk_session; \ + elif ! check_display_availability; then \ + log_error "Display :0 nicht verfügbar"; \ + restart_kiosk_session; \ + elif ! check_chromium_process; then \ + log_warn "Chromium-Kiosk-Prozess nicht gefunden"; \ + if is_service_enabled "$KIOSK_SERVICE"; then \ + systemctl --user start "$KIOSK_SERVICE" 2>/dev/null || true; \ + else \ + sudo -u "$KIOSK_USER" DISPLAY=:0 chromium --kiosk --no-sandbox --ignore-certificate-errors "$HTTPS_URL" >/dev/null 2>&1 & \ + fi; \ + sleep "$RESTART_DELAY"; \ fi; \ \ - # Prüfe X-Server für Kiosk-Display \ - if pgrep -u kiosk > /dev/null && ! pgrep -f "X.*:0" > /dev/null; then \ - echo "$(date): X-Server nicht gefunden aber Kiosk-User aktiv - starte X" >> /var/log/kiosk-watchdog.log; \ - # Versuche X-Server über Kiosk-User zu starten \ - sudo -u kiosk DISPLAY=:0 startx 2>/dev/null & \ - sleep 15; \ + # === SYSTEMRESSOURCEN ÜBERWACHUNG === \ + memory_usage=$(get_memory_usage); \ + if (( $(echo "$memory_usage > $MAX_MEMORY_PERCENT" | bc -l 2>/dev/null || echo 0) )); then \ + log_warn "Hohe Speichernutzung: ${memory_usage}%"; \ + cleanup_system_resources; \ fi; \ \ - # Prüfe Display-Verfügbarkeit \ - if pgrep -u kiosk > /dev/null && [ -z "$(DISPLAY=:0 xdpyinfo 2>/dev/null)" ]; then \ - echo "$(date): Display :0 nicht verfügbar - starte X-Session neu" >> /var/log/kiosk-watchdog.log; \ - # Beende alle X-Prozesse des Kiosk-Users und starte neu \ - pkill -u kiosk -f "X" 2>/dev/null || true; \ - sleep 5; \ - sudo -u kiosk DISPLAY=:0 startx 2>/dev/null & \ - sleep 15; \ + # === LOG-ROTATION === \ + if [ -f "$LOG_FILE" ] && [ $(stat -c%s "$LOG_FILE" 2>/dev/null || echo 0) -gt 10485760 ]; then \ + tail -n 1000 "$LOG_FILE" > "${LOG_FILE}.tmp" && mv "${LOG_FILE}.tmp" "$LOG_FILE"; \ + log_info "Log-Datei rotiert (>10MB)"; \ fi; \ \ - # Prüfe Systemressourcen und bereinige bei Bedarf \ - MEMORY_USAGE=$(free | grep Mem | awk "{print (\$3/\$2) * 100.0}"); \ - if (( $(echo "$MEMORY_USAGE > 90" | bc -l) )); then \ - echo "$(date): Hohe Speichernutzung ($MEMORY_USAGE%) - bereinige System" >> /var/log/kiosk-watchdog.log; \ - # Bereinige Browser-Cache \ - rm -rf /home/kiosk/.chromium-kiosk/Default/Cache/* 2>/dev/null || true; \ - rm -rf /home/kiosk/.cache/* 2>/dev/null || true; \ - # Garbage Collection \ - sync; \ - echo 3 > /proc/sys/vm/drop_caches 2>/dev/null || true; \ - fi; \ - \ - # Warte 30 Sekunden vor nächster Prüfung \ - sleep 30; \ + # Warte bis zur nächsten Prüfung \ + sleep "$CHECK_INTERVAL"; \ done' -# Umgebungsvariablen für HTTPS-Überwachung +# Umgebungsvariablen für optimierte Überwachung Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin Environment=DISPLAY=:0 Environment=PYTHONPATH=/opt/myp Environment=SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt +Environment=LC_ALL=C.UTF-8 +Environment=LANG=C.UTF-8 -# Logging +# Logging-Konfiguration StandardOutput=append:/var/log/kiosk-watchdog.log StandardError=append:/var/log/kiosk-watchdog.log # Sicherheitseinstellungen NoNewPrivileges=false PrivateTmp=false +ProtectSystem=strict ReadWritePaths=/var/log ReadWritePaths=/opt/myp ReadWritePaths=/home/kiosk ReadWritePaths=/proc/sys/vm +ReadWritePaths=/tmp + +# Resource-Limits +MemoryMax=256M +CPUQuota=25% [Install] WantedBy=multi-user.target \ No newline at end of file diff --git a/backend/utils/watchdog_manager.py b/backend/utils/watchdog_manager.py new file mode 100644 index 00000000..c8eab579 --- /dev/null +++ b/backend/utils/watchdog_manager.py @@ -0,0 +1,590 @@ +#!/usr/bin/env python3 +""" +Intelligenter Watchdog-Manager für MYP Druckerverwaltung +Erweiterte Überwachung mit Python für bessere Fehlerbehandlung und Logging +Optimiert für Debian/Linux-Systeme im Kiosk-Modus +""" + +import os +import sys +import time +import json +import logging +import subprocess +import threading +import signal +from pathlib import Path +from datetime import datetime, timedelta +from typing import Dict, List, Optional, Callable +import psutil +import requests +from urllib3.exceptions import InsecureRequestWarning + +# SSL-Warnungen unterdrücken für localhost +requests.packages.urllib3.disable_warnings(InsecureRequestWarning) + +class WatchdogConfig: + """Konfiguration für den Watchdog-Manager""" + + def __init__(self, app_dir: str = "/opt/myp"): + self.app_dir = Path(app_dir) + self.config_file = self.app_dir / "config" / "watchdog.json" + + # Standard-Konfiguration + self.defaults = { + "https_service": "myp-https", + "kiosk_service": "myp-kiosk", + "kiosk_user": "kiosk", + "https_url": "https://localhost:443", + "check_interval": 30, + "https_timeout": 10, + "restart_delay": 15, + "max_memory_percent": 85, + "cert_expire_days": 7, + "log_rotation_size_mb": 10, + "max_restart_attempts": 3, + "restart_cooldown": 300, + "enable_auto_cleanup": True, + "enable_performance_monitoring": True + } + + self.config = self.load_config() + + def load_config(self) -> Dict: + """Lädt Konfiguration aus Datei oder verwendet Defaults""" + try: + if self.config_file.exists(): + with open(self.config_file, 'r', encoding='utf-8') as f: + config = json.load(f) + # Merge mit Defaults + merged = self.defaults.copy() + merged.update(config) + return merged + else: + self.save_config(self.defaults) + return self.defaults.copy() + except Exception as e: + logging.error(f"Fehler beim Laden der Konfiguration: {e}") + return self.defaults.copy() + + def save_config(self, config: Dict) -> None: + """Speichert Konfiguration in Datei""" + try: + self.config_file.parent.mkdir(parents=True, exist_ok=True) + with open(self.config_file, 'w', encoding='utf-8') as f: + json.dump(config, f, indent=2, ensure_ascii=False) + except Exception as e: + logging.error(f"Fehler beim Speichern der Konfiguration: {e}") + + def get(self, key: str, default=None): + """Holt Konfigurationswert""" + return self.config.get(key, default) + + def set(self, key: str, value) -> None: + """Setzt Konfigurationswert""" + self.config[key] = value + self.save_config(self.config) + +class ServiceMonitor: + """Überwacht systemd-Services""" + + def __init__(self, config: WatchdogConfig): + self.config = config + self.restart_counts = {} + self.last_restart_times = {} + + def is_service_active(self, service_name: str) -> bool: + """Prüft ob Service aktiv ist""" + try: + result = subprocess.run( + ["systemctl", "is-active", "--quiet", service_name], + capture_output=True + ) + return result.returncode == 0 + except Exception: + return False + + def is_service_enabled(self, service_name: str) -> bool: + """Prüft ob Service aktiviert ist""" + try: + result = subprocess.run( + ["systemctl", "is-enabled", "--quiet", service_name], + capture_output=True + ) + return result.returncode == 0 + except Exception: + return False + + def restart_service(self, service_name: str) -> bool: + """Startet Service neu mit Cooldown-Logik""" + now = datetime.now() + + # Prüfe Restart-Cooldown + if service_name in self.last_restart_times: + time_since_last = (now - self.last_restart_times[service_name]).total_seconds() + if time_since_last < self.config.get("restart_cooldown", 300): + logging.warning(f"Service {service_name} im Cooldown ({time_since_last:.0f}s)") + return False + + # Prüfe maximale Restart-Versuche + restart_count = self.restart_counts.get(service_name, 0) + max_attempts = self.config.get("max_restart_attempts", 3) + + if restart_count >= max_attempts: + logging.error(f"Service {service_name} erreichte maximale Restart-Versuche ({max_attempts})") + return False + + try: + logging.info(f"Starte Service neu: {service_name} (Versuch {restart_count + 1}/{max_attempts})") + + result = subprocess.run( + ["systemctl", "restart", service_name], + capture_output=True, + text=True, + timeout=30 + ) + + if result.returncode == 0: + self.restart_counts[service_name] = restart_count + 1 + self.last_restart_times[service_name] = now + time.sleep(self.config.get("restart_delay", 15)) + logging.info(f"Service {service_name} erfolgreich neugestartet") + return True + else: + logging.error(f"Service-Neustart fehlgeschlagen: {result.stderr}") + return False + + except subprocess.TimeoutExpired: + logging.error(f"Service-Neustart Timeout: {service_name}") + return False + except Exception as e: + logging.error(f"Service-Neustart Fehler: {e}") + return False + + def reset_restart_counter(self, service_name: str) -> None: + """Setzt Restart-Zähler zurück""" + if service_name in self.restart_counts: + del self.restart_counts[service_name] + if service_name in self.last_restart_times: + del self.last_restart_times[service_name] + +class HTTPSMonitor: + """Überwacht HTTPS-Backend""" + + def __init__(self, config: WatchdogConfig): + self.config = config + self.session = requests.Session() + self.session.verify = False # Selbstsignierte Zertifikate + + def check_connectivity(self) -> bool: + """Prüft HTTPS-Erreichbarkeit""" + try: + url = self.config.get("https_url", "https://localhost:443") + timeout = self.config.get("https_timeout", 10) + + response = self.session.get( + url, + timeout=timeout, + allow_redirects=True + ) + + return response.status_code < 500 + + except Exception as e: + logging.debug(f"HTTPS-Konnektivitätsprüfung fehlgeschlagen: {e}") + return False + + def check_ssl_certificate(self) -> bool: + """Prüft SSL-Zertifikat-Gültigkeit""" + try: + cert_file = self.config.app_dir / "certs" / "localhost" / "localhost.crt" + + if not cert_file.exists(): + return False + + expire_days = self.config.get("cert_expire_days", 7) + expire_seconds = expire_days * 86400 + + result = subprocess.run([ + "openssl", "x509", + "-in", str(cert_file), + "-noout", "-checkend", str(expire_seconds) + ], capture_output=True) + + return result.returncode == 0 + + except Exception as e: + logging.error(f"SSL-Zertifikat-Prüfung fehlgeschlagen: {e}") + return False + + def regenerate_ssl_certificate(self) -> bool: + """Regeneriert SSL-Zertifikat""" + try: + logging.info("Regeneriere SSL-Zertifikat...") + + # Importiere SSL-Konfiguration + sys.path.insert(0, str(self.config.app_dir)) + from utils.ssl_config import ensure_ssl_certificates + + success = ensure_ssl_certificates(str(self.config.app_dir), force_regenerate=True) + + if success: + logging.info("SSL-Zertifikat erfolgreich regeneriert") + else: + logging.error("SSL-Zertifikat-Regenerierung fehlgeschlagen") + + return success + + except Exception as e: + logging.error(f"SSL-Zertifikat-Regenerierung Fehler: {e}") + return False + +class KioskMonitor: + """Überwacht Kiosk-Session und Browser""" + + def __init__(self, config: WatchdogConfig): + self.config = config + self.kiosk_user = config.get("kiosk_user", "kiosk") + + def check_user_session(self) -> bool: + """Prüft ob Kiosk-User-Session aktiv ist""" + try: + for proc in psutil.process_iter(['username']): + if proc.info['username'] == self.kiosk_user: + return True + return False + except Exception: + return False + + def check_chromium_process(self) -> bool: + """Prüft ob Chromium-Kiosk-Prozess läuft""" + try: + for proc in psutil.process_iter(['username', 'cmdline']): + if (proc.info['username'] == self.kiosk_user and + proc.info['cmdline'] and + any('chromium' in arg and 'kiosk' in arg for arg in proc.info['cmdline'])): + return True + return False + except Exception: + return False + + def check_x_server(self) -> bool: + """Prüft ob X-Server läuft""" + try: + for proc in psutil.process_iter(['cmdline']): + if (proc.info['cmdline'] and + any('X' in arg and ':0' in arg for arg in proc.info['cmdline'])): + return True + return False + except Exception: + return False + + def check_display_availability(self) -> bool: + """Prüft ob Display verfügbar ist""" + try: + result = subprocess.run( + ["xdpyinfo"], + env={"DISPLAY": ":0"}, + capture_output=True, + timeout=5 + ) + return result.returncode == 0 + except Exception: + return False + + def restart_kiosk_session(self) -> bool: + """Startet Kiosk-Session neu""" + try: + logging.info("Starte Kiosk-Session neu...") + + # Beende Kiosk-Prozesse sanft + subprocess.run(["pkill", "-u", self.kiosk_user, "-TERM"], timeout=10) + time.sleep(5) + + # Erzwinge Beendigung falls nötig + subprocess.run(["pkill", "-u", self.kiosk_user, "-KILL"], timeout=5) + time.sleep(2) + + # Starte Getty-Service neu für Autologin + subprocess.run(["systemctl", "restart", "getty@tty1.service"], timeout=15) + time.sleep(self.config.get("restart_delay", 15)) + + logging.info("Kiosk-Session neugestartet") + return True + + except Exception as e: + logging.error(f"Kiosk-Session-Neustart fehlgeschlagen: {e}") + return False + +class SystemMonitor: + """Überwacht Systemressourcen""" + + def __init__(self, config: WatchdogConfig): + self.config = config + + def get_memory_usage(self) -> float: + """Gibt Speichernutzung in Prozent zurück""" + try: + return psutil.virtual_memory().percent + except Exception: + return 0.0 + + def get_cpu_usage(self) -> float: + """Gibt CPU-Nutzung in Prozent zurück""" + try: + return psutil.cpu_percent(interval=1) + except Exception: + return 0.0 + + def get_disk_usage(self) -> float: + """Gibt Festplatten-Nutzung in Prozent zurück""" + try: + return psutil.disk_usage('/').percent + except Exception: + return 0.0 + + def cleanup_system_resources(self) -> None: + """Bereinigt Systemressourcen""" + try: + memory_before = self.get_memory_usage() + logging.info(f"Bereinige Systemressourcen (Speicher: {memory_before:.1f}%)") + + kiosk_user = self.config.get("kiosk_user", "kiosk") + app_dir = self.config.app_dir + + # Browser-Cache bereinigen + cache_dirs = [ + f"/home/{kiosk_user}/.chromium-kiosk/Default/Cache", + f"/home/{kiosk_user}/.cache" + ] + + for cache_dir in cache_dirs: + if os.path.exists(cache_dir): + subprocess.run(["rm", "-rf", f"{cache_dir}/*"], shell=True) + + # Temporäre Dateien bereinigen + temp_dirs = [ + "/tmp", + str(app_dir / "uploads" / "temp") + ] + + for temp_dir in temp_dirs: + if os.path.exists(temp_dir): + subprocess.run([ + "find", temp_dir, "-type", "f", "-atime", "+1", "-delete" + ], timeout=30) + + # System-Cache leeren + subprocess.run(["sync"]) + with open("/proc/sys/vm/drop_caches", "w") as f: + f.write("3") + + memory_after = self.get_memory_usage() + logging.info(f"Systemressourcen bereinigt (Speicher: {memory_after:.1f}%)") + + except Exception as e: + logging.error(f"Systemressourcen-Bereinigung fehlgeschlagen: {e}") + +class WatchdogManager: + """Hauptklasse für Watchdog-Management""" + + def __init__(self, app_dir: str = "/opt/myp"): + self.config = WatchdogConfig(app_dir) + self.service_monitor = ServiceMonitor(self.config) + self.https_monitor = HTTPSMonitor(self.config) + self.kiosk_monitor = KioskMonitor(self.config) + self.system_monitor = SystemMonitor(self.config) + + self.running = False + self.setup_logging() + self.setup_signal_handlers() + + def setup_logging(self) -> None: + """Konfiguriert Logging""" + log_file = Path("/var/log/kiosk-watchdog-python.log") + log_file.parent.mkdir(parents=True, exist_ok=True) + + logging.basicConfig( + level=logging.INFO, + format='%(asctime)s [%(levelname)s] %(message)s', + handlers=[ + logging.FileHandler(log_file), + logging.StreamHandler() + ] + ) + + def setup_signal_handlers(self) -> None: + """Konfiguriert Signal-Handler für sauberes Beenden""" + def signal_handler(signum, frame): + logging.info(f"Signal {signum} empfangen - beende Watchdog...") + self.running = False + + signal.signal(signal.SIGTERM, signal_handler) + signal.signal(signal.SIGINT, signal_handler) + + def rotate_log_if_needed(self) -> None: + """Rotiert Log-Datei bei Bedarf""" + try: + log_file = Path("/var/log/kiosk-watchdog-python.log") + max_size = self.config.get("log_rotation_size_mb", 10) * 1024 * 1024 + + if log_file.exists() and log_file.stat().st_size > max_size: + # Behalte nur die letzten 1000 Zeilen + subprocess.run([ + "tail", "-n", "1000", str(log_file) + ], stdout=open(f"{log_file}.tmp", "w")) + + log_file.unlink() + Path(f"{log_file}.tmp").rename(log_file) + + logging.info("Log-Datei rotiert (>10MB)") + + except Exception as e: + logging.error(f"Log-Rotation fehlgeschlagen: {e}") + + def check_https_backend(self) -> None: + """Prüft HTTPS-Backend""" + service_name = self.config.get("https_service", "myp-https") + + if not self.service_monitor.is_service_active(service_name): + logging.error("HTTPS-Service nicht aktiv") + self.service_monitor.restart_service(service_name) + elif not self.https_monitor.check_connectivity(): + logging.error("HTTPS Backend nicht erreichbar") + self.service_monitor.restart_service(service_name) + else: + # Service läuft - Reset Restart-Counter + self.service_monitor.reset_restart_counter(service_name) + + def check_ssl_certificate(self) -> None: + """Prüft SSL-Zertifikat""" + if not self.https_monitor.check_ssl_certificate(): + cert_file = self.config.app_dir / "certs" / "localhost" / "localhost.crt" + + if cert_file.exists(): + expire_days = self.config.get("cert_expire_days", 7) + logging.warning(f"SSL-Zertifikat läuft in {expire_days} Tagen ab") + else: + logging.error("SSL-Zertifikat fehlt") + + if self.https_monitor.regenerate_ssl_certificate(): + service_name = self.config.get("https_service", "myp-https") + self.service_monitor.restart_service(service_name) + + def check_kiosk_session(self) -> None: + """Prüft Kiosk-Session""" + if not self.kiosk_monitor.check_user_session(): + logging.error("Kiosk-Benutzer-Session nicht aktiv") + self.kiosk_monitor.restart_kiosk_session() + elif not self.kiosk_monitor.check_x_server(): + logging.error("X-Server nicht verfügbar") + self.kiosk_monitor.restart_kiosk_session() + elif not self.kiosk_monitor.check_display_availability(): + logging.error("Display :0 nicht verfügbar") + self.kiosk_monitor.restart_kiosk_session() + elif not self.kiosk_monitor.check_chromium_process(): + logging.warning("Chromium-Kiosk-Prozess nicht gefunden") + + # Versuche Kiosk-Service zu starten + kiosk_service = self.config.get("kiosk_service", "myp-kiosk") + if self.service_monitor.is_service_enabled(kiosk_service): + subprocess.run(["systemctl", "--user", "start", kiosk_service]) + else: + # Fallback: Browser direkt starten + https_url = self.config.get("https_url", "https://localhost:443") + kiosk_user = self.config.get("kiosk_user", "kiosk") + + subprocess.Popen([ + "sudo", "-u", kiosk_user, + "DISPLAY=:0", "chromium", + "--kiosk", "--no-sandbox", "--ignore-certificate-errors", + https_url + ], env={"DISPLAY": ":0"}) + + time.sleep(self.config.get("restart_delay", 15)) + + def check_system_resources(self) -> None: + """Prüft Systemressourcen""" + if not self.config.get("enable_performance_monitoring", True): + return + + memory_usage = self.system_monitor.get_memory_usage() + max_memory = self.config.get("max_memory_percent", 85) + + if memory_usage > max_memory: + logging.warning(f"Hohe Speichernutzung: {memory_usage:.1f}%") + + if self.config.get("enable_auto_cleanup", True): + self.system_monitor.cleanup_system_resources() + + def run_monitoring_cycle(self) -> None: + """Führt einen Überwachungszyklus durch""" + try: + # HTTPS Backend prüfen + self.check_https_backend() + + # SSL-Zertifikat prüfen + self.check_ssl_certificate() + + # Kiosk-Session prüfen + self.check_kiosk_session() + + # Systemressourcen prüfen + self.check_system_resources() + + # Log-Rotation + self.rotate_log_if_needed() + + except Exception as e: + logging.error(f"Fehler im Überwachungszyklus: {e}") + + def run(self) -> None: + """Startet Hauptüberwachungsschleife""" + self.running = True + check_interval = self.config.get("check_interval", 30) + + logging.info(f"Kiosk-Watchdog gestartet (PID: {os.getpid()})") + logging.info(f"Überwachungsintervall: {check_interval}s") + + while self.running: + try: + self.run_monitoring_cycle() + time.sleep(check_interval) + + except KeyboardInterrupt: + logging.info("Watchdog durch Benutzer beendet") + break + except Exception as e: + logging.error(f"Unerwarteter Fehler: {e}") + time.sleep(check_interval) + + logging.info("Kiosk-Watchdog beendet") + +def main(): + """Hauptfunktion""" + import argparse + + parser = argparse.ArgumentParser(description="MYP Kiosk Watchdog Manager") + parser.add_argument("--app-dir", default="/opt/myp", help="Anwendungsverzeichnis") + parser.add_argument("--config", help="Konfigurationsdatei") + parser.add_argument("--daemon", action="store_true", help="Als Daemon ausführen") + + args = parser.parse_args() + + try: + watchdog = WatchdogManager(args.app_dir) + + if args.daemon: + # Daemon-Modus (für systemd) + watchdog.run() + else: + # Interaktiver Modus + print("Starte Watchdog... (Strg+C zum Beenden)") + watchdog.run() + + except Exception as e: + logging.error(f"Watchdog-Start fehlgeschlagen: {e}") + sys.exit(1) + +if __name__ == "__main__": + main() \ No newline at end of file