257 lines
6.1 KiB
Bash
257 lines
6.1 KiB
Bash
|
|
#!/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}"
|
||
|
|
|