#!/bin/bash # AI Tax Agent Infrastructure Deployment Script # Supports multiple environments: local, development, production set -e # 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_info() { echo -e "${BLUE}ℹ️ $1${NC}" } log_success() { echo -e "${GREEN}✅ $1${NC}" } log_warning() { echo -e "${YELLOW}⚠️ $1${NC}" } log_error() { echo -e "${RED}❌ $1${NC}" } # Script directory SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" INFRA_DIR="$(dirname "$SCRIPT_DIR")" PROJECT_ROOT="$(dirname "$INFRA_DIR")" # Usage usage() { cat << EOF Usage: $0 [options] Environments: local - Local development (localhost) development - Development server (dev.harkon.co.uk) production - Production server (harkon.co.uk) Stacks: all - Deploy all stacks infrastructure - Core infrastructure (Vault, MinIO, DBs, Redis, NATS) monitoring - Monitoring stack (Prometheus, Grafana, Loki) services - Application services external - External services (Traefik, Authentik, Gitea) down - Stop and remove all stacks Options: --build - Build images before deploying --pull - Pull images before deploying --force - Force recreate containers Examples: $0 local all $0 production infrastructure $0 development services --build $0 production down EOF exit 1 } # Check arguments if [ $# -lt 2 ]; then usage fi ENVIRONMENT=$1 STACK=$2 shift 2 # Validate environment case $ENVIRONMENT in local|development|production) ;; *) log_error "Invalid environment: $ENVIRONMENT" usage ;; esac # Paths ENV_FILE="$INFRA_DIR/environments/$ENVIRONMENT/.env" BASE_DIR="$INFRA_DIR/base" # Check if environment file exists if [ ! -f "$ENV_FILE" ]; then log_error "Environment file not found: $ENV_FILE" log_info "Copy from template: cp $INFRA_DIR/environments/$ENVIRONMENT/.env.example $ENV_FILE" exit 1 fi # Load environment variables set -a source "$ENV_FILE" set +a log_info "Deploying AI Tax Agent Infrastructure" echo " Environment: $ENVIRONMENT" echo " Stack: $STACK" echo " Env File: $ENV_FILE" echo "" # Docker Compose command builder compose_cmd() { local file=$1 shift # For local environment, use the new unified compose.yaml if [ "$ENVIRONMENT" = "local" ] && [ "$file" = "all" ]; then docker compose -f "$INFRA_DIR/compose/compose.yaml" -f "$INFRA_DIR/compose/compose.override.yaml" --env-file "$ENV_FILE" --project-name "ai-tax-agent" "$@" return fi # For other environments or specific stacks, keep existing behavior for now # or adapt as needed. The goal is to eventually unify everything. # If file is 'infrastructure.yaml', etc., we might still want to use base/ # directly for production to avoid local overrides. docker compose -f "$BASE_DIR/$file" --env-file "$ENV_FILE" --project-name "ai-tax-agent-$ENVIRONMENT" "$@" } # Deploy infrastructure stack deploy_infrastructure() { log_info "Deploying infrastructure stack..." compose_cmd "infrastructure.yaml" up -d "$@" log_success "Infrastructure stack deployed" } # Deploy monitoring stack deploy_monitoring() { log_info "Deploying monitoring stack..." compose_cmd "monitoring.yaml" up -d "$@" log_success "Monitoring stack deployed" } # Deploy services stack deploy_services() { log_info "Deploying services stack..." compose_cmd "services.yaml" up -d "$@" log_success "Services stack deployed" } # Deploy external services stack deploy_external() { log_info "Deploying external services stack..." if [ "$ENVIRONMENT" = "production" ] || [ "$ENVIRONMENT" = "development" ]; then log_warning "External services (Traefik, Authentik, Gitea) may already exist on this server" read -p "Do you want to deploy external services? (y/N) " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then log_info "Skipping external services" return fi fi compose_cmd "external.yaml" up -d "$@" log_success "External services stack deployed" } # Stop all stacks stop_all() { log_info "Stopping all stacks..." if [ -f "$BASE_DIR/services.yaml" ]; then compose_cmd "services.yaml" down fi if [ -f "$BASE_DIR/monitoring.yaml" ]; then compose_cmd "monitoring.yaml" down fi if [ -f "$BASE_DIR/infrastructure.yaml" ]; then compose_cmd "infrastructure.yaml" down fi if [ -f "$BASE_DIR/external.yaml" ]; then log_warning "External services not stopped (may be shared)" fi log_success "All stacks stopped" } # Deploy all stacks deploy_all() { log_info "Deploying all stacks..." # Check if networks exist if ! docker network inspect apa-frontend >/dev/null 2>&1; then log_warning "Network 'apa-frontend' does not exist. Creating..." docker network create --opt com.docker.network.driver.mtu=1400 apa-frontend fi if ! docker network inspect apa-backend >/dev/null 2>&1; then log_warning "Network 'apa-backend' does not exist. Creating..." docker network create --opt com.docker.network.driver.mtu=1400 apa-backend fi # Deploy in order local unified_compose="$INFRA_DIR/environments/$ENVIRONMENT/compose.yaml" if [ "$ENVIRONMENT" = "local" ]; then log_info "Deploying unified stack for local environment..." compose_cmd "all" up -d "$@" elif [ -f "$unified_compose" ]; then log_info "Deploying unified stack for $ENVIRONMENT environment..." docker compose -f "$unified_compose" --env-file "$ENV_FILE" --project-name "ai-tax-agent-$ENVIRONMENT" up -d "$@" else deploy_infrastructure "$@" sleep 5 deploy_monitoring "$@" sleep 5 deploy_services "$@" fi log_success "All stacks deployed successfully!" echo "" log_info "Access your services:" echo " - Grafana: https://grafana.$DOMAIN" echo " - Prometheus: https://prometheus.$DOMAIN" echo " - Vault: https://vault.$DOMAIN" echo " - MinIO: https://minio.$DOMAIN" echo " - UI Review: https://ui-review.$DOMAIN" } # Main deployment logic case $STACK in all) deploy_all "$@" ;; infrastructure) deploy_infrastructure "$@" ;; monitoring) deploy_monitoring "$@" ;; services) deploy_services "$@" ;; external) deploy_external "$@" ;; down) stop_all ;; *) log_error "Invalid stack: $STACK" usage ;; esac log_success "Deployment complete!"