Files
hive/deploy/deploy.sh
anthonyrawlins 268214d971 Major WHOOSH system refactoring and feature enhancements
- Migrated from HIVE branding to WHOOSH across all components
- Enhanced backend API with new services: AI models, BZZZ integration, templates, members
- Added comprehensive testing suite with security, performance, and integration tests
- Improved frontend with new components for project setup, AI models, and team management
- Updated MCP server implementation with WHOOSH-specific tools and resources
- Enhanced deployment configurations with production-ready Docker setups
- Added comprehensive documentation and setup guides
- Implemented age encryption service and UCXL integration

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-27 08:34:48 +10:00

395 lines
11 KiB
Bash
Executable File

#!/bin/bash
# WHOOSH Production Deployment Script
set -euo pipefail
# Configuration
DEPLOY_ENV="${DEPLOY_ENV:-production}"
REGISTRY="${REGISTRY:-registry.home.deepblack.cloud}"
PROJECT_NAME="whoosh"
DOMAIN="${DOMAIN:-whoosh.deepblack.cloud}"
BACKUP_DIR="/rust/containers/whoosh/backups"
COMPOSE_FILE="docker-compose.prod.yml"
# Colors for output
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"
}
success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
error() {
echo -e "${RED}[ERROR]${NC} $1"
exit 1
}
# Function to check prerequisites
check_prerequisites() {
log "Checking deployment prerequisites..."
# Check if running as non-root
if [[ $EUID -eq 0 ]]; then
error "This script should not be run as root"
fi
# Check required commands
for cmd in docker docker-compose git curl; do
if ! command -v $cmd &> /dev/null; then
error "$cmd is not installed"
fi
done
# Check Docker daemon
if ! docker info >/dev/null 2>&1; then
error "Docker daemon is not running"
fi
# Check if in swarm mode (optional)
if docker info | grep -q "Swarm: active"; then
log "Docker Swarm is active"
SWARM_MODE=true
else
log "Docker Swarm is not active, using compose mode"
SWARM_MODE=false
fi
success "Prerequisites check completed"
}
# Function to setup secrets
setup_secrets() {
log "Setting up production secrets..."
if [[ "$SWARM_MODE" == "true" ]]; then
# Docker Swarm secrets
echo "Setting up Docker Swarm secrets..."
# Check if secrets exist, create if they don't
if ! docker secret ls | grep -q "whoosh_postgres_password"; then
openssl rand -base64 32 | docker secret create whoosh_postgres_password -
fi
if ! docker secret ls | grep -q "whoosh_secret_key"; then
openssl rand -base64 64 | docker secret create whoosh_secret_key -
fi
if ! docker secret ls | grep -q "whoosh_age_master_key"; then
age-keygen | grep "AGE-SECRET-KEY" | docker secret create whoosh_age_master_key -
fi
# GITEA token should be provided externally
if ! docker secret ls | grep -q "whoosh_gitea_token"; then
warning "GITEA token secret not found. Please create it manually:"
echo " echo 'your_gitea_token' | docker secret create whoosh_gitea_token -"
fi
else
# Docker Compose secrets (using .env file)
if [[ ! -f ".env.prod" ]]; then
log "Creating .env.prod file..."
cat > .env.prod << EOF
POSTGRES_PASSWORD=$(openssl rand -base64 32)
SECRET_KEY=$(openssl rand -base64 64)
AGE_MASTER_KEY=$(age-keygen | grep "AGE-SECRET-KEY")
GITEA_TOKEN=${GITEA_TOKEN:-""}
SENTRY_DSN=${SENTRY_DSN:-""}
GRAFANA_PASSWORD=$(openssl rand -base64 16)
EOF
warning "Created .env.prod file. Please update GITEA_TOKEN and SENTRY_DSN"
fi
fi
success "Secrets setup completed"
}
# Function to build and push images
build_and_push() {
log "Building and pushing Docker images..."
# Build backend
log "Building backend image..."
docker build -f backend/Dockerfile.prod -t ${REGISTRY}/${PROJECT_NAME}/backend:latest backend/
docker build -f backend/Dockerfile.prod -t ${REGISTRY}/${PROJECT_NAME}/backend:$(git rev-parse --short HEAD) backend/
# Build frontend
log "Building frontend image..."
docker build -f frontend/Dockerfile.prod -t ${REGISTRY}/${PROJECT_NAME}/frontend:latest frontend/
docker build -f frontend/Dockerfile.prod -t ${REGISTRY}/${PROJECT_NAME}/frontend:$(git rev-parse --short HEAD) frontend/
# Push to registry
if [[ "${PUSH_IMAGES:-true}" == "true" ]]; then
log "Pushing images to registry..."
docker push ${REGISTRY}/${PROJECT_NAME}/backend:latest
docker push ${REGISTRY}/${PROJECT_NAME}/backend:$(git rev-parse --short HEAD)
docker push ${REGISTRY}/${PROJECT_NAME}/frontend:latest
docker push ${REGISTRY}/${PROJECT_NAME}/frontend:$(git rev-parse --short HEAD)
fi
success "Images built and pushed successfully"
}
# Function to backup database
backup_database() {
if docker ps | grep -q "whoosh_postgres"; then
log "Creating database backup..."
mkdir -p "$BACKUP_DIR"
BACKUP_FILE="$BACKUP_DIR/whoosh_backup_$(date +%Y%m%d_%H%M%S).sql"
docker exec whoosh_postgres_prod pg_dump -U whoosh whoosh > "$BACKUP_FILE"
gzip "$BACKUP_FILE"
success "Database backup created: ${BACKUP_FILE}.gz"
# Keep only last 7 backups
find "$BACKUP_DIR" -name "whoosh_backup_*.sql.gz" -mtime +7 -delete
else
log "No existing database found to backup"
fi
}
# Function to deploy application
deploy_application() {
log "Deploying WHOOSH application..."
# Create necessary directories
mkdir -p logs nginx/ssl monitoring/grafana/{dashboards,datasources}
if [[ "$SWARM_MODE" == "true" ]]; then
# Deploy using Docker Swarm
log "Deploying to Docker Swarm..."
docker stack deploy -c docker-compose.prod.yml ${PROJECT_NAME}
# Wait for services to be ready
log "Waiting for services to be ready..."
for i in {1..30}; do
if docker service ls | grep -q "${PROJECT_NAME}_whoosh_backend" &&
docker service ls | grep -q "${PROJECT_NAME}_whoosh_frontend"; then
break
fi
echo -n "."
sleep 10
done
echo
else
# Deploy using Docker Compose
log "Deploying with Docker Compose..."
docker-compose -f $COMPOSE_FILE --env-file .env.prod up -d
# Wait for services to be ready
log "Waiting for services to be ready..."
for i in {1..30}; do
if docker-compose -f $COMPOSE_FILE ps | grep -q "Up" &&
curl -f http://localhost:8087/health >/dev/null 2>&1; then
break
fi
echo -n "."
sleep 10
done
echo
fi
success "Application deployed successfully"
}
# Function to run health checks
run_health_checks() {
log "Running health checks..."
# Check backend health
if curl -f http://localhost:8087/health >/dev/null 2>&1; then
success "Backend health check passed"
else
error "Backend health check failed"
fi
# Check frontend
if curl -f http://localhost:3000 >/dev/null 2>&1; then
success "Frontend health check passed"
else
warning "Frontend health check failed"
fi
# Check database
if docker exec whoosh_postgres_prod pg_isready -U whoosh >/dev/null 2>&1; then
success "Database health check passed"
else
error "Database health check failed"
fi
success "Health checks completed"
}
# Function to setup monitoring
setup_monitoring() {
log "Setting up monitoring and alerting..."
# Create Prometheus configuration
cat > monitoring/prometheus.yml << EOF
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
- "alert_rules.yml"
alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager:9093
scrape_configs:
- job_name: 'whoosh-backend'
static_configs:
- targets: ['whoosh_backend:8087']
metrics_path: /metrics
scrape_interval: 30s
- job_name: 'whoosh-postgres'
static_configs:
- targets: ['postgres_exporter:9187']
- job_name: 'whoosh-redis'
static_configs:
- targets: ['redis_exporter:9121']
- job_name: 'node-exporter'
static_configs:
- targets: ['node_exporter:9100']
EOF
# Create Grafana datasource
mkdir -p monitoring/grafana/datasources
cat > monitoring/grafana/datasources/prometheus.yml << EOF
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://whoosh_prometheus:9090
isDefault: true
EOF
success "Monitoring setup completed"
}
# Function to cleanup old deployments
cleanup() {
log "Cleaning up old deployments..."
# Remove old containers
docker container prune -f
# Remove old images
docker image prune -f
# Remove old volumes (careful!)
if [[ "${CLEANUP_VOLUMES:-false}" == "true" ]]; then
warning "Cleaning up old volumes..."
docker volume prune -f
fi
success "Cleanup completed"
}
# Function to show deployment status
show_status() {
log "Deployment Status:"
echo "===================="
if [[ "$SWARM_MODE" == "true" ]]; then
docker stack services ${PROJECT_NAME}
else
docker-compose -f $COMPOSE_FILE ps
fi
echo
log "Application URLs:"
echo "Frontend: http://localhost:3000"
echo "Backend API: http://localhost:8087"
echo "Prometheus: http://localhost:9090"
echo "Grafana: http://localhost:3001"
echo
log "Logs:"
echo "Backend: docker logs whoosh_backend_prod"
echo "Frontend: docker logs whoosh_frontend_prod"
echo "Database: docker logs whoosh_postgres_prod"
}
# Main deployment flow
main() {
log "Starting WHOOSH Production Deployment"
echo "======================================"
case "${1:-deploy}" in
"check")
check_prerequisites
;;
"secrets")
setup_secrets
;;
"build")
build_and_push
;;
"backup")
backup_database
;;
"deploy")
check_prerequisites
setup_secrets
backup_database
build_and_push
setup_monitoring
deploy_application
run_health_checks
show_status
success "WHOOSH deployment completed successfully!"
;;
"status")
show_status
;;
"cleanup")
cleanup
;;
"rollback")
log "Rolling back to previous deployment..."
if [[ "$SWARM_MODE" == "true" ]]; then
docker service update --rollback ${PROJECT_NAME}_whoosh_backend
docker service update --rollback ${PROJECT_NAME}_whoosh_frontend
else
docker-compose -f $COMPOSE_FILE down
# Would need previous image tags for proper rollback
warning "Manual rollback required for compose mode"
fi
;;
*)
echo "Usage: $0 {check|secrets|build|backup|deploy|status|cleanup|rollback}"
echo " check - Check prerequisites"
echo " secrets - Setup production secrets"
echo " build - Build and push images"
echo " backup - Backup database"
echo " deploy - Full deployment (default)"
echo " status - Show deployment status"
echo " cleanup - Clean up old resources"
echo " rollback- Rollback to previous version"
exit 1
;;
esac
}
# Run main function with all arguments
main "$@"