4194 lines
146 KiB
Bash
4194 lines
146 KiB
Bash
#!/bin/bash
|
||
|
||
# ===================================================================
|
||
# MYP Druckerverwaltung - KONSOLIDIERTES SETUP-SKRIPT (OPTIMIERT)
|
||
# Kombiniert alle Installationsfunktionen in einer einzigen Datei
|
||
# Optimiert für Debian/Linux (Raspberry Pi OS) - KEIN Windows-Support
|
||
# HTTPS auf Port 443 mit automatischer SSL-Zertifikat-Generierung
|
||
# Kiosk-Modus mit Chromium-Autostart ohne Desktop-Environment
|
||
# Version: 4.1.0 - Robuste Installation mit Retry-Mechanismen
|
||
# ===================================================================
|
||
|
||
set -euo pipefail
|
||
|
||
|
||
|
||
# =========================== GLOBALE KONFIGURATION ===========================
|
||
readonly APP_NAME="MYP Druckerverwaltung"
|
||
readonly APP_VERSION="4.1.0"
|
||
readonly APP_DIR="/opt/myp"
|
||
readonly HTTP_SERVICE_NAME="myp-https"
|
||
readonly KIOSK_SERVICE_NAME="myp-kiosk"
|
||
readonly WATCHDOG_SERVICE_NAME="kiosk-watchdog"
|
||
readonly WATCHDOG_PYTHON_SERVICE_NAME="kiosk-watchdog-python"
|
||
readonly FIREWALL_SERVICE_NAME="myp-firewall"
|
||
readonly KIOSK_USER="kiosk"
|
||
readonly CURRENT_DIR="$(pwd)"
|
||
# Log-Dateien - verwende relatives logs-Verzeichnis
|
||
mkdir -p "$CURRENT_DIR/logs" 2>/dev/null || true
|
||
INSTALL_LOG="$CURRENT_DIR/logs/install.log"
|
||
ERROR_LOG="$CURRENT_DIR/logs/errors.log"
|
||
WARNING_LOG="$CURRENT_DIR/logs/warnings.log"
|
||
DEBUG_LOG="$CURRENT_DIR/logs/debug.log"
|
||
readonly HTTP_PORT="5000"
|
||
readonly HTTP_URL="http://localhost:${HTTP_PORT}"
|
||
readonly SYSTEMD_DIR="$CURRENT_DIR/systemd"
|
||
readonly SYSTEM_SYSTEMD_DIR="/etc/systemd/system"
|
||
|
||
# Retry-Konfiguration
|
||
readonly MAX_RETRIES=3
|
||
readonly RETRY_DELAY=5
|
||
|
||
# Farben für Ausgabe
|
||
readonly RED='\033[0;31m'
|
||
readonly GREEN='\033[0;32m'
|
||
readonly YELLOW='\033[1;33m'
|
||
readonly BLUE='\033[0;34m'
|
||
readonly PURPLE='\033[0;35m'
|
||
readonly CYAN='\033[0;36m'
|
||
readonly NC='\033[0m'
|
||
|
||
# =========================== VERBESSERTE LOGGING-FUNKTIONEN ===========================
|
||
# Globale Variablen für Fehler-Tracking
|
||
ERROR_COUNT=0
|
||
WARNING_COUNT=0
|
||
|
||
# Log-Dateien initialisieren
|
||
init_logging() {
|
||
# Sichere Log-Verzeichnis-Erstellung
|
||
if ! mkdir -p "$CURRENT_DIR/logs" 2>/dev/null; then
|
||
echo "FEHLER: Kann logs-Verzeichnis nicht erstellen - verwende /tmp" >&2
|
||
INSTALL_LOG="/tmp/myp-install.log"
|
||
ERROR_LOG="/tmp/myp-install-errors.log"
|
||
WARNING_LOG="/tmp/myp-install-warnings.log"
|
||
DEBUG_LOG="/tmp/myp-install-debug.log"
|
||
fi
|
||
|
||
# Überschreibe bestehende Log-Dateien
|
||
{
|
||
echo "================================================================="
|
||
echo "MYP Installation Log - $(date '+%Y-%m-%d %H:%M:%S')"
|
||
echo "Script Version: $APP_VERSION"
|
||
echo "System: $(timeout 5 uname -a 2>/dev/null || echo 'System-Info nicht verfügbar')"
|
||
echo "Arbeitsverzeichnis: $CURRENT_DIR"
|
||
echo "Log-Verzeichnis: $(dirname "$INSTALL_LOG")"
|
||
echo "================================================================="
|
||
echo ""
|
||
} > "$INSTALL_LOG" 2>/dev/null || {
|
||
echo "KRITISCH: Kann Haupt-Log nicht schreiben!" >&2
|
||
exit 1
|
||
}
|
||
|
||
{
|
||
echo "================================================================="
|
||
echo "MYP Installation FEHLER Log - $(date '+%Y-%m-%d %H:%M:%S')"
|
||
echo "================================================================="
|
||
echo ""
|
||
} > "$ERROR_LOG"
|
||
|
||
{
|
||
echo "================================================================="
|
||
echo "MYP Installation WARNUNGEN Log - $(date '+%Y-%m-%d %H:%M:%S')"
|
||
echo "================================================================="
|
||
echo ""
|
||
} > "$WARNING_LOG"
|
||
|
||
{
|
||
echo "================================================================="
|
||
echo "MYP Installation DEBUG Log - $(date '+%Y-%m-%d %H:%M:%S')"
|
||
echo "================================================================="
|
||
echo ""
|
||
} > "$DEBUG_LOG"
|
||
}
|
||
|
||
log() {
|
||
local message="[$(date '+%Y-%m-%d %H:%M:%S')] $1"
|
||
echo -e "${GREEN}${message}${NC}" | tee -a "$INSTALL_LOG"
|
||
}
|
||
|
||
error() {
|
||
local timestamp="$(date '+%Y-%m-%d %H:%M:%S')"
|
||
local caller="${BASH_SOURCE[1]##*/}:${BASH_LINENO[0]}"
|
||
local message="[FEHLER] $1"
|
||
|
||
# Erhöhe Fehler-Zähler
|
||
((ERROR_COUNT++))
|
||
|
||
# Ausgabe auf Konsole
|
||
echo -e "${RED}${message}${NC}" | tee -a "$INSTALL_LOG"
|
||
|
||
# Detaillierte Fehler-Information in Fehler-Log
|
||
{
|
||
echo "[$timestamp] FEHLER #$ERROR_COUNT"
|
||
echo "Quelle: $caller"
|
||
echo "Nachricht: $1"
|
||
echo "Arbeitsverzeichnis: $(pwd)"
|
||
echo "Benutzer: $(whoami)"
|
||
echo "---"
|
||
echo ""
|
||
} >> "$ERROR_LOG"
|
||
|
||
# Debug-Informationen sammeln
|
||
{
|
||
echo "[$timestamp] FEHLER AUFGETRETEN - Debug-Info:"
|
||
echo "Caller: $caller"
|
||
echo "PWD: $(pwd)"
|
||
echo "User: $(whoami)"
|
||
echo "Disk Space: $(df -h / | tail -1)"
|
||
echo "Memory: $(free -m | grep '^Mem:' | awk '{print $3"/"$2" MB"}')"
|
||
echo "Load Average: $(uptime | awk -F'load average:' '{print $2}')"
|
||
echo "Recent commands from history:"
|
||
history | tail -5 2>/dev/null || echo "History nicht verfügbar"
|
||
echo "==============================================="
|
||
echo ""
|
||
} >> "$DEBUG_LOG"
|
||
|
||
exit 1
|
||
}
|
||
|
||
warning() {
|
||
local timestamp="$(date '+%Y-%m-%d %H:%M:%S')"
|
||
local caller="${BASH_SOURCE[1]##*/}:${BASH_LINENO[0]}"
|
||
local message="[WARNUNG] $1"
|
||
|
||
# Erhöhe Warnungs-Zähler
|
||
((WARNING_COUNT++))
|
||
|
||
# Ausgabe auf Konsole
|
||
echo -e "${YELLOW}${message}${NC}" | tee -a "$INSTALL_LOG"
|
||
|
||
# Detaillierte Warnungs-Information in Warnungs-Log
|
||
{
|
||
echo "[$timestamp] WARNUNG #$WARNING_COUNT"
|
||
echo "Quelle: $caller"
|
||
echo "Nachricht: $1"
|
||
echo "---"
|
||
echo ""
|
||
} >> "$WARNING_LOG"
|
||
}
|
||
|
||
info() {
|
||
echo -e "${BLUE}[INFO] $1${NC}" | tee -a "$INSTALL_LOG"
|
||
}
|
||
|
||
progress() {
|
||
echo -e "${PURPLE}[FORTSCHRITT] $1${NC}" | tee -a "$INSTALL_LOG"
|
||
}
|
||
|
||
success() {
|
||
echo -e "${CYAN}[ERFOLG] $1${NC}" | tee -a "$INSTALL_LOG"
|
||
}
|
||
|
||
debug() {
|
||
local timestamp="$(date '+%Y-%m-%d %H:%M:%S')"
|
||
local caller="${BASH_SOURCE[1]##*/}:${BASH_LINENO[0]}"
|
||
|
||
# Debug sowohl in normales Log als auch Debug-Log
|
||
echo -e "${BLUE}[DEBUG] $1${NC}" >> "$INSTALL_LOG"
|
||
|
||
{
|
||
echo "[$timestamp] DEBUG von $caller"
|
||
echo "$1"
|
||
echo "---"
|
||
echo ""
|
||
} >> "$DEBUG_LOG"
|
||
}
|
||
|
||
# Fehler-Zusammenfassung anzeigen
|
||
show_error_summary() {
|
||
echo ""
|
||
echo -e "${CYAN}=================================================================${NC}"
|
||
echo -e "${CYAN} INSTALLATION ABGESCHLOSSEN - FEHLER-ZUSAMMENFASSUNG${NC}"
|
||
echo -e "${CYAN}=================================================================${NC}"
|
||
echo ""
|
||
|
||
echo -e "${BLUE}📊 Statistiken:${NC}"
|
||
echo -e " ${RED}❌ Fehler: $ERROR_COUNT${NC}"
|
||
echo -e " ${YELLOW}⚠️ Warnungen: $WARNING_COUNT${NC}"
|
||
echo ""
|
||
|
||
echo -e "${BLUE}📁 Log-Dateien:${NC}"
|
||
echo -e " 📄 Vollständiges Log: $INSTALL_LOG"
|
||
echo -e " 🚨 Fehler-Log: $ERROR_LOG"
|
||
echo -e " ⚠️ Warnungs-Log: $WARNING_LOG"
|
||
echo -e " 🔍 Debug-Log: $DEBUG_LOG"
|
||
echo ""
|
||
|
||
if [ $ERROR_COUNT -gt 0 ]; then
|
||
echo -e "${RED}⚠️ Es sind $ERROR_COUNT Fehler aufgetreten!${NC}"
|
||
echo -e "${RED} Bitte prüfen Sie: $ERROR_LOG${NC}"
|
||
echo ""
|
||
|
||
# Zeige die letzten 3 Fehler an
|
||
if [ -f "$ERROR_LOG" ] && [ -s "$ERROR_LOG" ]; then
|
||
echo -e "${RED}🔍 Letzte Fehler:${NC}"
|
||
tail -n 20 "$ERROR_LOG" | head -n 15
|
||
echo ""
|
||
fi
|
||
fi
|
||
|
||
if [ $WARNING_COUNT -gt 0 ]; then
|
||
echo -e "${YELLOW}⚠️ Es sind $WARNING_COUNT Warnungen aufgetreten${NC}"
|
||
echo -e "${YELLOW} Bitte prüfen Sie: $WARNING_LOG${NC}"
|
||
echo ""
|
||
fi
|
||
|
||
if [ $ERROR_COUNT -eq 0 ] && [ $WARNING_COUNT -eq 0 ]; then
|
||
echo -e "${GREEN}✅ Installation ohne Fehler oder Warnungen abgeschlossen!${NC}"
|
||
elif [ $ERROR_COUNT -eq 0 ]; then
|
||
echo -e "${GREEN}✅ Installation erfolgreich mit $WARNING_COUNT Warnungen${NC}"
|
||
fi
|
||
|
||
echo -e "${CYAN}=================================================================${NC}"
|
||
|
||
# Erstelle automatische Log-Zusammenfassung
|
||
create_log_summary
|
||
}
|
||
|
||
# Automatische Log-Zusammenfassung erstellen
|
||
create_log_summary() {
|
||
local summary_file="$CURRENT_DIR/logs/install-summary.txt"
|
||
|
||
{
|
||
echo "================================================================="
|
||
echo "MYP INSTALLATION ZUSAMMENFASSUNG"
|
||
echo "Erstellt: $(date '+%Y-%m-%d %H:%M:%S')"
|
||
echo "================================================================="
|
||
echo ""
|
||
echo "STATISTIKEN:"
|
||
echo "- Fehler: $ERROR_COUNT"
|
||
echo "- Warnungen: $WARNING_COUNT"
|
||
echo "- Script Version: $APP_VERSION"
|
||
echo "- System: $(uname -a 2>/dev/null || echo 'Unbekannt')"
|
||
echo "- Hostname: $(hostname 2>/dev/null || echo 'Unbekannt')"
|
||
echo "- User: $(whoami 2>/dev/null || echo 'Unbekannt')"
|
||
echo ""
|
||
echo "SYSTEM-INFORMATIONEN:"
|
||
echo "- Festplattenspeicher: $(df -h / | tail -1 2>/dev/null || echo 'Nicht verfügbar')"
|
||
echo "- Arbeitsspeicher: $(free -m | grep '^Mem:' | awk '{print $3"/"$2" MB"}' 2>/dev/null || echo 'Nicht verfügbar')"
|
||
echo "- Python Version: $(python3 --version 2>&1 || echo 'Nicht installiert')"
|
||
echo "- Node.js Version: $(node --version 2>&1 || echo 'Nicht installiert')"
|
||
echo ""
|
||
echo "LOG-DATEIEN:"
|
||
echo "- Vollständiges Log: $INSTALL_LOG"
|
||
echo "- Fehler-Log: $ERROR_LOG"
|
||
echo "- Warnungs-Log: $WARNING_LOG"
|
||
echo "- Debug-Log: $DEBUG_LOG"
|
||
echo ""
|
||
|
||
if [ $ERROR_COUNT -gt 0 ] && [ -f "$ERROR_LOG" ] && [ -s "$ERROR_LOG" ]; then
|
||
echo "FEHLER-ÜBERSICHT:"
|
||
echo "================="
|
||
tail -n 50 "$ERROR_LOG"
|
||
echo ""
|
||
fi
|
||
|
||
if [ $WARNING_COUNT -gt 0 ] && [ -f "$WARNING_LOG" ] && [ -s "$WARNING_LOG" ]; then
|
||
echo "WARNUNGS-ÜBERSICHT:"
|
||
echo "==================="
|
||
tail -n 30 "$WARNING_LOG"
|
||
echo ""
|
||
fi
|
||
|
||
echo "INSTALLATION ABGESCHLOSSEN: $(date '+%Y-%m-%d %H:%M:%S')"
|
||
echo "================================================================="
|
||
|
||
} > "$summary_file"
|
||
|
||
# Berechtigung für Zusammenfassungs-Datei setzen
|
||
chmod 644 "$summary_file" 2>/dev/null || true
|
||
|
||
debug "Log-Zusammenfassung erstellt: $summary_file"
|
||
}
|
||
|
||
# =========================== RETRY-MECHANISMEN ===========================
|
||
retry_command() {
|
||
local cmd="$1"
|
||
local description="$2"
|
||
local attempts=0
|
||
|
||
while [ $attempts -lt $MAX_RETRIES ]; do
|
||
if eval "$cmd"; then
|
||
return 0
|
||
fi
|
||
|
||
attempts=$((attempts + 1))
|
||
if [ $attempts -lt $MAX_RETRIES ]; then
|
||
warning "$description fehlgeschlagen (Versuch $attempts/$MAX_RETRIES) - wiederhole in ${RETRY_DELAY}s..."
|
||
|
||
# Debug-Information für jeden fehlgeschlagenen Versuch
|
||
debug "Retry-Versuch für '$description': $attempts/$MAX_RETRIES"
|
||
debug "Fehlgeschlagener Befehl: $cmd"
|
||
debug "Aktuelles Arbeitsverzeichnis: $(pwd)"
|
||
debug "Verfügbarer Speicher: $(free -m | grep '^Mem:' | awk '{print $3"/"$2" MB"}' 2>/dev/null || echo 'Unbekannt')"
|
||
debug "Exit-Code des letzten Befehls: $?"
|
||
|
||
sleep $RETRY_DELAY
|
||
fi
|
||
done
|
||
|
||
# Detaillierte Fehler-Information vor dem Beenden
|
||
debug "CRITICAL: Retry-Mechanismus erschöpft für '$description'"
|
||
debug "Letzter Befehl: $cmd"
|
||
debug "Versuche: $MAX_RETRIES"
|
||
debug "System-Status zum Zeitpunkt des kritischen Fehlers:"
|
||
debug " - Disk Usage: $(df -h / | tail -1 2>/dev/null || echo 'Nicht verfügbar')"
|
||
debug " - Memory Usage: $(free -m 2>/dev/null || echo 'Nicht verfügbar')"
|
||
debug " - Load Average: $(uptime 2>/dev/null | awk -F'load average:' '{print $2}' || echo 'Nicht verfügbar')"
|
||
debug " - Network Status: $(ip addr show 2>/dev/null | grep 'inet ' | grep -v '127.0.0.1' || echo 'Nicht verfügbar')"
|
||
debug " - APT Status: $(ps aux | grep -i apt | grep -v grep || echo 'Keine APT-Prozesse')"
|
||
debug " - Python Status: $(python3 --version 2>&1 || echo 'Python nicht verfügbar')"
|
||
|
||
error "$description nach $MAX_RETRIES Versuchen fehlgeschlagen!"
|
||
}
|
||
|
||
# APT-Pakete mit Retry installieren
|
||
apt_install_retry() {
|
||
local packages="$*"
|
||
local cmd="DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends $packages"
|
||
|
||
progress "Installiere Pakete: $packages"
|
||
retry_command "$cmd" "APT Installation für: $packages"
|
||
}
|
||
|
||
# =========================== ERWEITERTE SYSTEM-VALIDIERUNG ===========================
|
||
check_root() {
|
||
if [ "$EUID" -ne 0 ]; then
|
||
error "Dieses Skript muss als Root ausgeführt werden: sudo $0"
|
||
fi
|
||
export PATH="/usr/sbin:/sbin:/usr/bin:/bin:/usr/local/bin:$PATH"
|
||
log "✅ Root-Berechtigung bestätigt"
|
||
}
|
||
|
||
check_system_resources() {
|
||
log "=== SYSTEM-RESSOURCEN PRÜFUNG ==="
|
||
|
||
# RAM prüfen (robuster)
|
||
progress "Prüfe RAM..."
|
||
local ram_mb=""
|
||
|
||
# Verschiedene Methoden zur RAM-Ermittlung
|
||
if command -v free >/dev/null 2>&1; then
|
||
ram_mb=$(free -m 2>/dev/null | awk '/^Mem:/{print $2}' 2>/dev/null || echo "")
|
||
fi
|
||
|
||
# Fallback über /proc/meminfo
|
||
if [ -z "$ram_mb" ] && [ -f "/proc/meminfo" ]; then
|
||
ram_mb=$(grep '^MemTotal:' /proc/meminfo 2>/dev/null | awk '{print int($2/1024)}' 2>/dev/null || echo "")
|
||
fi
|
||
|
||
if [ -n "$ram_mb" ] && [ "$ram_mb" -gt 0 ] 2>/dev/null; then
|
||
progress "Verfügbarer RAM: ${ram_mb}MB"
|
||
|
||
if [ "$ram_mb" -lt 512 ] 2>/dev/null; then
|
||
warning "⚠️ Wenig RAM verfügbar (${ram_mb}MB) - Installation könnte langsam sein"
|
||
else
|
||
success "✅ Ausreichend RAM verfügbar (${ram_mb}MB)"
|
||
fi
|
||
else
|
||
warning "⚠️ RAM-Größe konnte nicht ermittelt werden"
|
||
debug "RAM-Ermittlung fehlgeschlagen: free-Output: $(free -m 2>&1 || echo 'Befehl nicht verfügbar')"
|
||
fi
|
||
|
||
# Festplattenplatz prüfen (robuster ohne bc)
|
||
progress "Prüfe Festplattenplatz..."
|
||
local disk_free_gb=""
|
||
local disk_free_mb=""
|
||
|
||
if command -v df >/dev/null 2>&1; then
|
||
# Hole Festplattenplatz in MB
|
||
disk_free_mb=$(df / 2>/dev/null | awk 'NR==2{print int($4/1024)}' 2>/dev/null || echo "")
|
||
|
||
if [ -n "$disk_free_mb" ] && [ "$disk_free_mb" -gt 0 ] 2>/dev/null; then
|
||
# Berechne GB ohne bc (einfache Division)
|
||
disk_free_gb=$(awk -v mb="$disk_free_mb" 'BEGIN{printf "%.1f", mb/1024}' 2>/dev/null || echo "$((disk_free_mb/1024))")
|
||
|
||
progress "Verfügbarer Festplattenplatz: ${disk_free_gb}GB (${disk_free_mb}MB)"
|
||
|
||
# Prüfe ob mindestens 2GB verfügbar (2048 MB)
|
||
if [ "$disk_free_mb" -lt 2048 ] 2>/dev/null; then
|
||
warning "⚠️ Wenig Festplattenplatz verfügbar (${disk_free_gb}GB)"
|
||
else
|
||
success "✅ Ausreichend Festplattenplatz verfügbar (${disk_free_gb}GB)"
|
||
fi
|
||
else
|
||
warning "⚠️ Festplattenplatz konnte nicht ermittelt werden"
|
||
debug "Disk-Ermittlung fehlgeschlagen: df-Output: $(df / 2>&1 || echo 'Befehl nicht verfügbar')"
|
||
fi
|
||
else
|
||
warning "⚠️ df-Befehl nicht verfügbar - kann Festplattenplatz nicht prüfen"
|
||
fi
|
||
|
||
# CPU prüfen (robuster)
|
||
progress "Prüfe CPU..."
|
||
local cpu_count=""
|
||
local cpu_model=""
|
||
|
||
# CPU-Anzahl ermitteln
|
||
if command -v nproc >/dev/null 2>&1; then
|
||
cpu_count=$(nproc 2>/dev/null || echo "")
|
||
fi
|
||
|
||
if [ -z "$cpu_count" ] && [ -f "/proc/cpuinfo" ]; then
|
||
cpu_count=$(grep -c '^processor' /proc/cpuinfo 2>/dev/null || echo "")
|
||
fi
|
||
|
||
# CPU-Modell ermitteln
|
||
if [ -f "/proc/cpuinfo" ]; then
|
||
cpu_model=$(grep "model name" /proc/cpuinfo 2>/dev/null | head -1 | cut -d: -f2 2>/dev/null | sed 's/^[[:space:]]*//' 2>/dev/null || echo "Unbekannt")
|
||
fi
|
||
|
||
if [ -n "$cpu_count" ] && [ "$cpu_count" -gt 0 ] 2>/dev/null; then
|
||
progress "CPU: $cpu_count Kern(e) - $cpu_model"
|
||
success "✅ CPU-Information erfolgreich ermittelt"
|
||
else
|
||
progress "CPU: Unbekannte Anzahl Kerne - $cpu_model"
|
||
warning "⚠️ CPU-Kern-Anzahl konnte nicht ermittelt werden"
|
||
debug "CPU-Ermittlung fehlgeschlagen: nproc-Output: $(nproc 2>&1 || echo 'Befehl nicht verfügbar')"
|
||
fi
|
||
|
||
log "✅ System-Ressourcen-Prüfung abgeschlossen"
|
||
}
|
||
|
||
check_debian_system() {
|
||
progress "Prüfe Debian/Raspbian-System..."
|
||
|
||
# Robuste Debian-Erkennung
|
||
local is_debian=false
|
||
local debian_version="Unbekannt"
|
||
|
||
# Verschiedene Methoden zur Debian-Erkennung
|
||
if [ -f /etc/debian_version ]; then
|
||
debian_version=$(cat /etc/debian_version 2>/dev/null | head -1 | tr -d '\n\r' || echo "Unbekannt")
|
||
is_debian=true
|
||
debug "Debian erkannt über /etc/debian_version: $debian_version"
|
||
fi
|
||
|
||
# Fallback über os-release
|
||
if [ "$is_debian" = false ] && [ -f /etc/os-release ]; then
|
||
local os_id=$(grep '^ID=' /etc/os-release 2>/dev/null | cut -d= -f2 | tr -d '"' || echo "")
|
||
if [[ "$os_id" =~ ^(debian|raspbian|ubuntu)$ ]]; then
|
||
is_debian=true
|
||
local os_version=$(grep '^VERSION=' /etc/os-release 2>/dev/null | cut -d= -f2 | tr -d '"' || echo "Unbekannt")
|
||
debian_version="$os_id $os_version"
|
||
debug "Debian-basiertes System erkannt über os-release: $debian_version"
|
||
fi
|
||
fi
|
||
|
||
# Fallback über lsb_release
|
||
if [ "$is_debian" = false ] && command -v lsb_release >/dev/null 2>&1; then
|
||
local lsb_id=$(lsb_release -si 2>/dev/null | tr '[:upper:]' '[:lower:]' || echo "")
|
||
if [[ "$lsb_id" =~ ^(debian|raspbian|ubuntu)$ ]]; then
|
||
is_debian=true
|
||
debian_version="$lsb_id $(lsb_release -sr 2>/dev/null || echo 'Unbekannt')"
|
||
debug "Debian-basiertes System erkannt über lsb_release: $debian_version"
|
||
fi
|
||
fi
|
||
|
||
if [ "$is_debian" = false ]; then
|
||
warning "⚠️ System ist möglicherweise nicht Debian/Raspbian-basiert!"
|
||
warning "⚠️ Installation wird fortgesetzt, könnte aber fehlschlagen"
|
||
debug "System-Erkennung fehlgeschlagen. Verfügbare Info:"
|
||
debug " - /etc/debian_version: $([ -f /etc/debian_version ] && echo 'vorhanden' || echo 'nicht vorhanden')"
|
||
debug " - /etc/os-release: $([ -f /etc/os-release ] && grep '^ID=' /etc/os-release 2>/dev/null || echo 'nicht verfügbar')"
|
||
debug " - lsb_release: $(command -v lsb_release >/dev/null 2>&1 && lsb_release -si 2>/dev/null || echo 'nicht verfügbar')"
|
||
else
|
||
log "✅ Debian/Raspbian-basiertes System erkannt (Version: $debian_version)"
|
||
fi
|
||
|
||
# Prüfe auf Raspberry Pi (robuster)
|
||
progress "Prüfe Raspberry Pi Hardware..."
|
||
local is_raspberry_pi=false
|
||
local pi_model="Unbekannt"
|
||
|
||
# Methode 1: Device Tree Model
|
||
if [ -f /proc/device-tree/model ]; then
|
||
pi_model=$(cat /proc/device-tree/model 2>/dev/null | tr -d '\0\n\r' | head -c 100 || echo "")
|
||
if [[ "$pi_model" =~ [Rr]aspberry.*[Pp]i ]]; then
|
||
is_raspberry_pi=true
|
||
debug "Raspberry Pi erkannt über device-tree: $pi_model"
|
||
fi
|
||
fi
|
||
|
||
# Methode 2: CPU Info
|
||
if [ "$is_raspberry_pi" = false ] && [ -f /proc/cpuinfo ]; then
|
||
local cpu_hardware=$(grep '^Hardware' /proc/cpuinfo 2>/dev/null | cut -d: -f2 | sed 's/^[[:space:]]*//' | head -1 || echo "")
|
||
local cpu_model=$(grep '^Model' /proc/cpuinfo 2>/dev/null | cut -d: -f2 | sed 's/^[[:space:]]*//' | head -1 || echo "")
|
||
|
||
if [[ "$cpu_hardware" =~ [Bb][Cc][Mm] ]] || [[ "$cpu_model" =~ [Rr]aspberry.*[Pp]i ]]; then
|
||
is_raspberry_pi=true
|
||
pi_model="$cpu_model ($cpu_hardware)"
|
||
debug "Raspberry Pi erkannt über cpuinfo: $pi_model"
|
||
fi
|
||
fi
|
||
|
||
if [ "$is_raspberry_pi" = true ]; then
|
||
info "🍓 Raspberry Pi erkannt: $pi_model"
|
||
progress "Aktiviere Raspberry Pi spezifische Optimierungen..."
|
||
export RASPBERRY_PI_DETECTED=1
|
||
debug "Raspberry Pi Optimierungen aktiviert"
|
||
else
|
||
info "💻 Standard-PC/Server System (kein Raspberry Pi)"
|
||
debug "Kein Raspberry Pi erkannt. Hardware-Info:"
|
||
debug " - Device Tree: $([ -f /proc/device-tree/model ] && cat /proc/device-tree/model 2>/dev/null | tr -d '\0' || echo 'nicht verfügbar')"
|
||
debug " - CPU Hardware: $(grep '^Hardware' /proc/cpuinfo 2>/dev/null | cut -d: -f2 | sed 's/^[[:space:]]*//' || echo 'nicht verfügbar')"
|
||
fi
|
||
|
||
# System-Architektur prüfen (robuster)
|
||
progress "Prüfe System-Architektur..."
|
||
local arch=""
|
||
|
||
if command -v uname >/dev/null 2>&1; then
|
||
arch=$(uname -m 2>/dev/null || echo "Unbekannt")
|
||
info "📐 System-Architektur: $arch"
|
||
|
||
# Architektur-spezifische Hinweise
|
||
case "$arch" in
|
||
"aarch64"|"arm64")
|
||
info " → 64-Bit ARM Architektur erkannt"
|
||
;;
|
||
"armv7l"|"armv6l")
|
||
info " → 32-Bit ARM Architektur erkannt"
|
||
;;
|
||
"x86_64"|"amd64")
|
||
info " → 64-Bit x86 Architektur erkannt"
|
||
;;
|
||
"i386"|"i686")
|
||
info " → 32-Bit x86 Architektur erkannt"
|
||
;;
|
||
*)
|
||
warning "⚠️ Unbekannte Architektur: $arch"
|
||
;;
|
||
esac
|
||
else
|
||
warning "⚠️ uname-Befehl nicht verfügbar - kann Architektur nicht ermitteln"
|
||
fi
|
||
|
||
# Kernel-Version prüfen (robuster)
|
||
progress "Prüfe Kernel-Version..."
|
||
local kernel=""
|
||
|
||
if command -v uname >/dev/null 2>&1; then
|
||
kernel=$(uname -r 2>/dev/null || echo "Unbekannt")
|
||
info "🐧 Kernel-Version: $kernel"
|
||
debug "Vollständige Kernel-Info: $(uname -a 2>/dev/null || echo 'Nicht verfügbar')"
|
||
else
|
||
warning "⚠️ Kernel-Version konnte nicht ermittelt werden"
|
||
fi
|
||
|
||
log "✅ System-Analyse abgeschlossen"
|
||
}
|
||
|
||
check_internet_connection() {
|
||
progress "Prüfe Internetverbindung (erweiterte Methoden)..."
|
||
|
||
local connection_ok=false
|
||
local test_method=""
|
||
local debug_info=""
|
||
|
||
# Methode 1: DNS-Auflösung (robuster)
|
||
progress "Teste DNS-Auflösung..."
|
||
local dns_hosts=("8.8.8.8" "1.1.1.1" "google.com" "cloudflare.com")
|
||
|
||
for host in "${dns_hosts[@]}"; do
|
||
debug_info="${debug_info}Teste DNS für $host: "
|
||
|
||
# Teste nslookup
|
||
if command -v nslookup >/dev/null 2>&1; then
|
||
if timeout 10 nslookup "$host" >/dev/null 2>&1; then
|
||
connection_ok=true
|
||
test_method="DNS-Auflösung (nslookup: $host)"
|
||
debug_info="${debug_info}Erfolg mit nslookup. "
|
||
break
|
||
fi
|
||
debug_info="${debug_info}nslookup fehlgeschlagen. "
|
||
fi
|
||
|
||
# Teste getent hosts
|
||
if [ "$connection_ok" = false ] && command -v getent >/dev/null 2>&1; then
|
||
if timeout 8 getent hosts "$host" >/dev/null 2>&1; then
|
||
connection_ok=true
|
||
test_method="DNS-Auflösung (getent: $host)"
|
||
debug_info="${debug_info}Erfolg mit getent. "
|
||
break
|
||
fi
|
||
debug_info="${debug_info}getent fehlgeschlagen. "
|
||
fi
|
||
|
||
# Teste ping als Fallback
|
||
if [ "$connection_ok" = false ] && command -v ping >/dev/null 2>&1; then
|
||
if timeout 5 ping -c 1 "$host" >/dev/null 2>&1; then
|
||
connection_ok=true
|
||
test_method="Netzwerk-Verbindung (ping: $host)"
|
||
debug_info="${debug_info}Erfolg mit ping. "
|
||
break
|
||
fi
|
||
debug_info="${debug_info}ping fehlgeschlagen. "
|
||
fi
|
||
done
|
||
|
||
debug "DNS-Test Details: $debug_info"
|
||
|
||
# Methode 2: HTTP/HTTPS-Tests (robuster)
|
||
if [ "$connection_ok" = false ]; then
|
||
progress "Teste HTTP/HTTPS-Verbindungen..."
|
||
local http_urls=("http://connectivitycheck.gstatic.com/generate_204" "http://detectportal.firefox.com/success.txt" "https://www.google.com")
|
||
|
||
for url in "${http_urls[@]}"; do
|
||
debug_info="Teste HTTP für $url: "
|
||
|
||
# Teste curl
|
||
if command -v curl >/dev/null 2>&1; then
|
||
if timeout 15 curl -s --connect-timeout 8 --max-time 12 --fail "$url" >/dev/null 2>&1; then
|
||
connection_ok=true
|
||
test_method="HTTP/HTTPS (curl: $url)"
|
||
debug_info="${debug_info}Erfolg mit curl. "
|
||
break
|
||
fi
|
||
debug_info="${debug_info}curl fehlgeschlagen. "
|
||
fi
|
||
|
||
# Teste wget
|
||
if [ "$connection_ok" = false ] && command -v wget >/dev/null 2>&1; then
|
||
if timeout 15 wget -q --timeout=8 --tries=1 --spider "$url" 2>/dev/null; then
|
||
connection_ok=true
|
||
test_method="HTTP/HTTPS (wget: $url)"
|
||
debug_info="${debug_info}Erfolg mit wget. "
|
||
break
|
||
fi
|
||
debug_info="${debug_info}wget fehlgeschlagen. "
|
||
fi
|
||
|
||
debug "HTTP-Test Details: $debug_info"
|
||
done
|
||
fi
|
||
|
||
# Methode 3: Lokale Netzwerk-Interface Prüfung
|
||
if [ "$connection_ok" = false ]; then
|
||
progress "Prüfe lokale Netzwerk-Interfaces..."
|
||
|
||
local has_network_interface=false
|
||
|
||
# Prüfe ob aktive Netzwerk-Interfaces vorhanden sind
|
||
if command -v ip >/dev/null 2>&1; then
|
||
local active_interfaces=$(ip route show default 2>/dev/null | awk '{print $5}' | head -1)
|
||
if [ -n "$active_interfaces" ]; then
|
||
has_network_interface=true
|
||
local interface_ip=$(ip route get 1.1.1.1 2>/dev/null | awk '{print $7}' | head -1 || echo "Unbekannt")
|
||
info " 📡 Aktives Interface: $active_interfaces (IP: $interface_ip)"
|
||
debug "Netzwerk-Interface gefunden: $active_interfaces mit IP $interface_ip"
|
||
fi
|
||
fi
|
||
|
||
# Fallback über ifconfig
|
||
if [ "$has_network_interface" = false ] && command -v ifconfig >/dev/null 2>&1; then
|
||
local active_interfaces=$(ifconfig 2>/dev/null | grep -E '^[a-zA-Z]' | grep -v '^lo' | head -1 | cut -d: -f1)
|
||
if [ -n "$active_interfaces" ]; then
|
||
has_network_interface=true
|
||
info " 📡 Interface erkannt: $active_interfaces"
|
||
debug "Netzwerk-Interface über ifconfig gefunden: $active_interfaces"
|
||
fi
|
||
fi
|
||
|
||
if [ "$has_network_interface" = true ]; then
|
||
warning "⚠️ Netzwerk-Interface aktiv, aber Internet nicht erreichbar"
|
||
warning " → Möglicherweise Firewall, Proxy oder DNS-Problem"
|
||
else
|
||
warning "⚠️ Keine aktiven Netzwerk-Interfaces gefunden"
|
||
warning " → Bitte prüfen Sie die Netzwerk-Konfiguration"
|
||
fi
|
||
fi
|
||
|
||
# Methode 4: APT-Repository-Test (nur als letzter Test)
|
||
if [ "$connection_ok" = false ]; then
|
||
progress "Teste APT-Repository-Zugang (kann länger dauern)..."
|
||
|
||
# Sehr kurzer APT-Test ohne Update
|
||
if timeout 30 apt-get -qq --print-uris update 2>/dev/null | grep -q 'http'; then
|
||
connection_ok=true
|
||
test_method="APT-Repository-Konfiguration"
|
||
debug "APT-Repositories scheinen konfiguriert zu sein"
|
||
else
|
||
debug "APT-Repository-Test fehlgeschlagen"
|
||
fi
|
||
fi
|
||
|
||
# Ergebnis-Bewertung
|
||
if [ "$connection_ok" = true ]; then
|
||
success "✅ Internetverbindung verfügbar"
|
||
info " 🔍 Erkannt via: $test_method"
|
||
|
||
# Zusätzliche Informationen (robust)
|
||
if command -v curl >/dev/null 2>&1; then
|
||
progress "Ermittle externe IP-Adresse..."
|
||
local external_ip=""
|
||
local ip_services=("ifconfig.me" "ipinfo.io/ip" "icanhazip.com")
|
||
|
||
for service in "${ip_services[@]}"; do
|
||
external_ip=$(timeout 8 curl -s --connect-timeout 5 "$service" 2>/dev/null | head -1 | tr -d '\n\r' || echo "")
|
||
if [ -n "$external_ip" ] && [[ "$external_ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||
info " 🌐 Externe IP: $external_ip"
|
||
debug "Externe IP ermittelt über $service: $external_ip"
|
||
break
|
||
fi
|
||
done
|
||
|
||
if [ -z "$external_ip" ]; then
|
||
debug "Externe IP konnte nicht ermittelt werden"
|
||
fi
|
||
fi
|
||
else
|
||
warning "⚠️ Keine Internetverbindung erkannt"
|
||
info " → Installation wird fortgesetzt, aber Downloads könnten fehlschlagen"
|
||
warning " → Bitte prüfen Sie die Netzwerkverbindung!"
|
||
|
||
# Debug-Informationen bei fehlgeschlagener Verbindung
|
||
debug "Internet-Verbindungstest fehlgeschlagen. System-Info:"
|
||
debug " - DNS-Server: $(cat /etc/resolv.conf 2>/dev/null | grep nameserver | head -3 || echo 'Nicht verfügbar')"
|
||
debug " - Default Route: $(ip route show default 2>/dev/null || echo 'Nicht verfügbar')"
|
||
debug " - Network Interfaces: $(ip addr show 2>/dev/null | grep -E '^[0-9]+:' | cut -d: -f2 | tr -d ' ' | grep -v lo | head -3 || echo 'Nicht verfügbar')"
|
||
fi
|
||
}
|
||
|
||
# =========================== ROBUSTE SYSTEM-VORBEREITUNG ===========================
|
||
update_system() {
|
||
log "=== ANTI-HÄNGE SYSTEM-UPDATE MIT TIMEOUTS ==="
|
||
|
||
progress "Konfiguriere APT für bessere Zuverlässigkeit (timeout-gesichert)..."
|
||
|
||
# APT-Konfiguration optimieren (aggressivere Timeouts)
|
||
timeout 10 bash -c 'cat > /etc/apt/apt.conf.d/99myp-optimized << "EOF"
|
||
APT::Acquire::Retries "2";
|
||
APT::Acquire::http::Timeout "15";
|
||
APT::Acquire::https::Timeout "15";
|
||
APT::Acquire::ftp::Timeout "15";
|
||
APT::Install-Recommends "false";
|
||
APT::Install-Suggests "false";
|
||
Dpkg::Options {
|
||
"--force-confdef";
|
||
"--force-confold";
|
||
}
|
||
APT::Get::Assume-Yes "true";
|
||
APT::Get::Fix-Broken "true";
|
||
EOF' || warning "APT-Konfiguration timeout - verwende Defaults"
|
||
|
||
# Repository-Listen korrigieren (timeout-gesichert)
|
||
progress "Validiere APT-Repositories (timeout-gesichert)..."
|
||
timeout 20 bash -c '
|
||
if [ -f /etc/apt/sources.list ]; then
|
||
cp /etc/apt/sources.list /etc/apt/sources.list.backup 2>/dev/null || true
|
||
if grep -q "deb-src" /etc/apt/sources.list 2>/dev/null; then
|
||
sed -i "s/^deb-src/#deb-src/g" /etc/apt/sources.list 2>/dev/null || true
|
||
echo "Source-Repositories deaktiviert"
|
||
fi
|
||
fi
|
||
' || warning "Repository-Validierung timeout - fahre fort"
|
||
|
||
# APT-Lock-Dateien bereinigen (falls hängend)
|
||
progress "Bereinige APT-Lock-Dateien..."
|
||
timeout 10 bash -c '
|
||
rm -f /var/lib/dpkg/lock-frontend 2>/dev/null || true
|
||
rm -f /var/lib/dpkg/lock 2>/dev/null || true
|
||
rm -f /var/cache/apt/archives/lock 2>/dev/null || true
|
||
rm -f /var/lib/apt/lists/lock 2>/dev/null || true
|
||
' || true
|
||
|
||
progress "Aktualisiere Paketlisten (max 60s timeout)..."
|
||
if timeout 60 apt-get update 2>/dev/null; then
|
||
success "✅ APT Update erfolgreich"
|
||
else
|
||
warning "⚠️ APT Update timeout - fahre ohne Update fort"
|
||
fi
|
||
|
||
progress "Führe System-Upgrade durch (max 120s timeout)..."
|
||
if timeout 120 bash -c 'DEBIAN_FRONTEND=noninteractive apt-get upgrade -y 2>/dev/null'; then
|
||
success "✅ System Upgrade erfolgreich"
|
||
else
|
||
warning "⚠️ System Upgrade timeout - fahre ohne Upgrade fort"
|
||
fi
|
||
|
||
progress "Installiere essenzielle System-Tools..."
|
||
|
||
# Grundlegende Tools in optimierter Reihenfolge
|
||
local essential_packages=(
|
||
"ca-certificates"
|
||
"gnupg"
|
||
"curl"
|
||
"wget"
|
||
"git"
|
||
"nano"
|
||
"htop"
|
||
"rsync"
|
||
"unzip"
|
||
"sudo"
|
||
"systemd"
|
||
"lsb-release"
|
||
"apt-transport-https"
|
||
"software-properties-common"
|
||
"bc"
|
||
"dbus"
|
||
"systemd-timesyncd"
|
||
)
|
||
|
||
for package in "${essential_packages[@]}"; do
|
||
apt_install_retry "$package"
|
||
done
|
||
|
||
# Zeitserver synchronisieren
|
||
progress "Synchronisiere Systemzeit..."
|
||
systemctl enable systemd-timesyncd 2>/dev/null || true
|
||
systemctl start systemd-timesyncd 2>/dev/null || true
|
||
|
||
log "✅ Robustes System-Update abgeschlossen"
|
||
}
|
||
|
||
# =========================== VERBESSERTE PYTHON-INSTALLATION ===========================
|
||
install_python_dependencies() {
|
||
log "=== ROBUSTE PYTHON-INSTALLATION ==="
|
||
|
||
progress "Installiere Python 3 und Build-Abhängigkeiten..."
|
||
|
||
local python_packages=(
|
||
"python3"
|
||
"python3-pip"
|
||
"python3-dev"
|
||
"python3-setuptools"
|
||
"python3-venv"
|
||
"python3-wheel"
|
||
"build-essential"
|
||
"libssl-dev"
|
||
"libffi-dev"
|
||
"libbz2-dev"
|
||
"libreadline-dev"
|
||
"libsqlite3-dev"
|
||
"libncurses5-dev"
|
||
"libncursesw5-dev"
|
||
"zlib1g-dev"
|
||
"sqlite3"
|
||
)
|
||
|
||
for package in "${python_packages[@]}"; do
|
||
apt_install_retry "$package"
|
||
done
|
||
|
||
# Python-Version validieren
|
||
progress "Validiere Python-Installation..."
|
||
local python_version=$(python3 --version 2>&1 | cut -d' ' -f2)
|
||
log "✅ Python Version: $python_version"
|
||
|
||
# pip konfigurieren und aktualisieren
|
||
progress "Konfiguriere pip für bessere Zuverlässigkeit..."
|
||
|
||
# Root pip-Konfiguration
|
||
mkdir -p /root/.pip
|
||
cat > /root/.pip/pip.conf << 'EOF'
|
||
[global]
|
||
trusted-host = pypi.org
|
||
pypi.python.org
|
||
files.pythonhosted.org
|
||
cert = /etc/ssl/certs/ca-certificates.crt
|
||
timeout = 120
|
||
retries = 5
|
||
no-cache-dir = false
|
||
disable-pip-version-check = true
|
||
no-warn-script-location = true
|
||
break-system-packages = true
|
||
|
||
[install]
|
||
trusted-host = pypi.org
|
||
pypi.python.org
|
||
files.pythonhosted.org
|
||
user = false
|
||
break-system-packages = true
|
||
EOF
|
||
|
||
# Systemweite pip-Konfiguration für alle Benutzer
|
||
progress "Erstelle systemweite pip-Konfiguration..."
|
||
mkdir -p /etc/pip
|
||
cat > /etc/pip/pip.conf << 'EOF'
|
||
[global]
|
||
break-system-packages = true
|
||
trusted-host = pypi.org
|
||
pypi.python.org
|
||
files.pythonhosted.org
|
||
timeout = 120
|
||
retries = 5
|
||
disable-pip-version-check = true
|
||
|
||
[install]
|
||
break-system-packages = true
|
||
trusted-host = pypi.org
|
||
pypi.python.org
|
||
files.pythonhosted.org
|
||
user = false
|
||
EOF
|
||
|
||
# pip-Konfiguration für existierende Benutzer erstellen
|
||
progress "Konfiguriere pip für alle Benutzer..."
|
||
for user_home in "/home/"*; do
|
||
if [ -d "$user_home" ] && [ "$user_home" != "/home/lost+found" ]; then
|
||
local username=$(basename "$user_home")
|
||
if id "$username" &>/dev/null; then
|
||
mkdir -p "$user_home/.pip" 2>/dev/null || true
|
||
cat > "$user_home/.pip/pip.conf" << 'EOF'
|
||
[global]
|
||
break-system-packages = true
|
||
trusted-host = pypi.org
|
||
pypi.python.org
|
||
files.pythonhosted.org
|
||
timeout = 60
|
||
retries = 3
|
||
|
||
[install]
|
||
break-system-packages = true
|
||
trusted-host = pypi.org
|
||
pypi.python.org
|
||
files.pythonhosted.org
|
||
EOF
|
||
chown "$username:$username" "$user_home/.pip/pip.conf" 2>/dev/null || true
|
||
log "✅ pip konfiguriert für Benutzer: $username"
|
||
fi
|
||
fi
|
||
done
|
||
|
||
# pip selbst aktualisieren
|
||
progress "Aktualisiere pip mit Retry..."
|
||
retry_command "python3 -m pip install --break-system-packages --upgrade pip setuptools wheel" "pip Upgrade"
|
||
|
||
# pip-Version validieren
|
||
local pip_version=$(python3 -m pip --version | cut -d' ' -f2)
|
||
log "✅ pip Version: $pip_version"
|
||
|
||
log "✅ Robuste Python-Umgebung installiert"
|
||
}
|
||
|
||
install_python_packages() {
|
||
log "=== PYTHON-PAKETE INSTALLATION ==="
|
||
|
||
progress "Installiere Python-Pakete..."
|
||
|
||
if [ ! -f "$CURRENT_DIR/requirements.txt" ]; then
|
||
error "requirements.txt nicht gefunden: $CURRENT_DIR/requirements.txt"
|
||
fi
|
||
|
||
# Kopiere requirements.txt
|
||
cp "$CURRENT_DIR/requirements.txt" "$APP_DIR/" 2>/dev/null || true
|
||
|
||
# Installiere alle Pakete aus requirements.txt
|
||
progress "Installiere requirements.txt..."
|
||
|
||
if python3 -m pip install -r "$CURRENT_DIR/requirements.txt" --break-system-packages; then
|
||
success "✅ requirements.txt erfolgreich installiert"
|
||
else
|
||
error "❌ requirements.txt Installation fehlgeschlagen"
|
||
return 1
|
||
fi
|
||
|
||
# Validiere essenzielle Module
|
||
progress "Validiere essenzielle Python-Module..."
|
||
|
||
local essential_modules=("flask" "requests")
|
||
local validation_success=true
|
||
|
||
for module in "${essential_modules[@]}"; do
|
||
if python3 -c "import $module; print(f'✅ $module verfügbar')" 2>/dev/null; then
|
||
debug "$module erfolgreich importiert"
|
||
else
|
||
warning "⚠️ $module nicht verfügbar"
|
||
validation_success=false
|
||
fi
|
||
done
|
||
|
||
if [ "$validation_success" = true ]; then
|
||
success "✅ Essenzielle Python-Module verfügbar"
|
||
else
|
||
warning "⚠️ Einige essenzielle Module fehlen"
|
||
fi
|
||
|
||
log "✅ Python-Pakete Installation abgeschlossen"
|
||
|
||
# Zeige installierte Pakete
|
||
progress "Zeige installierte Python-Pakete..."
|
||
echo ""
|
||
echo "📦 Installierte Python-Pakete:"
|
||
python3 -m pip list 2>/dev/null | grep -E "(Flask|requests|Werkzeug|Jinja2)" | head -10 || echo " Keine relevanten Pakete gefunden"
|
||
echo ""
|
||
}
|
||
|
||
# =========================== ROBUSTE NODE.JS INSTALLATION ===========================
|
||
install_nodejs_npm() {
|
||
log "=== ROBUSTE NODE.JS UND NPM INSTALLATION ==="
|
||
|
||
# Alte Installationen entfernen
|
||
progress "Bereinige alte Node.js-Installationen..."
|
||
apt-get remove --purge -y nodejs npm 2>/dev/null || true
|
||
apt-get autoremove -y 2>/dev/null || true
|
||
rm -rf /usr/local/bin/node /usr/local/bin/npm 2>/dev/null || true
|
||
|
||
# NodeSource Repository mit Fallback
|
||
progress "Installiere Node.js mit Fallback-Strategie..."
|
||
|
||
local nodejs_installed=false
|
||
|
||
# Strategie 1: NodeSource Repository
|
||
if curl -fsSL https://deb.nodesource.com/setup_lts.x 2>/dev/null | bash - 2>/dev/null; then
|
||
if apt-get update -y && apt_install_retry nodejs; then
|
||
nodejs_installed=true
|
||
log "✅ Node.js via NodeSource Repository installiert"
|
||
fi
|
||
fi
|
||
|
||
# Strategie 2: Snap (falls verfügbar)
|
||
if [ "$nodejs_installed" = false ] && command -v snap >/dev/null 2>&1; then
|
||
progress "Versuche Node.js Installation via Snap..."
|
||
if snap install node --classic 2>/dev/null; then
|
||
nodejs_installed=true
|
||
log "✅ Node.js via Snap installiert"
|
||
fi
|
||
fi
|
||
|
||
# Strategie 3: Debian Repository (Fallback)
|
||
if [ "$nodejs_installed" = false ]; then
|
||
progress "Verwende Debian Repository als Fallback..."
|
||
apt_install_retry nodejs npm
|
||
nodejs_installed=true
|
||
log "✅ Node.js via Debian Repository installiert"
|
||
fi
|
||
|
||
# Validierung
|
||
progress "Validiere Node.js Installation..."
|
||
if command -v node >/dev/null 2>&1; then
|
||
local node_version=$(node --version)
|
||
log "✅ Node.js Version: $node_version"
|
||
else
|
||
error "❌ Node.js nicht verfügbar nach Installation"
|
||
fi
|
||
|
||
if command -v npm >/dev/null 2>&1; then
|
||
local npm_version=$(npm --version)
|
||
log "✅ npm Version: $npm_version"
|
||
|
||
# npm optimieren
|
||
progress "Optimiere npm-Konfiguration..."
|
||
npm config set fund false 2>/dev/null || true
|
||
npm config set audit-level moderate 2>/dev/null || true
|
||
npm config set progress false 2>/dev/null || true
|
||
npm config set loglevel warn 2>/dev/null || true
|
||
else
|
||
# Versuche npm separat zu installieren
|
||
progress "Installiere npm separat..."
|
||
apt_install_retry npm
|
||
fi
|
||
|
||
log "✅ Node.js und npm erfolgreich installiert"
|
||
}
|
||
|
||
# =========================== NETZWERK-SICHERHEIT ===========================
|
||
configure_network_security() {
|
||
log "=== SIMPLE NETZWERK-SICHERHEIT (ANTI-HÄNGE VERSION) ==="
|
||
|
||
# Standardmäßig überspringen um Hänger zu vermeiden
|
||
if [ "${SKIP_NETWORK_SECURITY:-1}" = "1" ]; then
|
||
info "🚀 Netzwerk-Sicherheit übersprungen für schnellere Installation"
|
||
info "📝 Kann später manuell aktiviert werden mit: SKIP_NETWORK_SECURITY=0"
|
||
return
|
||
fi
|
||
|
||
# Komplette Funktion mit aggressivem Timeout
|
||
if ! timeout 30 bash -c '
|
||
# Nur essenzielle IPv6-Deaktivierung
|
||
progress() { echo "[FORTSCHRITT] $1"; }
|
||
warning() { echo "[WARNUNG] $1"; }
|
||
success() { echo "[ERFOLG] $1"; }
|
||
|
||
progress "Deaktiviere IPv6 (essentiell, max 30s)..."
|
||
|
||
# 1. Einfache sysctl IPv6-Deaktivierung (schnell)
|
||
echo "net.ipv6.conf.all.disable_ipv6=1" > /etc/sysctl.d/99-myp-ipv6.conf 2>/dev/null || true
|
||
echo "net.ipv6.conf.default.disable_ipv6=1" >> /etc/sysctl.d/99-myp-ipv6.conf 2>/dev/null || true
|
||
|
||
# 2. IPv6 in /etc/hosts auskommentieren (schnell)
|
||
if [ -f /etc/hosts ]; then
|
||
sed -i.backup "s/^::1/#::1/" /etc/hosts 2>/dev/null || true
|
||
fi
|
||
|
||
# 3. GRUB nur wenn schnell verfügbar
|
||
if [ -f /etc/default/grub ] && command -v update-grub >/dev/null 2>&1; then
|
||
if ! grep -q "ipv6.disable=1" /etc/default/grub 2>/dev/null; then
|
||
cp /etc/default/grub /etc/default/grub.backup 2>/dev/null || true
|
||
sed -i "s/GRUB_CMDLINE_LINUX_DEFAULT=\"/&ipv6.disable=1 /" /etc/default/grub 2>/dev/null || true
|
||
# update-grub nur mit 10s timeout
|
||
if timeout 10 update-grub >/dev/null 2>&1; then
|
||
success "GRUB IPv6 deaktiviert"
|
||
else
|
||
warning "GRUB-Update timeout - wird beim nächsten Boot aktiv"
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
success "IPv6-Deaktivierung abgeschlossen"
|
||
'; then
|
||
warning "⚠️ Netzwerk-Sicherheit timeout (30s) - überspringe"
|
||
info " → System funktioniert trotzdem normal"
|
||
info " → IPv6-Deaktivierung kann später manuell durchgeführt werden"
|
||
else
|
||
log "✅ Basis-Netzwerk-Sicherheit konfiguriert:"
|
||
log " 🚫 IPv6 deaktiviert"
|
||
log " 📝 Konfiguration in /etc/sysctl.d/99-myp-ipv6.conf"
|
||
log " 🔄 Wird beim nächsten Boot vollständig aktiv"
|
||
fi
|
||
}
|
||
|
||
# =========================== DESKTOP-ENVIRONMENT ENTFERNUNG ===========================
|
||
remove_desktop_environments() {
|
||
log "=== ENTFERNE DESKTOP ENVIRONMENTS FÜR KIOSK-MODUS ==="
|
||
|
||
progress "Stoppe alle Desktop-Services..."
|
||
local desktop_services=("lightdm" "gdm3" "sddm" "xdm" "nodm")
|
||
|
||
for service in "${desktop_services[@]}"; do
|
||
systemctl stop "$service" 2>/dev/null || true
|
||
systemctl disable "$service" 2>/dev/null || true
|
||
done
|
||
|
||
progress "Entferne Desktop-Pakete vollständig..."
|
||
|
||
# Raspberry Pi OS Desktop-Pakete
|
||
apt-get remove --purge -y \
|
||
raspberrypi-ui-mods \
|
||
pi-package \
|
||
desktop-base \
|
||
lxde* \
|
||
xfce4* \
|
||
gnome* \
|
||
kde* \
|
||
mate* \
|
||
cinnamon* \
|
||
openbox \
|
||
pcmanfm \
|
||
file-manager* \
|
||
task-lxde-desktop \
|
||
task-xfce-desktop \
|
||
task-gnome-desktop \
|
||
task-kde-desktop \
|
||
2>/dev/null || true
|
||
|
||
# Display Manager entfernen
|
||
apt-get remove --purge -y \
|
||
lightdm* \
|
||
gdm3* \
|
||
sddm* \
|
||
xdm* \
|
||
nodm* \
|
||
2>/dev/null || true
|
||
|
||
# Unnötige Anwendungen entfernen
|
||
apt-get remove --purge -y \
|
||
libreoffice* \
|
||
thunderbird* \
|
||
firefox* \
|
||
vlc* \
|
||
gimp* \
|
||
scratch* \
|
||
minecraft-pi \
|
||
sonic-pi \
|
||
2>/dev/null || true
|
||
|
||
# Aufräumen
|
||
apt-get autoremove --purge -y
|
||
apt-get autoclean
|
||
|
||
log "✅ Desktop Environments vollständig entfernt"
|
||
}
|
||
|
||
# =========================== MINIMALE X11-UMGEBUNG ===========================
|
||
install_minimal_x11() {
|
||
log "=== INSTALLIERE MINIMALE X11-UMGEBUNG FÜR KIOSK ==="
|
||
|
||
progress "Installiere minimale X11-Pakete..."
|
||
apt-get install -y \
|
||
xserver-xorg-core \
|
||
xserver-xorg-input-all \
|
||
xserver-xorg-video-fbdev \
|
||
xserver-xorg-video-vesa \
|
||
xinit \
|
||
x11-xserver-utils \
|
||
xdotool \
|
||
unclutter \
|
||
openbox \
|
||
|| error "X11 Installation fehlgeschlagen"
|
||
|
||
# Browser-Installation mit Fallback-Mechanismus
|
||
progress "Installiere Browser für Kiosk-Modus..."
|
||
local browser_installed=false
|
||
|
||
# Versuche Chromium zu installieren
|
||
if apt-get install -y chromium 2>/dev/null; then
|
||
log "✅ Chromium erfolgreich installiert"
|
||
browser_installed=true
|
||
elif apt-get install -y chromium-browser 2>/dev/null; then
|
||
log "✅ Chromium-Browser erfolgreich installiert"
|
||
browser_installed=true
|
||
elif apt-get install -y firefox-esr 2>/dev/null; then
|
||
warning "⚠️ Chromium nicht verfügbar - Firefox ESR als Fallback installiert"
|
||
browser_installed=true
|
||
fi
|
||
|
||
if [ "$browser_installed" = false ]; then
|
||
error "❌ Kein Browser verfügbar (chromium, chromium-browser, firefox-esr)"
|
||
fi
|
||
|
||
log "✅ Minimale X11-Umgebung installiert"
|
||
}
|
||
|
||
# =========================== X11 KONFIGURATION FÜR RASPBERRY PI ===========================
|
||
configure_x11_for_raspberry_pi() {
|
||
log "=== KONFIGURIERE X11 FÜR RASPBERRY PI ==="
|
||
|
||
progress "Erstelle X11-Konfiguration für Raspberry Pi..."
|
||
|
||
# Erstelle xorg.conf.d Verzeichnis
|
||
mkdir -p /etc/X11/xorg.conf.d
|
||
|
||
# Erstelle 99-fbdev.conf um Framebuffer-Fehler zu beheben
|
||
cat > /etc/X11/xorg.conf.d/99-fbdev.conf << 'XORGEOF'
|
||
# X11 Konfiguration für Raspberry Pi - behebt Framebuffer-Fehler
|
||
Section "Device"
|
||
Identifier "Raspberry Pi FBDEV"
|
||
Driver "fbdev"
|
||
Option "fbdev" "/dev/fb0"
|
||
Option "SwapbuffersWait" "true"
|
||
EndSection
|
||
|
||
Section "Screen"
|
||
Identifier "Primary Screen"
|
||
Device "Raspberry Pi FBDEV"
|
||
DefaultDepth 24
|
||
SubSection "Display"
|
||
Depth 24
|
||
Modes "1920x1080" "1680x1050" "1600x900" "1280x1024" "1280x800" "1024x768"
|
||
EndSubSection
|
||
EndSection
|
||
|
||
Section "ServerLayout"
|
||
Identifier "Default Layout"
|
||
Screen "Primary Screen"
|
||
EndSection
|
||
|
||
Section "ServerFlags"
|
||
Option "BlankTime" "0"
|
||
Option "StandbyTime" "0"
|
||
Option "SuspendTime" "0"
|
||
Option "OffTime" "0"
|
||
Option "DPMS" "false"
|
||
EndSection
|
||
XORGEOF
|
||
|
||
# Alternative: Verwende modesetting Treiber statt fbdev
|
||
cat > /etc/X11/xorg.conf.d/20-modesetting.conf << 'MODESETEOF'
|
||
# Alternative Modesetting-Konfiguration
|
||
Section "Device"
|
||
Identifier "Raspberry Pi Modesetting"
|
||
Driver "modesetting"
|
||
Option "AccelMethod" "none"
|
||
EndSection
|
||
MODESETEOF
|
||
|
||
# Erstelle Wrapper-Skript für X11-Start mit korrekten Parametern
|
||
cat > /usr/local/bin/start-x11-kiosk << 'KIOSKSTARTEOF'
|
||
#!/bin/bash
|
||
|
||
# X11 Kiosk-Start-Wrapper für Raspberry Pi
|
||
# Behebt Framebuffer und Permission-Probleme
|
||
|
||
export DISPLAY=:0
|
||
export XAUTHORITY=/home/kiosk/.Xauthority
|
||
|
||
# Erstelle .Xauthority falls nicht vorhanden
|
||
if [ ! -f "$XAUTHORITY" ]; then
|
||
touch "$XAUTHORITY"
|
||
chown kiosk:kiosk "$XAUTHORITY"
|
||
chmod 600 "$XAUTHORITY"
|
||
fi
|
||
|
||
# Stoppe eventuell laufende X-Server
|
||
pkill -f "X :0" 2>/dev/null || true
|
||
pkill -f "Xorg" 2>/dev/null || true
|
||
sleep 2
|
||
|
||
# Versuche verschiedene X-Server Start-Methoden
|
||
echo "Starte X-Server für Kiosk-Modus..."
|
||
|
||
# Methode 1: Mit vt und novtswitch (empfohlen für Raspberry Pi)
|
||
if ! xinit /home/kiosk/.xinitrc -- :0 vt7 -novtswitch -nolisten tcp -dpi 96 2>/tmp/x11-error.log; then
|
||
echo "Methode 1 fehlgeschlagen, versuche Alternative..."
|
||
|
||
# Methode 2: Mit config und ignoreABI
|
||
if ! xinit /home/kiosk/.xinitrc -- :0 vt7 -config /etc/X11/xorg.conf.d/99-fbdev.conf -ignoreABI 2>>/tmp/x11-error.log; then
|
||
echo "Methode 2 fehlgeschlagen, versuche Fallback..."
|
||
|
||
# Methode 3: Minimaler Start
|
||
xinit /home/kiosk/.xinitrc -- :0 2>>/tmp/x11-error.log
|
||
fi
|
||
fi
|
||
|
||
# Fehlerlog anzeigen bei Problem
|
||
if [ -f /tmp/x11-error.log ]; then
|
||
echo "X11 Fehler-Log:"
|
||
tail -20 /tmp/x11-error.log
|
||
fi
|
||
KIOSKSTARTEOF
|
||
|
||
chmod +x /usr/local/bin/start-x11-kiosk
|
||
|
||
# Installiere fehlende Video-Treiber
|
||
progress "Installiere Video-Treiber für Raspberry Pi..."
|
||
apt-get install -y xserver-xorg-video-fbturbo 2>/dev/null || {
|
||
# Fallback zu Standard-Treibern
|
||
apt-get install -y xserver-xorg-video-all 2>/dev/null || true
|
||
}
|
||
|
||
# Raspberry Pi spezifische Video-Treiber
|
||
if [ -f /boot/config.txt ]; then
|
||
progress "Konfiguriere Raspberry Pi GPU-Einstellungen..."
|
||
|
||
# Backup config.txt
|
||
cp /boot/config.txt /boot/config.txt.backup
|
||
|
||
# GPU-Speicher erhöhen für bessere Grafik-Performance
|
||
if ! grep -q "^gpu_mem=" /boot/config.txt; then
|
||
echo "gpu_mem=128" >> /boot/config.txt
|
||
fi
|
||
|
||
# HDMI-Einstellungen für bessere Kompatibilität
|
||
if ! grep -q "^hdmi_force_hotplug=" /boot/config.txt; then
|
||
cat >> /boot/config.txt << 'BOOTEOF'
|
||
|
||
# X11 Kiosk-Modus Optimierungen
|
||
hdmi_force_hotplug=1
|
||
hdmi_drive=2
|
||
config_hdmi_boost=4
|
||
disable_overscan=1
|
||
framebuffer_width=1920
|
||
framebuffer_height=1080
|
||
framebuffer_depth=32
|
||
framebuffer_ignore_alpha=1
|
||
BOOTEOF
|
||
fi
|
||
fi
|
||
|
||
# Erstelle alternatives .xinitrc für kiosk User
|
||
cat > /home/kiosk/.xinitrc-fixed << 'XINITRCEOF'
|
||
#!/bin/bash
|
||
|
||
# Fehlerbehandlung
|
||
set -e
|
||
exec 2>/tmp/xinitrc-error.log
|
||
|
||
# X11 Einstellungen
|
||
xset s off
|
||
xset s noblank
|
||
xset -dpms
|
||
|
||
# Mauszeiger verstecken
|
||
unclutter -idle 0.1 -root -noevents &
|
||
|
||
# Window Manager starten (lightweight)
|
||
openbox-session &
|
||
|
||
# Warte kurz
|
||
sleep 2
|
||
|
||
# Browser starten
|
||
if command -v chromium >/dev/null 2>&1; then
|
||
BROWSER="chromium"
|
||
elif command -v chromium-browser >/dev/null 2>&1; then
|
||
BROWSER="chromium-browser"
|
||
else
|
||
BROWSER="firefox-esr"
|
||
fi
|
||
|
||
# Starte Browser im Kiosk-Modus
|
||
exec $BROWSER \
|
||
--kiosk \
|
||
--no-sandbox \
|
||
--disable-gpu-sandbox \
|
||
--disable-software-rasterizer \
|
||
--disable-dev-shm-usage \
|
||
--disable-setuid-sandbox \
|
||
--disable-gpu \
|
||
--no-first-run \
|
||
--noerrdialogs \
|
||
--disable-infobars \
|
||
--start-fullscreen \
|
||
http://localhost:5000
|
||
XINITRCEOF
|
||
|
||
chmod +x /home/kiosk/.xinitrc-fixed
|
||
chown kiosk:kiosk /home/kiosk/.xinitrc-fixed
|
||
|
||
# Aktualisiere die .bashrc für den alternativen Start
|
||
cat > /home/kiosk/.bashrc-kiosk << 'BASHRCEOF4'
|
||
# Kiosk-Autostart mit X11-Fixes
|
||
if [ -z "$DISPLAY" ] && [ "$XDG_VTNR" = "1" ]; then
|
||
echo "Starte Kiosk-Modus mit X11-Fixes..."
|
||
|
||
# Verwende das neue Start-Skript
|
||
exec /usr/local/bin/start-x11-kiosk
|
||
fi
|
||
BASHRCEOF4
|
||
|
||
log "✅ X11-Konfiguration für Raspberry Pi erstellt"
|
||
info " 📁 Konfiguration: /etc/X11/xorg.conf.d/"
|
||
info " 🚀 Start-Skript: /usr/local/bin/start-x11-kiosk"
|
||
info " 🔧 Alternative .xinitrc: /home/kiosk/.xinitrc-fixed"
|
||
}
|
||
|
||
# =========================== KIOSK-BENUTZER MANAGEMENT ===========================
|
||
create_kiosk_user() {
|
||
log "=== KIOSK-BENUTZER SETUP ==="
|
||
|
||
if ! id "$KIOSK_USER" &>/dev/null; then
|
||
progress "Erstelle Kiosk-Benutzer: $KIOSK_USER"
|
||
useradd -m -s /bin/bash "$KIOSK_USER" || error "Kann Kiosk-Benutzer nicht erstellen"
|
||
|
||
# Gruppen hinzufügen
|
||
usermod -aG audio,video,input,dialout,plugdev,users "$KIOSK_USER" 2>/dev/null || true
|
||
|
||
# pip-Konfiguration für Kiosk-Benutzer
|
||
local kiosk_home="/home/$KIOSK_USER"
|
||
mkdir -p "$kiosk_home/.pip" 2>/dev/null || true
|
||
cat > "$kiosk_home/.pip/pip.conf" << 'EOF'
|
||
[global]
|
||
break-system-packages = true
|
||
trusted-host = pypi.org
|
||
pypi.python.org
|
||
files.pythonhosted.org
|
||
timeout = 60
|
||
retries = 3
|
||
|
||
[install]
|
||
break-system-packages = true
|
||
trusted-host = pypi.org
|
||
pypi.python.org
|
||
files.pythonhosted.org
|
||
EOF
|
||
chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.pip/pip.conf" 2>/dev/null || true
|
||
else
|
||
info "Kiosk-Benutzer $KIOSK_USER existiert bereits"
|
||
fi
|
||
|
||
# Passwort entfernen für automatischen Login
|
||
passwd -d "$KIOSK_USER" || warning "Konnte Passwort nicht entfernen"
|
||
|
||
log "✅ Kiosk-Benutzer konfiguriert: $KIOSK_USER"
|
||
}
|
||
|
||
configure_autologin() {
|
||
log "=== KONFIGURIERE AUTOLOGIN FÜR KIOSK-BENUTZER ==="
|
||
|
||
# Getty-Service für automatischen Login konfigurieren
|
||
progress "Konfiguriere automatischen Login auf tty1..."
|
||
|
||
local getty_override_dir="/etc/systemd/system/getty@tty1.service.d"
|
||
mkdir -p "$getty_override_dir"
|
||
|
||
cat > "$getty_override_dir/override.conf" << EOF
|
||
[Service]
|
||
ExecStart=
|
||
ExecStart=-/sbin/agetty --autologin $KIOSK_USER --noclear %I \$TERM
|
||
EOF
|
||
|
||
# Systemd-Konfiguration neu laden
|
||
systemctl daemon-reload
|
||
systemctl enable getty@tty1.service
|
||
|
||
log "✅ Autologin für $KIOSK_USER konfiguriert"
|
||
}
|
||
|
||
configure_kiosk_autostart() {
|
||
log "=== KONFIGURIERE AUTOMATISCHEN KIOSK-START ==="
|
||
|
||
# Erstelle .bashrc für automatischen X-Server und Browser-Start
|
||
progress "Konfiguriere automatischen Kiosk-Start für $KIOSK_USER..."
|
||
|
||
local kiosk_home="/home/$KIOSK_USER"
|
||
|
||
# .bashrc für automatischen Start erstellen
|
||
cat > "$kiosk_home/.bashrc" << 'EOF'
|
||
# Automatischer Kiosk-Start beim Login
|
||
if [ -z "$DISPLAY" ] && [ "$XDG_VTNR" = "1" ]; then
|
||
echo "Starte Kiosk-Modus..."
|
||
|
||
# X-Server im Hintergrund starten
|
||
startx /home/kiosk/.xinitrc -- :0 vt1 &
|
||
|
||
# Warte bis X-Server bereit ist
|
||
sleep 5
|
||
|
||
# Setze DISPLAY-Variable
|
||
export DISPLAY=:0
|
||
|
||
# Warte auf HTTP-Backend
|
||
echo "Warte auf HTTP-Backend..."
|
||
for i in {1..60}; do
|
||
if curl -s http://localhost:5000 >/dev/null 2>&1; then
|
||
echo "HTTP-Backend erreichbar"
|
||
break
|
||
fi
|
||
echo "Warte... ($i/60)"
|
||
sleep 2
|
||
done
|
||
|
||
# Bildschirmschoner deaktivieren
|
||
xset s off
|
||
xset s noblank
|
||
xset -dpms
|
||
|
||
# Mauszeiger verstecken
|
||
unclutter -idle 0.1 -root -noevents &
|
||
|
||
# Browser im Kiosk-Modus starten
|
||
if command -v chromium >/dev/null 2>&1; then
|
||
BROWSER="chromium"
|
||
elif command -v chromium-browser >/dev/null 2>&1; then
|
||
BROWSER="chromium-browser"
|
||
else
|
||
BROWSER="firefox-esr"
|
||
fi
|
||
|
||
echo "Starte $BROWSER im Kiosk-Modus..."
|
||
|
||
if [[ "$BROWSER" == "chromium"* ]]; then
|
||
exec $BROWSER \
|
||
--kiosk \
|
||
--no-sandbox \
|
||
--disable-infobars \
|
||
--disable-session-crashed-bubble \
|
||
--disable-restore-session-state \
|
||
--disable-features=TranslateUI \
|
||
--disable-extensions \
|
||
--disable-plugins \
|
||
--disable-popup-blocking \
|
||
--disable-prompt-on-repost \
|
||
--disable-sync \
|
||
--disable-translate \
|
||
--noerrdialogs \
|
||
--no-first-run \
|
||
--no-default-browser-check \
|
||
--autoplay-policy=no-user-gesture-required \
|
||
--start-fullscreen \
|
||
--start-maximized \
|
||
--user-data-dir=/home/kiosk/.chromium-kiosk \
|
||
--disable-background-mode \
|
||
--force-device-scale-factor=1.0 \
|
||
--disable-pinch \
|
||
--overscroll-history-navigation=0 \
|
||
--disable-dev-shm-usage \
|
||
--memory-pressure-off \
|
||
--max_old_space_size=512 \
|
||
--disable-background-timer-throttling \
|
||
--disable-backgrounding-occluded-windows \
|
||
--disable-renderer-backgrounding \
|
||
--disable-features=VizDisplayCompositor \
|
||
--enable-features=OverlayScrollbar \
|
||
--hide-scrollbars \
|
||
--ignore-certificate-errors \
|
||
--ignore-ssl-errors \
|
||
--ignore-certificate-errors-spki-list \
|
||
--disable-web-security \
|
||
--allow-running-insecure-content \
|
||
http://localhost:5000
|
||
else
|
||
exec firefox-esr \
|
||
--kiosk \
|
||
http://localhost:5000
|
||
fi
|
||
fi
|
||
EOF
|
||
|
||
# .xinitrc für X-Server-Konfiguration erstellen
|
||
cat > "$kiosk_home/.xinitrc" << 'EOF'
|
||
#!/bin/bash
|
||
# Minimale X-Session für Kiosk-Modus
|
||
exec openbox-session
|
||
EOF
|
||
|
||
# Berechtigungen setzen
|
||
chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.bashrc"
|
||
chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.xinitrc"
|
||
chmod +x "$kiosk_home/.xinitrc"
|
||
|
||
# Erstelle Kiosk-Verzeichnisse
|
||
mkdir -p "$kiosk_home/.chromium-kiosk"
|
||
chown -R "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.chromium-kiosk"
|
||
|
||
# X11-Autorisierung für kiosk-User konfigurieren
|
||
progress "Konfiguriere X11-Autorisierung für kiosk-User..."
|
||
|
||
# Erstelle .Xauthority Datei
|
||
touch "$kiosk_home/.Xauthority"
|
||
chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.Xauthority"
|
||
chmod 600 "$kiosk_home/.Xauthority"
|
||
|
||
# Füge DISPLAY-Variable zum .bashrc hinzu
|
||
if ! grep -q "export DISPLAY=" "$kiosk_home/.bashrc" 2>/dev/null; then
|
||
cat >> "$kiosk_home/.bashrc" << 'BASHRCEOF3'
|
||
|
||
# X11 Display Konfiguration
|
||
export DISPLAY=:0.0
|
||
export XAUTHORITY=/home/kiosk/.Xauthority
|
||
|
||
# X11 Session Management
|
||
if [ -z "$DISPLAY" ] && [ "$XDG_VTNR" = "1" ]; then
|
||
export DISPLAY=:0.0
|
||
fi
|
||
|
||
BASHRCEOF3
|
||
chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.bashrc"
|
||
fi
|
||
|
||
# Erstelle X11-Startup-Hilfsskript
|
||
cat > "$kiosk_home/start-x11.sh" << 'EOF'
|
||
#!/bin/bash
|
||
|
||
# X11-Startup-Hilfsskript für kiosk-User
|
||
# Behebt .Xauthority und DISPLAY-Probleme
|
||
|
||
export HOME=/home/kiosk
|
||
export USER=kiosk
|
||
export DISPLAY=:0.0
|
||
export XAUTHORITY=/home/kiosk/.Xauthority
|
||
|
||
# Erstelle .Xauthority falls nicht vorhanden
|
||
if [ ! -f "$XAUTHORITY" ]; then
|
||
touch "$XAUTHORITY"
|
||
chmod 600 "$XAUTHORITY"
|
||
fi
|
||
|
||
# Prüfe ob X11-Server läuft
|
||
if ! pgrep -x "X" > /dev/null && ! pgrep -x "Xorg" > /dev/null; then
|
||
echo "Starte X11-Server..."
|
||
startx /home/kiosk/.xinitrc -- :0 vt1 &
|
||
sleep 3
|
||
fi
|
||
|
||
# Warte bis X11-Server verfügbar ist
|
||
timeout=30
|
||
elapsed=0
|
||
while [ $elapsed -lt $timeout ]; do
|
||
if xset q >/dev/null 2>&1; then
|
||
echo "X11-Server ist bereit"
|
||
break
|
||
fi
|
||
sleep 1
|
||
elapsed=$((elapsed + 1))
|
||
done
|
||
|
||
if [ $elapsed -ge $timeout ]; then
|
||
echo "FEHLER: X11-Server nicht verfügbar nach ${timeout}s"
|
||
exit 1
|
||
fi
|
||
|
||
echo "X11-Session erfolgreich gestartet"
|
||
EOF
|
||
|
||
chmod +x "$kiosk_home/start-x11.sh"
|
||
chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/start-x11.sh"
|
||
|
||
log "✅ Automatischer Kiosk-Start konfiguriert"
|
||
info "Der Kiosk-Modus startet automatisch beim Login des $KIOSK_USER"
|
||
|
||
# Wenn X11-Konfiguration für Raspberry Pi vorhanden ist, verwende sie
|
||
if [ -f /usr/local/bin/start-x11-kiosk ]; then
|
||
progress "Aktualisiere .bashrc für X11-Fix-Integration..."
|
||
|
||
# Backup der aktuellen .bashrc
|
||
cp "$kiosk_home/.bashrc" "$kiosk_home/.bashrc.backup"
|
||
|
||
# Verwende die korrigierte Version
|
||
cat > "$kiosk_home/.bashrc" << 'BASHRCFIXED'
|
||
# Automatischer Kiosk-Start beim Login mit X11-Fixes
|
||
if [ -z "$DISPLAY" ] && [ "$XDG_VTNR" = "1" ]; then
|
||
echo "Starte Kiosk-Modus mit X11-Fixes..."
|
||
|
||
# Verwende das X11-Fix Start-Skript wenn vorhanden
|
||
if [ -x /usr/local/bin/start-x11-kiosk ]; then
|
||
exec /usr/local/bin/start-x11-kiosk
|
||
else
|
||
# Fallback zum normalen Start
|
||
startx /home/kiosk/.xinitrc -- :0 vt1 &
|
||
sleep 5
|
||
export DISPLAY=:0
|
||
|
||
# Warte auf HTTP-Backend
|
||
echo "Warte auf HTTP-Backend..."
|
||
for i in {1..60}; do
|
||
if curl -s http://localhost:5000 >/dev/null 2>&1; then
|
||
echo "HTTP-Backend erreichbar"
|
||
break
|
||
fi
|
||
echo "Warte... ($i/60)"
|
||
sleep 2
|
||
done
|
||
|
||
# Bildschirmschoner deaktivieren
|
||
xset s off
|
||
xset s noblank
|
||
xset -dpms
|
||
|
||
# Mauszeiger verstecken
|
||
unclutter -idle 0.1 -root -noevents &
|
||
|
||
# Browser im Kiosk-Modus starten
|
||
if command -v chromium >/dev/null 2>&1; then
|
||
BROWSER="chromium"
|
||
elif command -v chromium-browser >/dev/null 2>&1; then
|
||
BROWSER="chromium-browser"
|
||
else
|
||
BROWSER="firefox-esr"
|
||
fi
|
||
|
||
echo "Starte $BROWSER im Kiosk-Modus..."
|
||
|
||
if [[ "$BROWSER" == "chromium"* ]]; then
|
||
exec $BROWSER \
|
||
--kiosk \
|
||
--no-sandbox \
|
||
--disable-infobars \
|
||
--disable-session-crashed-bubble \
|
||
--disable-restore-session-state \
|
||
--disable-features=TranslateUI \
|
||
--disable-extensions \
|
||
--disable-plugins \
|
||
--disable-popup-blocking \
|
||
--disable-prompt-on-repost \
|
||
--disable-sync \
|
||
--disable-translate \
|
||
--noerrdialogs \
|
||
--no-first-run \
|
||
--no-default-browser-check \
|
||
--autoplay-policy=no-user-gesture-required \
|
||
--start-fullscreen \
|
||
--start-maximized \
|
||
--user-data-dir=/home/kiosk/.chromium-kiosk \
|
||
--disable-background-mode \
|
||
--force-device-scale-factor=1.0 \
|
||
--disable-pinch \
|
||
--overscroll-history-navigation=0 \
|
||
--disable-dev-shm-usage \
|
||
--memory-pressure-off \
|
||
--max_old_space_size=512 \
|
||
--disable-background-timer-throttling \
|
||
--disable-backgrounding-occluded-windows \
|
||
--disable-renderer-backgrounding \
|
||
--disable-features=VizDisplayCompositor \
|
||
--enable-features=OverlayScrollbar \
|
||
--hide-scrollbars \
|
||
--ignore-certificate-errors \
|
||
--ignore-ssl-errors \
|
||
--ignore-certificate-errors-spki-list \
|
||
--disable-web-security \
|
||
--allow-running-insecure-content \
|
||
http://localhost:5000
|
||
else
|
||
exec firefox-esr \
|
||
--kiosk \
|
||
http://localhost:5000
|
||
fi
|
||
fi
|
||
fi
|
||
BASHRCFIXED
|
||
|
||
chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.bashrc"
|
||
log "✅ .bashrc für X11-Fix-Integration aktualisiert"
|
||
fi
|
||
}
|
||
|
||
# =========================== ROBUSTE SSL-ZERTIFIKATE INSTALLATION ===========================
|
||
install_ssl_certificates() {
|
||
log "=== ANTI-HÄNGE SSL-ZERTIFIKATE KONFIGURATION ==="
|
||
|
||
progress "Installiere SSL-Grundkomponenten (timeout-gesichert)..."
|
||
if timeout 60 apt-get install -y ca-certificates openssl 2>/dev/null; then
|
||
success "✅ SSL-Grundkomponenten installiert"
|
||
else
|
||
warning "⚠️ SSL-Installation timeout - verwende bestehende"
|
||
fi
|
||
|
||
progress "Überspringe CA-Update um Hänger zu vermeiden..."
|
||
info "💡 CA-Zertifikate werden beim nächsten Boot automatisch aktualisiert"
|
||
|
||
# SSL-Verzeichnisse sicherstellen (timeout-gesichert)
|
||
timeout 10 mkdir -p /usr/local/share/ca-certificates/myp 2>/dev/null || true
|
||
|
||
# Mercedes Corporate Zertifikate (ultra-vereinfacht)
|
||
if [ -d "$CURRENT_DIR/certs/mercedes" ] && [ "$(ls -A $CURRENT_DIR/certs/mercedes 2>/dev/null)" ]; then
|
||
progress "Kopiere Mercedes-Zertifikate (max 30s)..."
|
||
|
||
# Sehr einfacher und schneller Ansatz
|
||
timeout 30 bash -c '
|
||
cert_count=0
|
||
find "$1/certs/mercedes" -name "*.crt" -o -name "*.pem" | head -5 | while read cert_file; do
|
||
cert_count=$((cert_count + 1))
|
||
cert_name="mercedes-$(basename "$cert_file" | cut -d. -f1)"
|
||
if cp "$cert_file" "/usr/local/share/ca-certificates/myp/${cert_name}.crt" 2>/dev/null; then
|
||
echo "Zertifikat kopiert: $cert_name"
|
||
fi
|
||
[ $cert_count -ge 5 ] && break
|
||
done
|
||
' -- "$CURRENT_DIR" 2>/dev/null || warning "Mercedes-Zertifikate timeout - überspringe"
|
||
|
||
info "Mercedes-Zertifikate werden beim nächsten Boot aktiv"
|
||
else
|
||
info "Keine Mercedes-Zertifikate gefunden"
|
||
fi
|
||
|
||
# SSL-Umgebungsvariablen setzen (timeout-gesichert)
|
||
progress "Konfiguriere SSL-Umgebungsvariablen (schnell)..."
|
||
timeout 10 bash -c 'cat >> /etc/environment << "EOF"
|
||
|
||
# SSL Certificate Configuration für MYP
|
||
SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
|
||
REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
|
||
CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
|
||
EOF' || warning "SSL-Umgebungsvariablen timeout"
|
||
|
||
# SSL-Umgebungsvariablen für aktuelle Session
|
||
export SSL_CERT_FILE="/etc/ssl/certs/ca-certificates.crt" 2>/dev/null || true
|
||
export REQUESTS_CA_BUNDLE="/etc/ssl/certs/ca-certificates.crt" 2>/dev/null || true
|
||
export CURL_CA_BUNDLE="/etc/ssl/certs/ca-certificates.crt" 2>/dev/null || true
|
||
|
||
log "✅ SSL-Zertifikate anti-hänge konfiguriert"
|
||
info "📝 CA-Updates werden automatisch beim nächsten Boot durchgeführt"
|
||
}
|
||
|
||
# =========================== ROBUSTES ANWENDUNGS-DEPLOYMENT ===========================
|
||
deploy_application() {
|
||
log "=== ROBUSTES ANWENDUNGS-DEPLOYMENT ==="
|
||
|
||
progress "Erstelle sicheres Zielverzeichnis: $APP_DIR"
|
||
mkdir -p "$APP_DIR" || error "Konnte Zielverzeichnis nicht erstellen"
|
||
|
||
# Validiere Source-Verzeichnis
|
||
progress "Validiere Source-Dateien..."
|
||
if [ ! -f "$CURRENT_DIR/app.py" ]; then
|
||
error "Kritische Datei nicht gefunden: $CURRENT_DIR/app.py"
|
||
fi
|
||
|
||
if [ ! -f "$CURRENT_DIR/requirements.txt" ]; then
|
||
error "Kritische Datei nicht gefunden: $CURRENT_DIR/requirements.txt"
|
||
fi
|
||
|
||
progress "Kopiere Anwendungsdateien (robust)..."
|
||
|
||
# Kritische Dateien zuerst (mit Validierung)
|
||
local critical_files=(
|
||
"app.py"
|
||
"models.py"
|
||
"requirements.txt"
|
||
)
|
||
|
||
for file in "${critical_files[@]}"; do
|
||
if [ -f "$CURRENT_DIR/$file" ]; then
|
||
progress "Kopiere kritische Datei: $file"
|
||
if cp "$CURRENT_DIR/$file" "$APP_DIR/" 2>/dev/null; then
|
||
success "✅ $file erfolgreich kopiert"
|
||
else
|
||
error "❌ Fehler beim Kopieren der kritischen Datei: $file"
|
||
fi
|
||
else
|
||
error "❌ Kritische Datei fehlt: $file"
|
||
fi
|
||
done
|
||
|
||
# Verzeichnisse mit robuster Behandlung
|
||
local directories=(
|
||
"blueprints"
|
||
"config"
|
||
"database"
|
||
"static"
|
||
"templates"
|
||
"uploads"
|
||
"utils"
|
||
"logs"
|
||
"certs"
|
||
)
|
||
|
||
for dir in "${directories[@]}"; do
|
||
if [ -d "$CURRENT_DIR/$dir" ]; then
|
||
progress "Kopiere Verzeichnis: $dir"
|
||
if cp -r "$CURRENT_DIR/$dir" "$APP_DIR/" 2>/dev/null; then
|
||
success "✅ $dir erfolgreich kopiert"
|
||
else
|
||
warning "⚠️ Fehler beim Kopieren von $dir (möglicherweise nicht kritisch)"
|
||
fi
|
||
else
|
||
info "Verzeichnis nicht vorhanden: $dir"
|
||
fi
|
||
done
|
||
|
||
# Optionale Dateien
|
||
local optional_files=(
|
||
"package.json"
|
||
"package-lock.json"
|
||
"tailwind.config.js"
|
||
"postcss.config.js"
|
||
"README.md"
|
||
".gitignore"
|
||
)
|
||
|
||
for file in "${optional_files[@]}"; do
|
||
if [ -f "$CURRENT_DIR/$file" ]; then
|
||
progress "Kopiere optionale Datei: $file"
|
||
cp "$CURRENT_DIR/$file" "$APP_DIR/" 2>/dev/null || warning "⚠️ Kopieren von $file fehlgeschlagen"
|
||
fi
|
||
done
|
||
|
||
# Erstelle alle notwendigen Verzeichnisse mit korrekter Struktur
|
||
progress "Erstelle Verzeichnisstruktur..."
|
||
local required_dirs=(
|
||
"database/backups"
|
||
"logs/app"
|
||
"logs/auth"
|
||
"logs/errors"
|
||
"logs/system"
|
||
"uploads/temp"
|
||
"uploads/assets"
|
||
"uploads/avatars"
|
||
"uploads/backups"
|
||
"uploads/jobs"
|
||
"certs/localhost"
|
||
"instance"
|
||
"instance/ssl"
|
||
)
|
||
|
||
for dir in "${required_dirs[@]}"; do
|
||
mkdir -p "$APP_DIR/$dir" 2>/dev/null || warning "⚠️ Verzeichnis $dir konnte nicht erstellt werden"
|
||
done
|
||
|
||
# Sichere Berechtigungen setzen (robuster)
|
||
progress "Setze sichere Berechtigungen..."
|
||
|
||
# Basis-Berechtigungen
|
||
chown -R root:root "$APP_DIR" 2>/dev/null || warning "⚠️ Ownership konnte nicht gesetzt werden"
|
||
chmod 755 "$APP_DIR" 2>/dev/null || warning "⚠️ Verzeichnis-Permissions konnten nicht gesetzt werden"
|
||
|
||
# Ausführbare Dateien
|
||
if [ -f "$APP_DIR/app.py" ]; then
|
||
chmod +x "$APP_DIR/app.py" 2>/dev/null || warning "⚠️ app.py Ausführberechtigung konnte nicht gesetzt werden"
|
||
fi
|
||
|
||
# Sensitive Verzeichnisse
|
||
chmod 750 "$APP_DIR/database" 2>/dev/null || true
|
||
chmod 750 "$APP_DIR/logs" 2>/dev/null || true
|
||
chmod 750 "$APP_DIR/certs" 2>/dev/null || true
|
||
chmod 750 "$APP_DIR/instance" 2>/dev/null || true
|
||
|
||
# Upload-Verzeichnisse
|
||
chmod 755 "$APP_DIR/uploads" 2>/dev/null || true
|
||
chmod 755 "$APP_DIR/static" 2>/dev/null || true
|
||
|
||
# Python-Umgebung robust konfigurieren
|
||
progress "Konfiguriere robuste Python-Umgebung..."
|
||
|
||
# Ermittle Python site-packages Verzeichnis (robust)
|
||
local python_site_packages=""
|
||
for possible_path in \
|
||
"$(python3 -c "import site; print(site.getsitepackages()[0])" 2>/dev/null)" \
|
||
"/usr/local/lib/python3/dist-packages" \
|
||
"/usr/lib/python3/dist-packages" \
|
||
"/usr/local/lib/python$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")' 2>/dev/null)/dist-packages"; do
|
||
|
||
if [ -d "$possible_path" ]; then
|
||
python_site_packages="$possible_path"
|
||
break
|
||
fi
|
||
done
|
||
|
||
if [ -n "$python_site_packages" ]; then
|
||
echo "$APP_DIR" > "$python_site_packages/myp-app.pth" 2>/dev/null || warning "⚠️ Python-Pfad konnte nicht konfiguriert werden"
|
||
log "✅ Python-Pfad konfiguriert: $python_site_packages/myp-app.pth"
|
||
else
|
||
warning "⚠️ Python site-packages Verzeichnis nicht gefunden"
|
||
fi
|
||
|
||
# Systemweite Umgebungsvariablen robust setzen
|
||
progress "Konfiguriere Umgebungsvariablen..."
|
||
cat >> /etc/environment << EOF
|
||
|
||
# MYP Application Environment
|
||
MYP_APP_DIR=$APP_DIR
|
||
PYTHONPATH=$APP_DIR:\${PYTHONPATH:-}
|
||
FLASK_APP=$APP_DIR/app.py
|
||
FLASK_ENV=production
|
||
EOF
|
||
|
||
# Bash-Profile Updates (optional - überspringen bei Problemen)
|
||
progress "Versuche Bash-Profile zu aktualisieren (optional)..."
|
||
|
||
# Führe Updates nur in einem Subshell mit Timeout aus
|
||
(
|
||
# Setze eine maximale Laufzeit von 10 Sekunden für alle Bash-Profile Updates
|
||
export BASH_PROFILE_TIMEOUT=10
|
||
|
||
# Starte einen Background-Timer
|
||
(sleep $BASH_PROFILE_TIMEOUT && kill -TERM $$ 2>/dev/null) &
|
||
local timer_pid=$!
|
||
|
||
# Nur /root/.bashrc aktualisieren (schnell und sicher)
|
||
if [ -f "/root/.bashrc" ] && [ -w "/root/.bashrc" ]; then
|
||
if ! grep -q "MYP Application Environment" "/root/.bashrc" 2>/dev/null; then
|
||
echo "" >> "/root/.bashrc"
|
||
echo "# MYP Application Environment" >> "/root/.bashrc"
|
||
echo 'if [ -d "/opt/myp" ]; then' >> "/root/.bashrc"
|
||
echo ' export MYP_APP_DIR="/opt/myp"' >> "/root/.bashrc"
|
||
echo ' export FLASK_APP="/opt/myp/app.py"' >> "/root/.bashrc"
|
||
echo ' export FLASK_ENV="production"' >> "/root/.bashrc"
|
||
echo ' export PYTHONPATH="/opt/myp:${PYTHONPATH:-}"' >> "/root/.bashrc"
|
||
echo 'fi' >> "/root/.bashrc"
|
||
log "✅ Root Bash-Profile aktualisiert"
|
||
fi
|
||
fi
|
||
|
||
# Timer beenden
|
||
kill $timer_pid 2>/dev/null || true
|
||
|
||
) 2>/dev/null || {
|
||
warning "⚠️ Bash-Profile Update übersprungen (Timeout oder Fehler)"
|
||
debug "Bash-Profile Updates sind optional - Installation wird fortgesetzt"
|
||
}
|
||
|
||
# Validiere Deployment
|
||
progress "Validiere Application Deployment..."
|
||
local validation_errors=0
|
||
|
||
# Prüfe kritische Dateien
|
||
for file in "app.py" "models.py" "requirements.txt"; do
|
||
if [ ! -f "$APP_DIR/$file" ]; then
|
||
warning "❌ Kritische Datei fehlt: $file"
|
||
((validation_errors++))
|
||
fi
|
||
done
|
||
|
||
# Prüfe wichtige Verzeichnisse
|
||
for dir in "static" "templates" "blueprints"; do
|
||
if [ ! -d "$APP_DIR/$dir" ]; then
|
||
warning "❌ Wichtiges Verzeichnis fehlt: $dir"
|
||
((validation_errors++))
|
||
fi
|
||
done
|
||
|
||
if [ $validation_errors -eq 0 ]; then
|
||
success "✅ Application Deployment vollständig validiert"
|
||
else
|
||
warning "⚠️ $validation_errors Probleme beim Deployment gefunden"
|
||
fi
|
||
|
||
log "✅ Robustes Anwendungs-Deployment abgeschlossen"
|
||
log " 📁 App-Verzeichnis: $APP_DIR"
|
||
log " 🐍 Python-Pfad konfiguriert"
|
||
log " 🔧 Bash-Profile konfiguriert"
|
||
log " 🛡️ Sichere Berechtigungen gesetzt"
|
||
}
|
||
|
||
# =========================== BERECHTIGEN-MANAGEMENT ===========================
|
||
fix_project_permissions() {
|
||
log "=== BERECHTIGEN-MANAGEMENT FÜR KIOSK-USER ==="
|
||
|
||
progress "Korrigiere Projekt-Berechtigungen für kiosk-User..."
|
||
|
||
# Prüfe ob kiosk User existiert
|
||
if ! id "$KIOSK_USER" &>/dev/null; then
|
||
warning "⚠️ Kiosk-User '$KIOSK_USER' existiert nicht - erstelle ihn zuerst"
|
||
create_kiosk_user
|
||
fi
|
||
|
||
local kiosk_home="/home/$KIOSK_USER"
|
||
|
||
# Erstelle Entwicklungs-/Arbeitsverzeichnis im kiosk home
|
||
local kiosk_project_dir="$kiosk_home/manage-your-printer"
|
||
|
||
progress "Erstelle kiosk-Arbeitsverzeichnis: $kiosk_project_dir"
|
||
if [ ! -d "$kiosk_project_dir" ]; then
|
||
mkdir -p "$kiosk_project_dir" 2>/dev/null || true
|
||
fi
|
||
|
||
# Kopiere/Synchronisiere Projekt-Dateien zum kiosk-Verzeichnis
|
||
progress "Synchronisiere Projekt-Dateien für kiosk-User..."
|
||
|
||
# Verwende rsync wenn verfügbar, sonst cp
|
||
if command -v rsync >/dev/null 2>&1; then
|
||
rsync -av --exclude='.git' --exclude='__pycache__' --exclude='*.pyc' \
|
||
--exclude='instance/ssl/*' --exclude='logs/*' \
|
||
"$CURRENT_DIR/" "$kiosk_project_dir/" 2>/dev/null || {
|
||
warning "⚠️ rsync fehlgeschlagen - verwende cp als Fallback"
|
||
cp -r "$CURRENT_DIR"/* "$kiosk_project_dir/" 2>/dev/null || true
|
||
}
|
||
else
|
||
cp -r "$CURRENT_DIR"/* "$kiosk_project_dir/" 2>/dev/null || true
|
||
fi
|
||
|
||
# Setze kiosk als Besitzer des Arbeitsverzeichnisses
|
||
progress "Setze kiosk-User als Besitzer des Arbeitsverzeichnisses..."
|
||
chown -R "$KIOSK_USER:$KIOSK_USER" "$kiosk_project_dir" 2>/dev/null || warning "⚠️ Ownership konnte nicht vollständig gesetzt werden"
|
||
|
||
# Spezielle Berechtigungen für verschiedene Bereiche
|
||
progress "Konfiguriere spezielle Berechtigungen..."
|
||
|
||
# node_modules: kiosk User soll vollen Zugriff haben
|
||
if [ -d "$kiosk_project_dir/node_modules" ]; then
|
||
chown -R "$KIOSK_USER:$KIOSK_USER" "$kiosk_project_dir/node_modules" 2>/dev/null || true
|
||
chmod -R 755 "$kiosk_project_dir/node_modules" 2>/dev/null || true
|
||
success "✅ node_modules Berechtigungen für kiosk-User gesetzt"
|
||
fi
|
||
|
||
# package.json und package-lock.json: kiosk User soll schreiben können
|
||
for file in package.json package-lock.json; do
|
||
if [ -f "$kiosk_project_dir/$file" ]; then
|
||
chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_project_dir/$file" 2>/dev/null || true
|
||
chmod 664 "$kiosk_project_dir/$file" 2>/dev/null || true
|
||
fi
|
||
done
|
||
|
||
# logs Verzeichnis: kiosk User soll schreiben können
|
||
if [ -d "$kiosk_project_dir/logs" ]; then
|
||
chown -R "$KIOSK_USER:$KIOSK_USER" "$kiosk_project_dir/logs" 2>/dev/null || true
|
||
chmod -R 755 "$kiosk_project_dir/logs" 2>/dev/null || true
|
||
fi
|
||
|
||
# uploads Verzeichnis: kiosk User soll schreiben können
|
||
if [ -d "$kiosk_project_dir/uploads" ]; then
|
||
chown -R "$KIOSK_USER:$KIOSK_USER" "$kiosk_project_dir/uploads" 2>/dev/null || true
|
||
chmod -R 755 "$kiosk_project_dir/uploads" 2>/dev/null || true
|
||
fi
|
||
|
||
# Auch die Original node_modules in APP_DIR korrigieren
|
||
progress "Korrigiere node_modules Berechtigungen in $APP_DIR..."
|
||
if [ -d "$APP_DIR/node_modules" ]; then
|
||
# Erstelle kiosk-Gruppe und füge root hinzu für geteilten Zugriff
|
||
groupadd -f kiosk-shared 2>/dev/null || true
|
||
usermod -a -G kiosk-shared root 2>/dev/null || true
|
||
usermod -a -G kiosk-shared "$KIOSK_USER" 2>/dev/null || true
|
||
|
||
# Setze Gruppe auf kiosk-shared für geteilten Zugriff
|
||
chgrp -R kiosk-shared "$APP_DIR/node_modules" 2>/dev/null || true
|
||
chmod -R 775 "$APP_DIR/node_modules" 2>/dev/null || true
|
||
success "✅ node_modules geteilte Berechtigungen gesetzt"
|
||
fi
|
||
|
||
# Erstelle npm-Konfiguration für kiosk User
|
||
progress "Konfiguriere npm für kiosk-User..."
|
||
if [ ! -d "$kiosk_home/.npm" ]; then
|
||
mkdir -p "$kiosk_home/.npm" 2>/dev/null || true
|
||
chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.npm" 2>/dev/null || true
|
||
fi
|
||
|
||
# Erstelle .npmrc für kiosk User
|
||
cat > "$kiosk_home/.npmrc" << 'NPMRCEOF'
|
||
# npm-Konfiguration für kiosk User
|
||
fund=false
|
||
audit-level=moderate
|
||
progress=false
|
||
loglevel=warn
|
||
cache=/home/kiosk/.npm
|
||
prefix=/home/kiosk/.npm-global
|
||
NPMRCEOF
|
||
|
||
chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.npmrc" 2>/dev/null || true
|
||
|
||
# npm global Verzeichnis erstellen
|
||
mkdir -p "$kiosk_home/.npm-global" 2>/dev/null || true
|
||
chown -R "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.npm-global" 2>/dev/null || true
|
||
|
||
# X11-Autorisierung sicherstellen
|
||
progress "Sicherstelle X11-Autorisierung für kiosk-User..."
|
||
if [ ! -f "$kiosk_home/.Xauthority" ]; then
|
||
touch "$kiosk_home/.Xauthority"
|
||
chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.Xauthority"
|
||
chmod 600 "$kiosk_home/.Xauthority"
|
||
success "✅ .Xauthority Datei erstellt"
|
||
fi
|
||
|
||
# DISPLAY-Variable in bashrc sicherstellen
|
||
if ! grep -q "export DISPLAY=" "$kiosk_home/.bashrc" 2>/dev/null; then
|
||
cat >> "$kiosk_home/.bashrc" << 'EOF'
|
||
|
||
# X11 Display Konfiguration
|
||
export DISPLAY=:0.0
|
||
export XAUTHORITY=/home/kiosk/.Xauthority
|
||
|
||
EOF
|
||
chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.bashrc"
|
||
success "✅ X11-Variablen zu .bashrc hinzugefügt"
|
||
fi
|
||
|
||
success "✅ Projekt-Berechtigungen für kiosk-User konfiguriert"
|
||
info " 📁 Kiosk-Arbeitsverzeichnis: $kiosk_project_dir"
|
||
info " 👤 Besitzer: $KIOSK_USER"
|
||
info " 🔧 npm-Konfiguration erstellt"
|
||
}
|
||
|
||
create_permission_fix_script() {
|
||
log "=== ERSTELLE BERECHTIGEN-REPARATUR-SKRIPT ==="
|
||
|
||
local fix_script="$CURRENT_DIR/fix-permissions.sh"
|
||
|
||
progress "Erstelle automatisches Berechtigen-Reparatur-Skript..."
|
||
|
||
cat > "$fix_script" << 'FIXSCRIPTEOF'
|
||
#!/bin/bash
|
||
|
||
# ===================================================================
|
||
# MYP Berechtigen-Reparatur-Skript
|
||
# Behebt Berechtigungsprobleme nach npm install als root
|
||
# Kann von jedem User ausgeführt werden
|
||
# ===================================================================
|
||
|
||
set -euo pipefail
|
||
|
||
KIOSK_USER="kiosk"
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
|
||
# Farben für Ausgabe
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m'
|
||
|
||
log() {
|
||
echo -e "${GREEN}[$(date '+%H:%M:%S')] $1${NC}"
|
||
}
|
||
|
||
warning() {
|
||
echo -e "${YELLOW}[WARNUNG] $1${NC}"
|
||
}
|
||
|
||
error() {
|
||
echo -e "${RED}[FEHLER] $1${NC}"
|
||
exit 1
|
||
}
|
||
|
||
info() {
|
||
echo -e "${BLUE}[INFO] $1${NC}"
|
||
}
|
||
|
||
# Prüfe root-Berechtigung
|
||
if [ "$EUID" -ne 0 ]; then
|
||
error "Dieses Skript muss als Root ausgeführt werden: sudo $0"
|
||
fi
|
||
|
||
log "=== MYP BERECHTIGEN-REPARATUR ==="
|
||
log "Arbeitsverzeichnis: $SCRIPT_DIR"
|
||
|
||
# Prüfe ob kiosk User existiert
|
||
if ! id "$KIOSK_USER" &>/dev/null; then
|
||
error "Kiosk-User '$KIOSK_USER' existiert nicht!"
|
||
fi
|
||
|
||
# Lösche node_modules wenn vorhanden (für saubere Neuinstallation)
|
||
if [ -d "$SCRIPT_DIR/node_modules" ]; then
|
||
log "Entferne bestehende node_modules für saubere Neuinstallation..."
|
||
rm -rf "$SCRIPT_DIR/node_modules"
|
||
fi
|
||
|
||
# Erstelle kiosk-shared Gruppe für geteilten Zugriff
|
||
log "Erstelle geteilte Berechtigen-Gruppe..."
|
||
groupadd -f kiosk-shared 2>/dev/null || true
|
||
usermod -a -G kiosk-shared root 2>/dev/null || true
|
||
usermod -a -G kiosk-shared "$KIOSK_USER" 2>/dev/null || true
|
||
|
||
# Führe npm install als kiosk User aus
|
||
log "Führe npm install als kiosk-User aus..."
|
||
if [ -f "$SCRIPT_DIR/package.json" ]; then
|
||
# Wechsle zu kiosk User für npm install
|
||
sudo -u "$KIOSK_USER" bash -c "
|
||
cd '$SCRIPT_DIR'
|
||
export HOME=/home/$KIOSK_USER
|
||
if npm install --no-optional --no-audit --no-fund 2>/dev/null; then
|
||
echo 'npm install erfolgreich (Standard)'
|
||
elif npm install --legacy-peer-deps --no-optional 2>/dev/null; then
|
||
echo 'npm install erfolgreich (Legacy-Modus)'
|
||
elif npm install --force 2>/dev/null; then
|
||
echo 'npm install erfolgreich (Force-Modus)'
|
||
else
|
||
echo 'npm install fehlgeschlagen'
|
||
exit 1
|
||
fi
|
||
"
|
||
|
||
if [ $? -eq 0 ]; then
|
||
log "✅ npm install als kiosk-User erfolgreich"
|
||
else
|
||
warning "⚠️ npm install als kiosk-User fehlgeschlagen - versuche als root mit Berechtigen-Korrektur"
|
||
|
||
# Fallback: npm install als root, dann Berechtigungen korrigieren
|
||
if npm install --no-optional --no-audit --no-fund 2>/dev/null; then
|
||
log "npm install als root erfolgreich - korrigiere Berechtigungen..."
|
||
|
||
# Korrigiere node_modules Berechtigungen
|
||
if [ -d "$SCRIPT_DIR/node_modules" ]; then
|
||
chown -R "$KIOSK_USER:kiosk-shared" "$SCRIPT_DIR/node_modules" 2>/dev/null || true
|
||
chmod -R 775 "$SCRIPT_DIR/node_modules" 2>/dev/null || true
|
||
log "✅ node_modules Berechtigungen korrigiert"
|
||
fi
|
||
else
|
||
error "npm install auch als root fehlgeschlagen"
|
||
fi
|
||
fi
|
||
else
|
||
warning "Keine package.json gefunden"
|
||
fi
|
||
|
||
# Korrigiere allgemeine Projekt-Berechtigungen
|
||
log "Korrigiere allgemeine Projekt-Berechtigungen..."
|
||
|
||
# package.json und package-lock.json
|
||
for file in package.json package-lock.json; do
|
||
if [ -f "$SCRIPT_DIR/$file" ]; then
|
||
chown "$KIOSK_USER:kiosk-shared" "$SCRIPT_DIR/$file" 2>/dev/null || true
|
||
chmod 664 "$SCRIPT_DIR/$file" 2>/dev/null || true
|
||
fi
|
||
done
|
||
|
||
# logs Verzeichnis
|
||
if [ -d "$SCRIPT_DIR/logs" ]; then
|
||
chown -R "$KIOSK_USER:kiosk-shared" "$SCRIPT_DIR/logs" 2>/dev/null || true
|
||
chmod -R 775 "$SCRIPT_DIR/logs" 2>/dev/null || true
|
||
fi
|
||
|
||
# uploads Verzeichnis
|
||
if [ -d "$SCRIPT_DIR/uploads" ]; then
|
||
chown -R "$KIOSK_USER:kiosk-shared" "$SCRIPT_DIR/uploads" 2>/dev/null || true
|
||
chmod -R 775 "$SCRIPT_DIR/uploads" 2>/dev/null || true
|
||
fi
|
||
|
||
# static Verzeichnis (falls der User dort Änderungen macht)
|
||
if [ -d "$SCRIPT_DIR/static" ]; then
|
||
chgrp -R kiosk-shared "$SCRIPT_DIR/static" 2>/dev/null || true
|
||
chmod -R 775 "$SCRIPT_DIR/static" 2>/dev/null || true
|
||
fi
|
||
|
||
# X11-Autorisierung für kiosk-User sicherstellen
|
||
log "Sicherstelle X11-Autorisierung..."
|
||
kiosk_home="/home/$KIOSK_USER"
|
||
|
||
if [ ! -f "$kiosk_home/.Xauthority" ]; then
|
||
touch "$kiosk_home/.Xauthority"
|
||
chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.Xauthority"
|
||
chmod 600 "$kiosk_home/.Xauthority"
|
||
log "✅ .Xauthority Datei erstellt"
|
||
fi
|
||
|
||
# DISPLAY-Variable in bashrc sicherstellen
|
||
if [ -f "$kiosk_home/.bashrc" ] && ! grep -q "export DISPLAY=" "$kiosk_home/.bashrc" 2>/dev/null; then
|
||
cat >> "$kiosk_home/.bashrc" << 'BASHRCEOF'
|
||
|
||
# X11 Display Konfiguration
|
||
export DISPLAY=:0.0
|
||
export XAUTHORITY=/home/kiosk/.Xauthority
|
||
|
||
BASHRCEOF
|
||
chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.bashrc"
|
||
log "✅ X11-Variablen zu .bashrc hinzugefügt"
|
||
fi
|
||
|
||
log "✅ Berechtigen-Reparatur abgeschlossen"
|
||
info ""
|
||
info "📋 Zusammenfassung:"
|
||
info " - node_modules gehört jetzt dem kiosk-User"
|
||
info " - Geteilte kiosk-shared Gruppe erstellt"
|
||
info " - Entwicklungs-Dateien für kiosk-User beschreibbar"
|
||
info ""
|
||
info "🔧 Verwendung:"
|
||
info " - Als kiosk-User: cd $SCRIPT_DIR && npm install"
|
||
info " - Als root bei Problemen: sudo $0"
|
||
info ""
|
||
|
||
FIXSCRIPTEOF
|
||
|
||
# Mache Skript ausführbar
|
||
chmod +x "$fix_script" 2>/dev/null || warning "⚠️ Konnte fix-permissions.sh nicht ausführbar machen"
|
||
|
||
success "✅ Berechtigen-Reparatur-Skript erstellt: $fix_script"
|
||
info " 💡 Verwendung nach Setup: sudo ./fix-permissions.sh"
|
||
|
||
# Erstelle zusätzliches X11-Fix-Skript
|
||
local x11_fix_script="$CURRENT_DIR/fix-x11.sh"
|
||
|
||
progress "Erstelle X11-Reparatur-Skript..."
|
||
|
||
cat > "$x11_fix_script" << 'X11FIXSCRIPTEOF'
|
||
#!/bin/bash
|
||
|
||
# ===================================================================
|
||
# MYP X11-Reparatur-Skript
|
||
# Behebt X11/.Xauthority-Probleme für kiosk-User
|
||
# Kann als root oder kiosk-User ausgeführt werden
|
||
# ===================================================================
|
||
|
||
set -euo pipefail
|
||
|
||
KIOSK_USER="kiosk"
|
||
|
||
# Farben für Ausgabe
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m'
|
||
|
||
log() {
|
||
echo -e "${GREEN}[$(date '+%H:%M:%S')] $1${NC}"
|
||
}
|
||
|
||
warning() {
|
||
echo -e "${YELLOW}[WARNUNG] $1${NC}"
|
||
}
|
||
|
||
error() {
|
||
echo -e "${RED}[FEHLER] $1${NC}"
|
||
exit 1
|
||
}
|
||
|
||
info() {
|
||
echo -e "${BLUE}[INFO] $1${NC}"
|
||
}
|
||
|
||
log "=== MYP X11-REPARATUR ==="
|
||
|
||
# Prüfe ob kiosk User existiert
|
||
if ! id "$KIOSK_USER" &>/dev/null; then
|
||
error "Kiosk-User '$KIOSK_USER' existiert nicht!"
|
||
fi
|
||
|
||
kiosk_home="/home/$KIOSK_USER"
|
||
|
||
# Stoppe laufende X11-Prozesse
|
||
log "Stoppe laufende X11-Prozesse..."
|
||
pkill -f "startx" 2>/dev/null || true
|
||
pkill -f "X " 2>/dev/null || true
|
||
pkill -f "Xorg" 2>/dev/null || true
|
||
pkill -f "chromium" 2>/dev/null || true
|
||
sleep 2
|
||
|
||
# Bereinige alte X11-Session-Dateien
|
||
log "Bereinige alte X11-Session-Dateien..."
|
||
rm -f /tmp/.X0-lock 2>/dev/null || true
|
||
rm -f /tmp/.X11-unix/X0 2>/dev/null || true
|
||
|
||
# X11-Autorisierung neu erstellen
|
||
log "Erstelle X11-Autorisierung neu..."
|
||
|
||
# Entferne alte .Xauthority
|
||
if [ -f "$kiosk_home/.Xauthority" ]; then
|
||
rm -f "$kiosk_home/.Xauthority"
|
||
fi
|
||
|
||
# Erstelle neue .Xauthority
|
||
touch "$kiosk_home/.Xauthority"
|
||
|
||
# Setze korrekte Berechtigungen (funktioniert sowohl als root als auch als kiosk)
|
||
if [ "$EUID" -eq 0 ]; then
|
||
chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.Xauthority"
|
||
fi
|
||
chmod 600 "$kiosk_home/.Xauthority"
|
||
|
||
log "✅ .Xauthority neu erstellt"
|
||
|
||
# Prüfe und korrigiere .bashrc
|
||
log "Prüfe X11-Umgebungsvariablen..."
|
||
|
||
if [ -f "$kiosk_home/.bashrc" ]; then
|
||
if ! grep -q "export DISPLAY=" "$kiosk_home/.bashrc" 2>/dev/null; then
|
||
log "Füge X11-Variablen zu .bashrc hinzu..."
|
||
cat >> "$kiosk_home/.bashrc" << 'BASHEOF2'
|
||
|
||
# X11 Display Konfiguration
|
||
export DISPLAY=:0.0
|
||
export XAUTHORITY=/home/kiosk/.Xauthority
|
||
|
||
BASHEOF2
|
||
|
||
if [ "$EUID" -eq 0 ]; then
|
||
chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/.bashrc"
|
||
fi
|
||
log "✅ X11-Variablen hinzugefügt"
|
||
else
|
||
log "✅ X11-Variablen bereits konfiguriert"
|
||
fi
|
||
else
|
||
warning "⚠️ .bashrc nicht gefunden"
|
||
fi
|
||
|
||
# Erstelle X11-Test-Skript
|
||
log "Erstelle X11-Test-Skript..."
|
||
cat > "$kiosk_home/test-x11.sh" << 'TESTEOF'
|
||
#!/bin/bash
|
||
|
||
# X11-Test für kiosk-User
|
||
|
||
export DISPLAY=:0.0
|
||
export XAUTHORITY=/home/kiosk/.Xauthority
|
||
|
||
echo "=== X11-Test ==="
|
||
echo "DISPLAY: $DISPLAY"
|
||
echo "XAUTHORITY: $XAUTHORITY"
|
||
echo ""
|
||
|
||
if [ -f "$XAUTHORITY" ]; then
|
||
echo "✅ .Xauthority existiert"
|
||
ls -la "$XAUTHORITY"
|
||
else
|
||
echo "❌ .Xauthority fehlt"
|
||
exit 1
|
||
fi
|
||
|
||
echo ""
|
||
echo "Teste X11-Verbindung..."
|
||
|
||
if command -v xset >/dev/null 2>&1; then
|
||
if xset q >/dev/null 2>&1; then
|
||
echo "✅ X11-Server erreichbar"
|
||
xset q | head -3
|
||
else
|
||
echo "❌ X11-Server nicht erreichbar"
|
||
echo "Versuche X11-Server zu starten..."
|
||
startx /home/kiosk/.xinitrc -- :0 vt1 &
|
||
sleep 5
|
||
|
||
if xset q >/dev/null 2>&1; then
|
||
echo "✅ X11-Server nach Start erreichbar"
|
||
else
|
||
echo "❌ X11-Server konnte nicht gestartet werden"
|
||
exit 1
|
||
fi
|
||
fi
|
||
else
|
||
echo "⚠️ xset nicht verfügbar - kann X11 nicht testen"
|
||
fi
|
||
|
||
echo ""
|
||
echo "✅ X11-Test abgeschlossen"
|
||
TESTEOF
|
||
|
||
chmod +x "$kiosk_home/test-x11.sh"
|
||
if [ "$EUID" -eq 0 ]; then
|
||
chown "$KIOSK_USER:$KIOSK_USER" "$kiosk_home/test-x11.sh"
|
||
fi
|
||
|
||
log "✅ X11-Reparatur abgeschlossen"
|
||
info ""
|
||
info "📋 Was wurde behoben:"
|
||
info " - Alte .Xauthority entfernt und neu erstellt"
|
||
info " - X11-Umgebungsvariablen konfiguriert"
|
||
info " - X11-Test-Skript erstellt"
|
||
info ""
|
||
info "🔧 Nächste Schritte:"
|
||
info " - Als kiosk-User einloggen: su - kiosk"
|
||
info " - X11 testen: ./test-x11.sh"
|
||
info " - Kiosk-Modus starten: ./start-x11.sh"
|
||
info ""
|
||
info "💡 Bei weiteren Problemen:"
|
||
info " - Neustart: sudo reboot"
|
||
info " - Manual X11 start: startx"
|
||
info ""
|
||
|
||
X11FIXSCRIPTEOF
|
||
|
||
chmod +x "$x11_fix_script" 2>/dev/null || warning "⚠️ Konnte fix-x11.sh nicht ausführbar machen"
|
||
|
||
success "✅ X11-Reparatur-Skript erstellt: $x11_fix_script"
|
||
info " 💡 Verwendung bei X11-Problemen: sudo ./fix-x11.sh"
|
||
}
|
||
|
||
install_npm_dependencies() {
|
||
log "=== NPM-ABHÄNGIGKEITEN INSTALLATION ==="
|
||
|
||
if [ -f "$APP_DIR/package.json" ]; then
|
||
progress "Installiere npm-Abhängigkeiten..."
|
||
|
||
cd "$APP_DIR"
|
||
|
||
# npm install mit verschiedenen Fallback-Strategien
|
||
if npm install --no-optional --no-audit --no-fund 2>/dev/null; then
|
||
log "✅ npm install erfolgreich (Standard)"
|
||
elif npm install --legacy-peer-deps --no-optional 2>/dev/null; then
|
||
log "✅ npm install erfolgreich (Legacy-Modus)"
|
||
elif npm install --force 2>/dev/null; then
|
||
log "✅ npm install erfolgreich (Force-Modus)"
|
||
else
|
||
warning "⚠️ npm install fehlgeschlagen - überspringe"
|
||
fi
|
||
|
||
# WICHTIG: Korrigiere Berechtigungen nach npm install
|
||
progress "Korrigiere npm-Berechtigungen für kiosk-User..."
|
||
if [ -d "$APP_DIR/node_modules" ]; then
|
||
# Erstelle geteilte Gruppe wenn noch nicht vorhanden
|
||
groupadd -f kiosk-shared 2>/dev/null || true
|
||
usermod -a -G kiosk-shared root 2>/dev/null || true
|
||
if id "$KIOSK_USER" &>/dev/null; then
|
||
usermod -a -G kiosk-shared "$KIOSK_USER" 2>/dev/null || true
|
||
chown -R "$KIOSK_USER:kiosk-shared" "$APP_DIR/node_modules" 2>/dev/null || true
|
||
success "✅ node_modules Berechtigungen für kiosk-User korrigiert"
|
||
else
|
||
warning "⚠️ Kiosk-User nicht gefunden - Berechtigungen werden später korrigiert"
|
||
fi
|
||
chmod -R 775 "$APP_DIR/node_modules" 2>/dev/null || true
|
||
fi
|
||
|
||
cd "$CURRENT_DIR"
|
||
else
|
||
info "Keine package.json gefunden - überspringe npm-Installation"
|
||
fi
|
||
|
||
log "✅ NPM-Abhängigkeiten verarbeitet"
|
||
}
|
||
|
||
# =========================== SSL-ZERTIFIKAT GENERIERUNG (ENTFERNT) ===========================
|
||
# SSL-Zertifikate nicht mehr benötigt - verwende HTTP statt HTTPS
|
||
|
||
# =========================== ROBUSTE SYSTEMD-SERVICES INSTALLATION ===========================
|
||
install_systemd_services() {
|
||
log "=== ROBUSTE SYSTEMD-SERVICES INSTALLATION ==="
|
||
|
||
# Prüfe ob systemd verfügbar ist
|
||
if ! command -v systemctl >/dev/null 2>&1; then
|
||
warning "⚠️ systemctl nicht gefunden - überspringe Service-Installation"
|
||
info " → System läuft möglicherweise ohne systemd (WSL, Docker, etc.)"
|
||
return
|
||
fi
|
||
|
||
# Validiere systemd-Verzeichnis
|
||
if [ ! -d "$SYSTEMD_DIR" ]; then
|
||
warning "⚠️ systemd-Verzeichnis nicht gefunden: $SYSTEMD_DIR"
|
||
info " → Überspringe Service-Installation"
|
||
return
|
||
fi
|
||
|
||
progress "Validiere und kopiere Service-Dateien..."
|
||
|
||
# Definiere Service-Dateien mit Priorität
|
||
local essential_services=(
|
||
"$HTTP_SERVICE_NAME.service"
|
||
)
|
||
|
||
local optional_services=(
|
||
"$KIOSK_SERVICE_NAME.service"
|
||
"$WATCHDOG_SERVICE_NAME.service"
|
||
"$WATCHDOG_PYTHON_SERVICE_NAME.service"
|
||
"$FIREWALL_SERVICE_NAME.service"
|
||
)
|
||
|
||
local installed_services=0
|
||
local essential_errors=0
|
||
|
||
# Essenzielle Services zuerst
|
||
for service_file in "${essential_services[@]}"; do
|
||
if [ -f "$SYSTEMD_DIR/$service_file" ]; then
|
||
progress "Kopiere essenziellen Service: $service_file"
|
||
if cp "$SYSTEMD_DIR/$service_file" "$SYSTEM_SYSTEMD_DIR/" 2>/dev/null; then
|
||
success "✅ $service_file erfolgreich installiert"
|
||
((installed_services++))
|
||
else
|
||
error "❌ Fehler beim Kopieren des essenziellen Service: $service_file"
|
||
((essential_errors++))
|
||
fi
|
||
else
|
||
error "❌ Essenzieller Service nicht gefunden: $service_file"
|
||
((essential_errors++))
|
||
fi
|
||
done
|
||
|
||
# Optionale Services
|
||
for service_file in "${optional_services[@]}"; do
|
||
if [ -f "$SYSTEMD_DIR/$service_file" ]; then
|
||
progress "Kopiere optionalen Service: $service_file"
|
||
if cp "$SYSTEMD_DIR/$service_file" "$SYSTEM_SYSTEMD_DIR/" 2>/dev/null; then
|
||
success "✅ $service_file erfolgreich installiert"
|
||
((installed_services++))
|
||
else
|
||
warning "⚠️ Fehler beim Kopieren des optionalen Service: $service_file"
|
||
fi
|
||
else
|
||
info "Optionaler Service nicht gefunden: $service_file"
|
||
fi
|
||
done
|
||
|
||
# Prüfe auf kritische Fehler
|
||
if [ $essential_errors -gt 0 ]; then
|
||
error "❌ $essential_errors essenzielle Services konnten nicht installiert werden!"
|
||
fi
|
||
|
||
# Validiere kopierte Service-Dateien
|
||
progress "Validiere Service-Dateien..."
|
||
for service_file in "${essential_services[@]}" "${optional_services[@]}"; do
|
||
if [ -f "$SYSTEM_SYSTEMD_DIR/$service_file" ]; then
|
||
# Syntaxprüfung für systemd-Services
|
||
if systemd-analyze verify "$SYSTEM_SYSTEMD_DIR/$service_file" 2>/dev/null; then
|
||
success "✅ $service_file Syntax-Validierung erfolgreich"
|
||
else
|
||
warning "⚠️ $service_file hat möglicherweise Syntax-Probleme"
|
||
fi
|
||
fi
|
||
done
|
||
|
||
# Systemd-Konfiguration neu laden
|
||
progress "Lade systemd-Konfiguration neu..."
|
||
retry_command "systemctl daemon-reload" "systemd daemon-reload"
|
||
|
||
log "✅ Systemd-Services installiert: $installed_services Services"
|
||
}
|
||
|
||
enable_and_start_services() {
|
||
log "=== ROBUSTE SERVICES AKTIVIERUNG UND START ==="
|
||
|
||
# Prüfe ob systemd verfügbar ist
|
||
if ! command -v systemctl >/dev/null 2>&1; then
|
||
warning "⚠️ systemctl nicht gefunden - überspringe Service-Aktivierung"
|
||
return
|
||
fi
|
||
|
||
# Service-Status tracking
|
||
local successful_services=0
|
||
local failed_services=0
|
||
|
||
# HTTP-Backend-Service (kritisch)
|
||
progress "Aktiviere und starte HTTP-Backend-Service (kritisch)..."
|
||
|
||
if systemctl enable "$HTTP_SERVICE_NAME" 2>/dev/null; then
|
||
success "✅ HTTP-Backend-Service erfolgreich aktiviert"
|
||
|
||
if systemctl start "$HTTP_SERVICE_NAME" 2>/dev/null; then
|
||
success "✅ HTTP-Backend-Service erfolgreich gestartet"
|
||
|
||
# Warte und prüfe Status gründlich
|
||
local startup_timeout=15
|
||
local check_interval=2
|
||
local elapsed=0
|
||
|
||
while [ $elapsed -lt $startup_timeout ]; do
|
||
if systemctl is-active --quiet "$HTTP_SERVICE_NAME"; then
|
||
success "✅ HTTP-Backend-Service läuft stabil nach ${elapsed}s"
|
||
((successful_services++))
|
||
break
|
||
fi
|
||
sleep $check_interval
|
||
elapsed=$((elapsed + check_interval))
|
||
progress "Warte auf HTTP-Backend-Service Startup... (${elapsed}/${startup_timeout}s)"
|
||
done
|
||
|
||
if [ $elapsed -ge $startup_timeout ]; then
|
||
error "❌ HTTP-Backend-Service Timeout nach ${startup_timeout}s - Service nicht verfügbar"
|
||
|
||
# Debugging-Informationen
|
||
info "HTTP-Backend-Service Status-Debug:"
|
||
systemctl status "$HTTP_SERVICE_NAME" --no-pager -l || true
|
||
journalctl -u "$HTTP_SERVICE_NAME" --no-pager -n 10 || true
|
||
((failed_services++))
|
||
fi
|
||
else
|
||
error "❌ HTTP-Backend-Service konnte nicht gestartet werden"
|
||
((failed_services++))
|
||
fi
|
||
else
|
||
error "❌ HTTP-Backend-Service konnte nicht aktiviert werden"
|
||
((failed_services++))
|
||
fi
|
||
|
||
# Kiosk-Service (für Produktionsinstallation)
|
||
if [ -f "$SYSTEM_SYSTEMD_DIR/$KIOSK_SERVICE_NAME.service" ]; then
|
||
progress "Aktiviere Kiosk-Service (startet beim nächsten Boot)..."
|
||
if systemctl enable "$KIOSK_SERVICE_NAME" 2>/dev/null; then
|
||
success "✅ Kiosk-Service erfolgreich aktiviert"
|
||
((successful_services++))
|
||
else
|
||
warning "⚠️ Kiosk-Service konnte nicht aktiviert werden"
|
||
((failed_services++))
|
||
fi
|
||
fi
|
||
|
||
# Watchdog-Service (optional)
|
||
if [ -f "$SYSTEM_SYSTEMD_DIR/$WATCHDOG_SERVICE_NAME.service" ]; then
|
||
progress "Aktiviere und starte Watchdog-Service..."
|
||
if systemctl enable "$WATCHDOG_SERVICE_NAME" 2>/dev/null; then
|
||
if systemctl start "$WATCHDOG_SERVICE_NAME" 2>/dev/null; then
|
||
success "✅ Watchdog-Service erfolgreich aktiviert und gestartet"
|
||
((successful_services++))
|
||
else
|
||
warning "⚠️ Watchdog-Service aktiviert, aber Start fehlgeschlagen"
|
||
fi
|
||
else
|
||
warning "⚠️ Watchdog-Service konnte nicht aktiviert werden"
|
||
fi
|
||
fi
|
||
|
||
# Python Watchdog-Service (optional)
|
||
if [ -f "$SYSTEM_SYSTEMD_DIR/$WATCHDOG_PYTHON_SERVICE_NAME.service" ]; then
|
||
progress "Aktiviere Python Watchdog-Service..."
|
||
if systemctl enable "$WATCHDOG_PYTHON_SERVICE_NAME" 2>/dev/null; then
|
||
success "✅ Python Watchdog-Service erfolgreich aktiviert"
|
||
((successful_services++))
|
||
else
|
||
warning "⚠️ Python Watchdog-Service konnte nicht aktiviert werden"
|
||
fi
|
||
fi
|
||
|
||
# Firewall-Service (optional)
|
||
if [ -f "$SYSTEM_SYSTEMD_DIR/$FIREWALL_SERVICE_NAME.service" ]; then
|
||
progress "Aktiviere Firewall-Service..."
|
||
if systemctl enable "$FIREWALL_SERVICE_NAME" 2>/dev/null; then
|
||
success "✅ Firewall-Service erfolgreich aktiviert"
|
||
((successful_services++))
|
||
else
|
||
warning "⚠️ Firewall-Service konnte nicht aktiviert werden"
|
||
fi
|
||
fi
|
||
|
||
# Zusammenfassung
|
||
log "📊 Service-Aktivierung Zusammenfassung:"
|
||
log " ✅ Erfolgreich: $successful_services Services"
|
||
log " ❌ Fehlgeschlagen: $failed_services Services"
|
||
|
||
if [ $failed_services -eq 0 ]; then
|
||
success "✅ Alle verfügbaren Services erfolgreich konfiguriert"
|
||
elif [ $successful_services -gt 0 ]; then
|
||
warning "⚠️ $failed_services Services fehlgeschlagen, aber $successful_services Services funktionieren"
|
||
info "→ System ist grundsätzlich funktionsfähig"
|
||
else
|
||
error "❌ Alle Services fehlgeschlagen - System möglicherweise nicht funktionsfähig"
|
||
fi
|
||
}
|
||
|
||
# =========================== ROBUSTE SYSTEM-TESTS ===========================
|
||
test_application() {
|
||
log "=== UMFASSENDE SYSTEM-TESTS ==="
|
||
|
||
echo ""
|
||
echo -e "${BLUE}🔍 Führe System-Tests durch...${NC}"
|
||
echo ""
|
||
|
||
local test_errors=0
|
||
local test_warnings=0
|
||
|
||
# Test 1: Service-Status prüfen
|
||
progress "Teste Service-Status..."
|
||
if systemctl is-active --quiet "$HTTP_SERVICE_NAME"; then
|
||
success "✅ HTTP-Backend-Service ist aktiv"
|
||
else
|
||
warning "⚠️ HTTP-Backend-Service ist nicht aktiv"
|
||
((test_warnings++))
|
||
|
||
# Debug-Informationen
|
||
info "Service-Status Debug:"
|
||
systemctl status "$HTTP_SERVICE_NAME" --no-pager -l || true
|
||
fi
|
||
|
||
# Test 2: Port-Verfügbarkeit
|
||
progress "Teste Port-Verfügbarkeit..."
|
||
if ss -tlnp | grep -q ":5000 "; then
|
||
success "✅ Port 5000 ist geöffnet"
|
||
else
|
||
warning "⚠️ Port 5000 ist nicht geöffnet"
|
||
((test_warnings++))
|
||
fi
|
||
|
||
# Test 3: HTTP-Backend-Verbindung (robust mit mehreren Methoden)
|
||
progress "Teste HTTP-Backend-Verbindung (robust)..."
|
||
|
||
local max_attempts=20
|
||
local attempt=1
|
||
local connection_successful=false
|
||
|
||
while [ $attempt -le $max_attempts ]; do
|
||
# Methode 1: curl mit verschiedenen Optionen
|
||
if curl -s --connect-timeout 3 --max-time 8 "$HTTP_URL" >/dev/null 2>&1; then
|
||
connection_successful=true
|
||
break
|
||
fi
|
||
|
||
# Methode 2: wget als Fallback
|
||
if command -v wget >/dev/null 2>&1; then
|
||
if wget -q --timeout=3 --tries=1 "$HTTP_URL" -O /dev/null 2>/dev/null; then
|
||
connection_successful=true
|
||
break
|
||
fi
|
||
fi
|
||
|
||
# Methode 3: nc als direkter Port-Test
|
||
if command -v nc >/dev/null 2>&1; then
|
||
if echo "GET / HTTP/1.0" | nc -w 3 localhost 5000 2>/dev/null | grep -q "HTTP"; then
|
||
connection_successful=true
|
||
break
|
||
fi
|
||
fi
|
||
|
||
progress "Warte auf HTTP-Backend... ($attempt/$max_attempts)"
|
||
sleep 3
|
||
((attempt++))
|
||
done
|
||
|
||
if [ "$connection_successful" = true ]; then
|
||
success "✅ HTTP-Backend erreichbar unter $HTTP_URL"
|
||
|
||
# Erweiterte Verbindungstests
|
||
progress "Führe erweiterte HTTP-Tests durch..."
|
||
|
||
# Test Antwortzeit
|
||
local response_time=$(curl -s -w "%{time_total}" -o /dev/null "$HTTP_URL" 2>/dev/null || echo "timeout")
|
||
if [ "$response_time" != "timeout" ]; then
|
||
info "🕐 HTTP Antwortzeit: ${response_time}s"
|
||
|
||
# Bewerte Antwortzeit (ohne bc für bessere Kompatibilität)
|
||
local response_ms=$(echo "$response_time * 1000" | awk '{print int($1)}' 2>/dev/null || echo "9999")
|
||
if [ "$response_ms" -lt 2000 ]; then
|
||
success "✅ Gute Antwortzeit"
|
||
elif [ "$response_ms" -lt 5000 ]; then
|
||
info "ℹ️ Akzeptable Antwortzeit"
|
||
else
|
||
warning "⚠️ Langsame Antwortzeit"
|
||
((test_warnings++))
|
||
fi
|
||
fi
|
||
|
||
# Test HTTP-Status
|
||
local http_status=$(curl -s -o /dev/null -w "%{http_code}" "$HTTP_URL" 2>/dev/null || echo "000")
|
||
if [ "$http_status" = "200" ]; then
|
||
success "✅ HTTP Status 200 OK"
|
||
else
|
||
info "ℹ️ HTTP Status: $http_status (möglicherweise Redirect oder Login-Seite)"
|
||
fi
|
||
|
||
else
|
||
error "❌ HTTP-Backend nicht erreichbar nach $max_attempts Versuchen"
|
||
((test_errors++))
|
||
|
||
# Debugging-Informationen
|
||
info "HTTP-Debug Informationen:"
|
||
netstat -tlnp | grep ":5000" || info "Port 5000 nicht gefunden"
|
||
ss -tlnp | grep ":5000" || info "Port 5000 nicht in ss gefunden"
|
||
fi
|
||
|
||
# Test 4: HTTP-Header und Content-Type Prüfung
|
||
progress "Teste HTTP-Header und Content-Type..."
|
||
|
||
if [ "$connection_successful" = true ]; then
|
||
# Test Content-Type Header
|
||
local content_type=$(curl -s -I "$HTTP_URL" 2>/dev/null | grep -i "content-type:" | head -1 | cut -d: -f2 | tr -d ' \r\n' || echo "unknown")
|
||
if [[ "$content_type" == *"text/html"* ]]; then
|
||
success "✅ Korrekte HTML-Antwort erkannt"
|
||
else
|
||
info "ℹ️ Content-Type: $content_type"
|
||
fi
|
||
|
||
# Test Server Header
|
||
local server_header=$(curl -s -I "$HTTP_URL" 2>/dev/null | grep -i "server:" | head -1 | cut -d: -f2 | tr -d ' \r\n' || echo "unknown")
|
||
if [ "$server_header" != "unknown" ]; then
|
||
info "🖥️ Server: $server_header"
|
||
fi
|
||
else
|
||
info "ℹ️ HTTP-Header Test übersprungen (Backend nicht erreichbar)"
|
||
fi
|
||
|
||
# Test 5: Python-Anwendung Import-Test
|
||
progress "Teste Python-Anwendung Import..."
|
||
|
||
cd "$APP_DIR" 2>/dev/null || true
|
||
|
||
# Setze Test-Umgebung
|
||
export FLASK_ENV=testing
|
||
export MYP_TESTING=1
|
||
export PYTHONPATH="$APP_DIR:${PYTHONPATH:-}"
|
||
|
||
if timeout 15 python3 -c "
|
||
import sys
|
||
import os
|
||
sys.path.insert(0, '$APP_DIR')
|
||
os.chdir('$APP_DIR')
|
||
|
||
try:
|
||
import app
|
||
print('✅ Flask-App Import erfolgreich')
|
||
|
||
# Test ob Flask-App-Objekt verfügbar
|
||
if hasattr(app, 'app'):
|
||
print('✅ Flask-App-Objekt verfügbar')
|
||
else:
|
||
print('⚠️ Flask-App-Objekt nicht gefunden')
|
||
|
||
except Exception as e:
|
||
print(f'⚠️ App-Import-Problem: {e}')
|
||
exit(1)
|
||
" 2>&1; then
|
||
success "✅ Python-Anwendung kann erfolgreich importiert werden"
|
||
else
|
||
warning "⚠️ Python-Anwendung Import-Probleme (möglicherweise nicht kritisch)"
|
||
((test_warnings++))
|
||
fi
|
||
|
||
cd "$CURRENT_DIR" 2>/dev/null || true
|
||
|
||
# Test 6: Verzeichnisstruktur-Validierung
|
||
progress "Validiere Verzeichnisstruktur..."
|
||
|
||
local structure_ok=true
|
||
local required_files=("$APP_DIR/app.py" "$APP_DIR/models.py" "$APP_DIR/requirements.txt")
|
||
local required_dirs=("$APP_DIR/static" "$APP_DIR/templates" "$APP_DIR/blueprints")
|
||
|
||
for file in "${required_files[@]}"; do
|
||
if [ ! -f "$file" ]; then
|
||
warning "❌ Wichtige Datei fehlt: $file"
|
||
structure_ok=false
|
||
((test_warnings++))
|
||
fi
|
||
done
|
||
|
||
for dir in "${required_dirs[@]}"; do
|
||
if [ ! -d "$dir" ]; then
|
||
warning "❌ Wichtiges Verzeichnis fehlt: $dir"
|
||
structure_ok=false
|
||
((test_warnings++))
|
||
fi
|
||
done
|
||
|
||
if [ "$structure_ok" = true ]; then
|
||
success "✅ Verzeichnisstruktur vollständig"
|
||
fi
|
||
|
||
# Zusammenfassung der Tests
|
||
echo ""
|
||
echo -e "${CYAN}=================================================================${NC}"
|
||
echo -e "${CYAN} SYSTEM-TEST ERGEBNISSE${NC}"
|
||
echo -e "${CYAN}=================================================================${NC}"
|
||
echo ""
|
||
echo -e "${BLUE}📊 Test-Zusammenfassung:${NC}"
|
||
echo -e " ❌ Fehler: $test_errors"
|
||
echo -e " ⚠️ Warnungen: $test_warnings"
|
||
echo ""
|
||
|
||
if [ $test_errors -eq 0 ] && [ $test_warnings -eq 0 ]; then
|
||
echo -e "${GREEN}✅ Alle System-Tests erfolgreich!${NC}"
|
||
echo -e "${GREEN} → System vollständig funktionsfähig${NC}"
|
||
echo ""
|
||
return 0
|
||
elif [ $test_errors -eq 0 ]; then
|
||
echo -e "${YELLOW}⚠️ System-Tests mit $test_warnings Warnungen abgeschlossen${NC}"
|
||
echo -e "${YELLOW} → System grundsätzlich funktionsfähig${NC}"
|
||
echo ""
|
||
return 0
|
||
else
|
||
echo -e "${RED}❌ System-Tests mit $test_errors Fehlern fehlgeschlagen${NC}"
|
||
echo -e "${RED} → System möglicherweise nicht funktionsfähig${NC}"
|
||
echo ""
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# =========================== AUFRÄUMEN ===========================
|
||
cleanup_old_files() {
|
||
log "=== AUFRÄUMEN ALTE DATEIEN ==="
|
||
|
||
progress "Entferne alte Shell-Skripte..."
|
||
|
||
# Entferne alte Skripte (falls vorhanden)
|
||
local old_scripts=("combined.sh" "installer.sh")
|
||
|
||
for script in "${old_scripts[@]}"; do
|
||
if [ -f "$CURRENT_DIR/$script" ]; then
|
||
progress "Entferne: $script"
|
||
rm -f "$CURRENT_DIR/$script" || warning "Fehler beim Entfernen von $script"
|
||
fi
|
||
done
|
||
|
||
log "✅ Aufräumen abgeschlossen"
|
||
}
|
||
|
||
# =========================== HAUPTMENÜ ===========================
|
||
show_menu() {
|
||
clear
|
||
echo -e "${CYAN}=================================================================${NC}"
|
||
echo -e "${CYAN} $APP_NAME - Setup-Skript v$APP_VERSION${NC}"
|
||
echo -e "${CYAN}=================================================================${NC}"
|
||
echo ""
|
||
echo -e "${YELLOW}Bitte wählen Sie eine Option:${NC}"
|
||
echo ""
|
||
echo -e "${GREEN}1)${NC} Abhängigkeiten installieren und System für manuelles Testen vorbereiten"
|
||
echo -e " ${BLUE}→ Python, Node.js, SSL-Zertifikate, Anwendung deployed, minimaler Test${NC}"
|
||
echo -e " ${BLUE}→ System bereit für manuelle Tests und Entwicklung${NC}"
|
||
echo ""
|
||
echo -e "${GREEN}2)${NC} Vollständige Kiosk-Installation mit Remote-Zugang"
|
||
echo -e " ${BLUE}→ Komplette Produktionsinstallation mit automatischem Kiosk-Start${NC}"
|
||
echo -e " ${BLUE}→ RDP (root:744563017196A), SSH (user:raspberry), Firewall${NC}"
|
||
echo -e " ${BLUE}→ Automatischer Login und Kiosk-Modus beim Boot${NC}"
|
||
echo ""
|
||
echo -e "${GREEN}3)${NC} Beenden"
|
||
echo ""
|
||
echo -e "${CYAN}=================================================================${NC}"
|
||
echo -n "Ihre Wahl [1-3]: "
|
||
}
|
||
|
||
# =========================== INSTALLATIONS-MODI ===========================
|
||
install_dependencies_only() {
|
||
# Logging initialisieren (verwendet /tmp für Logs)
|
||
init_logging
|
||
|
||
log "=== MODUS: ROBUSTE ABHÄNGIGKEITEN-INSTALLATION FÜR MANUELLES TESTEN ==="
|
||
|
||
# Grundlegende System-Validierung
|
||
check_root
|
||
check_system_resources
|
||
check_debian_system
|
||
check_internet_connection
|
||
|
||
# System-Konfiguration
|
||
configure_hostname
|
||
update_system
|
||
configure_network_security
|
||
|
||
# Core-Abhängigkeiten installieren
|
||
install_python_dependencies
|
||
install_nodejs_npm
|
||
install_ssl_certificates
|
||
install_python_packages
|
||
|
||
# Anwendung deployen
|
||
deploy_application
|
||
install_npm_dependencies
|
||
|
||
# Berechtigungen für kiosk-User korrigieren
|
||
fix_project_permissions
|
||
create_permission_fix_script
|
||
|
||
# Services für manuelles Testen vorbereiten
|
||
install_systemd_services
|
||
enable_and_start_services
|
||
|
||
# Performance-Optimierungen auch für manuelles Testen
|
||
optimize_webapp_performance
|
||
optimize_static_assets
|
||
|
||
# Umfassende System-Tests
|
||
progress "Starte umfassende System-Tests..."
|
||
if test_application; then
|
||
success "✅ Alle System-Tests erfolgreich!"
|
||
else
|
||
warning "⚠️ System-Tests mit Problemen - System möglicherweise eingeschränkt funktionsfähig"
|
||
fi
|
||
|
||
# Cleanup
|
||
cleanup_old_files
|
||
|
||
success "✅ Robuste Abhängigkeiten-Installation abgeschlossen!"
|
||
log "📋 Installation Zusammenfassung:"
|
||
log " 🖥️ Hostname: raspberrypi"
|
||
log " 🐍 Python-Umgebung: Vollständig konfiguriert"
|
||
log " 🌐 Node.js: Installiert und optimiert"
|
||
log " 🔒 SSL-Zertifikate: Generiert und konfiguriert"
|
||
log " 📁 Anwendung: In $APP_DIR deployed"
|
||
log " ⚡ Performance: Optimiert für Raspberry Pi"
|
||
log " 🔧 Services: Installiert und gestartet"
|
||
info ""
|
||
info "🚀 System bereit für manuelle Tests und Entwicklung!"
|
||
info "🌐 HTTP-Backend sollte verfügbar sein: $HTTP_URL"
|
||
info "⚙️ Manuelle App-Start Alternative: cd /opt/myp && python3 app.py --production"
|
||
|
||
# Fehler-Zusammenfassung anzeigen
|
||
show_error_summary
|
||
|
||
# Finale Status-Anzeige
|
||
echo ""
|
||
echo -e "${GREEN}=================================================================${NC}"
|
||
echo -e "${GREEN} INSTALLATION ERFOLGREICH ABGESCHLOSSEN!${NC}"
|
||
echo -e "${GREEN}=================================================================${NC}"
|
||
echo ""
|
||
echo -e "${BLUE}📋 Was wurde installiert:${NC}"
|
||
echo -e " ✅ System-Updates und Tools"
|
||
echo -e " ✅ Python 3 und pip"
|
||
echo -e " ✅ Node.js und npm"
|
||
echo -e " ✅ SSL-Zertifikate"
|
||
echo -e " ✅ Anwendung deployed nach: $APP_DIR"
|
||
echo -e " ✅ Systemd-Services installiert"
|
||
echo ""
|
||
echo -e "${YELLOW}🚀 Nächste Schritte:${NC}"
|
||
echo -e " 1. Testen Sie die Anwendung:"
|
||
echo -e " ${CYAN}cd $APP_DIR && python3 app.py${NC}"
|
||
echo -e " 2. Oder prüfen Sie den Service:"
|
||
echo -e " ${CYAN}sudo systemctl status $HTTP_SERVICE_NAME${NC}"
|
||
echo -e " 3. Zugriff über Browser:"
|
||
echo -e " ${CYAN}$HTTP_URL${NC}"
|
||
echo ""
|
||
echo -e "${GREEN}✅ System bereit für manuelle Tests!${NC}"
|
||
echo -e "${GREEN}=================================================================${NC}"
|
||
}
|
||
|
||
install_full_production_system() {
|
||
# Logging initialisieren (verwendet /tmp für Logs)
|
||
init_logging
|
||
|
||
log "=== MODUS: VOLLSTÄNDIGE ROBUSTE KIOSK-INSTALLATION MIT REMOTE-ZUGANG ==="
|
||
|
||
# Umfassende System-Validierung
|
||
check_root
|
||
check_system_resources
|
||
check_debian_system
|
||
check_internet_connection
|
||
|
||
# System-Grundkonfiguration
|
||
configure_hostname
|
||
|
||
# Intelligente Abhängigkeiten-Installation
|
||
if [ ! -d "$APP_DIR" ] || [ ! -f "$APP_DIR/app.py" ]; then
|
||
warning "Anwendung noch nicht deployed - führe robuste Abhängigkeiten-Installation durch..."
|
||
|
||
# Vollständige Basis-Installation
|
||
update_system
|
||
configure_network_security
|
||
install_python_dependencies
|
||
install_nodejs_npm
|
||
install_ssl_certificates
|
||
install_python_packages
|
||
deploy_application
|
||
install_npm_dependencies
|
||
|
||
# Berechtigungen für kiosk-User korrigieren
|
||
fix_project_permissions
|
||
create_permission_fix_script
|
||
else
|
||
info "Anwendung bereits deployed - überspringe Basis-Installation"
|
||
# Trotzdem Netzwerk-Sicherheit aktualisieren
|
||
configure_network_security
|
||
fi
|
||
|
||
# Desktop-Environments entfernen und minimale X11 installieren
|
||
remove_desktop_environments
|
||
install_minimal_x11
|
||
configure_x11_for_raspberry_pi
|
||
|
||
# Performance-Optimierungen für Raspberry Pi Webapp
|
||
optimize_webapp_performance
|
||
|
||
# Static Assets nur optimieren wenn App deployed wurde
|
||
if [ -d "$APP_DIR" ] && [ -d "$APP_DIR/static" ]; then
|
||
optimize_static_assets
|
||
else
|
||
info "⏭️ Static Asset Optimierung übersprungen - App noch nicht deployed"
|
||
fi
|
||
|
||
# Remote-Zugang konfigurieren (robust)
|
||
install_remote_access
|
||
configure_firewall
|
||
|
||
# Kiosk-System konfigurieren
|
||
create_kiosk_user
|
||
configure_autologin
|
||
configure_kiosk_autostart
|
||
|
||
# Services installieren und aktivieren (robust)
|
||
install_systemd_services
|
||
enable_and_start_services
|
||
|
||
# Umfassende System-Tests
|
||
progress "Führe umfassende Produktions-System-Tests durch..."
|
||
local system_tests_passed=true
|
||
|
||
if test_application; then
|
||
success "✅ Anwendungs-Tests erfolgreich"
|
||
else
|
||
warning "⚠️ Anwendungs-Tests mit Problemen"
|
||
system_tests_passed=false
|
||
fi
|
||
|
||
if test_remote_access; then
|
||
success "✅ Remote-Zugang-Tests erfolgreich"
|
||
else
|
||
warning "⚠️ Remote-Zugang-Tests mit Problemen"
|
||
system_tests_passed=false
|
||
fi
|
||
|
||
# Aufräumen
|
||
cleanup_old_files
|
||
|
||
# Finale Status-Bewertung
|
||
if [ "$system_tests_passed" = true ]; then
|
||
success "✅ Vollständige robuste Kiosk-Installation erfolgreich abgeschlossen!"
|
||
else
|
||
warning "⚠️ Vollständige Kiosk-Installation mit Einschränkungen abgeschlossen"
|
||
info "→ Grundfunktionalität sollte verfügbar sein, manuelle Überprüfung empfohlen"
|
||
fi
|
||
|
||
log "📋 Vollständige Installation Zusammenfassung:"
|
||
log " 🖥️ Hostname: raspberrypi"
|
||
log " 🔐 Kiosk-Modus: Konfiguriert (startet beim nächsten Boot)"
|
||
log " 📡 SSH-Zugang: user:raspberry (Port 22)"
|
||
log " 🖥️ RDP-Zugang: root:744563017196A (Port 3389)"
|
||
log " 🔒 Firewall: Konfiguriert und aktiv"
|
||
log " ⚡ Performance: Optimiert für Raspberry Pi"
|
||
log " 🌐 HTTP-Backend: $HTTP_URL"
|
||
log " 🛡️ Sicherheit: IPv6 deaktiviert, erweiterte Netzwerk-Sicherheit"
|
||
info ""
|
||
success "🚀 Produktionssystem vollständig einsatzbereit!"
|
||
warning "⚠️ NEUSTART ERFORDERLICH für automatischen Kiosk-Start: sudo reboot"
|
||
|
||
# Fehler-Zusammenfassung anzeigen
|
||
show_error_summary
|
||
|
||
# Finale Status-Anzeige für Vollinstallation
|
||
echo ""
|
||
echo -e "${GREEN}=================================================================${NC}"
|
||
echo -e "${GREEN} VOLLSTÄNDIGE INSTALLATION ERFOLGREICH ABGESCHLOSSEN!${NC}"
|
||
echo -e "${GREEN}=================================================================${NC}"
|
||
echo ""
|
||
echo -e "${BLUE}📋 Was wurde installiert:${NC}"
|
||
echo -e " ✅ Komplettes Produktionssystem"
|
||
echo -e " ✅ Kiosk-Modus konfiguriert"
|
||
echo -e " ✅ Remote-Zugang (SSH & RDP)"
|
||
echo -e " ✅ Firewall konfiguriert"
|
||
echo -e " ✅ Automatischer Start beim Boot"
|
||
echo ""
|
||
echo -e "${YELLOW}🔐 Zugangsdaten:${NC}"
|
||
echo -e " SSH: user:raspberry (Port 22)"
|
||
echo -e " RDP: root:744563017196A (Port 3389)"
|
||
echo ""
|
||
echo -e "${RED}⚠️ WICHTIG: Neustart erforderlich!${NC}"
|
||
echo -e " ${CYAN}sudo reboot${NC}"
|
||
echo ""
|
||
echo -e "${GREEN}✅ Produktionssystem vollständig installiert!${NC}"
|
||
echo -e "${GREEN}=================================================================${NC}"
|
||
}
|
||
|
||
# =========================== RDP & SSH ZUGANG ===========================
|
||
install_remote_access() {
|
||
log "=== INSTALLIERE REMOTE-ZUGANG (RDP & SSH) ==="
|
||
|
||
# SSH-Server installieren und konfigurieren
|
||
progress "Installiere und konfiguriere SSH-Server..."
|
||
apt-get install -y openssh-server || error "SSH-Server Installation fehlgeschlagen"
|
||
|
||
# SSH-Service aktivieren
|
||
systemctl enable ssh
|
||
systemctl start ssh
|
||
|
||
# SSH-Benutzer 'user' erstellen (falls nicht vorhanden)
|
||
if ! id "user" &>/dev/null; then
|
||
progress "Erstelle SSH-Benutzer: user"
|
||
useradd -m -s /bin/bash user || error "Kann SSH-Benutzer nicht erstellen"
|
||
echo "user:raspberry" | chpasswd || error "Kann Passwort für SSH-Benutzer nicht setzen"
|
||
usermod -aG sudo user 2>/dev/null || true
|
||
|
||
# pip-Konfiguration für SSH-Benutzer
|
||
mkdir -p "/home/user/.pip" 2>/dev/null || true
|
||
cat > "/home/user/.pip/pip.conf" << 'EOF'
|
||
[global]
|
||
break-system-packages = true
|
||
trusted-host = pypi.org
|
||
pypi.python.org
|
||
files.pythonhosted.org
|
||
timeout = 60
|
||
retries = 3
|
||
|
||
[install]
|
||
break-system-packages = true
|
||
trusted-host = pypi.org
|
||
pypi.python.org
|
||
files.pythonhosted.org
|
||
EOF
|
||
chown "user:user" "/home/user/.pip/pip.conf" 2>/dev/null || true
|
||
|
||
log "✅ SSH-Benutzer 'user' erstellt mit Passwort 'raspberry'"
|
||
else
|
||
info "SSH-Benutzer 'user' existiert bereits"
|
||
echo "user:raspberry" | chpasswd || warning "Konnte Passwort für SSH-Benutzer nicht aktualisieren"
|
||
fi
|
||
|
||
# RDP-Server (xrdp) installieren - vereinfachter Ansatz
|
||
progress "Installiere RDP-Server (xrdp) - vereinfachte Installation..."
|
||
|
||
# Alle bestehenden xrdp-Installationen entfernen
|
||
progress "Entferne vorherige xrdp-Installationen..."
|
||
systemctl stop xrdp xrdp-sesman 2>/dev/null || true
|
||
systemctl disable xrdp xrdp-sesman 2>/dev/null || true
|
||
apt-get remove --purge -y xrdp 2>/dev/null || true
|
||
rm -rf /etc/xrdp /var/log/xrdp* 2>/dev/null || true
|
||
|
||
# XFCE Desktop installieren (minimal)
|
||
progress "Installiere minimale XFCE-Umgebung..."
|
||
if ! apt-get install -y xfce4-session xfce4-panel xfce4-terminal xfce4-settings xfdesktop4 dbus-x11; then
|
||
warning "Minimale XFCE-Installation fehlgeschlagen - verwende Fallback..."
|
||
apt-get install -y xfce4 dbus-x11 || error "XFCE Installation fehlgeschlagen"
|
||
fi
|
||
|
||
# xrdp neu installieren
|
||
progress "Installiere xrdp neu..."
|
||
apt-get update
|
||
apt-get install -y xrdp || error "xrdp Installation fehlgeschlagen"
|
||
|
||
# Benutzer zur xrdp-Gruppe hinzufügen
|
||
usermod -aG xrdp root 2>/dev/null || true
|
||
if id "user" &>/dev/null; then
|
||
usermod -aG xrdp user 2>/dev/null || true
|
||
fi
|
||
|
||
# Erstelle minimale xrdp-Konfiguration
|
||
progress "Erstelle minimale xrdp-Konfiguration..."
|
||
|
||
# Backup der Original-Konfiguration
|
||
cp /etc/xrdp/xrdp.ini /etc/xrdp/xrdp.ini.original 2>/dev/null || true
|
||
|
||
# Sehr einfache xrdp.ini
|
||
cat > /etc/xrdp/xrdp.ini << 'EOF'
|
||
[Globals]
|
||
ini_version=1
|
||
fork=true
|
||
port=3389
|
||
tcp_nodelay=true
|
||
tcp_keepalive=true
|
||
security_layer=rdp
|
||
autorun=
|
||
allow_channels=true
|
||
allow_multimon=false
|
||
bitmap_cache=true
|
||
bitmap_compression=true
|
||
bulk_compression=false
|
||
max_bpp=24
|
||
new_cursors=true
|
||
use_fastpath=both
|
||
require_credentials=true
|
||
ask_for_reconnect_reason=false
|
||
enable_token_login=false
|
||
|
||
[Xorg]
|
||
name=Xorg
|
||
lib=libxup.so
|
||
username=ask
|
||
password=ask
|
||
ip=127.0.0.1
|
||
port=-1
|
||
code=20
|
||
EOF
|
||
|
||
# Einfache sesman.ini
|
||
cp /etc/xrdp/sesman.ini /etc/xrdp/sesman.ini.original 2>/dev/null || true
|
||
|
||
cat > /etc/xrdp/sesman.ini << 'EOF'
|
||
[Globals]
|
||
ListenAddress=127.0.0.1
|
||
ListenPort=3350
|
||
EnableUserWindowManager=true
|
||
UserWindowManager=startxfce4
|
||
DefaultWindowManager=startxfce4
|
||
|
||
[Security]
|
||
AllowRootLogin=true
|
||
MaxLoginRetry=4
|
||
AlwaysGroupCheck=false
|
||
|
||
[Sessions]
|
||
X11DisplayOffset=10
|
||
MaxSessions=10
|
||
KillDisconnected=false
|
||
IdleTimeLimit=0
|
||
DisconnectedTimeLimit=0
|
||
|
||
[Logging]
|
||
LogFile=xrdp-sesman.log
|
||
LogLevel=INFO
|
||
EnableSyslog=true
|
||
SyslogLevel=INFO
|
||
|
||
[Xorg]
|
||
param1=-bs
|
||
param2=-nolisten
|
||
param3=tcp
|
||
param4=-dpi
|
||
param5=96
|
||
EOF
|
||
|
||
# Erstelle .xsession für XFCE
|
||
progress "Konfiguriere XFCE-Sessions..."
|
||
|
||
# Root .xsession
|
||
cat > /root/.xsession << 'EOF'
|
||
#!/bin/bash
|
||
export XDG_SESSION_DESKTOP=xfce
|
||
export XDG_DATA_DIRS=/usr/share/xfce4:/usr/local/share:/usr/share
|
||
export XDG_CONFIG_DIRS=/etc/xdg/xdg-xfce:/etc/xdg
|
||
exec startxfce4
|
||
EOF
|
||
chmod +x /root/.xsession
|
||
|
||
# User .xsession (falls user existiert)
|
||
if id "user" &>/dev/null; then
|
||
cat > /home/user/.xsession << 'EOF'
|
||
#!/bin/bash
|
||
export XDG_SESSION_DESKTOP=xfce
|
||
export XDG_DATA_DIRS=/usr/share/xfce4:/usr/local/share:/usr/share
|
||
export XDG_CONFIG_DIRS=/etc/xdg/xdg-xfce:/etc/xdg
|
||
exec startxfce4
|
||
EOF
|
||
chown user:user /home/user/.xsession
|
||
chmod +x /home/user/.xsession
|
||
fi
|
||
|
||
# Root-Passwort setzen
|
||
progress "Setze Root-Passwort für RDP..."
|
||
echo "root:744563017196A" | chpasswd || error "Kann Root-Passwort nicht setzen"
|
||
|
||
# Log-Verzeichnisse erstellen mit korrekten Berechtigungen
|
||
progress "Erstelle Log-Verzeichnisse..."
|
||
mkdir -p /var/log
|
||
touch /var/log/xrdp.log /var/log/xrdp-sesman.log 2>/dev/null || true
|
||
chown xrdp:xrdp /var/log/xrdp*.log 2>/dev/null || true
|
||
chmod 644 /var/log/xrdp*.log 2>/dev/null || true
|
||
|
||
# Erstelle xrdp-Konfigurationsverzeichnisse
|
||
mkdir -p /etc/xrdp/cert /var/run/xrdp
|
||
chown xrdp:xrdp /etc/xrdp/cert /var/run/xrdp 2>/dev/null || true
|
||
|
||
# Services aktivieren und starten
|
||
progress "Starte xrdp-Services..."
|
||
|
||
# systemd daemon reload
|
||
systemctl daemon-reload
|
||
|
||
# Services aktivieren
|
||
systemctl enable xrdp-sesman
|
||
systemctl enable xrdp
|
||
|
||
# Services starten (sesman zuerst)
|
||
systemctl start xrdp-sesman
|
||
sleep 3
|
||
|
||
# Prüfe sesman-Status
|
||
if systemctl is-active --quiet xrdp-sesman; then
|
||
success "✅ xrdp-sesman erfolgreich gestartet"
|
||
|
||
# Jetzt xrdp starten
|
||
systemctl start xrdp
|
||
sleep 3
|
||
|
||
if systemctl is-active --quiet xrdp; then
|
||
success "✅ xrdp erfolgreich gestartet"
|
||
else
|
||
warning "⚠️ xrdp konnte nicht gestartet werden"
|
||
journalctl -u xrdp --no-pager -l | tail -10
|
||
fi
|
||
else
|
||
warning "⚠️ xrdp-sesman konnte nicht gestartet werden"
|
||
journalctl -u xrdp-sesman --no-pager -l | tail -10
|
||
fi
|
||
|
||
cd "$CURRENT_DIR"
|
||
|
||
# Finaler Status-Check
|
||
if systemctl is-active --quiet xrdp && systemctl is-active --quiet xrdp-sesman; then
|
||
log "✅ Remote-Zugang vollständig konfiguriert:"
|
||
log " 📡 SSH: user:raspberry (Port 22)"
|
||
log " 🖥️ RDP: root:744563017196A (Port 3389)"
|
||
log " 🖥️ RDP: user:raspberry (Port 3389)"
|
||
elif systemctl is-active --quiet ssh; then
|
||
log "✅ SSH-Zugang konfiguriert:"
|
||
log " 📡 SSH: user:raspberry (Port 22)"
|
||
warning "⚠️ RDP-Installation unvollständig"
|
||
info "Manuelle Überprüfung erforderlich:"
|
||
info " systemctl status xrdp"
|
||
info " systemctl status xrdp-sesman"
|
||
info " journalctl -u xrdp -f"
|
||
else
|
||
error "❌ Weder SSH noch RDP konnten konfiguriert werden"
|
||
fi
|
||
}
|
||
|
||
# =========================== FIREWALL KONFIGURATION ===========================
|
||
configure_firewall() {
|
||
log "=== KONFIGURIERE FIREWALL (firewalld) ==="
|
||
|
||
# firewalld installieren
|
||
progress "Installiere firewalld..."
|
||
apt-get install -y firewalld || error "firewalld Installation fehlgeschlagen"
|
||
|
||
# firewalld aktivieren und starten
|
||
systemctl enable firewalld
|
||
systemctl start firewalld
|
||
|
||
# Warte kurz bis firewalld vollständig gestartet ist
|
||
sleep 5
|
||
|
||
progress "Konfiguriere firewalld-Zonen und -Regeln..."
|
||
|
||
# Firewall-Status prüfen
|
||
if ! firewall-cmd --state >/dev/null 2>&1; then
|
||
error "firewalld ist nicht aktiv oder reagiert nicht"
|
||
fi
|
||
|
||
# Bestehende Zone entfernen falls vorhanden
|
||
progress "Entferne bestehende myp-backend Zone falls vorhanden..."
|
||
if firewall-cmd --permanent --get-zones | grep -q "myp-backend"; then
|
||
log "Entferne bestehende myp-backend Zone..."
|
||
firewall-cmd --permanent --delete-zone=myp-backend 2>/dev/null || true
|
||
firewall-cmd --reload
|
||
sleep 2
|
||
fi
|
||
|
||
# Zone neu erstellen
|
||
progress "Erstelle neue myp-backend Zone..."
|
||
if ! firewall-cmd --permanent --new-zone=myp-backend; then
|
||
error "Fehler beim Erstellen der myp-backend Zone"
|
||
fi
|
||
|
||
# Konfiguration neu laden
|
||
firewall-cmd --reload
|
||
sleep 2
|
||
|
||
# Erweiterte Netzwerk-Quellen definieren (nur IPv4)
|
||
progress "Füge Netzwerk-Quellen hinzu..."
|
||
firewall-cmd --permanent --zone=myp-backend --add-source=192.168.0.0/16 || error "Fehler beim Hinzufügen des 192.168.0.0/16 Netzwerks"
|
||
firewall-cmd --permanent --zone=myp-backend --add-source=127.0.0.1/32 || error "Fehler beim Hinzufügen von localhost"
|
||
|
||
# Lokaler Hostname "raspberrypi" hinzufügen
|
||
local local_hostname="raspberrypi"
|
||
progress "Füge lokalen Hostname hinzu: $local_hostname"
|
||
local local_ip=$(getent hosts "$local_hostname" | awk '{print $1}' | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' | head -1 2>/dev/null || true)
|
||
if [ -n "$local_ip" ]; then
|
||
firewall-cmd --permanent --zone=myp-backend --add-source="$local_ip/32" 2>/dev/null || warning "Konnte lokalen Hostname nicht hinzufügen"
|
||
log "✅ Lokaler Hostname $local_hostname hinzugefügt: $local_ip"
|
||
else
|
||
info "Lokaler Hostname $local_hostname nicht auflösbar - wird beim nächsten Boot verfügbar sein"
|
||
fi
|
||
|
||
# Frontend-Server m040tbaraspi001 hinzufügen (falls auflösbar)
|
||
progress "Füge Frontend-Server hinzu: m040tbaraspi001"
|
||
local frontend_ip=$(getent hosts "m040tbaraspi001" | awk '{print $1}' | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' | head -1 2>/dev/null || true)
|
||
if [ -n "$frontend_ip" ]; then
|
||
firewall-cmd --permanent --zone=myp-backend --add-source="$frontend_ip/32" 2>/dev/null || warning "Konnte Frontend-Server IP nicht hinzufügen"
|
||
log "✅ Frontend-Server m040tbaraspi001 hinzugefügt: $frontend_ip"
|
||
else
|
||
# Versuche auch mit FQDN
|
||
local frontend_fqdn_ip=$(getent hosts "m040tbaraspi001.de040.corpintra.net" | awk '{print $1}' | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' | head -1 2>/dev/null || true)
|
||
if [ -n "$frontend_fqdn_ip" ]; then
|
||
firewall-cmd --permanent --zone=myp-backend --add-source="$frontend_fqdn_ip/32" 2>/dev/null || warning "Konnte Frontend-Server FQDN nicht hinzufügen"
|
||
log "✅ Frontend-Server m040tbaraspi001.de040.corpintra.net hinzugefügt: $frontend_fqdn_ip"
|
||
else
|
||
info "Frontend-Server m040tbaraspi001 nicht auflösbar - überspringe"
|
||
fi
|
||
fi
|
||
|
||
# Ports und Services hinzufügen
|
||
progress "Konfiguriere Ports und Services..."
|
||
|
||
# HTTPS für API & Kiosk zulassen
|
||
firewall-cmd --permanent --zone=myp-backend --add-port=443/tcp || error "Fehler beim Hinzufügen von Port 443"
|
||
|
||
# SSH für Wartung
|
||
firewall-cmd --permanent --zone=myp-backend --add-service=ssh || error "Fehler beim Hinzufügen des SSH-Service"
|
||
|
||
# RDP für Remote-Desktop
|
||
firewall-cmd --permanent --zone=myp-backend --add-port=3389/tcp || error "Fehler beim Hinzufügen von Port 3389"
|
||
|
||
# IPv6 in firewalld deaktivieren
|
||
progress "Deaktiviere IPv6 in firewalld..."
|
||
firewall-cmd --permanent --set-target=DROP --zone=public --family=ipv6 2>/dev/null || warning "IPv6 konnte nicht in public Zone deaktiviert werden"
|
||
firewall-cmd --permanent --set-target=DROP --zone=myp-backend --family=ipv6 2>/dev/null || warning "IPv6 konnte nicht in myp-backend Zone deaktiviert werden"
|
||
|
||
# Default-Zone setzen
|
||
progress "Setze Default-Zone..."
|
||
firewall-cmd --set-default-zone=myp-backend || error "Fehler beim Setzen der Default-Zone"
|
||
|
||
# Änderungen übernehmen
|
||
progress "Lade Firewall-Konfiguration neu..."
|
||
firewall-cmd --reload || error "Fehler beim Neuladen der Firewall-Konfiguration"
|
||
|
||
# Kurz warten und Status prüfen
|
||
sleep 3
|
||
|
||
# Firewall-Status anzeigen
|
||
progress "Firewall-Konfiguration:"
|
||
if firewall-cmd --list-all --zone=myp-backend 2>/dev/null; then
|
||
log "✅ Firewall-Konfiguration erfolgreich angezeigt"
|
||
else
|
||
warning "⚠️ Firewall-Status konnte nicht angezeigt werden"
|
||
fi
|
||
|
||
# Finale Validierung
|
||
progress "Validiere Firewall-Konfiguration..."
|
||
local validation_errors=0
|
||
|
||
# Prüfe ob Zone existiert
|
||
if ! firewall-cmd --get-zones | grep -q "myp-backend"; then
|
||
error "Zone myp-backend wurde nicht korrekt erstellt"
|
||
((validation_errors++))
|
||
fi
|
||
|
||
# Prüfe Default-Zone
|
||
if [ "$(firewall-cmd --get-default-zone)" != "myp-backend" ]; then
|
||
warning "Default-Zone ist nicht myp-backend"
|
||
((validation_errors++))
|
||
fi
|
||
|
||
# Prüfe Ports
|
||
if ! firewall-cmd --zone=myp-backend --query-port=443/tcp 2>/dev/null; then
|
||
warning "Port 443 nicht korrekt konfiguriert"
|
||
((validation_errors++))
|
||
fi
|
||
|
||
if ! firewall-cmd --zone=myp-backend --query-port=3389/tcp 2>/dev/null; then
|
||
warning "Port 3389 nicht korrekt konfiguriert"
|
||
((validation_errors++))
|
||
fi
|
||
|
||
if ! firewall-cmd --zone=myp-backend --query-service=ssh 2>/dev/null; then
|
||
warning "SSH-Service nicht korrekt konfiguriert"
|
||
((validation_errors++))
|
||
fi
|
||
|
||
if [ $validation_errors -eq 0 ]; then
|
||
log "✅ Firewall konfiguriert und validiert:"
|
||
log " 🔒 Zone: myp-backend (als Default gesetzt)"
|
||
log " 🌐 Netzwerk: 192.168.0.0/16 (nur IPv4)"
|
||
log " 🏠 Localhost: 127.0.0.1"
|
||
log " 🖥️ Lokaler Host: raspberrypi"
|
||
log " 📡 Frontend-Server: m040tbaraspi001"
|
||
log " 🔌 Ports: 443/tcp (HTTPS), 22/tcp (SSH), 3389/tcp (RDP)"
|
||
log " 🚫 IPv6 vollständig blockiert"
|
||
else
|
||
warning "⚠️ Firewall-Konfiguration mit $validation_errors Fehlern abgeschlossen"
|
||
info "System funktioniert möglicherweise trotzdem - manuelle Überprüfung empfohlen"
|
||
fi
|
||
}
|
||
|
||
# =========================== REMOTE-ZUGANG TESTEN ===========================
|
||
test_remote_access() {
|
||
log "=== TESTE REMOTE-ZUGANG ==="
|
||
|
||
# SSH-Service testen
|
||
progress "Teste SSH-Service..."
|
||
if systemctl is-active --quiet ssh; then
|
||
success "✅ SSH-Service läuft"
|
||
|
||
# SSH-Port testen
|
||
if ss -tlnp | grep -q ":22 "; then
|
||
success "✅ SSH-Port 22 ist offen"
|
||
else
|
||
warning "⚠️ SSH-Port 22 nicht erreichbar"
|
||
fi
|
||
else
|
||
warning "⚠️ SSH-Service läuft nicht"
|
||
fi
|
||
|
||
# RDP-Services testen
|
||
progress "Teste RDP-Services..."
|
||
|
||
local xrdp_sesman_status="❌"
|
||
local xrdp_status="❌"
|
||
|
||
if systemctl is-active --quiet xrdp-sesman; then
|
||
xrdp_sesman_status="✅"
|
||
success "✅ xrdp-sesman läuft"
|
||
else
|
||
warning "⚠️ xrdp-sesman läuft nicht"
|
||
fi
|
||
|
||
if systemctl is-active --quiet xrdp; then
|
||
xrdp_status="✅"
|
||
success "✅ xrdp läuft"
|
||
|
||
# RDP-Port testen
|
||
if ss -tlnp | grep -q ":3389 "; then
|
||
success "✅ RDP-Port 3389 ist offen"
|
||
else
|
||
warning "⚠️ RDP-Port 3389 nicht erreichbar"
|
||
fi
|
||
else
|
||
warning "⚠️ xrdp läuft nicht"
|
||
fi
|
||
|
||
# Firewall-Status testen
|
||
progress "Teste Firewall-Status..."
|
||
if systemctl is-active --quiet firewalld; then
|
||
success "✅ Firewall läuft"
|
||
|
||
# Prüfe ob Ports offen sind
|
||
if firewall-cmd --zone=myp-backend --query-port=22/tcp 2>/dev/null; then
|
||
success "✅ SSH-Port in Firewall freigegeben"
|
||
else
|
||
warning "⚠️ SSH-Port nicht in Firewall freigegeben"
|
||
fi
|
||
|
||
if firewall-cmd --zone=myp-backend --query-port=3389/tcp 2>/dev/null; then
|
||
success "✅ RDP-Port in Firewall freigegeben"
|
||
else
|
||
warning "⚠️ RDP-Port nicht in Firewall freigegeben"
|
||
fi
|
||
else
|
||
warning "⚠️ Firewall läuft nicht"
|
||
fi
|
||
|
||
# Netzwerk-Interface testen
|
||
progress "Teste Netzwerk-Konfiguration..."
|
||
local ip_address=$(ip route get 1.1.1.1 2>/dev/null | awk '{print $7}' | head -1 || echo "Unbekannt")
|
||
if [ "$ip_address" != "Unbekannt" ]; then
|
||
success "✅ Netzwerk-Interface aktiv: $ip_address"
|
||
info "Zugang-URLs:"
|
||
info " SSH: ssh user@$ip_address"
|
||
if [ "$xrdp_status" = "✅" ]; then
|
||
info " RDP: $ip_address:3389 (root:744563017196A oder user:raspberry)"
|
||
fi
|
||
else
|
||
warning "⚠️ Keine Netzwerk-IP ermittelt"
|
||
fi
|
||
|
||
# Status-Zusammenfassung
|
||
log "📊 Service-Status:"
|
||
log " SSH: $(systemctl is-active --quiet ssh && echo "✅ Aktiv" || echo "❌ Inaktiv")"
|
||
log " xrdp-sesman: $xrdp_sesman_status $(systemctl is-active --quiet xrdp-sesman && echo "Aktiv" || echo "Inaktiv")"
|
||
log " xrdp: $xrdp_status $(systemctl is-active --quiet xrdp && echo "Aktiv" || echo "Inaktiv")"
|
||
|
||
log "✅ Remote-Zugang-Test abgeschlossen"
|
||
}
|
||
|
||
# =========================== HOSTNAME KONFIGURATION ===========================
|
||
configure_hostname() {
|
||
log "=== KONFIGURIERE HOSTNAME ==="
|
||
|
||
local target_hostname="raspberrypi"
|
||
local current_hostname=$(hostname)
|
||
|
||
if [ "$current_hostname" != "$target_hostname" ]; then
|
||
progress "Setze Hostname von '$current_hostname' auf '$target_hostname'..."
|
||
|
||
# Hostname sofort setzen
|
||
hostnamectl set-hostname "$target_hostname" || error "Fehler beim Setzen des Hostnames"
|
||
|
||
# /etc/hostname aktualisieren
|
||
echo "$target_hostname" > /etc/hostname
|
||
|
||
# /etc/hosts aktualisieren
|
||
cp /etc/hosts /etc/hosts.backup
|
||
sed -i "s/127.0.1.1.*/127.0.1.1\t$target_hostname/" /etc/hosts
|
||
|
||
# Falls kein 127.0.1.1 Eintrag existiert, hinzufügen
|
||
if ! grep -q "127.0.1.1" /etc/hosts; then
|
||
echo "127.0.1.1 $target_hostname" >> /etc/hosts
|
||
fi
|
||
|
||
log "✅ Hostname erfolgreich auf '$target_hostname' gesetzt"
|
||
else
|
||
log "✅ Hostname bereits korrekt: '$target_hostname'"
|
||
fi
|
||
|
||
# Hostname-Auflösung testen
|
||
if getent hosts "$target_hostname" >/dev/null 2>&1; then
|
||
local resolved_ip=$(getent hosts "$target_hostname" | awk '{print $1}' | head -1)
|
||
log "✅ Hostname-Auflösung funktioniert: $target_hostname -> $resolved_ip"
|
||
else
|
||
warning "⚠️ Hostname-Auflösung für '$target_hostname' fehlgeschlagen"
|
||
fi
|
||
}
|
||
|
||
# =========================== WEBAPP PERFORMANCE-OPTIMIERUNG ===========================
|
||
optimize_webapp_performance() {
|
||
log "=== WEBAPP PERFORMANCE-OPTIMIERUNG FÜR RASPBERRY PI ==="
|
||
|
||
# Python/Flask spezifische Optimierungen
|
||
progress "Konfiguriere Python-Performance-Optimierungen..."
|
||
|
||
# Python Bytecode Optimierung aktivieren
|
||
cat > /etc/environment << 'EOF'
|
||
# Python Performance Optimierungen
|
||
PYTHONOPTIMIZE=2
|
||
PYTHONDONTWRITEBYTECODE=1
|
||
PYTHONUNBUFFERED=1
|
||
PYTHONHASHSEED=random
|
||
|
||
# Flask/SQLite Optimierungen
|
||
FLASK_ENV=production
|
||
FLASK_DEBUG=0
|
||
SQLITE_TMPDIR=/tmp
|
||
|
||
# Memory Optimierungen
|
||
MALLOC_ARENA_MAX=2
|
||
MALLOC_MMAP_THRESHOLD=131072
|
||
MALLOC_TRIM_THRESHOLD=131072
|
||
|
||
EOF
|
||
|
||
# Systemd Service-Optimierungen
|
||
progress "Optimiere Systemd-Services für bessere Performance..."
|
||
|
||
# Stoppe unnötige Services
|
||
local unnecessary_services=(
|
||
"bluetooth.service"
|
||
"hciuart.service"
|
||
"avahi-daemon.service"
|
||
"cups.service"
|
||
"cups-browsed.service"
|
||
"ModemManager.service"
|
||
"wpa_supplicant.service"
|
||
)
|
||
|
||
for service in "${unnecessary_services[@]}"; do
|
||
if systemctl is-enabled "$service" 2>/dev/null; then
|
||
systemctl disable "$service" 2>/dev/null || true
|
||
systemctl stop "$service" 2>/dev/null || true
|
||
log "✅ Service deaktiviert: $service"
|
||
fi
|
||
done
|
||
|
||
# Tmpfs für temporäre Dateien
|
||
progress "Konfiguriere tmpfs für bessere I/O Performance..."
|
||
|
||
cat >> /etc/fstab << 'EOF'
|
||
|
||
# MYP Performance Optimierungen - tmpfs für temporäre Dateien
|
||
tmpfs /tmp tmpfs defaults,noatime,nosuid,size=256m 0 0
|
||
tmpfs /var/tmp tmpfs defaults,noatime,nosuid,size=128m 0 0
|
||
tmpfs /var/log tmpfs defaults,noatime,nosuid,size=64m 0 0
|
||
|
||
EOF
|
||
|
||
# Logrotate für tmpfs-Logs konfigurieren
|
||
cat > /etc/logrotate.d/myp-tmpfs << 'EOF'
|
||
/var/log/*.log {
|
||
daily
|
||
missingok
|
||
rotate 2
|
||
compress
|
||
notifempty
|
||
create 0644 root root
|
||
copytruncate
|
||
}
|
||
EOF
|
||
|
||
# Systemd Journal Einstellungen optimieren
|
||
progress "Optimiere systemd Journal für bessere Performance..."
|
||
|
||
mkdir -p /etc/systemd/journald.conf.d
|
||
cat > /etc/systemd/journald.conf.d/myp-performance.conf << 'EOF'
|
||
[Journal]
|
||
# Journal Optimierungen für Raspberry Pi
|
||
Storage=volatile
|
||
RuntimeMaxUse=32M
|
||
RuntimeKeepFree=16M
|
||
RuntimeMaxFileSize=8M
|
||
RuntimeMaxFiles=4
|
||
MaxRetentionSec=1day
|
||
MaxFileSec=1hour
|
||
ForwardToSyslog=no
|
||
ForwardToKMsg=no
|
||
ForwardToConsole=no
|
||
ForwardToWall=no
|
||
EOF
|
||
|
||
# Crontab für regelmäßige Cache-Bereinigung
|
||
progress "Installiere automatische Cache-Bereinigung..."
|
||
|
||
cat > /etc/cron.d/myp-cache-cleanup << 'EOF'
|
||
# MYP Cache und Memory Cleanup
|
||
# Alle 6 Stunden Cache bereinigen
|
||
0 */6 * * * root /bin/echo 3 > /proc/sys/vm/drop_caches
|
||
# Täglich um 3 Uhr temporäre Dateien bereinigen
|
||
0 3 * * * root /usr/bin/find /tmp -type f -atime +1 -delete 2>/dev/null
|
||
# Wöchentlich Python Cache bereinigen
|
||
0 2 * * 0 root /usr/bin/find /opt/myp -name "*.pyc" -delete 2>/dev/null
|
||
0 2 * * 0 root /usr/bin/find /opt/myp -name "__pycache__" -type d -exec rm -rf {} + 2>/dev/null
|
||
EOF
|
||
|
||
# Limits für bessere Ressourcen-Verwaltung
|
||
progress "Konfiguriere System-Limits..."
|
||
|
||
cat >> /etc/security/limits.conf << 'EOF'
|
||
|
||
# MYP Performance Limits
|
||
* soft nofile 65536
|
||
* hard nofile 65536
|
||
* soft nproc 32768
|
||
* hard nproc 32768
|
||
root soft nofile 65536
|
||
root hard nofile 65536
|
||
|
||
EOF
|
||
|
||
# Apache/Nginx entfernen falls vorhanden (Konflikt mit Flask)
|
||
progress "Entferne konfliktbehaftete Webserver..."
|
||
|
||
local webservers=("apache2" "nginx" "lighttpd")
|
||
for webserver in "${webservers[@]}"; do
|
||
if systemctl is-enabled "$webserver" 2>/dev/null; then
|
||
systemctl stop "$webserver" 2>/dev/null || true
|
||
systemctl disable "$webserver" 2>/dev/null || true
|
||
apt-get remove --purge -y "$webserver" 2>/dev/null || true
|
||
log "✅ Webserver entfernt: $webserver"
|
||
fi
|
||
done
|
||
|
||
log "✅ Webapp Performance-Optimierung abgeschlossen:"
|
||
log " 🚀 Python Bytecode-Optimierung aktiviert"
|
||
log " 💾 tmpfs für temporäre Dateien konfiguriert"
|
||
log " 📝 Journal-Logging optimiert"
|
||
log " 🧹 Automatische Cache-Bereinigung installiert"
|
||
log " ⚡ Unnötige Services deaktiviert"
|
||
log " 📊 System-Limits für bessere Performance gesetzt"
|
||
}
|
||
|
||
# =========================== CSS/JS OPTIMIERUNG ===========================
|
||
optimize_static_assets() {
|
||
log "=== STATISCHE DATEIEN OPTIMIERUNG ==="
|
||
|
||
# Stelle sicher, dass APP_DIR existiert
|
||
if [ -z "$APP_DIR" ] || [ ! -d "$APP_DIR" ]; then
|
||
warning "⚠️ APP_DIR nicht definiert oder nicht vorhanden - überspringe Asset-Optimierung"
|
||
return
|
||
fi
|
||
|
||
if [ ! -d "$APP_DIR/static" ]; then
|
||
warning "⚠️ Static-Ordner nicht gefunden: $APP_DIR/static - überspringe Asset-Optimierung"
|
||
return
|
||
fi
|
||
|
||
progress "Analysiere und optimiere CSS/JS Dateien..."
|
||
|
||
# Speichere aktuelles Verzeichnis
|
||
local original_dir=$(pwd)
|
||
|
||
# Wechsle zu static Verzeichnis
|
||
cd "$APP_DIR/static" 2>/dev/null || {
|
||
warning "⚠️ Konnte nicht zu $APP_DIR/static wechseln"
|
||
return
|
||
}
|
||
|
||
# Erstelle optimierte CSS-Datei durch Kombination kritischer Styles
|
||
progress "Erstelle optimierte CSS-Kombination..."
|
||
|
||
cat > css/critical.min.css << 'EOF'
|
||
/* Kritische Styles für ersten Seitenaufbau - Inline-optimiert */
|
||
*{box-sizing:border-box}body{margin:0;font-family:system-ui,-apple-system,sans-serif;line-height:1.5}
|
||
.container{max-width:1200px;margin:0 auto;padding:0 1rem}
|
||
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}
|
||
.btn{display:inline-flex;align-items:center;padding:0.5rem 1rem;border:none;border-radius:0.375rem;font-weight:500;text-decoration:none;cursor:pointer;transition:all 0.15s}
|
||
.btn-primary{background:#3b82f6;color:white}.btn-primary:hover{background:#2563eb}
|
||
.card{background:white;border-radius:0.5rem;padding:1.5rem;box-shadow:0 1px 3px rgba(0,0,0,0.1)}
|
||
.flex{display:flex}.items-center{align-items:center}.justify-between{justify-content:space-between}
|
||
.hidden{display:none}.block{display:block}.inline-block{display:inline-block}
|
||
.text-sm{font-size:0.875rem}.text-lg{font-size:1.125rem}
|
||
.font-medium{font-weight:500}.font-bold{font-weight:700}
|
||
.text-gray-600{color:#4b5563}.text-gray-900{color:#111827}
|
||
.mb-4{margin-bottom:1rem}.mt-6{margin-top:1.5rem}.p-4{padding:1rem}
|
||
.w-full{width:100%}.h-full{height:100%}
|
||
@media(max-width:768px){.container{padding:0 0.5rem}.card{padding:1rem}}
|
||
EOF
|
||
|
||
# Erstelle minimale JavaScript-Loader
|
||
progress "Erstelle optimierten JavaScript-Loader..."
|
||
|
||
cat > js/loader.min.js << 'EOF'
|
||
/*Minimaler Async Loader für bessere Performance*/
|
||
(function(){var d=document,w=window;function loadCSS(href){var l=d.createElement('link');l.rel='stylesheet';l.href=href;l.media='print';l.onload=function(){this.media='all'};d.head.appendChild(l)}function loadJS(src,cb){var s=d.createElement('script');s.async=true;s.src=src;if(cb)s.onload=cb;d.head.appendChild(s)}w.loadAssets=function(){if(w.assetsLoaded)return;w.assetsLoaded=true;loadCSS('/static/css/tailwind.min.css');loadJS('/static/js/app.min.js')};if(d.readyState==='loading'){d.addEventListener('DOMContentLoaded',w.loadAssets)}else{w.loadAssets()}})();
|
||
EOF
|
||
|
||
# Service Worker für besseres Caching
|
||
progress "Erstelle optimierten Service Worker..."
|
||
|
||
cat > sw-optimized.js << 'EOF'
|
||
const CACHE_NAME = 'myp-webapp-v1';
|
||
const ASSETS_TO_CACHE = [
|
||
'/',
|
||
'/static/css/critical.min.css',
|
||
'/static/js/loader.min.js',
|
||
'/static/favicon.svg'
|
||
];
|
||
|
||
self.addEventListener('install', event => {
|
||
event.waitUntil(
|
||
caches.open(CACHE_NAME)
|
||
.then(cache => cache.addAll(ASSETS_TO_CACHE))
|
||
);
|
||
});
|
||
|
||
self.addEventListener('fetch', event => {
|
||
if (event.request.destination === 'image' ||
|
||
event.request.url.includes('/static/')) {
|
||
event.respondWith(
|
||
caches.match(event.request)
|
||
.then(response => response || fetch(event.request))
|
||
);
|
||
}
|
||
});
|
||
EOF
|
||
|
||
# Gzip-Kompression für statische Dateien
|
||
progress "Komprimiere statische Dateien..."
|
||
|
||
find . -name "*.css" -o -name "*.js" -o -name "*.html" | while read file; do
|
||
if [ -f "$file" ] && [ ! -f "$file.gz" ]; then
|
||
gzip -c "$file" > "$file.gz" 2>/dev/null || true
|
||
fi
|
||
done
|
||
|
||
# Zurück zum Original-Verzeichnis
|
||
cd "$original_dir" 2>/dev/null || cd "$CURRENT_DIR" 2>/dev/null || true
|
||
|
||
log "✅ Statische Dateien optimiert:"
|
||
log " 📦 Kritische CSS-Styles kombiniert"
|
||
log " ⚡ Asynchroner Asset-Loader erstellt"
|
||
log " 🗜️ Gzip-Kompression angewendet"
|
||
log " 🔄 Service Worker für Caching installiert"
|
||
}
|
||
|
||
# =========================== HAUPTPROGRAMM ===========================
|
||
main() {
|
||
# Stelle sicher, dass wir im richtigen Verzeichnis sind
|
||
cd "$CURRENT_DIR" 2>/dev/null || true
|
||
|
||
while true; do
|
||
show_menu
|
||
read -r choice
|
||
|
||
case $choice in
|
||
1)
|
||
install_dependencies_only
|
||
echo ""
|
||
echo -e "${BLUE}📁 Log-Dateien zur Überprüfung:${NC}"
|
||
echo -e " 📄 Vollständiges Log: $INSTALL_LOG"
|
||
[ $ERROR_COUNT -gt 0 ] && echo -e " 🚨 Fehler-Log: $ERROR_LOG"
|
||
[ $WARNING_COUNT -gt 0 ] && echo -e " ⚠️ Warnungs-Log: $WARNING_LOG"
|
||
echo -e " 🔍 Debug-Log: $DEBUG_LOG"
|
||
echo -e " 📊 Zusammenfassung: logs/install-summary.txt"
|
||
echo ""
|
||
echo -n "Drücken Sie Enter um fortzufahren..."
|
||
read -r
|
||
;;
|
||
2)
|
||
install_full_production_system
|
||
echo ""
|
||
echo -e "${BLUE}📁 Log-Dateien zur Überprüfung:${NC}"
|
||
echo -e " 📄 Vollständiges Log: $INSTALL_LOG"
|
||
[ $ERROR_COUNT -gt 0 ] && echo -e " 🚨 Fehler-Log: $ERROR_LOG"
|
||
[ $WARNING_COUNT -gt 0 ] && echo -e " ⚠️ Warnungs-Log: $WARNING_LOG"
|
||
echo -e " 🔍 Debug-Log: $DEBUG_LOG"
|
||
echo -e " 📊 Zusammenfassung: logs/install-summary.txt"
|
||
echo ""
|
||
echo -n "Drücken Sie Enter um fortzufahren..."
|
||
read -r
|
||
;;
|
||
3)
|
||
echo ""
|
||
echo -e "${CYAN}Setup-Skript beendet${NC}"
|
||
if [ -f "$INSTALL_LOG" ]; then
|
||
echo -e "${BLUE}📁 Verfügbare Log-Dateien:${NC}"
|
||
echo -e " 📄 Vollständiges Log: $INSTALL_LOG"
|
||
[ -f "$ERROR_LOG" ] && echo -e " 🚨 Fehler-Log: $ERROR_LOG"
|
||
[ -f "$WARNING_LOG" ] && echo -e " ⚠️ Warnungs-Log: $WARNING_LOG"
|
||
[ -f "$DEBUG_LOG" ] && echo -e " 🔍 Debug-Log: $DEBUG_LOG"
|
||
[ -f "logs/install-summary.txt" ] && echo -e " 📊 Zusammenfassung: logs/install-summary.txt"
|
||
fi
|
||
exit 0
|
||
;;
|
||
*)
|
||
echo -e "${RED}Ungültige Auswahl. Bitte wählen Sie 1-3.${NC}"
|
||
;;
|
||
esac
|
||
done
|
||
}
|
||
|
||
# Skript starten
|
||
main "$@" |