#!/bin/bash # # DAARION Production Deployment Script # Usage: ./scripts/deploy-prod.sh # set -e # Colors GREEN='\033[0;32m' RED='\033[0;31m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Configuration COMPOSE_FILE="docker-compose.all.yml" CADDY_COMPOSE_FILE="docker-compose.caddy.yml" ENV_FILE=".env" LOG_DIR="/var/log/daarion" BACKUP_DIR="/opt/daarion/backups" # Functions log_info() { echo -e "${BLUE}ℹ️ $1${NC}" } log_success() { echo -e "${GREEN}✅ $1${NC}" } log_error() { echo -e "${RED}❌ $1${NC}" } log_warning() { echo -e "${YELLOW}⚠️ $1${NC}" } # Banner echo -e "${BLUE}" cat << "EOF" ╔══════════════════════════════════════╗ ║ DAARION Production Deployment ║ ║ daarion.space ║ ╚══════════════════════════════════════╝ EOF echo -e "${NC}" # Pre-flight checks log_info "Running pre-flight checks..." # Check if running as root or with sudo if [ "$EUID" -ne 0 ] && [ -z "$SUDO_USER" ]; then log_warning "Not running as root. Some commands may require sudo." fi # Check Docker if ! command -v docker &> /dev/null; then log_error "Docker is not installed!" exit 1 fi log_success "Docker found" # Check Docker Compose if ! docker compose version &> /dev/null; then log_error "Docker Compose is not installed!" exit 1 fi log_success "Docker Compose found" # Check ENV file if [ ! -f "$ENV_FILE" ]; then log_error ".env file not found! Copy .env.example and configure it." exit 1 fi log_success ".env file found" # Check compose files if [ ! -f "$COMPOSE_FILE" ]; then log_error "$COMPOSE_FILE not found!" exit 1 fi log_success "Compose files found" # Create log directory mkdir -p "$LOG_DIR" mkdir -p "$BACKUP_DIR" log_success "Directories created" # Network setup log_info "Setting up Docker network..." docker network create daarion-network 2>/dev/null || log_warning "Network already exists" log_success "Network ready" # Database backup log_info "Creating database backup..." BACKUP_FILE="$BACKUP_DIR/backup_$(date +%Y%m%d_%H%M%S).sql" if docker ps --filter "name=daarion-postgres" --format "{{.Names}}" | grep -q postgres; then docker compose -f "$COMPOSE_FILE" exec -T postgres \ pg_dump -U daarion_user daarion > "$BACKUP_FILE" 2>/dev/null || log_warning "Backup failed (DB may not exist yet)" if [ -f "$BACKUP_FILE" ]; then gzip "$BACKUP_FILE" log_success "Backup created: ${BACKUP_FILE}.gz" fi else log_warning "PostgreSQL not running, skipping backup" fi # Pull latest images (if using registry) log_info "Pulling latest images..." docker compose -f "$COMPOSE_FILE" pull || log_warning "Pull failed, will build locally" # Build images log_info "Building Docker images..." docker compose -f "$COMPOSE_FILE" build log_success "Images built" # Start core services log_info "Starting core services (postgres, redis, nats)..." docker compose -f "$COMPOSE_FILE" up -d postgres redis nats sleep 10 log_success "Core services started" # Run migrations log_info "Running database migrations..." if [ -f "scripts/migrate.sh" ]; then bash scripts/migrate.sh else log_warning "migrate.sh not found, skipping migrations" fi # Start all services log_info "Starting all application services..." docker compose -f "$COMPOSE_FILE" up -d log_success "Application services started" # Wait for services to be healthy log_info "Waiting for services to be healthy..." sleep 15 # Start Caddy (SSL/HTTPS) if [ -f "$CADDY_COMPOSE_FILE" ]; then log_info "Starting Caddy (SSL/HTTPS)..." docker compose -f "$CADDY_COMPOSE_FILE" up -d log_success "Caddy started" else log_warning "Caddy compose file not found" fi # Health checks log_info "Running health checks..." HEALTH_FAILED=0 # Check PostgreSQL if docker compose -f "$COMPOSE_FILE" exec postgres pg_isready -U daarion_user > /dev/null 2>&1; then log_success "PostgreSQL: healthy" else log_error "PostgreSQL: unhealthy" HEALTH_FAILED=1 fi # Check Redis if docker compose -f "$COMPOSE_FILE" exec redis redis-cli PING > /dev/null 2>&1; then log_success "Redis: healthy" else log_error "Redis: unhealthy" HEALTH_FAILED=1 fi # Check Gateway (wait for Caddy SSL) sleep 5 if curl -sf https://app.daarion.space/health > /dev/null 2>&1; then log_success "Gateway: healthy" else log_warning "Gateway: not yet accessible (SSL may be provisioning)" fi # Show running containers echo "" log_info "Running containers:" docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | grep daarion || true # Show logs location echo "" log_info "Logs available at:" echo " - Docker logs: docker logs " echo " - Application logs: $LOG_DIR" echo " - Caddy logs: docker logs daarion-caddy" # Run infrastructure invariants check log_info "Running infrastructure invariants check..." INVARIANTS_FAILED=0 # Wait a bit more for services to fully initialize sleep 5 # Run invariants check if [ -f "scripts/check-invariants.py" ]; then # Try to run invariants check if command -v python3 &> /dev/null; then # Use internal Docker network URL or localhost CITY_URL="${CITY_SERVICE_URL:-http://localhost:7001}" # Install requests if needed (for check-deploy-post.py) pip3 install requests --quiet || true python3 scripts/check-invariants.py --base-url "$CITY_URL" || { INVARIANTS_FAILED=1 log_error "Infrastructure invariants check FAILED!" } # Run extended post-deploy checks if [ -f "scripts/check-deploy-post.py" ]; then log_info "Running extended post-deploy checks..." REPORT_PATH="logs/deploy/checks_$(date +%Y%m%d_%H%M%S).json" LATEST_PATH="logs/deploy/checks_latest.json" python3 scripts/check-deploy-post.py \ --base-url "$CITY_URL" \ --skip-smoke \ --output-file "$REPORT_PATH" || { INVARIANTS_FAILED=1 log_error "Extended post-deploy checks FAILED!" } # Create symlink/copy to latest if report exists if [ -f "$REPORT_PATH" ]; then mkdir -p logs/deploy cp "$REPORT_PATH" "$LATEST_PATH" log_success "Check report saved to $LATEST_PATH" fi else log_warning "check-deploy-post.py not found, skipping extended checks" fi else log_warning "Python3 not found, skipping invariants check" fi else log_warning "check-invariants.py not found, skipping invariants check" fi # Run smoke tests (optional) if [ -f "tests/test_infra_smoke.py" ] && [ "$RUN_SMOKE_TESTS" = "true" ]; then log_info "Running smoke tests..." pytest tests/test_infra_smoke.py -v --tb=short || { log_warning "Some smoke tests failed (non-blocking)" } fi # Success message echo "" if [ $HEALTH_FAILED -eq 0 ] && [ $INVARIANTS_FAILED -eq 0 ]; then log_success "🎉 Deployment completed successfully!" echo "" echo " 🌐 Application: https://app.daarion.space" echo " 📊 Monitoring: https://app.daarion.space/grafana/" echo "" echo " ✅ All infrastructure invariants passed" echo "" echo " Next steps:" echo " 1. Run smoke tests: RUN_SMOKE_TESTS=true ./scripts/deploy-prod.sh" echo " 2. Monitor logs: docker logs -f daarion-gateway" echo " 3. Check metrics: docker stats" elif [ $INVARIANTS_FAILED -eq 1 ]; then log_error "Deployment completed but INVARIANTS CHECK FAILED!" echo "" echo " ❌ Some infrastructure invariants are not met." echo " Please review the output above and fix the issues." echo "" echo " Common fixes:" echo " 1. Run migrations: scripts/migrate.sh" echo " 2. Seed agents: psql < migrations/038_agent_prompts_full_coverage.sql" echo " 3. Check node_cache: psql < migrations/036_node_metrics_extended.sql" exit 1 else log_error "Deployment completed with errors. Check logs above." exit 1 fi