#!/bin/bash set -e # BOC Deployment Script # Deploys the entire BOC stack to production echo "🚀 BOC Deployment Starting..." # Configuration SERVER=${SERVER:-"bernt.wavult.com"} SSH_USER=${SSH_USER:-"bernt"} DEPLOY_DIR=${DEPLOY_DIR:-"/opt/boc"} BACKUP_DIR=${BACKUP_DIR:-"/opt/backups/boc"} # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color log_info() { echo -e "${GREEN}[INFO]${NC} $1" } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1" } log_error() { echo -e "${RED}[ERROR]${NC} $1" } # Pre-deployment checks check_prerequisites() { log_info "Checking prerequisites..." # Check Docker if ! command -v docker &> /dev/null; then log_error "Docker is not installed" exit 1 fi # Check Docker Compose if ! command -v docker-compose &> /dev/null; then log_error "Docker Compose is not installed" exit 1 fi # Check SSH access if ! ssh -o ConnectTimeout=5 "${SSH_USER}@${SERVER}" echo "OK" &> /dev/null; then log_error "Cannot connect to ${SERVER} via SSH" exit 1 fi log_info "Prerequisites OK" } # Build locally build_locally() { log_info "Building BOC stack..." make clean make build log_info "Build complete" } # Backup database backup_database() { log_info "Creating database backup..." ssh "${SSH_USER}@${SERVER}" " mkdir -p ${BACKUP_DIR} docker exec boc-postgres pg_dump -U boc boc | gzip > ${BACKUP_DIR}/boc-$(date +%Y%m%d-%H%M%S).sql.gz " || log_warn "Database backup failed, continuing..." } # Deploy to server deploy_to_server() { log_info "Deploying to ${SERVER}..." # Create deploy directory ssh "${SSH_USER}@${SERVER}" "mkdir -p ${DEPLOY_DIR}" # Sync files rsync -avz --delete \ --exclude='.git' \ --exclude='backend/boc' \ --exclude='rust-service/target' \ --exclude='c-runtime/*.o' \ --exclude='c-runtime/*.so' \ --exclude='c-runtime/*.a' \ ./ "${SSH_USER}@${SERVER}:${DEPLOY_DIR}/" log_info "Files synced" } # Start services start_services() { log_info "Starting services..." ssh "${SSH_USER}@${SERVER}" " cd ${DEPLOY_DIR} # Pull latest images docker-compose pull # Build and start docker-compose up -d --build # Wait for health checks echo 'Waiting for services to be healthy...' sleep 10 # Check health docker-compose ps " log_info "Services started" } # Verify deployment verify_deployment() { log_info "Verifying deployment..." # Check API health if curl -sf "http://${SERVER}/health" > /dev/null; then log_info "API is healthy" else log_error "API health check failed" return 1 fi # Check Rust service if curl -sf "http://${SERVER}/rust/health" > /dev/null; then log_info "Rust service is healthy" else log_warn "Rust service health check failed" fi log_info "Deployment verified" } # Rollback on failure rollback() { log_error "Deployment failed, rolling back..." ssh "${SSH_USER}@${SERVER}" " cd ${DEPLOY_DIR} docker-compose down # Restore from latest backup LATEST_BACKUP=\$(ls -t ${BACKUP_DIR}/*.sql.gz | head -1) if [ -n \"\$LATEST_BACKUP\" ]; then zcat \$LATEST_BACKUP | docker exec -i boc-postgres psql -U boc boc fi docker-compose up -d " } # Main deployment flow main() { echo "================================" echo " BOC Deployment" echo " Target: ${SERVER}" echo " Time: $(date)" echo "================================" check_prerequisites build_locally backup_database deploy_to_server if start_services; then verify_deployment log_info "🎉 Deployment successful!" echo "" echo "BOC is now running at:" echo " Dashboard: http://${SERVER}" echo " API: http://${SERVER}/api/v1" echo " Kafka UI: http://${SERVER}/kafka-ui" else rollback exit 1 fi } # Run main trap 'log_error "Deployment interrupted"; exit 1' INT TERM main "$@"