#!/bin/bash # K3s Deployment Script con Tests y Smoke Tests # Uso: ./deploy.sh [all|test|build|deploy|smoke|status|clean|rollback] set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" # Colores RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # Configuración NAMESPACE="academia" DOMAIN="academia.ingeniumcodex.com" API_IMAGE="student-api:latest" FRONTEND_IMAGE="student-frontend:latest" log() { echo -e "${GREEN}[$(date +%T)]${NC} $1"; } warn() { echo -e "${YELLOW}[$(date +%T)]${NC} $1"; } err() { echo -e "${RED}[$(date +%T)]${NC} $1" >&2; exit 1; } pull_code() { log "=== Actualizando código ===" cd "$PROJECT_ROOT" git fetch origin main git reset --hard origin/main log "✓ Código actualizado" } run_tests() { log "=== Ejecutando tests ===" cd "$PROJECT_ROOT" if command -v dotnet &> /dev/null; then dotnet test tests/Domain.Tests --verbosity minimal || err "Domain tests fallaron" dotnet test tests/Application.Tests --verbosity minimal || err "Application tests fallaron" log "✓ Todos los tests pasaron" else warn "dotnet no instalado - omitiendo tests (ejecutar localmente antes del push)" fi } build_images() { log "=== Construyendo imágenes Docker (paralelo) ===" cd "$PROJECT_ROOT" sudo docker build -t "$API_IMAGE" -f deploy/docker/Dockerfile.api . & PID_API=$! sudo docker build -t "$FRONTEND_IMAGE" -f deploy/docker/Dockerfile.frontend . & PID_FE=$! wait $PID_API && log "✓ API imagen construida" || err "Error construyendo API" wait $PID_FE && log "✓ Frontend imagen construida" || err "Error construyendo Frontend" } import_images() { log "=== Importando imágenes a K3s ===" sudo sh -c "docker save $API_IMAGE | k3s ctr images import -" sudo sh -c "docker save $FRONTEND_IMAGE | k3s ctr images import -" log "✓ Imágenes importadas" } deploy_k8s() { log "=== Desplegando en K3s ===" cd "$SCRIPT_DIR" sudo kubectl apply -k . sudo kubectl rollout restart deployment/student-api deployment/student-frontend -n $NAMESPACE log "=== Esperando rollout ===" sudo kubectl rollout status deployment/student-api -n $NAMESPACE --timeout=180s sudo kubectl rollout status deployment/student-frontend -n $NAMESPACE --timeout=60s log "✓ Deploy completado" } smoke_tests() { log "=== Ejecutando smoke tests ===" sleep 10 # Health check if curl -sf https://$DOMAIN/health | grep -q '"status":"Healthy"'; then log "✓ Health check API" else err "Health check falló" fi # Frontend if curl -sf https://$DOMAIN/ | grep -q 'Sistema de Estudiantes'; then log "✓ Frontend check" else err "Frontend check falló" fi # GraphQL if curl -sf -X POST https://$DOMAIN/graphql \ -H "Content-Type: application/json" \ -d '{"query":"{ subjects { id name } }"}' | grep -q '"subjects"'; then log "✓ GraphQL check" else err "GraphQL check falló" fi # Database if curl -sf https://$DOMAIN/health | grep -q '"name":"database","status":"Healthy"'; then log "✓ Database check" else err "Database check falló" fi log "✓ Todos los smoke tests pasaron" } show_status() { log "=== Estado del cluster ===" sudo kubectl get pods -n $NAMESPACE -o wide echo "" sudo kubectl get svc -n $NAMESPACE } rollback() { warn "=== Rollback ===" sudo kubectl rollout undo deployment/student-api deployment/student-frontend -n $NAMESPACE log "✓ Rollback completado" } clean() { warn "=== Limpiando namespace $NAMESPACE ===" sudo kubectl delete namespace $NAMESPACE --ignore-not-found log "✓ Namespace eliminado" } # Main case "${1:-help}" in all) pull_code run_tests build_images import_images deploy_k8s smoke_tests show_status ;; test) run_tests ;; build) build_images import_images ;; deploy) deploy_k8s ;; smoke) smoke_tests ;; status) show_status ;; rollback) rollback ;; clean) clean ;; *) echo "Uso: $0 [all|test|build|deploy|smoke|status|rollback|clean]" echo "" echo " all - Pull, test, build, deploy y smoke tests" echo " test - Solo ejecutar tests" echo " build - Construir e importar imágenes" echo " deploy - Solo desplegar a K8s" echo " smoke - Solo ejecutar smoke tests" echo " status - Ver estado del cluster" echo " rollback - Revertir último deploy" echo " clean - Eliminar namespace" exit 0 ;; esac log "=== Completado ==="