#!/bin/bash # # The Order - Automated Deployment Script # Main orchestrator for deployment automation # set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "${SCRIPT_DIR}/config.sh" # Usage usage() { cat << EOF Usage: $0 [OPTIONS] [PHASES...] Deploy The Order application to Azure/Kubernetes. OPTIONS: -e, --environment ENV Environment (dev, stage, prod) [default: dev] -p, --phase PHASE Run specific phase (1-15) -a, --all Run all phases -s, --skip PHASE Skip specific phase -c, --continue Continue from last saved state --auto-apply Auto-apply Terraform changes (default: requires review) --skip-build Skip build steps --dry-run Show what would be done without executing -h, --help Show this help message PHASES: 1 - Prerequisites 2 - Azure Infrastructure Setup 3 - Entra ID Configuration (manual) 4 - Database & Storage Setup 5 - Container Registry Setup 6 - Application Build & Package 7 - Database Migrations 8 - Secrets Configuration (manual) 9 - Infrastructure Services Deployment 10 - Backend Services Deployment 11 - Frontend Applications Deployment 12 - Networking & Gateways 13 - Monitoring & Observability 14 - Testing & Validation 15 - Production Hardening EXAMPLES: # Deploy all phases for dev environment $0 --all --environment dev # Deploy specific phases $0 --phase 1 --phase 2 --phase 6 # Continue from last state $0 --continue # Deploy with auto-apply $0 --all --auto-apply EOF } # Parse arguments PHASES=() SKIP_PHASES=() RUN_ALL=false CONTINUE=false DRY_RUN=false while [[ $# -gt 0 ]]; do case $1 in -e|--environment) ENVIRONMENT="$2" export ENVIRONMENT shift 2 ;; -p|--phase) PHASES+=("$2") shift 2 ;; -a|--all) RUN_ALL=true shift ;; -s|--skip) SKIP_PHASES+=("$2") shift 2 ;; -c|--continue) CONTINUE=true shift ;; --auto-apply) export AUTO_APPLY=true shift ;; --skip-build) export SKIP_BUILD=true shift ;; --dry-run) DRY_RUN=true shift ;; -h|--help) usage exit 0 ;; *) echo "Unknown option: $1" usage exit 1 ;; esac done # Load state if continuing if [ "${CONTINUE}" = "true" ]; then STATE=$(load_state) LAST_PHASE=$(echo "${STATE}" | jq -r '.phase' 2>/dev/null || echo "none") log_info "Continuing from phase: ${LAST_PHASE}" fi # Phase scripts mapping declare -A PHASE_SCRIPTS=( ["1"]="phase1-prerequisites.sh" ["2"]="phase2-azure-infrastructure.sh" ["3"]="phase3-entra-id.sh" ["4"]="phase4-database-storage.sh" ["5"]="phase5-container-registry.sh" ["6"]="phase6-build-package.sh" ["7"]="phase7-database-migrations.sh" ["8"]="phase8-secrets.sh" ["9"]="phase9-infrastructure-services.sh" ["10"]="phase10-backend-services.sh" ["11"]="phase11-frontend-apps.sh" ["12"]="phase12-networking.sh" ["13"]="phase13-monitoring.sh" ["14"]="phase14-testing.sh" ["15"]="phase15-production.sh" ) # Determine phases to run PHASES_TO_RUN=() if [ "${RUN_ALL}" = "true" ]; then PHASES_TO_RUN=({1..15}) elif [ ${#PHASES[@]} -gt 0 ]; then PHASES_TO_RUN=("${PHASES[@]}") elif [ "${CONTINUE}" = "true" ]; then # Continue from last phase if [ "${LAST_PHASE}" != "none" ] && [ "${LAST_PHASE}" != "complete" ]; then LAST_PHASE_NUM=$(echo "${LAST_PHASE}" | sed 's/phase//') for i in $(seq "${LAST_PHASE_NUM}" 15); do PHASES_TO_RUN+=("$i") done else log_info "No previous state found, starting from phase 1" PHASES_TO_RUN=({1..15}) fi else log_error "No phases specified. Use --all, --phase, or --continue" usage exit 1 fi # Filter out skipped phases FILTERED_PHASES=() for phase in "${PHASES_TO_RUN[@]}"; do SKIP=false for skip in "${SKIP_PHASES[@]}"; do if [ "${phase}" = "${skip}" ]; then SKIP=true break fi done if [ "${SKIP}" = "false" ]; then FILTERED_PHASES+=("${phase}") fi done # Run phases log_info "==========================================" log_info "The Order - Automated Deployment" log_info "Environment: ${ENVIRONMENT}" log_info "Phases to run: ${FILTERED_PHASES[*]}" log_info "==========================================" if [ "${DRY_RUN}" = "true" ]; then log_info "DRY RUN MODE - No changes will be made" for phase in "${FILTERED_PHASES[@]}"; do SCRIPT="${PHASE_SCRIPTS[$phase]}" if [ -n "${SCRIPT}" ]; then log_info "Would run: ${SCRIPT_DIR}/${SCRIPT}" else log_warning "No script found for phase ${phase}" fi done exit 0 fi # Execute phases FAILED_PHASES=() for phase in "${FILTERED_PHASES[@]}"; do SCRIPT="${PHASE_SCRIPTS[$phase]}" if [ -z "${SCRIPT}" ]; then log_warning "No script found for phase ${phase}, skipping..." continue fi SCRIPT_PATH="${SCRIPT_DIR}/${SCRIPT}" if [ ! -f "${SCRIPT_PATH}" ]; then log_warning "Script not found: ${SCRIPT_PATH}" log_info "Phase ${phase} may require manual steps. See deployment guide." continue fi log_info "==========================================" log_info "Executing Phase ${phase}" log_info "==========================================" if bash "${SCRIPT_PATH}"; then log_success "Phase ${phase} completed successfully" else log_error "Phase ${phase} failed" FAILED_PHASES+=("${phase}") # Ask if should continue read -p "Continue with next phase? (y/N): " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then log_error "Deployment stopped by user" break fi fi done # Summary log_info "==========================================" log_info "Deployment Summary" log_info "==========================================" if [ ${#FAILED_PHASES[@]} -eq 0 ]; then log_success "All phases completed successfully!" save_state "complete" "all" else log_error "Failed phases: ${FAILED_PHASES[*]}" log_info "Review logs at: ${LOG_FILE}" exit 1 fi log_info "Deployment log: ${LOG_FILE}" log_info "State file: ${STATE_FILE}"