Projektarbeit-MYP/raspi-frontend-deploy.sh
Till Tomczak ef04d7fd0f Lade Umgebungsvariablen aus /srv/myp-env/github.env
- Füge Funktionalität hinzu, um OAuth-Konfiguration aus /srv zu laden
- Verwende env-file in Docker-Konfiguration
- Übernimm alle Umgebungsvariablen richtig in Container-Umgebung
- Behalte Fallback-Werte für fehlende Konfiguration bei
- Vereinfache Integration mit vorhandenem System

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-04-01 14:24:37 +02:00

567 lines
18 KiB
Bash
Executable File

#!/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"
ENV_FILE_PATH="/srv/myp-env/github.env"
# 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 Laden der Umgebungsvariablen aus /srv/myp-env/github.env
load_env_from_srv() {
if [ -f "$ENV_FILE_PATH" ]; then
log "Lade Umgebungsvariablen aus $ENV_FILE_PATH"
# Versuche, die Variablen aus der Datei zu laden
OAUTH_CLIENT_ID=$(grep -oP 'OAUTH_CLIENT_ID=\K.*' "$ENV_FILE_PATH" 2>/dev/null || echo "client_id")
OAUTH_CLIENT_SECRET=$(grep -oP 'OAUTH_CLIENT_SECRET=\K.*' "$ENV_FILE_PATH" 2>/dev/null || echo "client_secret")
# Prüfe, ob die Backend-URL in der Datei definiert ist
BACKEND_URL_FROM_FILE=$(grep -oP 'NEXT_PUBLIC_API_URL=\K.*' "$ENV_FILE_PATH" 2>/dev/null)
if [ -n "$BACKEND_URL_FROM_FILE" ]; then
log "Backend-URL aus $ENV_FILE_PATH geladen: $BACKEND_URL_FROM_FILE"
DEFAULT_BACKEND_URL="$BACKEND_URL_FROM_FILE"
fi
success_log "OAuth-Konfiguration aus $ENV_FILE_PATH geladen."
else
log "${YELLOW}Warnung: $ENV_FILE_PATH nicht gefunden. Verwende Standard-Konfiguration.${NC}"
OAUTH_CLIENT_ID="client_id"
OAUTH_CLIENT_SECRET="client_secret"
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"
# Lade OAuth-Konfiguration aus /srv
load_env_from_srv
# 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
# Bestimme den Hostnamen für OAuth
HOSTNAME=$(hostname)
if [[ "$HOSTNAME" == *"m040tbaraspi001"* ]] || [[ "$HOSTNAME" == *"corpintra"* ]]; then
FRONTEND_HOSTNAME="m040tbaraspi001.de040.corpintra.net"
OAUTH_URL="http://m040tbaraspi001.de040.corpintra.net/auth/login/callback"
log "Erkannt: Unternehmens-Hostname: $FRONTEND_HOSTNAME"
else
FRONTEND_HOSTNAME="$HOSTNAME"
OAUTH_URL="http://$HOSTNAME:3000/auth/login/callback"
log "Lokaler Hostname: $FRONTEND_HOSTNAME"
fi
# 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}
# Frontend-URL für OAuth Callback
NEXT_PUBLIC_FRONTEND_URL=http://${FRONTEND_HOSTNAME}
# Explizite OAuth Callback URL für GitHub
NEXT_PUBLIC_OAUTH_CALLBACK_URL=${OAUTH_URL}
# OAuth Konfiguration aus /srv/myp-env/github.env
OAUTH_CLIENT_ID=${OAUTH_CLIENT_ID}
OAUTH_CLIENT_SECRET=${OAUTH_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"
# Lade OAuth-Konfiguration aus /srv, falls noch nicht geschehen
if [ -z "$OAUTH_CLIENT_ID" ]; then
load_env_from_srv
fi
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}
- NEXT_PUBLIC_FRONTEND_URL=http://${FRONTEND_HOSTNAME}
- NEXT_PUBLIC_OAUTH_CALLBACK_URL=${OAUTH_URL}
- OAUTH_CLIENT_ID=${OAUTH_CLIENT_ID}
- OAUTH_CLIENT_SECRET=${OAUTH_CLIENT_SECRET}
env_file: "${ENV_FILE_PATH}"
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
# Lade OAuth-Konfiguration aus /srv, falls noch nicht geschehen
if [ -z "$OAUTH_CLIENT_ID" ]; then
load_env_from_srv
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 "NEXT_PUBLIC_FRONTEND_URL=http://${FRONTEND_HOSTNAME}" \
-e "NEXT_PUBLIC_OAUTH_CALLBACK_URL=${OAUTH_URL}" \
-e "OAUTH_CLIENT_ID=${OAUTH_CLIENT_ID}" \
-e "OAUTH_CLIENT_SECRET=${OAUTH_CLIENT_SECRET}" \
--env-file "$ENV_FILE_PATH" \
-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
# Lade OAuth-Konfiguration aus /srv und konfiguriere die Backend-URL
load_env_from_srv
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 \
NEXT_PUBLIC_FRONTEND_URL=http://${FRONTEND_HOSTNAME} \
NEXT_PUBLIC_OAUTH_CALLBACK_URL=${OAUTH_URL} \
OAUTH_CLIENT_ID=${OAUTH_CLIENT_ID} \
OAUTH_CLIENT_SECRET=${OAUTH_CLIENT_SECRET} \
pnpm start || \
NEXT_PUBLIC_API_URL=$BACKEND_URL \
NEXT_PUBLIC_FRONTEND_URL=http://${FRONTEND_HOSTNAME} \
NEXT_PUBLIC_OAUTH_CALLBACK_URL=${OAUTH_URL} \
OAUTH_CLIENT_ID=${OAUTH_CLIENT_ID} \
OAUTH_CLIENT_SECRET=${OAUTH_CLIENT_SECRET} \
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
export NEXT_PUBLIC_API_URL="$BACKEND_URL"
export NEXT_PUBLIC_FRONTEND_URL="http://${FRONTEND_HOSTNAME}"
export NEXT_PUBLIC_OAUTH_CALLBACK_URL="${OAUTH_URL}"
export OAUTH_CLIENT_ID="${OAUTH_CLIENT_ID}"
export OAUTH_CLIENT_SECRET="${OAUTH_CLIENT_SECRET}"
pnpm start || 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