#!/bin/bash ####################################################################### # MYP AIO-Installer (All-in-One Installation System) # # Automatisierte Installation und Einrichtung des MYP-Systems für # Mercedes-Benz 3D-Drucker-Management auf Debian/Linux-Systemen # # Autor: Till Tomczak # Version: 1.0.0 # Datum: $(date +%Y-%m-%d) # # Funktionen: # - Vollständige Systemeinrichtung # - Desktop-Environment Installation (LXDE) # - Chromium Kiosk-Modus # - Python/Node.js Dependencies # - SystemD Services # - Firewall-Konfiguration # - Upgrade-Funktionalität ####################################################################### set -euo pipefail # Strenge Fehlerbehandlung # === KONSTANTEN UND KONFIGURATION === readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" readonly PROJECT_ROOT="$(dirname "${SCRIPT_DIR}")" readonly LOG_FILE="/var/log/myp-installer.log" readonly CONFIG_FILE="${SCRIPT_DIR}/installer.conf" # Projekt-Konfiguration readonly PROJECT_NAME="MYP" readonly PROJECT_USER="myp" readonly PROJECT_GROUP="myp" readonly INSTALL_PATH="/opt/myp" readonly SERVICE_NAME="myp-https" readonly KIOSK_SERVICE="myp-kiosk" # System-Konfiguration readonly HOSTNAME_DEFAULT="myp-terminal" readonly CHROMIUM_FLAGS="--kiosk --disable-infobars --disable-session-crashed-bubble --disable-restore-session-state --disable-background-timer-throttling --disable-backgrounding-occluded-windows --disable-renderer-backgrounding --disable-features=TranslateUI --disable-web-security --disable-features=VizDisplayCompositor --no-first-run --autoplay-policy=no-user-gesture-required" # 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 NC='\033[0m' # No Color # === UTILITY-FUNKTIONEN === log() { local level="$1" shift local message="$*" local timestamp=$(date '+%Y-%m-%d %H:%M:%S') case "$level" in "INFO") echo -e "${GREEN}[INFO]${NC} $message" | tee -a "$LOG_FILE" ;; "WARN") echo -e "${YELLOW}[WARN]${NC} $message" | tee -a "$LOG_FILE" ;; "ERROR") echo -e "${RED}[ERROR]${NC} $message" | tee -a "$LOG_FILE" ;; "DEBUG") echo -e "${BLUE}[DEBUG]${NC} $message" | tee -a "$LOG_FILE" ;; esac echo "[$timestamp] [$level] $message" >> "$LOG_FILE" } check_root() { if [[ $EUID -ne 0 ]]; then log "ERROR" "Dieses Skript muss als root ausgeführt werden" exit 1 fi } check_system() { log "INFO" "Überprüfe Systemvoraussetzungen..." # Debian/Ubuntu Check if ! command -v apt &> /dev/null; then log "ERROR" "Dieses System wird nicht unterstützt (kein APT Package Manager)" exit 1 fi # Internet-Verbindung (VM-kompatibel) check_internet_connection_vm_compatible # Speicherplatz (mindestens 2GB frei) local free_space=$(df / | awk 'NR==2 {print $4}') if [[ $free_space -lt 2097152 ]]; then log "ERROR" "Nicht genügend Speicherplatz (mindestens 2GB erforderlich)" exit 1 fi log "INFO" "Systemvoraussetzungen erfüllt" } # VM-kompatible Internet-Verbindungsprüfung check_internet_connection_vm_compatible() { # Skip-Optionen prüfen if [[ "${SKIP_INTERNET_CHECK:-}" == "true" ]]; then log "WARN" "⚠️ Internet-Check übersprungen (--skip-internet-check)" return 0 fi if [[ "${FORCE_OFFLINE:-}" == "true" ]]; then log "WARN" "⚠️ Offline-Modus erzwungen (--force-offline)" return 0 fi log "INFO" "Prüfe Internet-Verbindung (VM-kompatibel)..." local connection_available=false local timeout_seconds=45 # Längerer Standard-Timeout local start_time=$(date +%s) # VM-Umgebung erkennen local is_vm=false if command -v systemd-detect-virt &>/dev/null; then local virt_type=$(systemd-detect-virt) if [[ "$virt_type" != "none" ]]; then is_vm=true log "INFO" "VM-Umgebung erkannt: $virt_type" timeout_seconds=120 # Deutlich längerer Timeout für VMs fi fi # VM-Mode Option berücksichtigen if [[ "${VM_MODE:-}" == "true" ]]; then is_vm=true timeout_seconds=120 # 2 Minuten für VM-Modus log "INFO" "VM-Modus manuell aktiviert (--vm-mode)" fi # Mehrere Test-Methoden mit VM-freundlichen Timeouts local test_methods=( "ping_multiple_hosts" "curl_connectivity_check" "dns_resolution_test" "gateway_ping_test" ) for method in "${test_methods[@]}"; do local current_time=$(date +%s) local elapsed=$((current_time - start_time)) if [[ $elapsed -gt $timeout_seconds ]]; then log "WARN" "Internet-Check Timeout erreicht (${timeout_seconds}s)" break fi log "INFO" "Teste Methode: $method" if $method "$is_vm"; then log "INFO" "✓ Internet-Verbindung via $method erfolgreich" connection_available=true break else log "WARN" "Methode $method fehlgeschlagen" sleep 2 # Kurze Pause zwischen Tests fi done if [[ "$connection_available" == "true" ]]; then log "INFO" "✅ Internet-Verbindung verfügbar" return 0 else log "ERROR" "❌ Keine Internet-Verbindung verfügbar" # Zusätzliche Diagnose-Informationen show_network_diagnostics_brief # Benutzer-Option in VMs if [[ "$is_vm" == "true" ]] && [[ "${FORCE_YES:-}" != "true" ]]; then log "WARN" "In VM-Umgebungen können Netzwerk-Checks fehlschlagen" log "INFO" "Mögliche Lösungen:" log "INFO" " 1. Warte 1-2 Minuten nach VM-Start" log "INFO" " 2. Prüfe VM-Netzwerk-Einstellungen (NAT/Bridge)" log "INFO" " 3. Teste Internet-Zugang im Browser" if confirm_action "Trotz Netzwerk-Problemen fortfahren? (Nicht empfohlen)"; then log "WARN" "⚠️ Installation trotz Netzwerk-Problemen fortgesetzt" return 0 fi fi return 1 fi } # Ping mit mehreren Hosts und VM-Timeouts ping_multiple_hosts() { local is_vm="$1" local timeout_per_host=5 local packet_count=2 if [[ "$is_vm" == "true" ]]; then timeout_per_host=15 # Längerer Timeout für VMs packet_count=4 # Mehr Ping-Pakete fi local hosts=( "8.8.8.8" # Google DNS "1.1.1.1" # Cloudflare DNS "9.9.9.9" # Quad9 DNS "208.67.222.222" # OpenDNS ) for host in "${hosts[@]}"; do log "DEBUG" "Ping zu $host (Timeout: ${timeout_per_host}s, Pakete: $packet_count)" if timeout $((timeout_per_host + 5)) ping -c $packet_count -W $timeout_per_host "$host" &>/dev/null; then log "INFO" "✓ Ping zu $host erfolgreich" return 0 fi done return 1 } # curl Konnektivitäts-Check mit mehreren URLs curl_connectivity_check() { local is_vm="$1" local connect_timeout=10 local max_time=15 if [[ "$is_vm" == "true" ]]; then connect_timeout=30 # Längerer Verbindungs-Timeout max_time=45 # Längere Gesamtzeit fi if ! command -v curl &>/dev/null; then return 1 fi local urls=( "http://connectivitycheck.gstatic.com/generate_204" "http://www.gstatic.com/generate_204" "http://clients3.google.com/generate_204" ) for url in "${urls[@]}"; do log "DEBUG" "curl zu $url (Timeout: ${connect_timeout}s/${max_time}s)" if curl -s -f --connect-timeout $connect_timeout --max-time $max_time "$url" &>/dev/null; then log "INFO" "✓ curl zu $url erfolgreich" return 0 fi done return 1 } # DNS-Resolution-Test dns_resolution_test() { local is_vm="$1" local timeout=10 if [[ "$is_vm" == "true" ]]; then timeout=20 fi local domains=("google.com" "cloudflare.com" "github.com") for domain in "${domains[@]}"; do log "DEBUG" "DNS-Test für $domain (Timeout: ${timeout}s)" if timeout $timeout nslookup "$domain" &>/dev/null; then log "INFO" "✓ DNS-Auflösung für $domain erfolgreich" return 0 fi done return 1 } # Gateway-Ping-Test gateway_ping_test() { local is_vm="$1" local gateway=$(ip route show default | awk '/default/ {print $3}' | head -1) if [[ -z "$gateway" ]]; then return 1 fi local timeout=5 if [[ "$is_vm" == "true" ]]; then timeout=10 fi log "DEBUG" "Gateway-Ping zu $gateway (Timeout: ${timeout}s)" if timeout $((timeout + 5)) ping -c 2 -W $timeout "$gateway" &>/dev/null; then log "INFO" "✓ Gateway $gateway erreichbar" return 0 fi return 1 } # Kurze Netzwerk-Diagnose show_network_diagnostics_brief() { log "INFO" "=== NETZWERK-DIAGNOSE ===" # Aktive Interfaces local interfaces=$(ip link show | grep -c "state UP") log "INFO" "Aktive Netzwerk-Interfaces: $interfaces" # Default Gateway local gateway=$(ip route show default | awk '/default/ {print $3}' | head -1) if [[ -n "$gateway" ]]; then log "INFO" "Default Gateway: $gateway" else log "WARN" "Kein Default Gateway konfiguriert" fi # DNS-Server if [[ -f /etc/resolv.conf ]]; then local dns_count=$(grep -c nameserver /etc/resolv.conf) log "INFO" "Konfigurierte DNS-Server: $dns_count" fi # VM-Detection if command -v systemd-detect-virt &>/dev/null; then local virt_type=$(systemd-detect-virt) if [[ "$virt_type" != "none" ]]; then log "INFO" "Virtualisierung: $virt_type" fi fi } confirm_action() { local message="$1" local default="${2:-n}" if [[ "${FORCE_YES:-}" == "true" ]]; then return 0 fi while true; do read -p "$message [y/N]: " -n 1 -r echo case $REPLY in [Yy]* ) return 0;; [Nn]* ) return 1;; "" ) [[ "$default" == "y" ]] && return 0 || return 1;; * ) echo "Bitte mit 'y' oder 'n' antworten.";; esac done } # === INSTALLATION MODULES === # Lädt alle Installationsmodule source "${SCRIPT_DIR}/modules/environment.sh" source "${SCRIPT_DIR}/modules/packages.sh" source "${SCRIPT_DIR}/modules/python_node.sh" source "${SCRIPT_DIR}/modules/desktop.sh" source "${SCRIPT_DIR}/modules/services.sh" source "${SCRIPT_DIR}/modules/firewall.sh" source "${SCRIPT_DIR}/modules/testing.sh" # === HAUPTFUNKTIONEN === show_banner() { clear cat << 'EOF' ███╗ ███╗██╗ ██╗██████╗ ██╗███╗ ██╗███████╗████████╗ █████╗ ██╗ ██╗ ███████╗██████╗ ████╗ ████║╚██╗ ██╔╝██╔══██╗ ██║████╗ ██║██╔════╝╚══██╔══╝██╔══██╗██║ ██║ ██╔════╝██╔══██╗ ██╔████╔██║ ╚████╔╝ ██████╔╝ ██║██╔██╗ ██║███████╗ ██║ ███████║██║ ██║ █████╗ ██████╔╝ ██║╚██╔╝██║ ╚██╔╝ ██╔═══╝ ██║██║╚██╗██║╚════██║ ██║ ██╔══██║██║ ██║ ██╔══╝ ██╔══██╗ ██║ ╚═╝ ██║ ██║ ██║ ██║██║ ╚████║███████║ ██║ ██║ ██║███████╗███████╗███████╗██║ ██║ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚══════╝╚═╝ ╚═╝ EOF echo echo " Mercedes-Benz 3D-Drucker Management System" echo " AIO-Installer v1.0.0" echo echo "==================================================================================" echo } show_menu() { echo "Verfügbare Optionen:" echo echo "1) Vollinstallation (Empfohlen für neue Systeme)" echo "2) Upgrade bestehender Installation" echo "3) Nur System-Test durchführen" echo "4) Einzelne Komponenten installieren" echo "5) System-Information anzeigen" echo "6) Deinstallation" echo "0) Beenden" echo } full_installation() { log "INFO" "Starte Vollinstallation des MYP-Systems..." if ! confirm_action "Vollinstallation durchführen? Dies wird das System erheblich verändern."; then log "INFO" "Installation abgebrochen" return 1 fi # Installations-Schritte in korrigierter Reihenfolge # WICHTIG: create_system_user MUSS VOR setup_environment stehen! local steps=( "create_system_user" "setup_environment" "update_system_packages" "install_python_dependencies" "install_node_dependencies" "setup_desktop_environment" "setup_systemd_services" "configure_firewall" "setup_autostart" "test_installation" ) local total_steps=${#steps[@]} local current_step=0 for step in "${steps[@]}"; do current_step=$((current_step + 1)) log "INFO" "Schritt $current_step/$total_steps: $step" if ! $step; then log "ERROR" "Fehler bei Schritt $step" return 1 fi log "INFO" "Schritt $current_step/$total_steps abgeschlossen" done log "INFO" "Vollinstallation erfolgreich abgeschlossen!" show_completion_info } upgrade_installation() { log "INFO" "Starte Upgrade bestehender Installation..." if [[ ! -d "$INSTALL_PATH" ]]; then log "ERROR" "Keine bestehende Installation gefunden in $INSTALL_PATH" return 1 fi # Backup erstellen create_backup # Upgrade-Schritte update_system_packages install_python_dependencies install_node_dependencies update_project_files restart_services test_installation log "INFO" "Upgrade erfolgreich abgeschlossen!" } component_installation() { echo "Einzelne Komponenten:" echo "1) Umgebung einrichten" echo "2) System-Packages aktualisieren" echo "3) Python-Abhängigkeiten installieren" echo "4) Node.js-Abhängigkeiten installieren" echo "5) Desktop-Environment einrichten" echo "6) Systemd-Services einrichten" echo "7) Firewall konfigurieren" echo "8) Tests durchführen" echo "0) Zurück" read -p "Komponente auswählen: " choice case $choice in 1) setup_environment ;; 2) update_system_packages ;; 3) install_python_dependencies ;; 4) install_node_dependencies ;; 5) setup_desktop_environment ;; 6) setup_systemd_services ;; 7) configure_firewall ;; 8) test_installation ;; 0) return ;; *) log "ERROR" "Ungültige Auswahl" ;; esac } show_system_info() { echo "=== SYSTEM-INFORMATION ===" echo "Betriebssystem: $(lsb_release -d | cut -f2)" echo "Kernel: $(uname -r)" echo "Architektur: $(uname -m)" echo "Verfügbarer Speicher: $(free -h | awk 'NR==2{print $7}')" echo "Festplattenspeicher: $(df -h / | awk 'NR==2{print $4}')" echo if [[ -d "$INSTALL_PATH" ]]; then echo "=== MYP-INSTALLATION ===" echo "Installationspfad: $INSTALL_PATH" echo "Status: $(systemctl is-active $SERVICE_NAME 2>/dev/null || echo 'Nicht installiert')" echo "Version: $(cat $INSTALL_PATH/VERSION 2>/dev/null || echo 'Unbekannt')" echo fi echo "=== NETZWERK ===" echo "IP-Adresse: $(hostname -I | awk '{print $1}')" echo "Hostname: $(hostname)" echo } uninstall_system() { log "WARN" "WARNUNG: Dies wird das gesamte MYP-System entfernen!" if ! confirm_action "Sind Sie sicher, dass Sie das System deinstallieren möchten?"; then return 1 fi if ! confirm_action "LETZTE WARNUNG: Alle Daten gehen verloren! Fortfahren?"; then return 1 fi log "INFO" "Starte Deinstallation..." # Services stoppen und entfernen systemctl stop "$SERVICE_NAME" 2>/dev/null || true systemctl stop "$KIOSK_SERVICE" 2>/dev/null || true systemctl disable "$SERVICE_NAME" 2>/dev/null || true systemctl disable "$KIOSK_SERVICE" 2>/dev/null || true # Service-Dateien entfernen rm -f "/etc/systemd/system/${SERVICE_NAME}.service" rm -f "/etc/systemd/system/${KIOSK_SERVICE}.service" systemctl daemon-reload # Benutzer entfernen if id "$PROJECT_USER" &>/dev/null; then userdel -r "$PROJECT_USER" 2>/dev/null || true fi # Installationsverzeichnis entfernen rm -rf "$INSTALL_PATH" # Desktop-Konfiguration entfernen rm -rf "/home/$PROJECT_USER" log "INFO" "Deinstallation abgeschlossen" } show_completion_info() { echo echo "==================================================================================" echo " INSTALLATION ABGESCHLOSSEN" echo "==================================================================================" echo echo "Das MYP-System wurde erfolgreich installiert und konfiguriert." echo echo "Wichtige Informationen:" echo echo "• System-URL: https://$(hostname -I | awk '{print $1}')" echo "• Installationspfad: $INSTALL_PATH" echo "• Service: $SERVICE_NAME" echo "• Benutzer: $PROJECT_USER" echo "• Log-Datei: $LOG_FILE" echo echo "Nächste Schritte:" echo "1. System neu starten: sudo reboot" echo "2. Nach Neustart automatischer Kiosk-Modus" echo "3. Admin-Zugang über: https://IP-ADRESSE/admin" echo echo "Bei Problemen:" echo "• Logs prüfen: sudo journalctl -u $SERVICE_NAME -f" echo "• Service-Status: sudo systemctl status $SERVICE_NAME" echo "• Installer-Log: sudo cat $LOG_FILE" echo echo "==================================================================================" } create_backup() { if [[ -d "$INSTALL_PATH" ]]; then local backup_dir="/opt/myp-backup-$(date +%Y%m%d-%H%M%S)" log "INFO" "Erstelle Backup in $backup_dir" cp -r "$INSTALL_PATH" "$backup_dir" log "INFO" "Backup erstellt: $backup_dir" fi } # === HAUPTPROGRAMM === main() { # Log-Datei initialisieren touch "$LOG_FILE" chmod 644 "$LOG_FILE" log "INFO" "MYP AIO-Installer gestartet" # Root-Rechte prüfen check_root # System prüfen check_system # Banner anzeigen show_banner # Hauptmenü while true; do show_menu read -p "Option auswählen: " choice case $choice in 1) full_installation ;; 2) upgrade_installation ;; 3) test_installation ;; 4) component_installation ;; 5) show_system_info ;; 6) uninstall_system ;; 0) log "INFO" "Installation beendet" exit 0 ;; *) log "ERROR" "Ungültige Auswahl: $choice" ;; esac echo read -p "Drücken Sie Enter zum Fortfahren..." clear show_banner done } # Kommandozeilen-Argumente verarbeiten while [[ $# -gt 0 ]]; do case $1 in --full) FORCE_YES="true" full_installation exit $? ;; --upgrade) FORCE_YES="true" upgrade_installation exit $? ;; --test) test_installation exit $? ;; --uninstall) uninstall_system exit $? ;; --skip-internet-check) log "WARN" "Internet-Check wird übersprungen" export SKIP_INTERNET_CHECK="true" ;; --vm-mode) log "INFO" "VM-Modus aktiviert (erweiterte Timeouts)" export VM_MODE="true" ;; --force-offline) log "WARN" "Offline-Modus erzwungen" export FORCE_OFFLINE="true" ;; --network-debug) log "INFO" "Netzwerk-Debug-Modus aktiviert" export NETWORK_DEBUG="true" ;; --help|-h) echo "MYP AIO-Installer" echo "Verwendung: $0 [OPTION]" echo echo "Optionen:" echo " --full Vollinstallation ohne Bestätigung" echo " --upgrade Upgrade bestehender Installation" echo " --test Nur Tests durchführen" echo " --uninstall System deinstallieren" echo " --skip-internet-check Internet-Verbindungsprüfung überspringen" echo " --vm-mode VM-Modus (erweiterte Timeouts)" echo " --force-offline Offline-Installation erzwingen" echo " --network-debug Detaillierte Netzwerk-Diagnose" echo " --help, -h Diese Hilfe anzeigen" echo echo "VM-spezifische Optionen:" echo " Für VMs empfohlene Verwendung:" echo " $0 --vm-mode --full" echo " $0 --force-offline --full (bei Netzwerk-Problemen)" echo exit 0 ;; *) log "ERROR" "Unbekannte Option: $1" exit 1 ;; esac shift done # Hauptprogramm ausführen wenn keine Kommandozeilen-Argumente main exit 0