#!/usr/bin/env bash # ============================================================================== # Help Desk — Script de Despliegue a Producción # Ecosistema Telcotronics # ============================================================================== # Convención del ecosistema (proyecto webapp Node.js): # 1. Lee servers.conf (creado desde servers.conf.example, no commiteado). # 2. Sincroniza código vía rsync hacia el servidor remoto. # 3. Instala dependencias y ejecuta setup de BD en el servidor. # 4. Solicita reinicio y supervisión a SIAX Monitor (API REST en :8080). # - No requiere sudo interactivo ni contraseñas. # - SIAX Monitor gestiona la unidad siax-app-HELPDESK.service. # 5. Verifica estado de salud y métricas de proceso vía SIAX Monitor y HTTP. # 6. Actualiza ficha del servicio en el MCP de Infraestructura (:3007). # ============================================================================== set -euo pipefail # Colores para la salida GREEN='\033[0;32m' BLUE='\033[0;34m' YELLOW='\033[1;33m' RED='\033[0;31m' CYAN='\033[0;36m' NC='\033[0m' SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" cd "$SCRIPT_DIR" APP_NAME="HELPDESK" APP_PORT="3008" MCP_SERVICE_ID="35" CONF_FILE="${SERVERS_CONF:-$SCRIPT_DIR/servers.conf}" mostrar_ayuda() { echo -e "${BLUE}Help Desk — Script de Despliegue a Producción${NC}" echo "Uso: ./desplegar.sh [opciones]" echo "" echo "Opciones:" echo " --help Muestra esta ayuda y termina." echo " --check Solo verifica estado de servidores y SIAX Monitor." echo " --skip-git Omite la advertencia de cambios locales no commiteados." echo "" echo "Configuración:" echo " Los destinos se leen de servers.conf con formato: usuario@host:puerto_ssh:ruta_remota" exit 0 } CHECK_ONLY=false SKIP_GIT=false for arg in "$@"; do case "$arg" in --help|-h) mostrar_ayuda ;; --check|-c) CHECK_ONLY=true ;; --skip-git) SKIP_GIT=true ;; *) echo -e "${RED}Opción desconocida: $arg${NC}" mostrar_ayuda ;; esac done echo -e "${BLUE}=====================================================${NC}" echo -e "${BLUE}🚀 Help Desk — Despliegue con SIAX Monitor${NC}" echo -e "${BLUE}=====================================================${NC}" # 1. Validar existencia de servers.conf if [ ! -f "$CONF_FILE" ]; then echo -e "${RED}❌ Error: Falta archivo de configuración $CONF_FILE${NC}" echo -e "${YELLOW}👉 Crea uno copiando la plantilla:${NC} cp servers.conf.example servers.conf" exit 1 fi # 2. Validar estructura del proyecto local if [ ! -f "app.js" ] || [ ! -f "package.json" ]; then echo -e "${RED}❌ Error: Ejecuta el script desde la raíz del proyecto help_desk.${NC}" exit 1 fi # 3. Advertencia de cambios sin commitear if [ "$SKIP_GIT" = false ] && command -v git >/dev/null 2>&1; then if [ -n "$(git status --porcelain 2>/dev/null || true)" ]; then echo -e "${YELLOW}⚠️ Aviso: Existen cambios locales no commiteados en Git.${NC}" echo -e " Continuando despliegue de archivos actuales..." fi fi # 4. Procesar cada servidor definido en servers.conf grep -vE '^\s*(#|$)' "$CONF_FILE" | while IFS=: read -r DESTINO PUERTO_SSH RUTA_REMOTA; do HOST="${DESTINO#*@}" PUERTO_SSH="${PUERTO_SSH:-22}" echo -e "\n${CYAN}-----------------------------------------------------${NC}" echo -e "🎯 Destino: ${YELLOW}$DESTINO${NC} (SSH :$PUERTO_SSH) -> ${YELLOW}$RUTA_REMOTA${NC}" echo -e "${CYAN}-----------------------------------------------------${NC}" # Verificación previa de conectividad SSH echo -e "${YELLOW}🔍 [1/5] Verificando conectividad SSH con $HOST...${NC}" if ! ssh -o BatchMode=yes -o ConnectTimeout=5 -o IdentitiesOnly=yes -p "$PUERTO_SSH" "$DESTINO" echo "OK" >/dev/null 2>&1; then echo -e "${RED}❌ Error: No se pudo conectar vía SSH a $DESTINO en el puerto $PUERTO_SSH.${NC}" exit 1 fi echo -e "${GREEN}✓ Conexión SSH establecida.${NC}" if [ "$CHECK_ONLY" = true ]; then echo -e "${YELLOW}Auditoría de estado actual en SIAX Monitor ($HOST:8080)...${NC}" curl -s "http://$HOST:8080/api/apps/$APP_NAME/status" || true echo "" continue fi # Sincronización de código vía rsync echo -e "${YELLOW}📡 [2/5] Sincronizando código a $RUTA_REMOTA vía rsync...${NC}" rsync -avz \ -e "ssh -o IdentitiesOnly=yes -p $PUERTO_SSH" \ --exclude 'node_modules/' \ --exclude '.git/' \ --exclude 'scratch/' \ --exclude '.env' \ --exclude 'servers.conf' \ --exclude '*.log' \ ./ "$DESTINO:$RUTA_REMOTA/" # Sincronizar .env seguro si existe localmente if [ -f .env ]; then echo -e " Sincronizando .env de configuración..." scp -o IdentitiesOnly=yes -P "$PUERTO_SSH" .env "$DESTINO:$RUTA_REMOTA/.env" fi echo -e "${GREEN}✓ Archivos sincronizados exitosamente.${NC}" # Instalación de dependencias y migraciones remotas echo -e "${YELLOW}⚙️ [3/5] Instalando dependencias y setup de BD en el servidor...${NC}" ssh -o IdentitiesOnly=yes -p "$PUERTO_SSH" "$DESTINO" "bash -s" << EOF set -e export PATH="\$HOME/.nvm/versions/node/v24.12.0/bin:/usr/local/bin:/usr/bin:\$PATH" cd "$RUTA_REMOTA" npm install --omit=dev --no-audit --no-fund node config/setup.js EOF echo -e "${GREEN}✓ Dependencias y esquema MariaDB verificados en el servidor.${NC}" # Reinicio coordinado con SIAX Monitor echo -e "${YELLOW}🔄 [4/5] Coordinando reinicio vía SIAX Monitor ($HOST:8080)...${NC}" RESTART_RES=$(curl -s -m 15 -X POST "http://$HOST:8080/api/apps/$APP_NAME/restart" || true) if echo "$RESTART_RES" | grep -q '"success":true'; then echo -e "${GREEN}✓ SIAX Monitor confirmó el reinicio exitoso de $APP_NAME.${NC}" else echo -e "${YELLOW}⚠️ SIAX Monitor restart retornó:${NC} $RESTART_RES" echo -e " Intentando registrar app en SIAX Monitor si no estaba creada..." curl -s -m 15 -X POST "http://$HOST:8080/api/apps" \ -H "Content-Type: application/json" \ -d "{ \"app_name\": \"$APP_NAME\", \"app_type\": \"nodejs\", \"working_directory\": \"$RUTA_REMOTA\", \"script_path\": \"app.js\", \"user\": \"${DESTINO%@*}\", \"use_npm_start\": false, \"restart_policy\": \"always\", \"environment\": { \"PORT\": \"$APP_PORT\" } }" >/dev/null 2>&1 || true sleep 1 curl -s -m 15 -X POST "http://$HOST:8080/api/apps/$APP_NAME/restart" >/dev/null 2>&1 || true fi # Espera breve para estabilización de socket sleep 2 # Verificación de salud y métricas de SIAX Monitor echo -e "${YELLOW}🩺 [5/5] Auditando salud, PID y métricas operativas...${NC}" STATUS_JSON=$(curl -s "http://$HOST:8080/api/apps/$APP_NAME/status" || echo "{}") PID_ACTUAL=$(echo "$STATUS_JSON" | grep -o '"pid":[0-9]*' | cut -d: -f2 || echo "desconocido") RAM_ACTUAL=$(echo "$STATUS_JSON" | grep -o '"memory_usage":"[^"]*"' | cut -d'"' -f4 || echo "desconocido") SYS_STATUS=$(echo "$STATUS_JSON" | grep -o '"systemd_status":"[^"]*"' | cut -d'"' -f4 || echo "desconocido") echo -e " • Estado SIAX Monitor: ${GREEN}$SYS_STATUS${NC}" echo -e " • PID autoritativo: ${GREEN}$PID_ACTUAL${NC}" echo -e " • Consumo de RAM: ${GREEN}$RAM_ACTUAL${NC}" # Test HTTP directo en el puerto de la aplicación HTTP_CODE=$(curl -fsS -m 10 -o /dev/null -w "%{http_code}" "http://$HOST:$APP_PORT/login" || echo "000") if [ "$HTTP_CODE" = "200" ]; then echo -e " • Verificación HTTP: ${GREEN}HTTP 200 OK (http://$HOST:$APP_PORT/login)${NC}" else echo -e " • Verificación HTTP: ${RED}HTTP $HTTP_CODE${NC} (revisar logs en SIAX Monitor)" fi # Actualizar estado y URL en el MCP de Infraestructura echo -e "\n${YELLOW}🌐 Notificando estado al MCP de Infraestructura (:3007)...${NC}" node -e " const http = require('http'); const payload = JSON.stringify({ status: 'ACTIVE', url: 'https://soporte.sigmac.app' }); const req = http.request({ hostname: '$HOST', port: 3007, path: '/api/services/$MCP_SERVICE_ID', method: 'PUT', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) } }, res => { console.log(' ✓ Ficha MCP #$MCP_SERVICE_ID sincronizada (HTTP ' + res.statusCode + ')'); }); req.on('error', err => console.warn(' ⚠️ MCP aviso:', err.message)); req.write(payload); req.end(); " || true done echo -e "\n${BLUE}=====================================================${NC}" echo -e "${GREEN}🎉 ¡Despliegue a Producción finalizado con éxito!${NC}" echo -e "🌐 Dominio público: ${CYAN}https://soporte.sigmac.app${NC}" echo -e "🎯 Upstream interno: ${CYAN}http://192.168.10.160:$APP_PORT${NC}" echo -e "👁️ SIAX Monitor: ${CYAN}http://192.168.10.160:8080/#/apps/$APP_NAME${NC}" echo -e "📋 Ficha MCP: ${CYAN}ID $MCP_SERVICE_ID (Status: ACTIVE)${NC}" echo -e "${BLUE}=====================================================${NC}"