From a9a1bf52db1d25c30ccf4bd475d79eff70aeadf7 Mon Sep 17 00:00:00 2001 From: Till Tomczak Date: Tue, 1 Apr 2025 13:47:23 +0200 Subject: [PATCH] =?UTF-8?q?F=C3=BCge=20umfassendes=20Frontend-Deployment-S?= =?UTF-8?q?kript=20hinzu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Erstellt ein interaktives Skript mit mehreren Deployment-Optionen - Konfiguriert Backend-URL für Kommunikation mit 192.168.0.105:5000 - Bietet vollautomatischen Deployment-Workflow und manuelle Schritte - Funktionen: Image bauen, speichern, laden, Containers starten - Unterstützt Docker Compose, direktes Docker und direkte Ausführung - Intelligente Fehlerbehandlung und Integritätsprüfungen 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- raspi-frontend-deploy.sh | 487 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 487 insertions(+) create mode 100755 raspi-frontend-deploy.sh diff --git a/raspi-frontend-deploy.sh b/raspi-frontend-deploy.sh new file mode 100755 index 0000000..36099cf --- /dev/null +++ b/raspi-frontend-deploy.sh @@ -0,0 +1,487 @@ +#!/bin/bash + +# Frontend-Deployment-Skript für MYP-Projekt +# Bietet verschiedene Möglichkeiten, das Frontend zu deployen + +# Farbcodes für Ausgabe +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +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 +} + +success_log() { + echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] ERFOLG:${NC} $1" +} + +header() { + echo "" + echo -e "${CYAN}===== $1 =====${NC}" + echo "" +} + +# Variablen definieren +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +FRONTEND_DIR="$SCRIPT_DIR/packages/reservation-platform" +DOCKER_DIR="$FRONTEND_DIR/docker" +DEFAULT_BACKEND_URL="http://192.168.0.105:5000" +IMAGE_NAME="myp-rp:latest" +CONTAINER_NAME="myp-rp" +DB_VOLUME_DIR="/srv/MYP-DB" + +# Prüfen, ob wir im Root des Projektverzeichnisses sind +if [ ! -d "packages/reservation-platform" ]; then + error_log "Dieses Skript muss im Root-Verzeichnis des MYP-Projekts ausgeführt werden." + error_log "Bitte wechseln Sie in das Verzeichnis, das die 'packages/reservation-platform' enthält." + exit 1 +fi + +# Prüfen, ob Docker installiert ist +if ! command -v docker &> /dev/null; then + error_log "Docker ist nicht installiert. Bitte installieren Sie Docker zuerst." + exit 1 +fi + +# Prüfen, ob Docker läuft +if ! docker info &> /dev/null; then + error_log "Docker-Daemon läuft nicht. Bitte starten Sie Docker mit 'sudo systemctl start docker'." + exit 1 +fi + +# Prüfen, ob der Benutzer in der Docker-Gruppe ist +if ! groups | grep -q '\bdocker\b'; then + error_log "Aktueller Benutzer hat keine Docker-Berechtigungen." + error_log "Bitte führen Sie das Skript mit 'sudo' aus oder fügen Sie den Benutzer zur Docker-Gruppe hinzu:" + error_log "sudo usermod -aG docker $USER && newgrp docker" + exit 1 +fi + +# Erstelle Datenbank-Verzeichnis, falls nicht vorhanden +if [ ! -d "$DB_VOLUME_DIR" ]; then + log "Erstelle Datenbankverzeichnis: $DB_VOLUME_DIR" + if ! mkdir -p "$DB_VOLUME_DIR"; then + if ! sudo mkdir -p "$DB_VOLUME_DIR"; then + error_log "Konnte Datenbankverzeichnis nicht erstellen. Bitte erstellen Sie es manuell:" + error_log "sudo mkdir -p $DB_VOLUME_DIR && sudo chown $USER:$USER $DB_VOLUME_DIR" + exit 1 + fi + sudo chown $USER:$USER "$DB_VOLUME_DIR" + fi +else + log "Datenbankverzeichnis existiert bereits: $DB_VOLUME_DIR" +fi + +# Funktion zum Konfigurieren der Backend-URL +configure_backend_url() { + local backend_url="${1:-$DEFAULT_BACKEND_URL}" + + header "Backend-URL konfigurieren" + log "Konfiguriere Backend-URL für Frontend: $backend_url" + + # Prüfen, ob setup-backend-url.sh existiert + if [ -f "$FRONTEND_DIR/setup-backend-url.sh" ]; then + chmod +x "$FRONTEND_DIR/setup-backend-url.sh" + if ! "$FRONTEND_DIR/setup-backend-url.sh" "$backend_url"; then + error_log "Fehler beim Konfigurieren der Backend-URL." + return 1 + fi + else + # Erstelle .env.local-Datei manuell + log "Erstelle .env.local-Datei manuell..." + cat > "$FRONTEND_DIR/.env.local" << EOL +# Backend API Konfiguration +NEXT_PUBLIC_API_URL=${backend_url} + +# OAuth Konfiguration (falls nötig) +OAUTH_CLIENT_ID=client_id +OAUTH_CLIENT_SECRET=client_secret +EOL + + if [ ! -f "$FRONTEND_DIR/.env.local" ]; then + error_log "Konnte .env.local-Datei nicht erstellen." + return 1 + fi + + chmod 600 "$FRONTEND_DIR/.env.local" + fi + + success_log "Backend-URL erfolgreich konfiguriert: $backend_url" + return 0 +} + +# Funktion zum Bauen des Images +build_image() { + header "Docker-Image bauen" + log "Baue Docker-Image: $IMAGE_NAME" + + if [ ! -f "$FRONTEND_DIR/Dockerfile" ]; then + error_log "Dockerfile nicht gefunden in $FRONTEND_DIR" + return 1 + fi + + cd "$FRONTEND_DIR" || return 1 + + # Vorhandenes Image entfernen, falls gewünscht + if docker image inspect "$IMAGE_NAME" &>/dev/null; then + log "Image $IMAGE_NAME existiert bereits." + read -p "Möchten Sie das existierende Image überschreiben? (j/n): " rebuild_choice + if [[ "$rebuild_choice" == "j" ]]; then + log "Entferne existierendes Image..." + docker rmi "$IMAGE_NAME" &>/dev/null || true + else + log "Behalte existierendes Image." + return 0 + fi + fi + + # Baue das Image + log "${YELLOW}Baue Docker-Image... (Dies kann auf einem Raspberry Pi mehrere Minuten dauern)${NC}" + if ! docker build -t "$IMAGE_NAME" .; then + error_log "Fehler beim Bauen des Docker-Images." + return 1 + fi + + success_log "Docker-Image erfolgreich gebaut: $IMAGE_NAME" + return 0 +} + +# Funktion zum Speichern des Images +save_image() { + header "Docker-Image speichern" + local save_dir="${1:-$DOCKER_DIR/images}" + local save_file="$save_dir/myp-frontend.tar" + + # Prüfen, ob das Image existiert + if ! docker image inspect "$IMAGE_NAME" &>/dev/null; then + error_log "Image $IMAGE_NAME existiert nicht. Bitte bauen Sie es zuerst." + return 1 + fi + + # Verzeichnis erstellen, falls es nicht existiert + mkdir -p "$save_dir" + + log "Speichere Docker-Image in: $save_file" + log "${YELLOW}Dies kann einige Minuten dauern...${NC}" + + if ! docker save -o "$save_file" "$IMAGE_NAME"; then + error_log "Fehler beim Speichern des Docker-Images." + return 1 + fi + + # Prüfe, ob die Datei erstellt wurde + if [ ! -f "$save_file" ]; then + error_log "Konnte Docker-Image nicht speichern." + return 1 + fi + + # Prüfe Dateigröße + local filesize=$(stat -c%s "$save_file") + if [ "$filesize" -lt 1000000 ]; then # Kleiner als 1MB ist verdächtig + error_log "Gespeichertes Image ist ungewöhnlich klein ($filesize Bytes). Möglicherweise ist etwas schief gelaufen." + return 1 + fi + + success_log "Docker-Image erfolgreich gespeichert: $save_file (Größe: $(du -h "$save_file" | cut -f1))" + return 0 +} + +# Funktion zum Laden des Images +load_image() { + header "Docker-Image laden" + local load_dir="${1:-$DOCKER_DIR/images}" + local load_file="$load_dir/myp-frontend.tar" + + # Prüfen, ob die Datei existiert + if [ ! -f "$load_file" ]; then + error_log "Image-Datei nicht gefunden: $load_file" + return 1 + fi + + # Prüfe Dateigröße + local filesize=$(stat -c%s "$load_file") + if [ "$filesize" -lt 1000000 ]; then # Kleiner als 1MB ist verdächtig + error_log "Image-Datei ist ungewöhnlich klein ($filesize Bytes). Möglicherweise ist sie beschädigt." + return 1 + fi + + log "Lade Docker-Image aus: $load_file" + log "${YELLOW}Dies kann einige Minuten dauern...${NC}" + + if ! docker load -i "$load_file"; then + error_log "Fehler beim Laden des Docker-Images. Die Datei könnte beschädigt sein." + return 1 + fi + + success_log "Docker-Image erfolgreich geladen." + return 0 +} + +# Funktion zum Starten des Containers mit Docker Compose +start_container_compose() { + header "Container mit Docker Compose starten" + + # Erstellen der vereinfachten docker-compose.yml-Datei + local compose_file="$DOCKER_DIR/compose.simple.yml" + + log "Erstelle vereinfachte Docker-Compose-Datei: $compose_file" + cat > "$compose_file" << EOL +services: + myp-rp: + image: ${IMAGE_NAME} + container_name: ${CONTAINER_NAME} + environment: + - NEXT_PUBLIC_API_URL=${BACKEND_URL} + - OAUTH_CLIENT_ID=client_id + - OAUTH_CLIENT_SECRET=client_secret + ports: + - "3000:3000" + volumes: + - ${DB_VOLUME_DIR}:/app/db + restart: unless-stopped + healthcheck: + test: ["CMD", "wget", "--spider", "http://localhost:3000"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s +EOL + + # Prüfen, ob die Datei erstellt wurde + if [ ! -f "$compose_file" ]; then + error_log "Konnte Docker-Compose-Datei nicht erstellen." + return 1 + fi + + # Stoppen des vorhandenen Containers + if docker ps -a | grep -q "$CONTAINER_NAME"; then + log "Stoppe und entferne existierenden Container..." + docker stop "$CONTAINER_NAME" &>/dev/null || true + docker rm "$CONTAINER_NAME" &>/dev/null || true + fi + + # Container starten + log "Starte Container..." + cd "$DOCKER_DIR" || return 1 + + if ! docker compose -f "$(basename "$compose_file")" up -d; then + # Versuche mit docker-compose, falls docker compose nicht funktioniert + if ! docker-compose -f "$(basename "$compose_file")" up -d; then + error_log "Fehler beim Starten des Containers." + return 1 + fi + fi + + success_log "Container erfolgreich gestartet: $CONTAINER_NAME" + return 0 +} + +# Funktion zum Starten des Containers mit Docker Run +start_container_run() { + header "Container direkt starten" + + # Stoppen des vorhandenen Containers + if docker ps -a | grep -q "$CONTAINER_NAME"; then + log "Stoppe und entferne existierenden Container..." + docker stop "$CONTAINER_NAME" &>/dev/null || true + docker rm "$CONTAINER_NAME" &>/dev/null || true + fi + + # Container starten + log "Starte Container mit 'docker run'..." + + if ! docker run -d --name "$CONTAINER_NAME" \ + -p 3000:3000 \ + -e "NEXT_PUBLIC_API_URL=$BACKEND_URL" \ + -e "OAUTH_CLIENT_ID=client_id" \ + -e "OAUTH_CLIENT_SECRET=client_secret" \ + -v "$DB_VOLUME_DIR:/app/db" \ + --restart unless-stopped \ + "$IMAGE_NAME"; then + error_log "Fehler beim Starten des Containers." + return 1 + fi + + success_log "Container erfolgreich gestartet: $CONTAINER_NAME" + return 0 +} + +# Funktion zum Starten der Anwendung ohne Docker +start_without_docker() { + header "Anwendung ohne Docker starten" + + cd "$FRONTEND_DIR" || return 1 + + # Prüfen, ob Node.js und pnpm installiert sind + if ! command -v node &> /dev/null; then + error_log "Node.js ist nicht installiert. Bitte installieren Sie Node.js zuerst." + return 1 + fi + + if ! command -v pnpm &> /dev/null; then + log "pnpm ist nicht installiert. Installiere pnpm..." + npm install -g pnpm + if [ $? -ne 0 ]; then + error_log "Fehler beim Installieren von pnpm." + return 1 + fi + fi + + # Installiere Abhängigkeiten + log "Installiere Abhängigkeiten..." + if ! pnpm install; then + error_log "Fehler beim Installieren der Abhängigkeiten." + return 1 + fi + + # Konfiguriere die Backend-URL + if ! configure_backend_url "$BACKEND_URL"; then + error_log "Fehler beim Konfigurieren der Backend-URL." + return 1 + fi + + # Baue und starte die Anwendung + log "Baue und starte die Anwendung..." + if ! pnpm build; then + log "${YELLOW}Warnung: Build fehlgeschlagen. Versuche, im Dev-Modus zu starten...${NC}" + fi + + # Starte im Screen-Session, damit die Anwendung im Hintergrund läuft + if command -v screen &> /dev/null; then + log "Starte Anwendung in Screen-Session..." + screen -dmS myp-frontend bash -c "cd $FRONTEND_DIR && NEXT_PUBLIC_API_URL=$BACKEND_URL pnpm start || NEXT_PUBLIC_API_URL=$BACKEND_URL pnpm dev" + success_log "Anwendung im Hintergrund gestartet. Verbinden mit: screen -r myp-frontend" + else + log "${YELLOW}Screen ist nicht installiert. Starte Anwendung im Vordergrund...${NC}" + log "${YELLOW}Beenden mit Strg+C. Die Anwendung wird dann beendet.${NC}" + sleep 3 + NEXT_PUBLIC_API_URL="$BACKEND_URL" pnpm start || NEXT_PUBLIC_API_URL="$BACKEND_URL" pnpm dev + fi + + return 0 +} + +# Funktion für das Hauptmenü +main_menu() { + local choice + header "MYP Frontend Deployment" + echo "Bitte wählen Sie eine Option:" + echo "" + echo "1) Alles automatisch (Build, Deploy, Starten)" + echo "2) Docker-Image bauen" + echo "3) Docker-Image speichern" + echo "4) Docker-Image laden" + echo "5) Container mit Docker Compose starten" + echo "6) Container direkt mit Docker Run starten" + echo "7) Anwendung ohne Docker starten" + echo "8) Nur Backend-URL konfigurieren" + echo "9) Beenden" + echo "" + read -p "Ihre Wahl (1-9): " choice + + case $choice in + 1) auto_deploy ;; + 2) build_image ;; + 3) save_image ;; + 4) load_image ;; + 5) configure_backend_url && start_container_compose ;; + 6) configure_backend_url && start_container_run ;; + 7) start_without_docker ;; + 8) configure_backend_url ;; + 9) log "Beende das Programm." && exit 0 ;; + *) error_log "Ungültige Auswahl. Bitte versuchen Sie es erneut." && main_menu ;; + esac + + # Zurück zum Hauptmenü, es sei denn, der Benutzer hat das Programm beendet + if [ $choice -ne 9 ]; then + read -p "Drücken Sie Enter, um zum Hauptmenü zurückzukehren..." + main_menu + fi +} + +# Automatischer Deployment-Workflow +auto_deploy() { + header "Automatisches Deployment" + log "Starte automatischen Deployment-Workflow..." + + # Konfiguriere Backend-URL + if ! configure_backend_url; then + error_log "Fehler beim Konfigurieren der Backend-URL." + return 1 + fi + + # Versuche zunächst, das Image zu laden + local load_dir="$DOCKER_DIR/images" + local load_file="$load_dir/myp-frontend.tar" + + if [ -f "$load_file" ]; then + log "Image-Datei gefunden. Versuche zu laden..." + if load_image; then + log "Image erfolgreich geladen. Überspringe Bauen." + else + log "Konnte Image nicht laden. Versuche zu bauen..." + if ! build_image; then + error_log "Automatisches Deployment fehlgeschlagen beim Bauen des Images." + return 1 + fi + fi + else + log "Keine Image-Datei gefunden. Baue neues Image..." + if ! build_image; then + error_log "Automatisches Deployment fehlgeschlagen beim Bauen des Images." + return 1 + fi + fi + + # Speichere das Image für zukünftige Verwendung + log "Speichere Image für zukünftige Verwendung..." + save_image + + # Starte den Container + log "Starte Container..." + if ! start_container_compose; then + error_log "Konnte Container nicht mit Docker Compose starten. Versuche direkten Start..." + if ! start_container_run; then + error_log "Automatisches Deployment fehlgeschlagen beim Starten des Containers." + return 1 + fi + fi + + success_log "Automatisches Deployment erfolgreich abgeschlossen!" + log "Frontend ist unter http://localhost:3000 erreichbar" + log "API-Kommunikation mit Backend: $BACKEND_URL" + + return 0 +} + +# Hauptanwendung +# Zuerst nach Backend-URL fragen +header "Backend-URL Konfiguration" +log "Standard-Backend-URL: $DEFAULT_BACKEND_URL" +read -p "Möchten Sie eine andere Backend-URL verwenden? (j/n): " change_url_choice + +if [[ "$change_url_choice" == "j" ]]; then + read -p "Geben Sie die neue Backend-URL ein (z.B. http://192.168.0.105:5000): " custom_url + if [ -n "$custom_url" ]; then + BACKEND_URL="$custom_url" + log "Verwende benutzerdefinierte Backend-URL: $BACKEND_URL" + else + BACKEND_URL="$DEFAULT_BACKEND_URL" + log "Leere Eingabe. Verwende Standard-Backend-URL: $BACKEND_URL" + fi +else + BACKEND_URL="$DEFAULT_BACKEND_URL" + log "Verwende Standard-Backend-URL: $BACKEND_URL" +fi + +# Anzeigen des Hauptmenüs +main_menu \ No newline at end of file