#!/usr/bin/env bash # =============================================================================================================== # rollback.sh - Rollback de la API backend y/o frontend de proyectosacc # Descripción: # Restaura la versión anterior de la API desde backup local en la EC2. # Opcionalmente puede restaurar el frontend en S3 usando versionamiento. # # Uso: # bash /home/thoth/deploy/scripts/rollback.sh [api|frontend|both] # # Autor: Área de Tecnología y Desarrollo - CCsoft # =============================================================================================================== set -euo pipefail # ------------------------------------------------------------------------------- # Configuración # ------------------------------------------------------------------------------- ROLLBACK_TARGET="${1:-api}" readonly APP_NAME="proyectosacc-app" readonly ARTIFACTS_DIR="/home/thoth/deploy/artifacts" readonly CURRENT_DIR="${ARTIFACTS_DIR}/current" readonly BACKUP_DIR="${ARTIFACTS_DIR}/backup" readonly SYSTEMD_SERVICE="${APP_NAME}.service" readonly CLR_RED='\033[0;31m' readonly CLR_GREEN='\033[0;32m' readonly CLR_YELLOW='\033[1;33m' readonly CLR_BLUE='\033[0;34m' readonly CLR_NC='\033[0m' _log_info() { echo -e "${CLR_GREEN}[INFO]${CLR_NC} $*"; } _log_warn() { echo -e "${CLR_YELLOW}[WARN]${CLR_NC} $*" >&2; } _log_error() { echo -e "${CLR_RED}[ERROR]${CLR_NC} $*" >&2; } _log_step() { echo ""; echo -e "${CLR_BLUE}==== $* ====${CLR_NC}"; } _fail() { _log_error "$*"; exit 1; } # ------------------------------------------------------------------------------- # Rollback API # ------------------------------------------------------------------------------- rollback_api() { _log_step "Iniciando rollback de la API" if [[ ! -d "$BACKUP_DIR" ]]; then _fail "Directorio de backups no encontrado: ${BACKUP_DIR}" fi local latest_backup latest_backup=$(ls -t "${BACKUP_DIR}/${APP_NAME}"-*.jar 2>/dev/null | head -n 1 || true) if [[ -z "$latest_backup" ]]; then _fail "No se encontraron backups de la API en ${BACKUP_DIR}" fi _log_info "Backup seleccionado: ${latest_backup}" # Detener servicio actual if systemctl is-active --quiet "${SYSTEMD_SERVICE}"; then sudo systemctl stop "${SYSTEMD_SERVICE}" || true _log_info "Servicio detenido" fi # Guardar versión fallida local current_jar="${CURRENT_DIR}/${APP_NAME}.jar" if [[ -f "$current_jar" ]]; then mv "$current_jar" "${current_jar}.fallo-$(date +%Y%m%d_%H%M%S)" fi # Restaurar backup cp "$latest_backup" "$current_jar" chown osiris:osiris "$current_jar" _log_info "Backup restaurado a ${current_jar}" # Reiniciar servicio sudo systemctl daemon-reload sudo systemctl start "${SYSTEMD_SERVICE}" _log_info "Servicio reiniciado con versión anterior" # Health check local attempt=1 local max_retries=30 local retry_interval=2 while [[ $attempt -le $max_retries ]]; do _log_info "Health check intento ${attempt}/${max_retries}..." if curl -sf http://localhost:8080/actuator/health | grep -q '"status":"UP"'; then _log_info "Rollback de API exitoso - API saludable" return 0 fi sleep "$retry_interval" ((attempt++)) done _fail "Rollback de API falló - Health check no pasó" } # ------------------------------------------------------------------------------- # Rollback Frontend # ------------------------------------------------------------------------------- rollback_frontend() { _log_step "Iniciando rollback del frontend en S3" local bucket="${S3_FRONTEND_BUCKET:-}" local distribution_id="${CLOUDFRONT_DISTRIBUTION_ID:-}" if [[ -z "$bucket" ]]; then _fail "Variable S3_FRONTEND_BUCKET no definida" fi _log_info "Listando versiones anteriores de index.html..." local version_id version_id=$(aws s3api list-object-versions \ --bucket "$bucket" \ --prefix index.html \ --query 'Versions[?IsLatest==`false`].VersionId' \ --output text 2>/dev/null | awk '{print $1}' || true) if [[ -z "$version_id" ]]; then _fail "No se encontró versión anterior de index.html en S3" fi aws s3api copy-object \ --bucket "$bucket" \ --copy-source "${bucket}/index.html?versionId=${version_id}" \ --key index.html _log_info "index.html restaurado a versión anterior" if [[ -n "$distribution_id" ]]; then aws cloudfront create-invalidation \ --distribution-id "$distribution_id" \ --paths "/*" _log_info "Invalidación de CloudFront creada" else _log_warn "CLOUDFRONT_DISTRIBUTION_ID no definido, omitiendo invalidación" fi } # ------------------------------------------------------------------------------- # Main # ------------------------------------------------------------------------------- main() { case "$ROLLBACK_TARGET" in api) rollback_api ;; frontend) rollback_frontend ;; both) rollback_api rollback_frontend ;; *) echo "Uso: $0 [api|frontend|both]" exit 1 ;; esac _log_info "Rollback completado" } main "$@"