#!/bin/bash # BZZZ SLURP Distributed Context Distribution - Deployment Script # This script automates the deployment of the SLURP system to various environments set -euo pipefail # Configuration SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$(dirname "$SCRIPT_DIR")" DEPLOYMENT_DIR="${PROJECT_DIR}/deployments" VERSION="${VERSION:-latest}" ENVIRONMENT="${ENVIRONMENT:-development}" REGISTRY="${REGISTRY:-registry.home.deepblack.cloud}" NAMESPACE="${NAMESPACE:-bzzz-slurp}" KUBECONFIG="${KUBECONFIG:-}" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Logging functions log() { echo -e "${BLUE}[INFO]${NC} $1" >&2 } warn() { echo -e "${YELLOW}[WARN]${NC} $1" >&2 } error() { echo -e "${RED}[ERROR]${NC} $1" >&2 exit 1 } success() { echo -e "${GREEN}[SUCCESS]${NC} $1" >&2 } # Help function show_help() { cat << EOF BZZZ SLURP Deployment Script Usage: $0 [OPTIONS] COMMAND Commands: build Build Docker images push Push images to registry deploy Deploy to Kubernetes dev Start development environment test Run deployment tests cleanup Clean up resources status Show deployment status logs Show service logs help Show this help Options: -e, --environment Environment (development, staging, production) [default: development] -v, --version Image version/tag [default: latest] -r, --registry Docker registry [default: registry.home.deepblack.cloud] -n, --namespace Kubernetes namespace [default: bzzz-slurp] -c, --kubeconfig Kubeconfig file path -f, --force Force operation without confirmation -h, --help Show help Examples: $0 build # Build images for development $0 -e production deploy # Deploy to production $0 -v v1.2.3 push # Push specific version $0 dev # Start development environment $0 cleanup -e staging # Cleanup staging environment EOF } # Parse command line arguments parse_args() { while [[ $# -gt 0 ]]; do case $1 in -e|--environment) ENVIRONMENT="$2" shift 2 ;; -v|--version) VERSION="$2" shift 2 ;; -r|--registry) REGISTRY="$2" shift 2 ;; -n|--namespace) NAMESPACE="$2" shift 2 ;; -c|--kubeconfig) KUBECONFIG="$2" shift 2 ;; -f|--force) FORCE=true shift ;; -h|--help) show_help exit 0 ;; build|push|deploy|dev|test|cleanup|status|logs|help) COMMAND="$1" shift ;; *) error "Unknown option: $1" ;; esac done if [[ -z "${COMMAND:-}" ]]; then error "No command specified. Use --help for usage information." fi } # Environment validation validate_environment() { case $ENVIRONMENT in development|staging|production) log "Environment: $ENVIRONMENT" ;; *) error "Invalid environment: $ENVIRONMENT. Must be development, staging, or production." ;; esac } # Check prerequisites check_prerequisites() { local missing=() if ! command -v docker &> /dev/null; then missing+=("docker") fi if ! command -v kubectl &> /dev/null; then missing+=("kubectl") fi if ! command -v helm &> /dev/null && [[ "$COMMAND" == "deploy" ]]; then missing+=("helm") fi if [[ ${#missing[@]} -ne 0 ]]; then error "Missing required tools: ${missing[*]}" fi # Check Docker daemon if ! docker info &> /dev/null; then error "Docker daemon is not running" fi # Check Kubernetes connectivity for relevant commands if [[ "$COMMAND" =~ ^(deploy|status|logs|cleanup)$ ]]; then if [[ -n "$KUBECONFIG" ]]; then export KUBECONFIG="$KUBECONFIG" fi if ! kubectl cluster-info &> /dev/null; then error "Cannot connect to Kubernetes cluster" fi log "Connected to Kubernetes cluster: $(kubectl config current-context)" fi } # Build Docker images build_images() { log "Building SLURP Docker images..." local images=( "slurp-coordinator:Dockerfile.slurp-coordinator" "slurp-distributor:Dockerfile.slurp-distributor" ) cd "$PROJECT_DIR" for image_def in "${images[@]}"; do IFS=':' read -r image dockerfile <<< "$image_def" local full_image="$REGISTRY/bzzz/$image:$VERSION" log "Building $full_image..." docker build \ -f "$DEPLOYMENT_DIR/docker/$dockerfile" \ -t "$full_image" \ --build-arg VERSION="$VERSION" \ --build-arg BUILD_DATE="$(date -u +'%Y-%m-%dT%H:%M:%SZ')" \ --build-arg VCS_REF="$(git rev-parse --short HEAD 2>/dev/null || echo 'unknown')" \ . success "Built $full_image" done } # Push images to registry push_images() { log "Pushing images to registry..." local images=( "$REGISTRY/bzzz/slurp-coordinator:$VERSION" "$REGISTRY/bzzz/slurp-distributor:$VERSION" ) for image in "${images[@]}"; do log "Pushing $image..." docker push "$image" success "Pushed $image" done } # Deploy to Kubernetes deploy_k8s() { log "Deploying SLURP to Kubernetes environment: $ENVIRONMENT" # Create namespace if it doesn't exist if ! kubectl get namespace "$NAMESPACE" &> /dev/null; then log "Creating namespace $NAMESPACE..." kubectl apply -f "$DEPLOYMENT_DIR/kubernetes/namespace.yaml" fi # Apply configurations log "Applying configuration..." envsubst < "$DEPLOYMENT_DIR/kubernetes/configmap.yaml" | kubectl apply -f - # Deploy coordinator log "Deploying coordinator..." envsubst < "$DEPLOYMENT_DIR/kubernetes/coordinator-deployment.yaml" | kubectl apply -f - # Deploy distributors log "Deploying distributors..." envsubst < "$DEPLOYMENT_DIR/kubernetes/distributor-statefulset.yaml" | kubectl apply -f - # Apply ingress if [[ "$ENVIRONMENT" != "development" ]]; then log "Applying ingress..." envsubst < "$DEPLOYMENT_DIR/kubernetes/ingress.yaml" | kubectl apply -f - fi # Wait for deployment to be ready log "Waiting for deployments to be ready..." kubectl wait --for=condition=available --timeout=300s deployment/slurp-coordinator -n "$NAMESPACE" kubectl wait --for=condition=ready --timeout=300s statefulset/slurp-distributor -n "$NAMESPACE" success "Deployment completed successfully!" # Show status kubectl get pods -n "$NAMESPACE" } # Start development environment start_dev() { log "Starting development environment..." cd "$DEPLOYMENT_DIR/docker" # Build images if they don't exist if ! docker images | grep -q "slurp-coordinator"; then log "Building development images..." REGISTRY="localhost" VERSION="dev" build_images fi # Start services log "Starting Docker Compose services..." docker-compose up -d # Wait for services log "Waiting for services to be ready..." sleep 10 # Show status docker-compose ps success "Development environment is ready!" log "Services available at:" log " - Coordinator API: http://localhost:8080" log " - Distributor APIs: http://localhost:8081, http://localhost:8082, http://localhost:8083" log " - Prometheus: http://localhost:9090" log " - Grafana: http://localhost:3000 (admin/admin123)" log " - Jaeger: http://localhost:16686" log " - Kibana: http://localhost:5601" } # Run tests run_tests() { log "Running deployment tests..." case $ENVIRONMENT in development) test_docker_compose ;; staging|production) test_kubernetes ;; esac } # Test Docker Compose deployment test_docker_compose() { local services=("slurp-coordinator" "slurp-distributor-01" "slurp-distributor-02" "slurp-distributor-03") for service in "${services[@]}"; do log "Testing $service..." # Check if container is running if ! docker-compose ps | grep -q "$service.*Up"; then error "$service is not running" fi # Check health endpoint (assuming port 8080 for coordinator, 8081+ for distributors) local port=8080 if [[ "$service" =~ distributor-0[1-9] ]]; then port=$((8080 + ${service: -1})) fi if ! curl -f -s "http://localhost:$port/health" > /dev/null; then error "$service health check failed" fi success "$service is healthy" done } # Test Kubernetes deployment test_kubernetes() { log "Testing Kubernetes deployment..." # Check pod status if ! kubectl get pods -n "$NAMESPACE" | grep -q "Running"; then error "No running pods found" fi # Test coordinator endpoint log "Testing coordinator endpoint..." kubectl port-forward -n "$NAMESPACE" service/slurp-coordinator 8080:8080 & local pf_pid=$! sleep 5 if curl -f -s "http://localhost:8080/health" > /dev/null; then success "Coordinator health check passed" else error "Coordinator health check failed" fi kill $pf_pid 2>/dev/null || true # Test distributor endpoints log "Testing distributor endpoints..." kubectl port-forward -n "$NAMESPACE" service/slurp-distributor 8080:8080 & pf_pid=$! sleep 5 if curl -f -s "http://localhost:8080/health" > /dev/null; then success "Distributor health check passed" else error "Distributor health check failed" fi kill $pf_pid 2>/dev/null || true success "All tests passed!" } # Show deployment status show_status() { case $ENVIRONMENT in development) log "Docker Compose Status:" cd "$DEPLOYMENT_DIR/docker" docker-compose ps ;; staging|production) log "Kubernetes Status:" kubectl get all -n "$NAMESPACE" echo log "Pod Details:" kubectl describe pods -n "$NAMESPACE" ;; esac } # Show service logs show_logs() { case $ENVIRONMENT in development) cd "$DEPLOYMENT_DIR/docker" docker-compose logs -f ;; staging|production) kubectl logs -f -l app.kubernetes.io/part-of=bzzz-slurp -n "$NAMESPACE" ;; esac } # Cleanup resources cleanup() { if [[ "${FORCE:-}" != "true" ]]; then read -p "Are you sure you want to cleanup $ENVIRONMENT environment? (y/N): " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then log "Cleanup cancelled" exit 0 fi fi case $ENVIRONMENT in development) log "Stopping Docker Compose services..." cd "$DEPLOYMENT_DIR/docker" docker-compose down -v docker-compose rm -f success "Development environment cleaned up" ;; staging|production) log "Deleting Kubernetes resources..." kubectl delete namespace "$NAMESPACE" --ignore-not-found=true success "Kubernetes resources cleaned up" ;; esac } # Export environment variables for envsubst export_env_vars() { export REGISTRY export VERSION export NAMESPACE export ENVIRONMENT } # Main function main() { parse_args "$@" validate_environment check_prerequisites export_env_vars case $COMMAND in build) build_images ;; push) push_images ;; deploy) if [[ "$ENVIRONMENT" == "development" ]]; then error "Use 'dev' command for development deployment" fi deploy_k8s ;; dev) start_dev ;; test) run_tests ;; status) show_status ;; logs) show_logs ;; cleanup) cleanup ;; help) show_help ;; *) error "Unknown command: $COMMAND" ;; esac } # Run main function with all arguments main "$@"