#!/bin/bash # Sharenet Production Deployment Script # This script handles safe production deployments with migrations set -e # Configuration APP_NAME="sharenet" BACKUP_DIR="backups" MIGRATION_SCRIPT="./scripts/migrate.sh" # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; } log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } # Pre-deployment checks pre_deployment_checks() { log_info "Running pre-deployment checks..." # Check if migration script exists if [ ! -f "$MIGRATION_SCRIPT" ]; then log_error "Migration script not found: $MIGRATION_SCRIPT" log_error "Current directory: $(pwd)" log_error "Available files in scripts/:" ls -la scripts/ 2>/dev/null || log_error "scripts/ directory not found" exit 1 fi # Check if migration script is executable if [ ! -x "$MIGRATION_SCRIPT" ]; then log_info "Making migration script executable" chmod +x "$MIGRATION_SCRIPT" fi # Check database connection if ! "$MIGRATION_SCRIPT" status >/dev/null 2>&1; then log_error "Cannot connect to database" log_error "Running migration script with verbose output:" "$MIGRATION_SCRIPT" status exit 1 fi log_success "Pre-deployment checks passed" } # Create backup create_backup() { log_info "Creating database backup..." mkdir -p "$BACKUP_DIR" if "$MIGRATION_SCRIPT" backup; then log_success "Backup created successfully" else log_error "Backup failed" exit 1 fi } # Run migrations run_migrations() { log_info "Running database migrations..." if "$MIGRATION_SCRIPT" run; then log_success "Migrations completed successfully" else log_error "Migrations failed" log_warning "Consider restoring from backup" exit 1 fi } # Deploy application deploy_application() { log_info "Deploying application..." # Pull latest images docker-compose pull # Stop current services docker-compose down # Start services with new images docker-compose up -d # Wait for services to be healthy log_info "Waiting for services to be healthy..." local max_attempts=60 # 5 minutes with 5-second intervals local attempt=0 while [ $attempt -lt $max_attempts ]; do if docker-compose ps | grep -q "healthy"; then log_success "All services are healthy" return 0 fi log_info "Waiting for services to become healthy... (attempt $((attempt + 1))/$max_attempts)" sleep 5 attempt=$((attempt + 1)) done log_error "Services failed to become healthy within timeout" log_error "Current service status:" docker-compose ps log_error "Recent logs:" docker-compose logs --tail=50 exit 1 } # Rollback function rollback() { log_warning "Rolling back deployment..." # Stop services docker-compose down # Restore from backup local latest_backup=$(ls -t "$BACKUP_DIR"/backup_*.sql 2>/dev/null | head -1) if [ -n "$latest_backup" ]; then log_info "Restoring from backup: $latest_backup" "$MIGRATION_SCRIPT" restore "$latest_backup" else log_warning "No backup found for rollback" fi # Start services with previous images docker-compose up -d log_warning "Rollback completed" } # Main deployment process main() { local command="${1:-deploy}" case "$command" in deploy) log_info "Starting production deployment..." pre_deployment_checks create_backup run_migrations deploy_application log_success "Production deployment completed successfully" ;; rollback) log_warning "Starting rollback process..." rollback log_success "Rollback completed successfully" ;; check) log_info "Running deployment checks..." pre_deployment_checks "$MIGRATION_SCRIPT" status log_success "All checks passed" ;; *) log_error "Unknown command: $command" echo "Usage: $0 {deploy|rollback|check}" exit 1 ;; esac } # Handle interrupts gracefully trap 'log_error "Deployment interrupted"; exit 1' INT TERM # Run main function main "$@"