#!/bin/bash # BMC Hub Production Deployment Script # Usage: ./updateto.sh v1.3.15 set -e # Exit on any error VERSION=$1 # This production deployment is designed for ROOTLESS Podman. # Running with sudo will use a different Podman storage (rootful) and can make it look # like "data disappeared" because volumes/networks are separate. if [ "${EUID:-$(id -u)}" -eq 0 ]; then echo "❌ Fejl: Kør ikke dette script som root (sudo)." echo " Brug i stedet: sudo -iu bmcadmin && cd /srv/podman/bmc_hub_v1.0 && ./updateto.sh $VERSION" exit 1 fi PODMAN_COMPOSE_FILE="docker-compose.prod.yml" if [ -z "$VERSION" ]; then echo "❌ Fejl: Ingen version angivet" echo "Usage: ./updateto.sh v1.3.15" exit 1 fi # SAFETY CHECK: Verify we're on production server CURRENT_IP=$(hostname -I | awk '{print $1}' 2>/dev/null || echo "unknown") CURRENT_DIR=$(pwd) if [[ "$CURRENT_IP" != "172.16.31.183" ]] && [[ "$CURRENT_DIR" != "/srv/podman/bmc_hub_v2" ]]; then echo "⚠️ ADVARSEL: Dette script skal kun køres på PRODUCTION serveren!" echo " Forventet IP: 172.16.31.183" echo " Forventet mappe: /srv/podman/bmc_hub_v2" echo " Nuværende IP: $CURRENT_IP" echo " Nuværende mappe: $CURRENT_DIR" echo "" read -p "Er du SIKKER på du vil fortsætte? (skriv 'JA' for at fortsætte): " CONFIRM if [ "$CONFIRM" != "JA" ]; then echo "❌ Deployment afbrudt" exit 1 fi fi echo "🚀 Deploying BMC Hub version: $VERSION" echo "================================" # Check if .env exists if [ ! -f ".env" ]; then echo "❌ Fejl: .env fil ikke fundet" exit 1 fi if [ ! -f "$PODMAN_COMPOSE_FILE" ]; then echo "❌ Fejl: $PODMAN_COMPOSE_FILE ikke fundet i $(pwd)" echo " Kør fra /srv/podman/bmc_hub_v1.0" exit 1 fi # Load environment variables (DB credentials) set -a source .env set +a if [ -z "${API_PORT:-}" ]; then if [ "$CURRENT_DIR" = "/srv/podman/bmc_hub_v2" ]; then API_PORT="8001" else API_PORT="8000" fi fi # Update RELEASE_VERSION in .env echo "📝 Opdaterer .env med version $VERSION..." if grep -q "^RELEASE_VERSION=" .env; then # Replace existing line sed -i.bak "s/^RELEASE_VERSION=.*/RELEASE_VERSION=$VERSION/" .env else # Add if missing echo "RELEASE_VERSION=$VERSION" >> .env fi echo "✅ .env opdateret" # Cleanup legacy container names from older compose variants (can lock host ports) echo "" echo "🧹 Rydder legacy containere (v2-navne)..." podman update --restart=no bmc-hub-api-v2 bmc-hub-postgres-v2 >/dev/null 2>&1 || true podman stop bmc-hub-api-v2 bmc-hub-postgres-v2 >/dev/null 2>&1 || true podman rm -f bmc-hub-api-v2 bmc-hub-postgres-v2 >/dev/null 2>&1 || true # Also cleanup legacy compose-style names that can keep host ports locked LEGACY_CONTAINERS=$(podman ps -a --format '{{.Names}}' | grep -E '^(bmc_hub_v2_|bmc-hub-.*-v2)' || true) if [ -n "$LEGACY_CONTAINERS" ]; then echo "$LEGACY_CONTAINERS" | while read -r name; do [ -z "$name" ] && continue podman update --restart=no "$name" >/dev/null 2>&1 || true podman stop "$name" >/dev/null 2>&1 || true podman rm -f "$name" >/dev/null 2>&1 || true done fi # Guard against host port conflicts before attempting startup POSTGRES_BIND_ADDR="${POSTGRES_BIND_ADDR:-127.0.0.1}" POSTGRES_PORT="${POSTGRES_PORT:-5432}" if podman ps --format '{{.Names}} {{.Ports}}' | grep -E "${POSTGRES_BIND_ADDR}:${POSTGRES_PORT}->5432/tcp" | grep -v "bmc-hub-postgres-prod" >/dev/null 2>&1; then echo "❌ Fejl: Portkonflikt på ${POSTGRES_BIND_ADDR}:${POSTGRES_PORT} (Postgres host-port)" echo " Sæt en ledig port i .env, fx POSTGRES_PORT=5433" podman ps --format 'table {{.Names}}\t{{.Ports}}' exit 1 fi # Also detect stopped containers reserving legacy port mappings in config (rootlessport conflicts) if podman ps -a --format '{{.Names}} {{.Ports}}' | grep -E "${POSTGRES_BIND_ADDR}:${POSTGRES_PORT}->5432/tcp" | grep -v "bmc-hub-postgres-prod" >/dev/null 2>&1; then echo "⚠️ Finder gamle containere med portbinding ${POSTGRES_BIND_ADDR}:${POSTGRES_PORT}; forsøger oprydning..." podman ps -a --format '{{.Names}} {{.Ports}}' \ | grep -E "${POSTGRES_BIND_ADDR}:${POSTGRES_PORT}->5432/tcp" \ | grep -v "bmc-hub-postgres-prod" \ | awk '{print $1}' \ | while read -r holder; do [ -z "$holder" ] && continue podman update --restart=no "$holder" >/dev/null 2>&1 || true podman stop "$holder" >/dev/null 2>&1 || true podman rm -f "$holder" >/dev/null 2>&1 || true done fi # Stop containers echo "" echo "⏹️ Stopper containere..." podman-compose -f "$PODMAN_COMPOSE_FILE" down # Pull/rebuild with new version echo "" echo "🔨 Bygger nyt image med version $VERSION (--no-cache for at sikre ny kode fra Gitea)..." if ! podman-compose -f "$PODMAN_COMPOSE_FILE" build --no-cache && podman-compose -f "$PODMAN_COMPOSE_FILE" up -d; then echo "❌ Fejl: podman-compose up fejlede" echo " Tjek logs med: podman-compose -f $PODMAN_COMPOSE_FILE logs --tail=200" exit 1 fi # Validate that key containers are actually running after startup if ! podman ps --format '{{.Names}}' | grep -q '^bmc-hub-postgres-prod$'; then echo "❌ Fejl: bmc-hub-postgres-prod kører ikke efter startup" podman ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}' exit 1 fi if ! podman ps --format '{{.Names}}' | grep -q '^bmc-hub-api-prod$'; then echo "❌ Fejl: bmc-hub-api-prod kører ikke efter startup" podman ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}' exit 1 fi # Verify API health before continuing HEALTH_OK=false for i in {1..30}; do if curl -fsS "http://localhost:${API_PORT}/health" >/dev/null 2>&1; then HEALTH_OK=true break fi echo "⏳ Venter på API health... ($i/30)" sleep 2 done if [ "$HEALTH_OK" != "true" ]; then echo "❌ Fejl: API health fejlede på http://localhost:${API_PORT}/health" podman logs --tail 120 bmc-hub-api-prod || true exit 1 fi # Sync migrations from container to host echo "" echo "📁 Syncer migrations fra container til host..." SYNC_OK=false for i in {1..20}; do rm -rf ./migrations_temp if podman cp bmc-hub-api-prod:/app/migrations ./migrations_temp 2>/dev/null; then rm -rf ./migrations mv ./migrations_temp ./migrations chmod -R 755 ./migrations SYNC_OK=true echo "✅ Migrations synced" break fi echo "⏳ Venter på API container for migration sync... ($i/20)" sleep 2 done if [ "$SYNC_OK" != "true" ]; then echo "❌ Fejl: Kunne ikke sync'e migrations fra bmc-hub-api-prod:/app/migrations" echo " Afbryder for at undgå kørsel af gamle migrations" exit 1 fi if [ ! -f "./migrations/138_customers_economic_unique_constraint.sql" ]; then echo "❌ Fejl: Forventet migration 138 mangler efter sync" exit 1 fi # Wait a bit for startup echo "" echo "⏳ Venter på container startup..." sleep 5 # Database migrations echo "" echo "🧱 Database migrationer" echo " NOTE: Scriptet kører ikke længere en hardcoded enkelt-migration automatisk." echo " Brug migrations-UI'en i BMC Hub, eller sæt RUN_MIGRATIONS=true for at køre alle .sql i /docker-entrypoint-initdb.d/ i sorteret rækkefølge." if [ "${RUN_MIGRATIONS:-false}" = "true" ]; then if [ -z "$POSTGRES_USER" ] || [ -z "$POSTGRES_DB" ]; then echo "❌ Fejl: POSTGRES_USER/POSTGRES_DB mangler i .env" exit 1 fi for i in {1..30}; do if podman exec bmc-hub-postgres-prod pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB" >/dev/null 2>&1; then break fi echo "⏳ Venter på postgres... ($i/30)" sleep 2 done echo "📄 Kører alle migrations fra /docker-entrypoint-initdb.d (sorteret)..." podman exec bmc-hub-postgres-prod sh -lc "ls -1 /docker-entrypoint-initdb.d/*.sql 2>/dev/null | sort" \ | while read -r file; do [ -z "$file" ] && continue echo "➡️ $file" podman exec -i bmc-hub-postgres-prod psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$POSTGRES_DB" -f "$file" done echo "✅ Migrations kørt" else echo "ℹ️ RUN_MIGRATIONS=false (default)" fi # Show logs echo "" echo "📋 Logs fra startup:" echo "================================" podman logs --tail 50 bmc-hub-api-prod echo "" echo "✅ Deployment fuldført!" echo "" echo "🔍 Tjek status med:" echo " podman-compose -f $PODMAN_COMPOSE_FILE ps" echo " podman logs -f bmc-hub-api-prod" echo "" echo "🌐 Test health endpoint:" echo " curl http://localhost:${API_PORT}/health" echo "" echo "📊 Sync kunder fra e-conomic:" echo " curl -X POST http://localhost:${API_PORT}/api/v1/system/sync/economic" echo "" echo "🔗 Link vTiger til kunder:" echo " curl -X POST http://localhost:${API_PORT}/api/v1/system/sync/vtiger"