#!/bin/bash # MYP Backend Installations-Skript # Dieses Skript installiert das Backend mit Docker und Host-Netzwerkanbindung # Farbcodes für Ausgabe RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Funktion zur Ausgabe mit Zeitstempel log() { echo -e "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1" } error_log() { echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] FEHLER:${NC} $1" >&2 } # Funktion zum Bereinigen vorhandener Installationen cleanup_existing_installation() { log "${YELLOW}Bereinige vorhandene Installation...${NC}" # Stoppe und entferne existierende Container if docker ps -a | grep -q "myp-backend"; then log "Stoppe und entferne existierenden Backend-Container..." docker stop myp-backend &>/dev/null || true docker rm myp-backend &>/dev/null || true fi # Entferne Docker Images if docker images | grep -q "myp-backend"; then log "Entferne existierendes Backend-Image..." docker rmi myp-backend &>/dev/null || true fi log "${GREEN}Bereinigung abgeschlossen.${NC}" } # Pfade definieren SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" BACKEND_DIR="$SCRIPT_DIR/backend" # Prüfen ob Verzeichnis existiert if [ ! -d "$BACKEND_DIR" ]; then error_log "Backend-Verzeichnis '$BACKEND_DIR' nicht gefunden." exit 1 fi # Bereinige existierende Installation cleanup_existing_installation # Funktion zur Installation von Docker und Docker Compose für Raspberry Pi install_docker() { log "${YELLOW}Docker ist nicht installiert. Installation wird gestartet...${NC}" # Erkenne Raspberry Pi if [ -f /proc/device-tree/model ] && grep -q "Raspberry Pi" /proc/device-tree/model; then log "${GREEN}Raspberry Pi erkannt. Installiere Docker für ARM-Architektur...${NC}" IS_RASPBERRY_PI=true else IS_RASPBERRY_PI=false fi # Aktualisiere Paketindex if ! sudo apt-get update; then error_log "Konnte Paketindex nicht aktualisieren. Bitte manuell installieren." exit 1 fi # Installiere erforderliche Pakete if ! sudo apt-get install -y apt-transport-https ca-certificates curl gnupg software-properties-common; then error_log "Konnte erforderliche Pakete nicht installieren. Bitte manuell installieren." exit 1 fi # Raspberry Pi-spezifische Installation if [ "$IS_RASPBERRY_PI" = true ]; then # Setze Systemarchitektur für Raspberry Pi (armhf oder arm64) ARCH=$(dpkg --print-architecture) log "Erkannte Systemarchitektur: ${ARCH}" # Installiere Docker mit convenience script (für Raspberry Pi empfohlen) log "${YELLOW}Installiere Docker mit dem convenience script...${NC}" curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh if [ $? -ne 0 ]; then error_log "Docker-Installation fehlgeschlagen. Bitte manuell installieren." exit 1 fi else # Standard-Installation für andere Systeme # Füge Docker's offiziellen GPG-Schlüssel hinzu curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - # Füge Docker-Repository hinzu if ! sudo add-apt-repository "deb [arch=$(dpkg --print-architecture)] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"; then error_log "Konnte Docker-Repository nicht hinzufügen. Prüfen Sie, ob Ihr System unterstützt wird." exit 1 fi # Aktualisiere Paketindex erneut sudo apt-get update # Installiere Docker if ! sudo apt-get install -y docker-ce docker-ce-cli containerd.io; then error_log "Konnte Docker nicht installieren. Bitte manuell installieren." exit 1 fi fi # Füge aktuellen Benutzer zur Docker-Gruppe hinzu sudo usermod -aG docker "$USER" log "${GREEN}Docker wurde installiert.${NC}" log "${YELLOW}WICHTIG: Möglicherweise müssen Sie sich neu anmelden, damit die Gruppenänderung wirksam wird.${NC}" # Prüfen, ob Docker Compose v2 Plugin verfügbar ist (bevorzugt, da moderner) log "${YELLOW}Prüfe Docker Compose Version...${NC}" if docker compose version &> /dev/null; then log "${GREEN}Docker Compose v2 Plugin ist bereits installiert.${NC}" DOCKER_COMPOSE_V2=true else log "${YELLOW}Docker Compose v2 Plugin nicht gefunden. Versuche Docker Compose v1 zu installieren...${NC}" DOCKER_COMPOSE_V2=false if [ "$IS_RASPBERRY_PI" = true ]; then # Für Raspberry Pi ist es besser, die richtige Architektur zu verwenden if [ "$ARCH" = "armhf" ]; then log "Installiere Docker Compose für armhf (32-bit)..." sudo curl -L "https://github.com/docker/compose/releases/download/v2.6.1/docker-compose-linux-armv7" -o /usr/local/bin/docker-compose elif [ "$ARCH" = "arm64" ]; then log "Installiere Docker Compose für arm64 (64-bit)..." sudo curl -L "https://github.com/docker/compose/releases/download/v2.6.1/docker-compose-linux-aarch64" -o /usr/local/bin/docker-compose else # Fallback auf v1.29.2 für unbekannte ARM-Architekturen log "Verwende automatische Architekturerkennung für Docker Compose v1.29.2..." sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose fi else # Für andere Systeme versuche zuerst v2, dann v1.29.2 als Fallback log "Installiere Docker Compose v2 für $(uname -s)/$(uname -m)..." if ! sudo curl -L "https://github.com/docker/compose/releases/download/v2.6.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose; then log "${YELLOW}Konnte Docker Compose v2 nicht herunterladen. Versuche v1.29.2...${NC}" sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose fi fi if [ $? -ne 0 ]; then error_log "Konnte Docker Compose nicht herunterladen. Bitte manuell installieren." exit 1 fi sudo chmod +x /usr/local/bin/docker-compose log "${GREEN}Docker Compose wurde installiert.${NC}" fi # Starte Docker-Dienst if command -v systemctl &> /dev/null; then sudo systemctl enable docker sudo systemctl start docker elif command -v service &> /dev/null; then sudo service docker enable sudo service docker start fi } # Prüfen ob Docker installiert ist if ! command -v docker &> /dev/null; then log "${YELLOW}Docker ist nicht installiert.${NC}" read -p "Möchten Sie Docker installieren? (j/n): " install_docker_choice if [[ "$install_docker_choice" == "j" ]]; then install_docker else error_log "Docker wird für die Installation benötigt. Bitte installieren Sie Docker manuell." log "Siehe: https://docs.docker.com/get-docker/" exit 1 fi fi # Prüfen ob Docker Daemon läuft if ! docker info &> /dev/null; then log "${YELLOW}Docker-Daemon läuft nicht. Versuche, den Dienst zu starten...${NC}" # Versuche, Docker zu starten if command -v systemctl &> /dev/null; then sudo systemctl start docker elif command -v service &> /dev/null; then sudo service docker start else error_log "Konnte Docker-Daemon nicht starten. Bitte starten Sie den Docker-Dienst manuell." log "Starten mit: sudo systemctl start docker oder sudo service docker start" exit 1 fi # Prüfe erneut, ob Docker läuft if ! docker info &> /dev/null; then error_log "Docker-Daemon konnte nicht gestartet werden. Bitte starten Sie den Docker-Dienst manuell." exit 1 fi log "${GREEN}Docker-Daemon wurde erfolgreich gestartet.${NC}" fi # Prüfen ob Docker Compose installiert ist if docker compose version &> /dev/null; then log "${GREEN}Docker Compose v2 Plugin ist bereits installiert.${NC}" DOCKER_COMPOSE_V2=true elif command -v docker-compose &> /dev/null; then log "${GREEN}Docker Compose v1 ist bereits installiert.${NC}" DOCKER_COMPOSE_V2=false else log "${YELLOW}Docker Compose ist nicht installiert.${NC}" DOCKER_COMPOSE_V2=false read -p "Möchten Sie Docker Compose installieren? (j/n): " install_compose_choice if [[ "$install_compose_choice" == "j" ]]; then log "${YELLOW}Installiere Docker Compose...${NC}" # Prüfe ob das Betriebssystem ARM-basiert ist (z.B. Raspberry Pi) if grep -q "arm" /proc/cpuinfo 2> /dev/null; then ARCH=$(dpkg --print-architecture 2> /dev/null || echo "unknown") IS_RASPBERRY_PI=true else IS_RASPBERRY_PI=false fi # Versuche zuerst Docker Compose v2 zu installieren if [ "$IS_RASPBERRY_PI" = true ]; then if [ "$ARCH" = "armhf" ]; then log "Installiere Docker Compose für armhf (32-bit)..." sudo curl -L "https://github.com/docker/compose/releases/download/v2.6.1/docker-compose-linux-armv7" -o /usr/local/bin/docker-compose elif [ "$ARCH" = "arm64" ]; then log "Installiere Docker Compose für arm64 (64-bit)..." sudo curl -L "https://github.com/docker/compose/releases/download/v2.6.1/docker-compose-linux-aarch64" -o /usr/local/bin/docker-compose else log "Verwende automatische Architekturerkennung für Docker Compose v1.29.2..." sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose fi else log "Installiere Docker Compose v2 für $(uname -s)/$(uname -m)..." if ! sudo curl -L "https://github.com/docker/compose/releases/download/v2.6.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose; then log "${YELLOW}Konnte Docker Compose v2 nicht herunterladen. Versuche v1.29.2...${NC}" sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose fi fi if [ $? -ne 0 ]; then error_log "Konnte Docker Compose nicht herunterladen. Bitte manuell installieren." exit 1 fi sudo chmod +x /usr/local/bin/docker-compose log "${GREEN}Docker Compose wurde installiert.${NC}" else error_log "Docker Compose wird für die Installation benötigt. Bitte installieren Sie es manuell." log "Siehe: https://docs.docker.com/compose/install/" exit 1 fi fi # Prüfen ob wget installiert ist (wird für healthcheck verwendet) if ! command -v wget &> /dev/null; then error_log "wget ist nicht installiert, wird aber für den Container-Healthcheck benötigt." log "Installation mit: sudo apt-get install wget" exit 1 fi # Wechsle ins Backend-Verzeichnis log "Wechsle ins Verzeichnis: $BACKEND_DIR" cd "$BACKEND_DIR" || { error_log "Konnte nicht ins Verzeichnis $BACKEND_DIR wechseln." exit 1 } # Prüfe ob Dockerfile existiert if [ ! -f "Dockerfile" ]; then error_log "Dockerfile nicht gefunden in $BACKEND_DIR." exit 1 fi # Prüfe ob docker-compose.yml existiert if [ ! -f "docker-compose.yml" ]; then error_log "docker-compose.yml nicht gefunden in $BACKEND_DIR." exit 1 fi # Erstelle .env-Datei log "${YELLOW}Erstelle .env Datei...${NC}" cat > .env << EOL SECRET_KEY=7445630171969DFAC92C53CEC92E67A9CB2E00B3CB2F DATABASE_PATH=instance/myp.db TAPO_USERNAME=till.tomczak@mercedes-benz.com TAPO_PASSWORD=744563017196A PRINTERS={"Printer 1": {"ip": "192.168.0.100"}, "Printer 2": {"ip": "192.168.0.101"}, "Printer 3": {"ip": "192.168.0.102"}, "Printer 4": {"ip": "192.168.0.103"}, "Printer 5": {"ip": "192.168.0.104"}, "Printer 6": {"ip": "192.168.0.106"}} EOL if [ ! -f ".env" ]; then error_log "Konnte .env-Datei nicht erstellen. Prüfen Sie die Berechtigungen." exit 1 fi log "${GREEN}.env Datei erfolgreich erstellt${NC}" # Verzeichnisse erstellen log "Erstelle benötigte Verzeichnisse" if ! mkdir -p logs; then error_log "Konnte Verzeichnis 'logs' nicht erstellen. Prüfen Sie die Berechtigungen." exit 1 fi if ! mkdir -p instance; then error_log "Konnte Verzeichnis 'instance' nicht erstellen. Prüfen Sie die Berechtigungen." exit 1 fi # Docker-Image bauen und starten log "${YELLOW}Baue und starte Backend-Container...${NC}" log "${YELLOW}Dies kann auf einem Raspberry Pi einige Minuten dauern - bitte geduldig sein${NC}" # Prüfe, ob Docker-Daemon läuft if ! docker info &>/dev/null; then log "${YELLOW}Docker-Daemon scheint nicht zu laufen. Versuche zu starten...${NC}" # Versuche Docker zu starten if command -v systemctl &>/dev/null; then sudo systemctl start docker || true sleep 5 elif command -v service &>/dev/null; then sudo service docker start || true sleep 5 fi # Prüfe erneut, ob Docker jetzt läuft if ! docker info &>/dev/null; then error_log "Docker-Daemon konnte nicht gestartet werden." log "Führen Sie vor der Installation bitte folgende Befehle aus:" log " sudo systemctl start docker" log " sudo systemctl enable docker" log "Starten Sie dann das Installationsskript erneut." exit 1 fi fi # Docker-Rechte prüfen if ! docker ps &>/dev/null; then error_log "Sie haben keine Berechtigung, Docker ohne sudo zu verwenden." log "Bitte führen Sie folgenden Befehl aus und melden Sie sich danach neu an:" log " sudo usermod -aG docker $USER" exit 1 fi # Prüfen, ob erforderliche Basis-Images lokal verfügbar sind if ! docker image inspect python:3-slim &>/dev/null; then log "${YELLOW}Prüfe und setze DNS-Server für Docker...${NC}" # DNS-Einstellungen prüfen und anpassen if [ -f /etc/docker/daemon.json ]; then log "Bestehende Docker-Konfiguration gefunden." else log "Erstelle Docker-Konfiguration mit Google DNS..." sudo mkdir -p /etc/docker echo '{ "dns": ["8.8.8.8", "8.8.4.4"] }' | sudo tee /etc/docker/daemon.json > /dev/null # Docker neu starten, damit die Änderungen wirksam werden if command -v systemctl &>/dev/null; then sudo systemctl restart docker sleep 5 elif command -v service &>/dev/null; then sudo service docker restart sleep 5 fi fi # Versuche Image explizit mit anderen Tags herunterzuladen log "${YELLOW}Versuche lokal vorhandene Python-Version zu finden...${NC}" # Suche nach allen verfügbaren Python-Images PYTHON_IMAGES=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep "python:") if [ -n "$PYTHON_IMAGES" ]; then log "Gefundene Python-Images: $PYTHON_IMAGES" # Verwende das erste gefundene Python-Image FIRST_PYTHON=$(echo "$PYTHON_IMAGES" | head -n 1) log "${GREEN}Verwende vorhandenes Python-Image: $FIRST_PYTHON${NC}" # Aktualisiere den Dockerfile sed -i "s|FROM python:3-slim|FROM $FIRST_PYTHON|g" Dockerfile log "Dockerfile aktualisiert, um lokales Image zu verwenden." else # Versuche unterschiedliche Python-Versionen for PYTHON_VERSION in "python:3.11-slim" "python:3.10-slim" "python:3.9-slim" "python:slim" "python:alpine"; do log "Versuche $PYTHON_VERSION zu laden..." if docker pull $PYTHON_VERSION; then log "${GREEN}Erfolgreich $PYTHON_VERSION heruntergeladen${NC}" # Aktualisiere den Dockerfile sed -i "s|FROM python:3-slim|FROM $PYTHON_VERSION|g" Dockerfile log "Dockerfile aktualisiert, um $PYTHON_VERSION zu verwenden." break fi done fi fi # Erhöhe Docker-Timeout für langsame Verbindungen und Raspberry Pi export DOCKER_CLIENT_TIMEOUT=300 export COMPOSE_HTTP_TIMEOUT=300 # Verwende die richtige Docker Compose Version if [ "${DOCKER_COMPOSE_V2:-false}" = true ]; then # Docker Compose V2 Plugin (docker compose) log "Baue lokales Image..." if ! docker compose build --no-cache; then error_log "Docker Compose Build (v2) fehlgeschlagen. Versuche mit v1 Format..." if ! docker-compose build --no-cache; then error_log "Docker Compose Build fehlgeschlagen. Siehe Fehlermeldung oben." exit 1 fi fi log "Starte Container aus lokalem Image..." if ! docker compose up -d; then error_log "Docker Compose Up (v2) fehlgeschlagen. Versuche mit v1 Format..." if ! docker-compose up -d; then error_log "Docker Compose Up fehlgeschlagen. Siehe Fehlermeldung oben." exit 1 fi fi else # Docker Compose V1 (docker-compose) log "Baue lokales Image..." if ! docker-compose build --no-cache; then error_log "Docker Compose Build fehlgeschlagen. Siehe Fehlermeldung oben." exit 1 fi log "Starte Container aus lokalem Image..." if ! docker-compose up -d; then error_log "Docker Compose Up fehlgeschlagen. Siehe Fehlermeldung oben." exit 1 fi fi # Prüfe, ob der Container läuft log "Warte 10 Sekunden, bis der Container gestartet ist..." sleep 10 if docker ps | grep -q "myp-backend"; then log "${GREEN}Backend-Container läuft${NC}" else error_log "Backend-Container läuft nicht. Container-Status:" docker ps -a | grep myp-backend log "Container-Logs:" docker logs myp-backend exit 1 fi # Test API-Endpunkt log "${YELLOW}Teste Backend-API...${NC}" log "${YELLOW}HINWEIS: Der API-Server ist bei der ersten Installation oft noch nicht erreichbar${NC}" log "${YELLOW}Dies ist ein bekanntes Verhalten wegen der Netzwerkkonfiguration${NC}" log "${YELLOW}Bitte nach der Installation das System neu starten, danach sollte der API-Server erreichbar sein${NC}" # Wir versuchen es trotzdem einmal, um zu sehen, ob er vielleicht doch läuft if curl -s http://localhost:5000/health 2>/dev/null | grep -q "healthy"; then log "${GREEN}Backend-API ist erreichbar und funktioniert${NC}" else log "${YELLOW}Backend-API ist wie erwartet noch nicht erreichbar${NC}" log "${GREEN}Das ist völlig normal bei der Erstinstallation${NC}" log "${GREEN}Nach einem Neustart des Systems sollte der API-Server korrekt erreichbar sein${NC}" log "Container-Status prüfen mit: docker logs myp-backend" fi # Initialisierung der Datenbank prüfen log "${YELLOW}Prüfe Datenbank-Initialisierung...${NC}" if [ ! -s "instance/myp.db" ]; then log "${YELLOW}Datenbank scheint leer zu sein. Führe Initialisierungsskript aus...${NC}" DB_INIT_OUTPUT=$(docker exec myp-backend python -c "from app import init_db; init_db()" 2>&1) if [ $? -eq 0 ]; then log "${GREEN}Datenbank erfolgreich initialisiert${NC}" else error_log "Fehler bei der Datenbank-Initialisierung:" echo "$DB_INIT_OUTPUT" log "Container-Logs:" docker logs myp-backend fi else log "${GREEN}Datenbank existiert bereits${NC}" fi # Teste, ob ein API-Endpunkt Daten zurückgibt log "${YELLOW}Teste Datenbank-Verbindung über API...${NC}" if curl -s http://localhost:5000/api/printers | grep -q "\[\]"; then log "${GREEN}Datenbank-Verbindung funktioniert${NC}" else log "${YELLOW}API gibt keine leere Drucker-Liste zurück. Möglicherweise ist die DB nicht korrekt initialisiert.${NC}" log "API-Antwort:" curl -s http://localhost:5000/api/printers fi log "${GREEN}=== Installation abgeschlossen ===${NC}" log "${YELLOW}WICHTIG: Nach der Erstinstallation ist ein Systemneustart erforderlich${NC}" log "${YELLOW}Danach ist das Backend unter http://localhost:5000 erreichbar${NC}" log "Anzeigen der Logs: docker logs -f myp-backend" # Verwende die richtige Docker Compose Version für Hinweis if [ "${DOCKER_COMPOSE_V2:-false}" = true ]; then log "Backend stoppen: docker compose -f $BACKEND_DIR/docker-compose.yml down" else log "Backend stoppen: docker-compose -f $BACKEND_DIR/docker-compose.yml down" fi