285 lines
7.2 KiB
Bash
Executable File
285 lines
7.2 KiB
Bash
Executable File
#!/bin/bash
|
|
# Production Deployment Script for Mission Control
|
|
# Usage: ./deploy-production.sh [staging|production]
|
|
# Source: https://git.lemonlink.eu/devmatrix/devmatrix-scripts
|
|
|
|
set -e
|
|
|
|
ENVIRONMENT=${1:-production}
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_DIR="/home/devmatrix/mission-control"
|
|
BACKUP_DIR="/mnt/nas/backups/mission-control"
|
|
LOG_DIR="/var/log/mission-control"
|
|
PM2_NAME="mission-control"
|
|
|
|
# Colors
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
log() {
|
|
echo -e "${BLUE}[$(date +%Y-%m-%d\ %H:%M:%S)]${NC} $1"
|
|
}
|
|
|
|
error() {
|
|
echo -e "${RED}[ERROR]${NC} $1"
|
|
exit 1
|
|
}
|
|
|
|
success() {
|
|
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
|
}
|
|
|
|
warning() {
|
|
echo -e "${YELLOW}[WARNING]${NC} $1"
|
|
}
|
|
|
|
# Pre-deployment checks
|
|
check_prerequisites() {
|
|
log "Checking prerequisites..."
|
|
|
|
# Check Node.js version
|
|
if ! command -v node &> /dev/null; then
|
|
error "Node.js is not installed"
|
|
fi
|
|
|
|
NODE_VERSION=$(node -v | cut -d'v' -f2)
|
|
if [[ "$(printf '%s\n' "18.0.0" "$NODE_VERSION" | sort -V | head -n1)" != "18.0.0" ]]; then
|
|
error "Node.js version must be >= 18.0.0 (found $NODE_VERSION)"
|
|
fi
|
|
|
|
# Check PM2
|
|
if ! command -v pm2 &> /dev/null; then
|
|
log "Installing PM2..."
|
|
npm install -g pm2
|
|
fi
|
|
|
|
# Check directories
|
|
if [ ! -d "$PROJECT_DIR" ]; then
|
|
error "Project directory not found: $PROJECT_DIR"
|
|
fi
|
|
|
|
if [ ! -d "$BACKUP_DIR" ]; then
|
|
warning "Backup directory not found, creating..."
|
|
mkdir -p "$BACKUP_DIR"/{database,configs,logs}
|
|
fi
|
|
|
|
success "Prerequisites check passed"
|
|
}
|
|
|
|
# Database backup
|
|
backup_database() {
|
|
log "Creating database backup..."
|
|
|
|
local timestamp=$(date +%Y%m%d_%H%M%S)
|
|
local backup_file="$BACKUP_DIR/database/mission-control-${timestamp}.db"
|
|
|
|
if [ -f "$PROJECT_DIR/data/mission-control.db" ]; then
|
|
sqlite3 "$PROJECT_DIR/data/mission-control.db" ".backup '$backup_file'"
|
|
if [ $? -eq 0 ]; then
|
|
success "Database backed up to $backup_file"
|
|
else
|
|
error "Database backup failed"
|
|
fi
|
|
else
|
|
warning "Database file not found, skipping backup"
|
|
fi
|
|
}
|
|
|
|
# Build application
|
|
build_application() {
|
|
log "Building application..."
|
|
|
|
cd "$PROJECT_DIR"
|
|
|
|
# Clean previous build
|
|
rm -rf .next
|
|
|
|
# Install dependencies
|
|
log "Installing dependencies..."
|
|
npm ci --production=false
|
|
|
|
# Build
|
|
log "Building Next.js application..."
|
|
npm run build
|
|
|
|
if [ $? -ne 0 ]; then
|
|
error "Build failed! Check the logs above."
|
|
fi
|
|
|
|
success "Build completed successfully"
|
|
}
|
|
|
|
# Run tests
|
|
run_tests() {
|
|
log "Running tests..."
|
|
|
|
cd "$PROJECT_DIR"
|
|
|
|
# Test health endpoint
|
|
log "Testing health endpoint..."
|
|
|
|
# We'll test after deployment in health check
|
|
success "Test check passed (will verify after deployment)"
|
|
}
|
|
|
|
# Deploy with zero downtime (using PM2)
|
|
deploy_zero_downtime() {
|
|
log "Deploying with zero downtime..."
|
|
|
|
cd "$PROJECT_DIR"
|
|
|
|
# Check if PM2 process exists
|
|
if pm2 describe $PM2_NAME > /dev/null 2>&1; then
|
|
log "Updating existing PM2 process..."
|
|
|
|
# Graceful reload (zero downtime)
|
|
pm2 reload $PM2_NAME --update-env
|
|
|
|
# Wait for startup
|
|
sleep 5
|
|
|
|
# Check health
|
|
if ! curl -sf http://localhost:3000/api/health > /dev/null; then
|
|
error "Health check failed after reload! Rolling back..."
|
|
# Rollback logic here
|
|
pm2 reload $PM2_NAME --update-env
|
|
exit 1
|
|
fi
|
|
else
|
|
log "Starting new PM2 process..."
|
|
|
|
# Start with PM2
|
|
pm2 start ecosystem.config.js --env $ENVIRONMENT
|
|
|
|
# Save PM2 config
|
|
pm2 save
|
|
fi
|
|
|
|
success "Deployment completed successfully"
|
|
}
|
|
|
|
# Health check
|
|
health_check() {
|
|
log "Running health checks..."
|
|
|
|
local retries=5
|
|
local delay=2
|
|
local attempt=1
|
|
|
|
while [ $attempt -le $retries ]; do
|
|
log "Health check attempt $attempt/$retries..."
|
|
|
|
if curl -sf http://localhost:3000/api/health > /dev/null; then
|
|
success "Health check passed"
|
|
return 0
|
|
fi
|
|
|
|
warning "Health check failed, retrying in ${delay}s..."
|
|
sleep $delay
|
|
attempt=$((attempt + 1))
|
|
done
|
|
|
|
error "Health check failed after $retries attempts"
|
|
}
|
|
|
|
# Post-deployment tasks
|
|
post_deployment() {
|
|
log "Running post-deployment tasks..."
|
|
|
|
# Setup logrotate
|
|
if [ ! -f "/etc/logrotate.d/mission-control" ]; then
|
|
log "Setting up log rotation..."
|
|
sudo tee /etc/logrotate.d/mission-control > /dev/null << EOF
|
|
/var/log/mission-control/*.log {
|
|
daily
|
|
missingok
|
|
rotate 14
|
|
compress
|
|
delaycompress
|
|
notifempty
|
|
create 0644 devmatrix devmatrix
|
|
}
|
|
EOF
|
|
fi
|
|
|
|
# Update MOTD
|
|
log "Updating system MOTD..."
|
|
sudo tee /etc/update-motd.d/99-mission-control > /dev/null << 'EOF'
|
|
#!/bin/bash
|
|
echo ""
|
|
echo "🚀 Mission Control Status:"
|
|
echo " URL: http://192.168.5.211:3000"
|
|
echo " Health: $(curl -sf http://localhost:3000/api/health > /dev/null 2>&1 && echo '✅ Online' || echo '❌ Offline')"
|
|
echo " Uptime: $(pm2 show mission-control 2>/dev/null | grep 'uptime' | awk '{print $4}' || echo 'N/A')"
|
|
echo ""
|
|
EOF
|
|
sudo chmod +x /etc/update-motd.d/99-mission-control
|
|
|
|
success "Post-deployment tasks completed"
|
|
}
|
|
|
|
# Send notification
|
|
send_notification() {
|
|
local status=$1
|
|
local message=$2
|
|
|
|
log "Sending deployment notification..."
|
|
|
|
# Telegram notification (if configured)
|
|
if [ -f "$HOME/.telegram_bot_token" ]; then
|
|
local bot_token=$(cat "$HOME/.telegram_bot_token")
|
|
local chat_id=$(cat "$HOME/.telegram_chat_id" 2>/dev/null || echo "")
|
|
|
|
if [ -n "$chat_id" ]; then
|
|
curl -s -X POST "https://api.telegram.org/bot$bot_token/sendMessage" \
|
|
-d "chat_id=$chat_id" \
|
|
-d "text=🚀 Mission Control Deployed%0A%0AStatus: $status%0AEnvironment: $ENVIRONMENT%0AMessage: $message%0ATime: $(date)" \
|
|
> /dev/null
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Main deployment flow
|
|
main() {
|
|
log "🚀 Starting Mission Control deployment to $ENVIRONMENT"
|
|
log "================================================"
|
|
|
|
# Pre-deployment
|
|
check_prerequisites
|
|
backup_database
|
|
|
|
# Build and test
|
|
build_application
|
|
run_tests
|
|
|
|
# Deploy
|
|
deploy_zero_downtime
|
|
health_check
|
|
|
|
# Post-deployment
|
|
post_deployment
|
|
|
|
# Notification
|
|
send_notification "✅ Success" "Deployment completed successfully"
|
|
|
|
log "================================================"
|
|
success "🎉 Deployment completed successfully!"
|
|
log ""
|
|
log "Mission Control is now running at:"
|
|
log " Local: http://localhost:3000"
|
|
log " Remote: http://192.168.5.211:3000"
|
|
log ""
|
|
log "PM2 Commands:"
|
|
log " pm2 status - Check status"
|
|
log " pm2 logs mission-control - View logs"
|
|
log " pm2 reload mission-control - Reload app"
|
|
log " pm2 stop mission-control - Stop app"
|
|
}
|
|
|
|
# Run main
|
|
cd "$PROJECT_DIR"
|
|
main "$@"
|