Initial commit: Terraform infrastructure, pipelines, docs and scripts
This commit is contained in:
Executable
+37
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env bash
|
||||
# ===============================================================================================================
|
||||
# deploy-frontend-s3.sh - Sincroniza el frontend React con S3
|
||||
# Descripción:
|
||||
# Sube la carpeta build/ al bucket S3 designado para el sitio estático.
|
||||
# La invalidación de CloudFront se realiza en el pipeline (paso 7).
|
||||
#
|
||||
# Uso:
|
||||
# S3_FRONTEND_BUCKET=ccsoft-proyectosacc-frontend bash deploy-frontend-s3.sh
|
||||
#
|
||||
# Autor: Área de Tecnología y Desarrollo - CCsoft
|
||||
# ===============================================================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# -------------------------------------------------------------------------------
|
||||
# Validación de variables
|
||||
# -------------------------------------------------------------------------------
|
||||
S3_FRONTEND_BUCKET="${S3_FRONTEND_BUCKET:-}"
|
||||
BUILD_DIR="${BUILD_DIR:-build}"
|
||||
|
||||
if [[ -z "$S3_FRONTEND_BUCKET" ]]; then
|
||||
echo "[ERROR] Variable S3_FRONTEND_BUCKET no definida" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -d "$BUILD_DIR" ]]; then
|
||||
echo "[ERROR] Directorio ${BUILD_DIR} no encontrado" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# -------------------------------------------------------------------------------
|
||||
# Sincronización a S3
|
||||
# -------------------------------------------------------------------------------
|
||||
echo "[INFO] Sincronizando ${BUILD_DIR}/ a s3://${S3_FRONTEND_BUCKET}/ ..."
|
||||
aws s3 sync "${BUILD_DIR}/" "s3://${S3_FRONTEND_BUCKET}/" --delete
|
||||
echo "[INFO] Sincronización completada exitosamente"
|
||||
Executable
+149
@@ -0,0 +1,149 @@
|
||||
#!/usr/bin/env bash
|
||||
# ===============================================================================================================
|
||||
# deploy.sh - Script de despliegue de la API backend en EC2
|
||||
# Descripción:
|
||||
# Despliega el artefacto .jar de la API en la EC2, gestiona backups,
|
||||
# configura el servicio systemd y ejecuta health check.
|
||||
#
|
||||
# Uso:
|
||||
# bash /home/thoth/deploy/setup/deploy.sh
|
||||
#
|
||||
# Autor: Área de Tecnología y Desarrollo - CCsoft
|
||||
# ===============================================================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# -------------------------------------------------------------------------------
|
||||
# Configuración
|
||||
# -------------------------------------------------------------------------------
|
||||
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 LOGS_DIR="/var/log/proyectosacc/${APP_NAME}"
|
||||
readonly SYSTEMD_SERVICE="${APP_NAME}.service"
|
||||
readonly HEALTH_ENDPOINT="http://localhost:8080/actuator/health"
|
||||
readonly MAX_RETRIES=30
|
||||
readonly RETRY_INTERVAL=2
|
||||
|
||||
# -------------------------------------------------------------------------------
|
||||
# Colores y logging
|
||||
# -------------------------------------------------------------------------------
|
||||
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; }
|
||||
|
||||
# -------------------------------------------------------------------------------
|
||||
# Funciones
|
||||
# -------------------------------------------------------------------------------
|
||||
ensure_directories() {
|
||||
_log_step "Verificando directorios de despliegue"
|
||||
mkdir -p "${CURRENT_DIR}" "${BACKUP_DIR}" "${ARTIFACTS_DIR}/pids" "${LOGS_DIR}"
|
||||
chown -R osiris:osiris "${ARTIFACTS_DIR}"
|
||||
chmod 750 "${ARTIFACTS_DIR}"
|
||||
_log_info "Directorios listos"
|
||||
}
|
||||
|
||||
backup_current_version() {
|
||||
_log_step "Creando backup de la versión actual"
|
||||
local current_jar="${CURRENT_DIR}/${APP_NAME}.jar"
|
||||
if [[ -f "$current_jar" ]]; then
|
||||
local timestamp
|
||||
timestamp=$(date +%Y%m%d_%H%M%S)
|
||||
local backup_name="${BACKUP_DIR}/${APP_NAME}-${timestamp}.jar"
|
||||
cp "$current_jar" "$backup_name"
|
||||
_log_info "Backup creado: ${backup_name}"
|
||||
else
|
||||
_log_warn "No hay versión actual para hacer backup"
|
||||
fi
|
||||
}
|
||||
|
||||
stop_service() {
|
||||
_log_step "Deteniendo servicio actual"
|
||||
if systemctl is-active --quiet "${SYSTEMD_SERVICE}"; then
|
||||
sudo systemctl stop "${SYSTEMD_SERVICE}" || true
|
||||
_log_info "Servicio detenido"
|
||||
else
|
||||
_log_warn "El servicio no estaba activo"
|
||||
fi
|
||||
}
|
||||
|
||||
create_systemd_service() {
|
||||
_log_step "Configurando servicio systemd"
|
||||
sudo tee "/etc/systemd/system/${SYSTEMD_SERVICE}" > /dev/null <<EOF
|
||||
[Unit]
|
||||
Description=Proyecto SACC App Service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=osiris
|
||||
Group=osiris
|
||||
WorkingDirectory=${CURRENT_DIR}
|
||||
ExecStart=/usr/bin/java -jar ${CURRENT_DIR}/${APP_NAME}.jar
|
||||
SuccessExitStatus=143
|
||||
Restart=on-failure
|
||||
RestartSec=10
|
||||
StandardOutput=append:${LOGS_DIR}/${APP_NAME}-service.log
|
||||
StandardError=append:${LOGS_DIR}/${APP_NAME}-service.log
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
sudo systemctl daemon-reload
|
||||
_log_info "Servicio systemd actualizado"
|
||||
}
|
||||
|
||||
start_service() {
|
||||
_log_step "Iniciando servicio"
|
||||
sudo systemctl enable "${SYSTEMD_SERVICE}" || true
|
||||
sudo systemctl start "${SYSTEMD_SERVICE}"
|
||||
_log_info "Servicio iniciado"
|
||||
}
|
||||
|
||||
health_check() {
|
||||
_log_step "Ejecutando health check"
|
||||
local attempt=1
|
||||
while [[ $attempt -le $MAX_RETRIES ]]; do
|
||||
_log_info "Intento ${attempt}/${MAX_RETRIES}..."
|
||||
if curl -sf "${HEALTH_ENDPOINT}" | grep -q '"status":"UP"'; then
|
||||
_log_info "Health check PASÓ"
|
||||
return 0
|
||||
fi
|
||||
sleep "${RETRY_INTERVAL}"
|
||||
((attempt++))
|
||||
done
|
||||
_fail "Health check FALLÓ después de ${MAX_RETRIES} intentos"
|
||||
}
|
||||
|
||||
save_pid() {
|
||||
local pid
|
||||
pid=$(systemctl show -p MainPID --value "${SYSTEMD_SERVICE}")
|
||||
echo "$pid" > "${ARTIFACTS_DIR}/pids/${APP_NAME}.pid"
|
||||
_log_info "PID guardado: ${pid}"
|
||||
}
|
||||
|
||||
# -------------------------------------------------------------------------------
|
||||
# Main
|
||||
# -------------------------------------------------------------------------------
|
||||
main() {
|
||||
_log_step "Iniciando despliegue de ${APP_NAME}"
|
||||
ensure_directories
|
||||
backup_current_version
|
||||
stop_service
|
||||
create_systemd_service
|
||||
start_service
|
||||
health_check
|
||||
save_pid
|
||||
_log_info "Despliegue de ${APP_NAME} completado exitosamente"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Executable
+61
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env bash
|
||||
# ===============================================================================================================
|
||||
# health-check.sh - Verifica que la API backend esté saludable
|
||||
# Descripción:
|
||||
# Realiza peticiones al endpoint de salud de la API con reintentos.
|
||||
# Puede ejecutarse desde la EC2 localmente o desde el pipeline.
|
||||
#
|
||||
# Uso:
|
||||
# HEALTH_URL=http://localhost:8080/actuator/health bash health-check.sh
|
||||
#
|
||||
# Autor: Área de Tecnología y Desarrollo - CCsoft
|
||||
# ===============================================================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# -------------------------------------------------------------------------------
|
||||
# Configuración
|
||||
# -------------------------------------------------------------------------------
|
||||
HEALTH_URL="${HEALTH_URL:-http://localhost:8080/actuator/health}"
|
||||
MAX_RETRIES="${MAX_RETRIES:-30}"
|
||||
RETRY_INTERVAL="${RETRY_INTERVAL:-2}"
|
||||
|
||||
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}"; }
|
||||
|
||||
# -------------------------------------------------------------------------------
|
||||
# Health Check
|
||||
# -------------------------------------------------------------------------------
|
||||
main() {
|
||||
_log_step "Health Check: ${HEALTH_URL}"
|
||||
|
||||
local attempt=1
|
||||
while [[ $attempt -le $MAX_RETRIES ]]; do
|
||||
_log_info "Intento ${attempt}/${MAX_RETRIES}..."
|
||||
|
||||
if curl -sf "${HEALTH_URL}" | grep -q '"status":"UP"'; then
|
||||
_log_info "Health check PASÓ - API saludable"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ $attempt -lt $MAX_RETRIES ]]; then
|
||||
_log_warn "API no responde aún, reintentando en ${RETRY_INTERVAL}s..."
|
||||
sleep "${RETRY_INTERVAL}"
|
||||
fi
|
||||
|
||||
((attempt++))
|
||||
done
|
||||
|
||||
_log_error "Health check FALLÓ después de ${MAX_RETRIES} intentos"
|
||||
return 1
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Executable
+47
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env bash
|
||||
# ===============================================================================================================
|
||||
# notify-telegram.sh - Envía notificaciones a Telegram
|
||||
# Descripción:
|
||||
# Wrapper simple para enviar mensajes a un chat de Telegram.
|
||||
# Requiere TELEGRAM_BOT_TOKEN y TELEGRAM_CHAT_ID como variables
|
||||
# de entorno.
|
||||
#
|
||||
# Uso:
|
||||
# bash notify-telegram.sh "Mensaje de prueba"
|
||||
#
|
||||
# Autor: Área de Tecnología y Desarrollo - CCsoft
|
||||
# ===============================================================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# -------------------------------------------------------------------------------
|
||||
# Validación
|
||||
# -------------------------------------------------------------------------------
|
||||
TELEGRAM_BOT_TOKEN="${TELEGRAM_BOT_TOKEN:-}"
|
||||
TELEGRAM_CHAT_ID="${TELEGRAM_CHAT_ID:-}"
|
||||
MESSAGE="${1:-}"
|
||||
|
||||
if [[ -z "$TELEGRAM_BOT_TOKEN" ]]; then
|
||||
echo "[ERROR] TELEGRAM_BOT_TOKEN no definido" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$TELEGRAM_CHAT_ID" ]]; then
|
||||
echo "[ERROR] TELEGRAM_CHAT_ID no definido" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$MESSAGE" ]]; then
|
||||
echo "[ERROR] Debe proporcionar un mensaje como primer argumento" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# -------------------------------------------------------------------------------
|
||||
# Envío de mensaje
|
||||
# -------------------------------------------------------------------------------
|
||||
curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
|
||||
-d "chat_id=${TELEGRAM_CHAT_ID}" \
|
||||
-d "text=${MESSAGE}" \
|
||||
-d "parse_mode=Markdown" > /dev/null
|
||||
|
||||
echo "[INFO] Mensaje enviado a Telegram"
|
||||
Executable
+163
@@ -0,0 +1,163 @@
|
||||
#!/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 "$@"
|
||||
Reference in New Issue
Block a user