1816 lines
72 KiB
Bash
Executable File
1816 lines
72 KiB
Bash
Executable File
#!/bin/bash
|
|
#===============================================================================
|
|
# BDT PLATFORM - Shell de Deployment y Operaciones para Servidor
|
|
#===============================================================================
|
|
# Uso: ./bdt.sh [comando] [opciones]
|
|
# Ejecutar sin argumentos para ver la ayuda completa.
|
|
#
|
|
# Este script gestiona TODO el ciclo de vida del sistema BDT:
|
|
# - Clonar/actualizar repositorios desde GitLab
|
|
# - Instalar dependencias y compilar todos los servicios
|
|
# - Levantar/detener infraestructura y aplicaciones
|
|
# - Monitorear logs en tiempo real
|
|
# - Verificar salud de todos los servicios
|
|
# - Gestionar ambientes (desarrollo, calidad, demo, produccion)
|
|
#===============================================================================
|
|
|
|
set -euo pipefail
|
|
|
|
#===============================================================================
|
|
# CONFIGURACION
|
|
#===============================================================================
|
|
|
|
SCRIPT_VERSION="2.1.0"
|
|
SCRIPT_NAME="$(basename "$0")"
|
|
|
|
# Directorios - resolver symlinks para encontrar la ruta real
|
|
_resolve_root() {
|
|
local source="${BASH_SOURCE[0]}"
|
|
# Seguir symlinks hasta llegar al archivo real
|
|
while [[ -L "$source" ]]; do
|
|
local dir="$(cd "$(dirname "$source")" && pwd)"
|
|
source="$(readlink "$source")"
|
|
# Si readlink devolvió ruta relativa, resolver contra el directorio
|
|
[[ "$source" != /* ]] && source="$dir/$source"
|
|
done
|
|
cd "$(dirname "$source")" && pwd
|
|
}
|
|
BDT_ROOT="${BDT_ROOT:-$(_resolve_root)}"
|
|
|
|
# Si existe ~/.bdt/project-root, usarlo como override
|
|
if [[ -f "${HOME}/.bdt/project-root" ]]; then
|
|
_saved_root="$(cat "${HOME}/.bdt/project-root")"
|
|
if [[ -d "$_saved_root" && -f "$_saved_root/bdt.sh" ]]; then
|
|
BDT_ROOT="$_saved_root"
|
|
fi
|
|
fi
|
|
|
|
# Configuracion global del usuario (GITLAB_URL, DEPLOY_SERVER, etc.)
|
|
# Variables de entorno ya definidas tienen prioridad sobre el archivo.
|
|
if [[ -f "${HOME}/.bdt/config" ]]; then
|
|
while IFS='=' read -r _k _v; do
|
|
[[ "$_k" =~ ^[A-Z_]+$ ]] || continue
|
|
[[ -n "${!_k:-}" ]] || export "$_k"="$_v"
|
|
done < "${HOME}/.bdt/config" || true
|
|
fi
|
|
INFRA_DIR="${BDT_ROOT}/infrastructure"
|
|
COMPOSE_FILE="${INFRA_DIR}/docker-compose.yml"
|
|
FRONTEND_DIR="${BDT_ROOT}/frontend/bdt-internet-banking"
|
|
GATEWAY_DIR="${BDT_ROOT}/backend/gateway"
|
|
CHANNELS_DIR="${BDT_ROOT}/backend/channels"
|
|
CANALES_DIR="${BDT_ROOT}/backend/canales"
|
|
SERVICEBUS_DIR="${BDT_ROOT}/backend/service-bus"
|
|
APIBANK_DIR="${BDT_ROOT}/backend/apiBank"
|
|
DATABASE_DIR="${BDT_ROOT}/database"
|
|
LOG_DIR="${BDT_ROOT}/logs"
|
|
mkdir -p "${LOG_DIR}"
|
|
|
|
# GitLab
|
|
GITLAB_URL="${GITLAB_URL:-http://gitlab.bicentenariobu.com.ve}"
|
|
GITLAB_GROUP="${GITLAB_GROUP:-dcgeeks}"
|
|
|
|
# Lista de servicios
|
|
ALL_SERVICES="frontend gateway service-bus canales-admin-web canales-worker apibank infrastructure database"
|
|
APP_SERVICES="frontend gateway service-bus canales-admin-web canales-worker"
|
|
|
|
# Funciones de lookup (compatible bash 3.2 — sin declare -A)
|
|
repo_url() {
|
|
case "$1" in
|
|
frontend) echo "${GITLAB_URL}/${GITLAB_GROUP}/bdt-frontend.git" ;;
|
|
gateway) echo "${GITLAB_URL}/${GITLAB_GROUP}/bdt-gateway.git" ;;
|
|
service-bus) echo "${GITLAB_URL}/${GITLAB_GROUP}/bdt-service-bus.git" ;;
|
|
canales-admin-web) echo "${GITLAB_URL}/${GITLAB_GROUP}/bdt_canales.git" ;;
|
|
canales-worker) echo "${GITLAB_URL}/${GITLAB_GROUP}/bdt_canales.git" ;;
|
|
apibank) echo "${GITLAB_URL}/${GITLAB_GROUP}/bdt-apibank.git" ;;
|
|
infrastructure) echo "${GITLAB_URL}/${GITLAB_GROUP}/bdt-infrastructure.git" ;;
|
|
database) echo "${GITLAB_URL}/${GITLAB_GROUP}/bdt-database.git" ;;
|
|
esac
|
|
}
|
|
|
|
repo_dir() {
|
|
case "$1" in
|
|
frontend) echo "${FRONTEND_DIR}" ;;
|
|
gateway) echo "${GATEWAY_DIR}" ;;
|
|
service-bus) echo "${SERVICEBUS_DIR}" ;;
|
|
canales-admin-web) echo "${CANALES_DIR}" ;;
|
|
canales-worker) echo "${CANALES_DIR}" ;;
|
|
apibank) echo "${APIBANK_DIR}" ;;
|
|
infrastructure) echo "${INFRA_DIR}" ;;
|
|
database) echo "${DATABASE_DIR}" ;;
|
|
esac
|
|
}
|
|
|
|
repo_branch() {
|
|
case "$1" in
|
|
frontend) echo "develop" ;;
|
|
gateway) echo "develop" ;;
|
|
service-bus) echo "develop" ;;
|
|
canales-admin-web) echo "master" ;;
|
|
canales-worker) echo "master" ;;
|
|
apibank) echo "desarrollo" ;;
|
|
infrastructure) echo "develop" ;;
|
|
database) echo "main" ;;
|
|
esac
|
|
}
|
|
|
|
# Remote que apunta al GitLab del banco. El nombre varía por repo
|
|
# (origin en canales, dcgeeks en gateway/frontend/infra). Vacío si no hay.
|
|
_bank_remote() {
|
|
local dir="$1" host
|
|
host="$(echo "$GITLAB_URL" | sed 's|^[a-z]*://||')"
|
|
git -C "$dir" remote -v 2>/dev/null | awk -v h="$host" '$2 ~ h {print $1; exit}'
|
|
}
|
|
|
|
svc_port() {
|
|
case "$1" in
|
|
postgres) echo 55432 ;; redis) echo 56379 ;; redpanda) echo 59092 ;;
|
|
keycloak) echo 58181 ;; mailpit) echo 58025 ;; prometheus) echo 59090 ;;
|
|
grafana) echo 53000 ;; frontend) echo 59002 ;; gateway) echo 58050 ;;
|
|
canales-admin-web) echo 58180 ;; canales-worker) echo 59091 ;;
|
|
service-bus) echo 58060 ;; adminer) echo 55050 ;;
|
|
redis-insight) echo 58081 ;; redpanda-console) echo 58080 ;;
|
|
esac
|
|
}
|
|
|
|
svc_health_url() {
|
|
case "$1" in
|
|
gateway) echo "http://localhost:58050/actuator/health" ;;
|
|
service-bus) echo "http://localhost:58060/actuator/health" ;;
|
|
canales-admin-web) echo "http://localhost:58180/api/health" ;;
|
|
canales-worker) echo "http://localhost:59091/health" ;;
|
|
frontend) echo "http://localhost:59002" ;;
|
|
keycloak) echo "http://localhost:58181" ;;
|
|
prometheus) echo "http://localhost:59090" ;;
|
|
grafana) echo "http://localhost:53000" ;;
|
|
mailpit) echo "http://localhost:58025" ;;
|
|
esac
|
|
}
|
|
|
|
docker_name() {
|
|
case "$1" in
|
|
postgres) echo "bdt-postgres" ;; redis) echo "bdt-redis" ;; redpanda) echo "bdt-redpanda" ;;
|
|
keycloak) echo "bdt-keycloak" ;; mailpit) echo "bdt-mailpit" ;; prometheus) echo "bdt-prometheus" ;;
|
|
grafana) echo "bdt-grafana" ;; frontend) echo "bdt-frontend" ;; gateway) echo "bdt-gateway" ;;
|
|
canales-admin-web) echo "bdt-canales-admin-web" ;; canales-worker) echo "bdt-canales-worker" ;;
|
|
service-bus) echo "bdt-service-bus" ;; adminer) echo "bdt-adminer" ;;
|
|
redis-insight) echo "bdt-redis-insight" ;; redpanda-console) echo "bdt-redpanda-console" ;;
|
|
esac
|
|
}
|
|
|
|
# Ambiente
|
|
ENV_FILE="${BDT_ROOT}/.bdt-env"
|
|
if [[ -f "$ENV_FILE" ]]; then
|
|
CURRENT_ENV=$(cat "$ENV_FILE")
|
|
else
|
|
CURRENT_ENV="desarrollo"
|
|
echo "$CURRENT_ENV" > "$ENV_FILE"
|
|
fi
|
|
|
|
# Docker Compose
|
|
COMPOSE_CMD=""
|
|
if docker compose version &>/dev/null 2>&1; then
|
|
COMPOSE_CMD="docker compose"
|
|
elif command -v docker-compose &>/dev/null; then
|
|
COMPOSE_CMD="docker-compose"
|
|
else
|
|
COMPOSE_CMD="docker compose"
|
|
fi
|
|
|
|
# Servicios (lookup via funciones svc_port, svc_health_url, docker_name arriba)
|
|
|
|
#===============================================================================
|
|
# COLORES
|
|
#===============================================================================
|
|
|
|
NC='\033[0m'; BOLD='\033[1m'; DIM='\033[2m'
|
|
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'; CYAN='\033[0;36m'; WHITE='\033[1;37m'
|
|
GRAY='\033[38;5;245m'
|
|
O1='\033[38;5;202m'; O2='\033[38;5;208m'; O3='\033[38;5;214m'
|
|
|
|
ok() { echo -e " ${GREEN}${BOLD}✓${NC} $1"; }
|
|
err() { echo -e " ${RED}${BOLD}✗${NC} $1"; }
|
|
warn() { echo -e " ${YELLOW}${BOLD}⚠${NC} $1"; }
|
|
info() { echo -e " ${O3}→${NC} $1"; }
|
|
step() { echo -e "\n ${O2}${BOLD}[$1]${NC} ${WHITE}$2${NC}"; echo -e " ${GRAY}$(printf '%.0s─' {1..60})${NC}"; }
|
|
|
|
env_label() {
|
|
case "$CURRENT_ENV" in
|
|
desarrollo) echo "DEV" ;;
|
|
calidad) echo "QA" ;;
|
|
demo) echo "DEMO" ;;
|
|
produccion) echo "PROD" ;;
|
|
*) echo "$CURRENT_ENV" ;;
|
|
esac
|
|
}
|
|
|
|
banner() {
|
|
echo ""
|
|
echo -e "${O1} ██████╗ ██████╗ ████████╗${NC}"
|
|
echo -e "${O2} ██╔══██╗██╔══██╗╚══██╔══╝${NC} ${WHITE}${BOLD}BDT Platform v${SCRIPT_VERSION}${NC}"
|
|
echo -e "${O3} ██████╔╝██║ ██║ ██║ ${NC} Ambiente: ${CYAN}${BOLD}$(env_label)${NC} (${CURRENT_ENV})"
|
|
echo -e "${O2} ██╔══██╗██║ ██║ ██║ ${NC} Servidor: ${WHITE}$(hostname)${NC}"
|
|
echo -e "${O1} ██████╔╝██████╔╝ ██║ ${NC} Fecha: ${WHITE}$(date '+%Y-%m-%d %H:%M')${NC}"
|
|
echo -e "${O1} ╚═════╝ ╚═════╝ ╚═╝ ${NC}"
|
|
echo ""
|
|
}
|
|
|
|
#===============================================================================
|
|
# COMANDO: clone - Clonar todos los repositorios
|
|
#===============================================================================
|
|
|
|
cmd_clone() {
|
|
banner
|
|
step "CLONE" "Clonando repositorios desde GitLab (${GITLAB_GROUP})"
|
|
local branch="${1:-}"
|
|
|
|
for svc in $ALL_SERVICES; do
|
|
local dir="$(repo_dir "$svc")"
|
|
local repo="$(repo_url "$svc")"
|
|
local br="${branch:-$(repo_branch "$svc")}"
|
|
|
|
if [[ -d "$dir/.git" ]]; then
|
|
local remote
|
|
remote="$(_bank_remote "$dir")"; remote="${remote:-origin}"
|
|
info "${svc}: ya existe en ${dir}, actualizando (remote: ${remote})..."
|
|
cd "$dir"
|
|
git fetch "$remote" --prune 2>/dev/null
|
|
git checkout "$br" 2>/dev/null || git checkout -b "$br" "${remote}/${br}" 2>/dev/null || true
|
|
git pull "$remote" "$br" 2>/dev/null && ok "${svc}: actualizado (${br})" || warn "${svc}: pull falló"
|
|
cd "$BDT_ROOT"
|
|
else
|
|
info "${svc}: clonando..."
|
|
local parent_dir="$(dirname "$dir")"
|
|
mkdir -p "$parent_dir"
|
|
git clone -b "$br" "$repo" "$dir" 2>/dev/null && \
|
|
ok "${svc}: clonado (${br})" || err "${svc}: error al clonar"
|
|
fi
|
|
done
|
|
}
|
|
|
|
#===============================================================================
|
|
# COMANDO: pull - Actualizar todos los repositorios
|
|
#===============================================================================
|
|
|
|
cmd_pull() {
|
|
banner
|
|
step "PULL" "Actualizando todos los repositorios"
|
|
local branch="${1:-}"
|
|
|
|
for svc in $ALL_SERVICES; do
|
|
local dir="$(repo_dir "$svc")"
|
|
local br="${branch:-$(repo_branch "$svc")}"
|
|
|
|
if [[ -d "$dir/.git" ]]; then
|
|
cd "$dir"
|
|
local remote
|
|
remote="$(_bank_remote "$dir")"; remote="${remote:-origin}"
|
|
local current_br=$(git branch --show-current 2>/dev/null)
|
|
if [[ -n "$branch" && "$current_br" != "$br" ]]; then
|
|
git fetch "$remote" --prune 2>/dev/null || true
|
|
git checkout "$br" 2>/dev/null || git checkout -b "$br" "${remote}/${br}" 2>/dev/null || true
|
|
current_br="$br"
|
|
fi
|
|
git pull "$remote" "${current_br:-$br}" 2>/dev/null && ok "${svc}: actualizado (${current_br:-$br})" || warn "${svc}: sin cambios o error"
|
|
cd "$BDT_ROOT"
|
|
else
|
|
warn "${svc}: no existe. Usa './bdt.sh clone' primero"
|
|
fi
|
|
done
|
|
}
|
|
|
|
#===============================================================================
|
|
# COMANDO: install - Instalar dependencias y compilar todo
|
|
#===============================================================================
|
|
|
|
cmd_install() {
|
|
banner
|
|
step "INSTALL" "Instalando dependencias y compilando todo"
|
|
local errors=0
|
|
|
|
# Prerequisitos
|
|
info "Verificando prerequisitos..."
|
|
command -v docker &>/dev/null && ok "Docker: $(docker --version 2>/dev/null | head -c 50)" || { err "Docker no instalado"; errors=$((errors+1)); }
|
|
command -v java &>/dev/null && ok "Java: $(java -version 2>&1 | head -1)" || { err "Java no instalado"; errors=$((errors+1)); }
|
|
command -v node &>/dev/null && ok "Node.js: $(node --version)" || { err "Node.js no instalado"; errors=$((errors+1)); }
|
|
[[ $errors -gt 0 ]] && { err "Prerequisitos faltantes. Abortando."; return 1; }
|
|
echo ""
|
|
|
|
# Frontend
|
|
step "NPM" "Instalando Frontend (Next.js)"
|
|
if [[ -d "$FRONTEND_DIR" ]]; then
|
|
cd "$FRONTEND_DIR"
|
|
npm install --legacy-peer-deps > "${LOG_DIR}/frontend-install.log" 2>&1 && \
|
|
ok "Frontend: dependencias instaladas" || { err "Frontend: npm install falló"; errors=$((errors+1)); }
|
|
npm run build > "${LOG_DIR}/frontend-build.log" 2>&1 && \
|
|
ok "Frontend: build exitoso" || { err "Frontend: build falló (ver ${LOG_DIR}/frontend-build.log)"; errors=$((errors+1)); }
|
|
cd "$BDT_ROOT"
|
|
fi
|
|
|
|
# Backends Gradle (canales compila dentro del Docker build, no acá)
|
|
for svc in gateway service-bus; do
|
|
local dir="$(repo_dir "$svc")"
|
|
step "GRADLE" "Compilando ${svc}"
|
|
if [[ -d "$dir" && -f "${dir}/build.gradle" ]]; then
|
|
cd "$dir"
|
|
./gradlew clean build -x test > "${LOG_DIR}/${svc}-build.log" 2>&1 && \
|
|
ok "${svc}: compilado" || { err "${svc}: build falló (ver ${LOG_DIR}/${svc}-build.log)"; errors=$((errors+1)); }
|
|
cd "$BDT_ROOT"
|
|
else
|
|
warn "${svc}: sin build.gradle"
|
|
fi
|
|
done
|
|
|
|
echo ""
|
|
[[ $errors -eq 0 ]] && ok "${GREEN}${BOLD}Instalación completa sin errores${NC}" || \
|
|
warn "${YELLOW}Instalación con ${errors} error(es). Revisa logs en ${LOG_DIR}/${NC}"
|
|
}
|
|
|
|
#===============================================================================
|
|
# COMANDO: build - Construir imágenes Docker
|
|
#===============================================================================
|
|
|
|
# Build local de bdt-<svc>:latest con el Dockerfile correcto
|
|
# (canales-* lo tienen en apps/<app>/Dockerfile, contexto = raíz del monorepo canales)
|
|
_docker_build_local() {
|
|
local svc="$1"
|
|
local dir dockerfile dockerfile_path
|
|
dir="$(repo_dir "$svc")"
|
|
[[ -z "$dir" ]] && { err "Servicio desconocido: ${svc}"; return 1; }
|
|
dockerfile="$(_image_dockerfile "$svc")"
|
|
dockerfile_path="${dir}/${dockerfile:-Dockerfile}"
|
|
[[ ! -f "$dockerfile_path" ]] && { err "Sin Dockerfile: ${svc} (${dockerfile_path})"; return 1; }
|
|
|
|
local args=(-t "bdt-${svc}:latest")
|
|
[[ -n "$dockerfile" ]] && args+=(-f "$dockerfile_path")
|
|
args+=("$dir")
|
|
info "Construyendo bdt-${svc}:latest..."
|
|
if docker build "${args[@]}" > "${LOG_DIR}/${svc}-docker-build.log" 2>&1; then
|
|
ok "bdt-${svc}: imagen construida"
|
|
else
|
|
err "bdt-${svc}: build falló (ver ${LOG_DIR}/${svc}-docker-build.log)"
|
|
tail -15 "${LOG_DIR}/${svc}-docker-build.log" | while read -r l; do echo -e " ${GRAY}${l}${NC}"; done
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
cmd_build() {
|
|
banner
|
|
local svc="${1:-all}"
|
|
step "BUILD" "Construyendo imágenes Docker"
|
|
|
|
if [[ "$svc" == "all" ]]; then
|
|
for s in $APP_SERVICES; do
|
|
_docker_build_local "$s" || true
|
|
done
|
|
else
|
|
_docker_build_local "$svc"
|
|
fi
|
|
}
|
|
|
|
#===============================================================================
|
|
# COMANDO: up - Levantar servicios
|
|
#===============================================================================
|
|
|
|
cmd_up() {
|
|
banner
|
|
local target="${1:-all}"
|
|
cd "$INFRA_DIR"
|
|
|
|
case "$target" in
|
|
infra)
|
|
step "UP" "Levantando infraestructura"
|
|
$COMPOSE_CMD up -d postgres redis redpanda keycloak mailpit prometheus grafana 2>&1 | while read -r l; do echo -e " ${GRAY}${l}${NC}"; done
|
|
ok "Infraestructura levantada"
|
|
;;
|
|
apps)
|
|
step "UP" "Levantando aplicaciones"
|
|
$COMPOSE_CMD --profile apps up -d 2>&1 | while read -r l; do echo -e " ${GRAY}${l}${NC}"; done
|
|
ok "Aplicaciones levantadas"
|
|
;;
|
|
tools)
|
|
step "UP" "Levantando herramientas"
|
|
$COMPOSE_CMD --profile tools up -d 2>&1 | while read -r l; do echo -e " ${GRAY}${l}${NC}"; done
|
|
ok "Herramientas levantadas"
|
|
;;
|
|
all)
|
|
step "UP" "Levantando TODOS los servicios"
|
|
$COMPOSE_CMD --profile apps --profile tools up -d 2>&1 | while read -r l; do echo -e " ${GRAY}${l}${NC}"; done
|
|
ok "Todos los servicios levantados"
|
|
;;
|
|
*)
|
|
step "UP" "Levantando servicio: ${target}"
|
|
$COMPOSE_CMD --profile apps --profile tools up -d "$target" 2>&1 | while read -r l; do echo -e " ${GRAY}${l}${NC}"; done
|
|
ok "${target} levantado"
|
|
;;
|
|
esac
|
|
|
|
cd "$BDT_ROOT"
|
|
echo ""
|
|
cmd_status
|
|
}
|
|
|
|
#===============================================================================
|
|
# COMANDO: down - Detener servicios
|
|
#===============================================================================
|
|
|
|
cmd_down() {
|
|
banner
|
|
local target="${1:-all}"
|
|
cd "$INFRA_DIR"
|
|
|
|
case "$target" in
|
|
all)
|
|
step "DOWN" "Deteniendo TODOS los servicios"
|
|
$COMPOSE_CMD --profile apps --profile tools down 2>&1 | while read -r l; do echo -e " ${GRAY}${l}${NC}"; done
|
|
pkill -f "java.*bootRun" 2>/dev/null || true
|
|
pkill -f "next dev" 2>/dev/null || true
|
|
ok "Todos los servicios detenidos"
|
|
;;
|
|
*)
|
|
step "DOWN" "Deteniendo: ${target}"
|
|
$COMPOSE_CMD --profile apps --profile tools stop "$target" 2>&1 | while read -r l; do echo -e " ${GRAY}${l}${NC}"; done
|
|
ok "${target} detenido"
|
|
;;
|
|
esac
|
|
cd "$BDT_ROOT"
|
|
}
|
|
|
|
#===============================================================================
|
|
# COMANDO: restart - Reiniciar servicios
|
|
#===============================================================================
|
|
|
|
cmd_restart() {
|
|
local target="${1:-all}"
|
|
if [[ "$target" == "all" ]]; then
|
|
cmd_down all
|
|
sleep 2
|
|
cmd_up all
|
|
else
|
|
banner
|
|
step "RESTART" "Reiniciando: ${target}"
|
|
cd "$INFRA_DIR"
|
|
$COMPOSE_CMD --profile apps --profile tools restart "$target" 2>&1 | while read -r l; do echo -e " ${GRAY}${l}${NC}"; done
|
|
ok "${target} reiniciado"
|
|
cd "$BDT_ROOT"
|
|
fi
|
|
}
|
|
|
|
#===============================================================================
|
|
# COMANDO: status - Estado de todos los servicios
|
|
#===============================================================================
|
|
|
|
cmd_status() {
|
|
banner
|
|
step "STATUS" "Estado de servicios"
|
|
|
|
echo -e "\n ${O3}${BOLD}Endpoints HTTP:${NC}"
|
|
for svc in gateway service-bus canales-admin-web canales-worker frontend keycloak prometheus grafana mailpit; do
|
|
local url="$(svc_health_url "$svc")"
|
|
local code
|
|
code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 3 "$url" 2>/dev/null || echo "000")
|
|
if [[ "$code" =~ ^(200|302|401)$ ]]; then
|
|
echo -e " ${GREEN}●${NC} ${WHITE}${svc}${NC}$(printf '%*s' $((18 - ${#svc})) '')${GREEN}HTTP ${code}${NC} ${DIM}${url}${NC}"
|
|
else
|
|
echo -e " ${RED}●${NC} ${GRAY}${svc}${NC}$(printf '%*s' $((18 - ${#svc})) '')${RED}HTTP ${code}${NC} ${DIM}detenido${NC}"
|
|
fi
|
|
done
|
|
|
|
echo -e "\n ${O3}${BOLD}Contenedores Docker:${NC}"
|
|
for svc in postgres redis redpanda keycloak gateway canales-admin-web canales-worker service-bus frontend mailpit prometheus grafana; do
|
|
local cname="$(docker_name "$svc")"
|
|
local st
|
|
st=$(docker inspect --format='{{.State.Status}}' "$cname" 2>/dev/null || echo "not found")
|
|
local hp
|
|
hp=$(docker inspect --format='{{if .State.Health}}{{.State.Health.Status}}{{else}}-{{end}}' "$cname" 2>/dev/null || echo "-")
|
|
|
|
if [[ "$st" == "running" ]]; then
|
|
local color="$GREEN"
|
|
[[ "$hp" != "healthy" && "$hp" != "-" ]] && color="$YELLOW"
|
|
echo -e " ${color}●${NC} ${WHITE}${cname}${NC}$(printf '%*s' $((22 - ${#cname})) '')${color}${st}${NC} ${DIM}(${hp})${NC}"
|
|
else
|
|
echo -e " ${RED}●${NC} ${GRAY}${cname}${NC}$(printf '%*s' $((22 - ${#cname})) '')${RED}${st}${NC}"
|
|
fi
|
|
done
|
|
|
|
echo -e "\n ${O3}${BOLD}Recursos Docker:${NC}"
|
|
local imgs=$(docker images -q 2>/dev/null | wc -l | tr -d ' ')
|
|
local ctrs=$(docker ps -q 2>/dev/null | wc -l | tr -d ' ')
|
|
echo -e " Contenedores activos: ${WHITE}${ctrs}${NC} | Imágenes: ${WHITE}${imgs}${NC}"
|
|
}
|
|
|
|
#===============================================================================
|
|
# COMANDO: logs - Ver logs de servicios
|
|
#===============================================================================
|
|
|
|
cmd_logs() {
|
|
local svc="${1:-}"
|
|
local lines="${2:-100}"
|
|
|
|
if [[ -z "$svc" ]]; then
|
|
banner
|
|
step "LOGS" "Servicios disponibles"
|
|
echo ""
|
|
echo -e " ${O3}${BOLD}Docker (tiempo real con -f):${NC}"
|
|
echo -e " ${WHITE}gateway${NC} ${WHITE}canales-admin-web${NC} ${WHITE}canales-worker${NC} ${WHITE}service-bus${NC}"
|
|
echo -e " ${WHITE}frontend${NC} ${WHITE}postgres${NC} ${WHITE}redis${NC} ${WHITE}redpanda${NC}"
|
|
echo -e " ${WHITE}keycloak${NC} ${WHITE}prometheus${NC} ${WHITE}grafana${NC} ${WHITE}mailpit${NC}"
|
|
echo ""
|
|
echo -e " ${O3}${BOLD}Uso:${NC}"
|
|
echo -e " ${GRAY}./bdt.sh logs gateway${NC} Últimas 100 líneas"
|
|
echo -e " ${GRAY}./bdt.sh logs gateway 500${NC} Últimas 500 líneas"
|
|
echo -e " ${GRAY}./bdt.sh logs gateway -f${NC} Seguir en tiempo real"
|
|
echo -e " ${GRAY}./bdt.sh logs all${NC} Todos los servicios combinados"
|
|
echo ""
|
|
return
|
|
fi
|
|
|
|
if [[ "$svc" == "all" ]]; then
|
|
cd "$INFRA_DIR"
|
|
echo -e " ${O3}Mostrando logs combinados (Ctrl+C para salir)...${NC}"
|
|
$COMPOSE_CMD --profile apps --profile tools logs -f --tail="$lines" 2>&1
|
|
cd "$BDT_ROOT"
|
|
return
|
|
fi
|
|
|
|
local cname="$(docker_name "$svc")"
|
|
if [[ -z "$cname" ]]; then
|
|
err "Servicio desconocido: ${svc}"
|
|
return 1
|
|
fi
|
|
|
|
if [[ "$lines" == "-f" ]]; then
|
|
echo -e " ${O3}Siguiendo logs de ${svc} (Ctrl+C para salir)...${NC}"
|
|
docker logs -f --tail=100 "$cname" 2>&1
|
|
else
|
|
echo -e " ${O3}Últimas ${lines} líneas de ${svc}:${NC}"
|
|
echo ""
|
|
docker logs --tail="$lines" "$cname" 2>&1
|
|
fi
|
|
}
|
|
|
|
#===============================================================================
|
|
# COMANDO: health - Health check completo
|
|
#===============================================================================
|
|
|
|
cmd_health() {
|
|
banner
|
|
step "HEALTH" "Verificación de salud del sistema"
|
|
local total=0 healthy=0
|
|
|
|
check() {
|
|
local name=$1 url=$2
|
|
total=$((total + 1))
|
|
local code
|
|
code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "$url" 2>/dev/null || echo "000")
|
|
if [[ "$code" =~ ^(200|302|401)$ ]]; then
|
|
healthy=$((healthy + 1))
|
|
echo -e " ${GREEN}✓${NC} ${WHITE}${name}${NC}$(printf '%*s' $((22 - ${#name})) '')HTTP ${GREEN}${code}${NC}"
|
|
else
|
|
echo -e " ${RED}✗${NC} ${GRAY}${name}${NC}$(printf '%*s' $((22 - ${#name})) '')HTTP ${RED}${code}${NC}"
|
|
fi
|
|
}
|
|
|
|
echo -e "\n ${O3}${BOLD}Aplicaciones:${NC}"
|
|
check "Gateway API" "http://localhost:58050/actuator/health"
|
|
check "Channels Admin" "http://localhost:58180"
|
|
check "Service-Bus" "http://localhost:58060/actuator/health"
|
|
check "Frontend" "http://localhost:59002"
|
|
|
|
echo -e "\n ${O3}${BOLD}Infraestructura:${NC}"
|
|
check "Keycloak" "http://localhost:58181"
|
|
check "Grafana" "http://localhost:53000"
|
|
check "Prometheus" "http://localhost:59090"
|
|
check "Mailpit" "http://localhost:58025"
|
|
|
|
echo -e "\n ${O3}${BOLD}Base de Datos:${NC}"
|
|
if docker exec bdt-postgres pg_isready -U postgres -d bdt_ebanking_db &>/dev/null; then
|
|
total=$((total + 1)); healthy=$((healthy + 1))
|
|
echo -e " ${GREEN}✓${NC} ${WHITE}PostgreSQL${NC} ${GREEN}Aceptando conexiones${NC}"
|
|
else
|
|
total=$((total + 1))
|
|
echo -e " ${RED}✗${NC} ${GRAY}PostgreSQL${NC} ${RED}No disponible${NC}"
|
|
fi
|
|
|
|
echo -e "\n ${O3}${BOLD}Cache:${NC}"
|
|
if docker exec bdt-redis redis-cli ping &>/dev/null; then
|
|
total=$((total + 1)); healthy=$((healthy + 1))
|
|
echo -e " ${GREEN}✓${NC} ${WHITE}Redis${NC} ${GREEN}PONG${NC}"
|
|
else
|
|
total=$((total + 1))
|
|
echo -e " ${RED}✗${NC} ${GRAY}Redis${NC} ${RED}No disponible${NC}"
|
|
fi
|
|
|
|
echo ""
|
|
local pct=0
|
|
[[ $total -gt 0 ]] && pct=$((healthy * 100 / total))
|
|
if [[ $pct -eq 100 ]]; then
|
|
echo -e " ${GREEN}${BOLD}Sistema: ${healthy}/${total} (${pct}%) — OPERATIVO${NC}"
|
|
elif [[ $pct -ge 60 ]]; then
|
|
echo -e " ${YELLOW}${BOLD}Sistema: ${healthy}/${total} (${pct}%) — PARCIAL${NC}"
|
|
else
|
|
echo -e " ${RED}${BOLD}Sistema: ${healthy}/${total} (${pct}%) — CON PROBLEMAS${NC}"
|
|
fi
|
|
}
|
|
|
|
#===============================================================================
|
|
# COMANDO: verify-db - Verificar base de datos
|
|
#===============================================================================
|
|
|
|
cmd_verify_db() {
|
|
banner
|
|
step "DB" "Verificación de Base de Datos"
|
|
|
|
if ! docker exec bdt-postgres pg_isready -U postgres &>/dev/null; then
|
|
err "PostgreSQL no accesible"
|
|
return 1
|
|
fi
|
|
ok "Conexión PostgreSQL OK"
|
|
|
|
echo -e "\n ${O3}${BOLD}Bases de datos:${NC}"
|
|
docker exec bdt-postgres psql -U postgres -t -c \
|
|
"SELECT datname, pg_size_pretty(pg_database_size(datname)) FROM pg_database WHERE datistemplate=false ORDER BY datname;" 2>/dev/null | \
|
|
while IFS='|' read -r db size; do
|
|
db=$(echo "$db" | xargs); size=$(echo "$size" | xargs)
|
|
[[ -n "$db" ]] && echo -e " ${GREEN}●${NC} ${WHITE}${db}${NC}$(printf '%*s' $((25 - ${#db})) '')${GRAY}${size}${NC}"
|
|
done
|
|
|
|
echo -e "\n ${O3}${BOLD}Tablas en bdt_ebanking_db:${NC}"
|
|
local count
|
|
count=$(docker exec bdt-postgres psql -U postgres -d bdt_ebanking_db -t -c \
|
|
"SELECT count(*) FROM information_schema.tables WHERE table_schema NOT IN ('pg_catalog','information_schema');" 2>/dev/null | xargs)
|
|
echo -e " Total: ${WHITE}${count:-0}${NC} tablas"
|
|
|
|
echo -e "\n ${O3}${BOLD}Conexiones activas:${NC}"
|
|
local conns
|
|
conns=$(docker exec bdt-postgres psql -U postgres -t -c "SELECT count(*) FROM pg_stat_activity WHERE state='active';" 2>/dev/null | xargs)
|
|
echo -e " Activas: ${WHITE}${conns:-0}${NC}"
|
|
}
|
|
|
|
#===============================================================================
|
|
# COMANDO: verify-api - Verificar endpoints API
|
|
#===============================================================================
|
|
|
|
cmd_verify_api() {
|
|
banner
|
|
step "API" "Verificación de endpoints API"
|
|
local total=0 ok_count=0
|
|
|
|
test_ep() {
|
|
local name=$1 method=$2 url=$3 expected=$4
|
|
total=$((total + 1))
|
|
local code
|
|
code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 -X "$method" "$url" 2>/dev/null || echo "000")
|
|
local match=false
|
|
for c in $expected; do [[ "$code" == "$c" ]] && match=true; done
|
|
if [[ "$match" == true ]]; then
|
|
ok_count=$((ok_count + 1))
|
|
echo -e " ${GREEN}✓${NC} ${WHITE}${name}${NC}$(printf '%*s' $((30 - ${#name})) '')${GREEN}${code}${NC}"
|
|
else
|
|
echo -e " ${RED}✗${NC} ${GRAY}${name}${NC}$(printf '%*s' $((30 - ${#name})) '')${RED}${code}${NC}"
|
|
fi
|
|
}
|
|
|
|
echo -e "\n ${O3}${BOLD}Gateway (:58050):${NC}"
|
|
test_ep "Health" GET "http://localhost:58050/actuator/health" "200"
|
|
test_ep "Login" POST "http://localhost:58050/api/login" "400 401 200 415"
|
|
test_ep "KS2 Cuentas" GET "http://localhost:58050/api/v1/ks2/consulta/cuentas/test" "401 403 200 404"
|
|
|
|
echo -e "\n ${O3}${BOLD}Service-Bus (:58060):${NC}"
|
|
test_ep "Health" GET "http://localhost:58060/actuator/health" "200"
|
|
test_ep "Endpoints List" GET "http://localhost:58060/api/v1/endpoints" "200 401"
|
|
|
|
echo -e "\n ${O3}${BOLD}Channels (:58180):${NC}"
|
|
test_ep "Home" GET "http://localhost:58180" "200 302"
|
|
test_ep "Bank Config" GET "http://localhost:58180/api/v1/bank-config/health" "200"
|
|
|
|
echo -e "\n ${O3}${BOLD}Frontend (:59002):${NC}"
|
|
test_ep "Home" GET "http://localhost:59002" "200 302 307"
|
|
test_ep "Login Page" GET "http://localhost:59002/login" "200 302 307"
|
|
|
|
echo ""
|
|
local pct=0
|
|
[[ $total -gt 0 ]] && pct=$((ok_count * 100 / total))
|
|
echo -e " APIs: ${WHITE}${ok_count}/${total}${NC} (${pct}%)"
|
|
}
|
|
|
|
#===============================================================================
|
|
# COMANDO: env - Cambiar ambiente
|
|
#===============================================================================
|
|
|
|
cmd_env() {
|
|
local new_env="${1:-}"
|
|
if [[ -z "$new_env" ]]; then
|
|
banner
|
|
step "ENV" "Ambiente actual: ${CURRENT_ENV} ($(env_label))"
|
|
echo ""
|
|
echo -e " ${GREEN}desarrollo${NC} — Desarrollo local, debug activo"
|
|
echo -e " ${YELLOW}calidad${NC} — QA, tests de integración"
|
|
echo -e " ${BLUE}demo${NC} — Presentaciones, datos demo"
|
|
echo -e " ${RED}produccion${NC} — Servidor de producción"
|
|
echo ""
|
|
echo -e " Uso: ${GRAY}./bdt.sh env desarrollo${NC}"
|
|
return
|
|
fi
|
|
|
|
case "$new_env" in
|
|
desarrollo|calidad|demo|produccion)
|
|
CURRENT_ENV="$new_env"
|
|
echo "$CURRENT_ENV" > "$ENV_FILE"
|
|
ok "Ambiente cambiado a: ${BOLD}${CURRENT_ENV} ($(env_label))${NC}"
|
|
;;
|
|
*)
|
|
err "Ambiente no válido: ${new_env}. Opciones: desarrollo, calidad, demo, produccion"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
#===============================================================================
|
|
# COMANDO: update - Actualizar, compilar y reiniciar un servicio
|
|
#===============================================================================
|
|
|
|
cmd_update() {
|
|
local svc="${1:-all}"
|
|
banner
|
|
step "UPDATE" "Actualizar servicio: ${svc}"
|
|
|
|
if [[ "$svc" == "all" ]]; then
|
|
cmd_pull
|
|
cmd_install
|
|
cmd_build all
|
|
cmd_restart all
|
|
else
|
|
local dir="$(repo_dir "$svc")"
|
|
if [[ -z "$dir" ]]; then
|
|
err "Servicio desconocido: ${svc}"
|
|
return 1
|
|
fi
|
|
|
|
# Pull (remote del banco, detectado por URL)
|
|
info "Actualizando código..."
|
|
local remote
|
|
remote="$(_bank_remote "$dir")"; remote="${remote:-origin}"
|
|
cd "$dir" && git pull "$remote" "$(git branch --show-current)" 2>/dev/null && \
|
|
ok "Código actualizado (${remote})" || warn "Sin cambios"
|
|
cd "$BDT_ROOT"
|
|
|
|
# Build previo solo para Java: el Dockerfile espera el JAR en build/libs/
|
|
# (frontend y canales compilan dentro del Docker build multi-stage)
|
|
if [[ -f "${dir}/build.gradle" ]]; then
|
|
info "Compilando (Gradle bootJar)..."
|
|
cd "$dir" && ./gradlew clean bootJar -x test > "${LOG_DIR}/${svc}-update-build.log" 2>&1 && \
|
|
ok "Compilado" || { err "Build falló (ver ${LOG_DIR}/${svc}-update-build.log)"; cd "$BDT_ROOT"; return 1; }
|
|
cd "$BDT_ROOT"
|
|
fi
|
|
|
|
# Docker rebuild + restart
|
|
if _docker_build_local "$svc"; then
|
|
info "Reiniciando contenedor..."
|
|
cd "$INFRA_DIR"
|
|
$COMPOSE_CMD --profile apps up -d --force-recreate "$svc" 2>/dev/null && \
|
|
ok "${svc} reiniciado" || warn "Reinicio manual necesario"
|
|
cd "$BDT_ROOT"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
#===============================================================================
|
|
# COMANDO: clean - Limpiar Docker
|
|
#===============================================================================
|
|
|
|
cmd_clean() {
|
|
banner
|
|
step "CLEAN" "Limpieza Docker"
|
|
|
|
local stopped=$(docker ps -aq --filter "status=exited" 2>/dev/null | wc -l | tr -d ' ')
|
|
local dangling=$(docker images -f "dangling=true" -q 2>/dev/null | wc -l | tr -d ' ')
|
|
echo -e " Contenedores detenidos: ${WHITE}${stopped}${NC}"
|
|
echo -e " Imágenes sin tag: ${WHITE}${dangling}${NC}"
|
|
echo ""
|
|
|
|
docker container prune -f 2>/dev/null && ok "Contenedores limpiados"
|
|
docker image prune -f 2>/dev/null && ok "Imágenes limpiadas"
|
|
docker network prune -f 2>/dev/null && ok "Redes limpiadas"
|
|
}
|
|
|
|
#===============================================================================
|
|
# COMANDO: git-auth - Configurar credenciales Git permanentes
|
|
#===============================================================================
|
|
|
|
cmd_git_auth() {
|
|
banner
|
|
step "GIT-AUTH" "Configurar credenciales GitLab"
|
|
echo ""
|
|
|
|
local git_user="${1:-}"
|
|
local git_pass="${2:-}"
|
|
|
|
if [[ -z "$git_user" ]]; then
|
|
echo -ne " Usuario GitLab: "
|
|
read -r git_user
|
|
fi
|
|
|
|
if [[ -z "$git_pass" ]]; then
|
|
echo -ne " Contraseña GitLab: "
|
|
read -rs git_pass
|
|
echo ""
|
|
fi
|
|
|
|
if [[ -z "$git_user" || -z "$git_pass" ]]; then
|
|
err "Usuario y contraseña son requeridos"
|
|
return 1
|
|
fi
|
|
|
|
# Método 1: Git credential store (almacena en archivo)
|
|
git config --global credential.helper store
|
|
ok "Credential helper configurado: store"
|
|
|
|
# Método 2: Crear entrada en el credential store
|
|
local cred_file="${HOME}/.git-credentials"
|
|
local encoded_pass
|
|
encoded_pass=$(python3 -c "import urllib.parse; print(urllib.parse.quote('${git_pass}', safe=''))" 2>/dev/null || echo "$git_pass")
|
|
local cred_line="http://${git_user}:${encoded_pass}@gitlab.bicentenariobu.com.ve"
|
|
|
|
# Verificar si ya existe
|
|
if grep -q "gitlab.bicentenariobu.com.ve" "$cred_file" 2>/dev/null; then
|
|
# Reemplazar credencial existente
|
|
sed -i.bak "/gitlab.bicentenariobu.com.ve/d" "$cred_file" 2>/dev/null || true
|
|
fi
|
|
|
|
echo "$cred_line" >> "$cred_file"
|
|
chmod 600 "$cred_file"
|
|
ok "Credenciales guardadas en ${cred_file}"
|
|
|
|
# Método 3: Actualizar URLs de los remotes para usar el usuario (sin password en URL)
|
|
info "Actualizando remotes de los repositorios..."
|
|
for svc in $ALL_SERVICES; do
|
|
local dir="$(repo_dir "$svc")"
|
|
if [[ -d "$dir/.git" ]]; then
|
|
cd "$dir"
|
|
# Verificar si tiene remote dcgeeks
|
|
if git remote get-url dcgeeks &>/dev/null; then
|
|
local current_url=$(git remote get-url dcgeeks)
|
|
# Limpiar credenciales de la URL si las tiene
|
|
local clean_url=$(echo "$current_url" | sed 's|http://[^@]*@|http://|')
|
|
git remote set-url dcgeeks "$clean_url" 2>/dev/null
|
|
fi
|
|
# Verificar si tiene remote origin
|
|
if git remote get-url origin &>/dev/null; then
|
|
local current_url=$(git remote get-url origin)
|
|
local clean_url=$(echo "$current_url" | sed 's|http://[^@]*@|http://|')
|
|
git remote set-url origin "$clean_url" 2>/dev/null
|
|
fi
|
|
cd "$BDT_ROOT"
|
|
fi
|
|
done
|
|
ok "Remotes actualizados"
|
|
|
|
# Test
|
|
echo ""
|
|
info "Verificando acceso..."
|
|
local test_dir="$(repo_dir frontend)"
|
|
if [[ -d "$test_dir/.git" ]]; then
|
|
cd "$test_dir"
|
|
if GIT_TERMINAL_PROMPT=0 git ls-remote --heads origin 2>/dev/null | head -1 > /dev/null; then
|
|
ok "Acceso a GitLab verificado correctamente"
|
|
else
|
|
if GIT_TERMINAL_PROMPT=0 git ls-remote --heads dcgeeks 2>/dev/null | head -1 > /dev/null; then
|
|
ok "Acceso a GitLab verificado (remote dcgeeks)"
|
|
else
|
|
warn "No se pudo verificar. Las credenciales se usarán en el próximo push/pull"
|
|
fi
|
|
fi
|
|
cd "$BDT_ROOT"
|
|
fi
|
|
|
|
echo ""
|
|
ok "Git configurado. Los próximos git pull/push no pedirán contraseña."
|
|
}
|
|
|
|
#===============================================================================
|
|
# COMANDO: creds - Mostrar credenciales
|
|
#===============================================================================
|
|
|
|
cmd_creds() {
|
|
banner
|
|
step "CREDS" "Credenciales del sistema"
|
|
echo ""
|
|
echo -e " ${O3}${BOLD}PostgreSQL:${NC} localhost:${WHITE}55432${NC} user: ${WHITE}postgres${NC} pass: ${WHITE}postgres${NC}"
|
|
echo -e " ${O3}${BOLD}Redis:${NC} localhost:${WHITE}56379${NC} ${GRAY}sin password (dev)${NC}"
|
|
echo -e " ${O3}${BOLD}Keycloak:${NC} localhost:${WHITE}58181${NC} user: ${WHITE}admin${NC} pass: ${WHITE}admin${NC}"
|
|
echo -e " ${O3}${BOLD}Grafana:${NC} localhost:${WHITE}53000${NC} user: ${WHITE}admin${NC} pass: ${WHITE}admin${NC}"
|
|
echo -e " ${O3}${BOLD}Mailpit:${NC} localhost:${WHITE}58025${NC} ${GRAY}sin auth${NC}"
|
|
echo -e " ${O3}${BOLD}Adminer:${NC} localhost:${WHITE}55050${NC} ${GRAY}usar creds de PostgreSQL${NC}"
|
|
echo -e " ${O3}${BOLD}Redpanda Console:${NC} localhost:${WHITE}58080${NC} ${GRAY}sin auth${NC}"
|
|
echo -e " ${O3}${BOLD}Redis Insight:${NC} localhost:${WHITE}58081${NC} ${GRAY}sin auth${NC}"
|
|
echo ""
|
|
echo -e " ${O3}${BOLD}URLs DNS (si Nginx configurado):${NC}"
|
|
echo -e " Frontend: ${WHITE}https://ebanking.bdt.local${NC}"
|
|
echo -e " Gateway: ${WHITE}https://gateway.bdt.local${NC}"
|
|
echo -e " Channels: ${WHITE}https://channels.bdt.local${NC}"
|
|
echo -e " Keycloak: ${WHITE}https://keycloak.bdt.local${NC}"
|
|
}
|
|
|
|
#===============================================================================
|
|
# COMANDO: deploy - Pipeline completo: pull → build → docker → restart
|
|
#===============================================================================
|
|
|
|
cmd_deploy() {
|
|
banner
|
|
local env="${1:-$CURRENT_ENV}"
|
|
step "DEPLOY" "Deploy completo — Ambiente: ${env}"
|
|
local start_time=$(date +%s)
|
|
|
|
echo ""
|
|
info "Paso 1/5: Actualizando repositorios..."
|
|
cmd_pull
|
|
echo ""
|
|
|
|
info "Paso 2/5: Compilando aplicaciones..."
|
|
cmd_install
|
|
echo ""
|
|
|
|
info "Paso 3/5: Construyendo imágenes Docker..."
|
|
cmd_build all
|
|
echo ""
|
|
|
|
info "Paso 4/5: Levantando servicios..."
|
|
cmd_up all
|
|
echo ""
|
|
|
|
info "Paso 5/5: Verificando salud..."
|
|
sleep 10
|
|
cmd_health
|
|
|
|
local elapsed=$(( $(date +%s) - start_time ))
|
|
echo ""
|
|
ok "Deploy completado en ${elapsed} segundos"
|
|
}
|
|
|
|
#===============================================================================
|
|
# COMANDO: setup - Autoinstalador global
|
|
#===============================================================================
|
|
|
|
cmd_setup() {
|
|
banner
|
|
step "SETUP" "Autoinstalador global de BDT Platform"
|
|
echo ""
|
|
|
|
local install_dir="/usr/local/bin"
|
|
local config_dir="${HOME}/.bdt"
|
|
local completions_dir=""
|
|
|
|
# Detectar shell del usuario
|
|
local user_shell="$(basename "$SHELL" 2>/dev/null || echo "bash")"
|
|
|
|
# 1. Instalar comando global 'bdt'
|
|
echo -e " ${O3}${BOLD}[1/5] Instalando comando global 'bdt'...${NC}"
|
|
echo ""
|
|
|
|
if [[ -w "$install_dir" ]]; then
|
|
# Sin sudo
|
|
ln -sf "${BDT_ROOT}/bdt.sh" "${install_dir}/bdt" 2>/dev/null
|
|
ok "Enlace creado: ${install_dir}/bdt -> bdt.sh"
|
|
else
|
|
info "Se necesita sudo para instalar en ${install_dir}"
|
|
sudo ln -sf "${BDT_ROOT}/bdt.sh" "${install_dir}/bdt" 2>/dev/null && \
|
|
ok "Enlace creado: ${install_dir}/bdt -> bdt.sh" || {
|
|
# Fallback: instalar en ~/bin
|
|
install_dir="${HOME}/bin"
|
|
mkdir -p "$install_dir"
|
|
ln -sf "${BDT_ROOT}/bdt.sh" "${install_dir}/bdt" 2>/dev/null
|
|
ok "Enlace creado: ${install_dir}/bdt -> bdt.sh"
|
|
warn "Asegurate de que ${install_dir} este en tu PATH"
|
|
}
|
|
fi
|
|
echo ""
|
|
|
|
# 2. Crear directorio de configuracion
|
|
echo -e " ${O3}${BOLD}[2/5] Configurando directorio ~/.bdt...${NC}"
|
|
mkdir -p "$config_dir"
|
|
|
|
# Guardar ruta del proyecto
|
|
echo "${BDT_ROOT}" > "${config_dir}/project-root"
|
|
|
|
# Crear archivo de configuracion si no existe
|
|
if [[ ! -f "${config_dir}/config" ]]; then
|
|
cat > "${config_dir}/config" << 'CONF'
|
|
# BDT Platform - Configuracion global
|
|
# Este archivo se carga automaticamente al ejecutar 'bdt'
|
|
|
|
# GitLab
|
|
GITLAB_URL=http://gitlab.bicentenariobu.com.ve
|
|
GITLAB_GROUP=dcgeeks
|
|
|
|
# Ambiente por defecto (desarrollo|calidad|demo|produccion)
|
|
DEFAULT_ENV=desarrollo
|
|
|
|
# Servidor de deploy remoto (comando server-deploy)
|
|
# DEPLOY_SERVER=10.0.0.1
|
|
# DEPLOY_USER=usuario.ssh
|
|
|
|
# Logs
|
|
LOG_RETENTION_DAYS=30
|
|
CONF
|
|
ok "Archivo de configuracion creado: ${config_dir}/config"
|
|
else
|
|
ok "Configuracion existente preservada: ${config_dir}/config"
|
|
fi
|
|
echo ""
|
|
|
|
# 3. Autocompletado
|
|
echo -e " ${O3}${BOLD}[3/5] Instalando autocompletado...${NC}"
|
|
|
|
local completion_script="${config_dir}/completion.bash"
|
|
cat > "$completion_script" << 'COMP'
|
|
# BDT Platform - Bash/Zsh completion
|
|
_bdt_completions() {
|
|
local cur="${COMP_WORDS[COMP_CWORD]}"
|
|
local prev="${COMP_WORDS[COMP_CWORD-1]}"
|
|
|
|
local commands="clone pull install build up down restart status logs health verify-db verify-api deploy construir publish env update creds clean setup menu help image-login image-build image-push image-pull image-deploy image-build-amd64 server-deploy"
|
|
local services="frontend gateway service-bus canales-admin-web canales-worker apibank infrastructure database"
|
|
local up_targets="all infra apps tools frontend gateway canales-admin-web canales-worker service-bus postgres redis keycloak"
|
|
local envs="desarrollo calidad demo produccion"
|
|
local log_services="gateway canales-admin-web canales-worker service-bus frontend postgres redis redpanda keycloak prometheus grafana mailpit all"
|
|
|
|
case "$prev" in
|
|
bdt|bdt.sh|./bdt.sh)
|
|
COMPREPLY=($(compgen -W "$commands" -- "$cur"))
|
|
;;
|
|
up|start|down|stop|restart|update|build)
|
|
COMPREPLY=($(compgen -W "$up_targets" -- "$cur"))
|
|
;;
|
|
logs|log)
|
|
COMPREPLY=($(compgen -W "$log_services" -- "$cur"))
|
|
;;
|
|
env)
|
|
COMPREPLY=($(compgen -W "$envs" -- "$cur"))
|
|
;;
|
|
clone|pull)
|
|
COMPREPLY=($(compgen -W "main develop calidad produccion" -- "$cur"))
|
|
;;
|
|
esac
|
|
}
|
|
complete -F _bdt_completions bdt
|
|
complete -F _bdt_completions bdt.sh
|
|
complete -F _bdt_completions ./bdt.sh
|
|
COMP
|
|
ok "Script de completado generado: ${completion_script}"
|
|
|
|
# Agregar source al perfil del shell
|
|
local profile_file=""
|
|
case "$user_shell" in
|
|
zsh) profile_file="${HOME}/.zshrc" ;;
|
|
bash) profile_file="${HOME}/.bashrc" ;;
|
|
*) profile_file="${HOME}/.profile" ;;
|
|
esac
|
|
|
|
local source_line="[[ -f ~/.bdt/completion.bash ]] && source ~/.bdt/completion.bash"
|
|
if [[ -f "$profile_file" ]] && ! grep -q ".bdt/completion.bash" "$profile_file" 2>/dev/null; then
|
|
echo "" >> "$profile_file"
|
|
echo "# BDT Platform - autocompletado" >> "$profile_file"
|
|
echo "$source_line" >> "$profile_file"
|
|
ok "Autocompletado agregado a ${profile_file}"
|
|
else
|
|
ok "Autocompletado ya configurado en ${profile_file}"
|
|
fi
|
|
echo ""
|
|
|
|
# 4. Alias utiles
|
|
echo -e " ${O3}${BOLD}[4/5] Configurando alias...${NC}"
|
|
|
|
local alias_file="${config_dir}/aliases.bash"
|
|
cat > "$alias_file" << ALIASES
|
|
# BDT Platform - Alias utiles
|
|
alias bdt-up='bdt up all'
|
|
alias bdt-down='bdt down all'
|
|
alias bdt-status='bdt status'
|
|
alias bdt-logs='bdt logs'
|
|
alias bdt-deploy='bdt deploy'
|
|
alias bdt-health='bdt health'
|
|
alias bdt-menu='bdt menu'
|
|
|
|
# Ir al directorio del proyecto
|
|
alias bdt-cd='cd ${BDT_ROOT}'
|
|
|
|
# Logs rapidos
|
|
alias bdt-lg='bdt logs gateway -f'
|
|
alias bdt-lc='bdt logs canales-admin-web -f'
|
|
alias bdt-lw='bdt logs canales-worker -f'
|
|
alias bdt-ls='bdt logs service-bus -f'
|
|
alias bdt-lf='bdt logs frontend -f'
|
|
alias bdt-la='bdt logs all'
|
|
ALIASES
|
|
|
|
local alias_source_line="[[ -f ~/.bdt/aliases.bash ]] && source ~/.bdt/aliases.bash"
|
|
if [[ -f "$profile_file" ]] && ! grep -q ".bdt/aliases.bash" "$profile_file" 2>/dev/null; then
|
|
echo "$alias_source_line" >> "$profile_file"
|
|
ok "Alias configurados en ${profile_file}"
|
|
else
|
|
ok "Alias ya configurados"
|
|
fi
|
|
echo ""
|
|
|
|
# 5. Verificar instalacion
|
|
echo -e " ${O3}${BOLD}[5/5] Verificando instalacion...${NC}"
|
|
|
|
if command -v bdt &>/dev/null || [[ -x "${install_dir}/bdt" ]]; then
|
|
ok "Comando 'bdt' disponible globalmente"
|
|
else
|
|
warn "El comando 'bdt' se instalara tras recargar el shell"
|
|
fi
|
|
|
|
ok "Directorio de config: ${config_dir}"
|
|
ok "Proyecto raiz: ${BDT_ROOT}"
|
|
echo ""
|
|
|
|
echo -e " ${GRAY}$(printf '%.0s─' {1..60})${NC}"
|
|
echo -e " ${GREEN}${BOLD}Instalacion completada.${NC}"
|
|
echo ""
|
|
echo -e " ${O3}${BOLD}Para activar ahora:${NC}"
|
|
echo -e " ${GRAY}source ${profile_file}${NC}"
|
|
echo ""
|
|
echo -e " ${O3}${BOLD}Despues puedes usar desde cualquier lugar:${NC}"
|
|
echo -e " ${WHITE}bdt${NC} Menu interactivo"
|
|
echo -e " ${WHITE}bdt deploy${NC} Deploy completo"
|
|
echo -e " ${WHITE}bdt status${NC} Estado del sistema"
|
|
echo -e " ${WHITE}bdt logs gw -f${NC} Seguir logs"
|
|
echo ""
|
|
echo -e " ${O3}${BOLD}Alias disponibles:${NC}"
|
|
echo -e " ${WHITE}bdt-up${NC} ${WHITE}bdt-down${NC} ${WHITE}bdt-status${NC} ${WHITE}bdt-deploy${NC}"
|
|
echo -e " ${WHITE}bdt-lg${NC} (logs gateway) ${WHITE}bdt-lc${NC} (logs channels)"
|
|
echo -e " ${WHITE}bdt-ls${NC} (logs service-bus) ${WHITE}bdt-lf${NC} (logs frontend)"
|
|
echo -e " ${WHITE}bdt-cd${NC} (ir al proyecto) ${WHITE}bdt-menu${NC} (menu interactivo)"
|
|
echo ""
|
|
}
|
|
|
|
#===============================================================================
|
|
# COMANDO: menu - Menu interactivo
|
|
#===============================================================================
|
|
|
|
# Ejecuta la opción elegida. Llamado con `|| true` para que un comando
|
|
# fallido no mate el menú (set -e).
|
|
_menu_dispatch() {
|
|
local choice="$1"
|
|
case "$choice" in
|
|
0) cmd_construir ;;
|
|
1) cmd_up all ;;
|
|
2) cmd_up infra ;;
|
|
3) cmd_up apps ;;
|
|
4) cmd_down all ;;
|
|
5)
|
|
echo -ne " Servicio a reiniciar (gateway/canales-admin-web/canales-worker/service-bus/frontend/postgres/redis/keycloak): "
|
|
read -r svc_name
|
|
[[ -n "$svc_name" ]] && cmd_restart "$svc_name"
|
|
;;
|
|
6) cmd_status ;;
|
|
7) cmd_health ;;
|
|
8)
|
|
echo -ne " Servicio (gateway/canales-admin-web/canales-worker/service-bus/frontend/postgres/redis/keycloak/all): "
|
|
read -r log_svc
|
|
echo -ne " Lineas (100) o -f para seguir: "
|
|
read -r log_lines
|
|
[[ -n "$log_svc" ]] && cmd_logs "$log_svc" "${log_lines:-100}"
|
|
;;
|
|
9) cmd_logs all 200 ;;
|
|
a) cmd_verify_db ;;
|
|
b) cmd_verify_api ;;
|
|
c) cmd_creds ;;
|
|
d) cmd_deploy ;;
|
|
e) cmd_install ;;
|
|
f) cmd_build all ;;
|
|
g) cmd_clone ;;
|
|
h) cmd_pull ;;
|
|
i)
|
|
echo -ne " Servicio a actualizar (gateway/canales-admin-web/canales-worker/service-bus/frontend/all): "
|
|
read -r upd_svc
|
|
[[ -n "$upd_svc" ]] && cmd_update "$upd_svc"
|
|
;;
|
|
j)
|
|
echo -ne " Ambiente (desarrollo/calidad/demo/produccion): "
|
|
read -r new_env
|
|
[[ -n "$new_env" ]] && cmd_env "$new_env"
|
|
;;
|
|
k) cmd_clean ;;
|
|
r) cmd_image_build_amd64 all ;;
|
|
t) cmd_server_deploy ;;
|
|
s) cmd_setup ;;
|
|
\?) cmd_help ;;
|
|
q|Q)
|
|
echo ""
|
|
echo -e " ${O3}Hasta luego!${NC}"
|
|
echo ""
|
|
exit 0
|
|
;;
|
|
*) warn "Opcion no valida" ;;
|
|
esac
|
|
}
|
|
|
|
cmd_menu() {
|
|
while true; do
|
|
banner
|
|
echo -e " ${O1}${BOLD}0) CONSTRUIR SERVICIO${NC} ${GRAY}— asistente: git banco → build → docker → up${NC}"
|
|
echo ""
|
|
echo -e " ${O2}${BOLD}SERVICIOS${NC} ${O3}${BOLD}MONITOREO${NC} ${O1}${BOLD}VERIFICACION${NC}"
|
|
echo -e " ${GRAY}$(printf '%.0s─' {1..60})${NC}"
|
|
echo -e " ${WHITE}1${NC}) Levantar todo ${WHITE}6${NC}) Estado servicios ${WHITE}a${NC}) Verificar DB"
|
|
echo -e " ${WHITE}2${NC}) Solo infraestructura ${WHITE}7${NC}) Health check ${WHITE}b${NC}) Verificar APIs"
|
|
echo -e " ${WHITE}3${NC}) Solo aplicaciones ${WHITE}8${NC}) Ver logs ${WHITE}c${NC}) Credenciales"
|
|
echo -e " ${WHITE}4${NC}) Detener todo ${WHITE}9${NC}) Logs combinados"
|
|
echo -e " ${WHITE}5${NC}) Reiniciar servicio"
|
|
echo ""
|
|
echo -e " ${O2}${BOLD}DEPLOYMENT${NC} ${O3}${BOLD}REPOSITORIOS${NC} ${O1}${BOLD}SISTEMA${NC}"
|
|
echo -e " ${GRAY}$(printf '%.0s─' {1..60})${NC}"
|
|
echo -e " ${WHITE}d${NC}) Deploy completo ${WHITE}g${NC}) Clonar repos ${WHITE}s${NC}) Setup global"
|
|
echo -e " ${WHITE}e${NC}) Compilar todo ${WHITE}h${NC}) Actualizar repos ${WHITE}j${NC}) Cambiar ambiente"
|
|
echo -e " ${WHITE}f${NC}) Build Docker ${WHITE}i${NC}) Actualizar servicio ${WHITE}k${NC}) Limpiar Docker"
|
|
echo -e " ${WHITE}r${NC}) Build amd64 + push registry ${WHITE}t${NC}) Deploy en server (SSH)"
|
|
echo ""
|
|
echo -e " ${WHITE}?${NC}) Ayuda ${WHITE}q${NC}) Salir"
|
|
echo ""
|
|
echo -ne " ${O3}bdt [$(env_label)]${NC} ${O1}>${NC} "
|
|
read -r choice
|
|
|
|
_menu_dispatch "$choice" || warn "El comando terminó con error (el menú sigue activo)"
|
|
|
|
echo ""
|
|
echo -ne " ${GRAY}Presiona Enter para continuar...${NC}"
|
|
read -r
|
|
done
|
|
}
|
|
|
|
#===============================================================================
|
|
# COMANDOS: image-build / image-push / image-pull / image-deploy
|
|
# Build Docker local → push a Gitea Registry → pull en server banco.
|
|
# Credenciales en ~/.bdt/gitea-registry.env (chmod 600).
|
|
#===============================================================================
|
|
|
|
IMAGE_SERVICES=(gateway frontend service-bus canales-admin-web canales-worker)
|
|
|
|
_image_dir() {
|
|
case "$1" in
|
|
gateway) echo "${GATEWAY_DIR}" ;;
|
|
frontend) echo "${FRONTEND_DIR}" ;;
|
|
service-bus) echo "${SERVICEBUS_DIR}" ;;
|
|
canales-admin-web) echo "${CANALES_DIR}" ;;
|
|
canales-worker) echo "${CANALES_DIR}" ;;
|
|
*) return 1 ;;
|
|
esac
|
|
}
|
|
|
|
# Dockerfile relativo al build context (_image_dir). Vacío = usar default "<dir>/Dockerfile".
|
|
_image_dockerfile() {
|
|
case "$1" in
|
|
canales-admin-web) echo "apps/admin-web/Dockerfile" ;;
|
|
canales-worker) echo "apps/worker/Dockerfile" ;;
|
|
*) echo "" ;;
|
|
esac
|
|
}
|
|
|
|
_image_load_creds() {
|
|
local env_file="${HOME}/.bdt/gitea-registry.env"
|
|
if [[ ! -f "$env_file" ]]; then
|
|
err "Falta ${env_file}"
|
|
echo " Ejecutá: ${GRAY}./bdt.sh image-login${NC}"
|
|
return 1
|
|
fi
|
|
# shellcheck disable=SC1090
|
|
set -a; source "$env_file"; set +a
|
|
: "${GITEA_REGISTRY_URL:?GITEA_REGISTRY_URL no definido}"
|
|
: "${GITEA_CI_USER:?GITEA_CI_USER no definido}"
|
|
: "${GITEA_CI_TOKEN:?GITEA_CI_TOKEN no definido}"
|
|
: "${GITEA_ORG:=bdt}"
|
|
}
|
|
|
|
_image_tag() {
|
|
local svc="$1" kind="${2:-latest}"
|
|
echo "${GITEA_REGISTRY_URL}/${GITEA_ORG}/${svc}:${kind}"
|
|
}
|
|
|
|
_image_sha() {
|
|
local dir="$1"
|
|
(cd "$dir" && git rev-parse --short HEAD 2>/dev/null) || echo "local"
|
|
}
|
|
|
|
# Copia el JAR desde ~/.bdt/jars/<svc>/ → <dir>/build/libs/
|
|
# El usuario debe dejar el JAR compilado en esa carpeta antes de llamar image-build.
|
|
_jar_copy() {
|
|
local svc="$1" dir="$2"
|
|
local jar_inbox="${HOME}/.bdt/jars/${svc}"
|
|
local jar_dest="${dir}/build/libs"
|
|
local jar_file
|
|
jar_file="$(ls "${jar_inbox}"/*.jar 2>/dev/null | head -1)"
|
|
if [[ -z "$jar_file" ]]; then
|
|
err "No hay JAR en ${jar_inbox}/"
|
|
warn "Copiá el .jar compilado → ${jar_inbox}/ y volvé a correr"
|
|
return 1
|
|
fi
|
|
mkdir -p "$jar_dest"
|
|
rm -f "${jar_dest}"/*.jar
|
|
case "$svc" in
|
|
service-bus)
|
|
cp "$jar_file" "${jar_dest}/service-bus.jar"
|
|
ok "JAR → ${jar_dest}/service-bus.jar"
|
|
;;
|
|
*)
|
|
cp "$jar_file" "${jar_dest}/"
|
|
ok "JAR → ${jar_dest}/$(basename "$jar_file")"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
cmd_image_login() {
|
|
banner
|
|
step "IMAGE-LOGIN" "Docker login Gitea Registry"
|
|
_image_load_creds || return 1
|
|
echo "$GITEA_CI_TOKEN" | docker login "$GITEA_REGISTRY_URL" -u "$GITEA_CI_USER" --password-stdin 2>&1 \
|
|
| while read -r l; do echo -e " ${GRAY}${l}${NC}"; done
|
|
ok "Login OK: ${GITEA_REGISTRY_URL}"
|
|
}
|
|
|
|
cmd_image_build() {
|
|
banner
|
|
_image_load_creds || return 1
|
|
local target="${1:-all}"
|
|
local services=()
|
|
if [[ "$target" == "all" ]]; then services=("${IMAGE_SERVICES[@]}"); else services=("$target"); fi
|
|
|
|
for svc in "${services[@]}"; do
|
|
local dir dockerfile dockerfile_path
|
|
dir="$(_image_dir "$svc")" || { err "Servicio desconocido: $svc"; continue; }
|
|
dockerfile="$(_image_dockerfile "$svc")"
|
|
if [[ -n "$dockerfile" ]]; then
|
|
dockerfile_path="${dir}/${dockerfile}"
|
|
else
|
|
dockerfile_path="${dir}/Dockerfile"
|
|
fi
|
|
[[ ! -f "$dockerfile_path" ]] && { warn "Sin Dockerfile: ${svc} (${dockerfile_path})"; continue; }
|
|
|
|
local sha tag_sha tag_latest
|
|
sha="$(_image_sha "$dir")"
|
|
tag_sha="$(_image_tag "$svc" "$sha")"
|
|
tag_latest="$(_image_tag "$svc" latest)"
|
|
|
|
# JAR pre-compilado desde ~/.bdt/jars/<svc>/ (el usuario lo sube antes)
|
|
case "$svc" in
|
|
gateway|service-bus)
|
|
step "JAR-COPY" "${svc}"
|
|
_jar_copy "$svc" "$dir" || return 1
|
|
;;
|
|
esac
|
|
|
|
step "IMAGE-BUILD" "${svc} @ ${sha}"
|
|
local build_args=(--no-cache -t "$tag_sha" -t "$tag_latest")
|
|
[[ -n "$dockerfile" ]] && build_args+=(-f "$dockerfile_path")
|
|
build_args+=("$dir")
|
|
echo -e " ${GRAY}docker build ${build_args[*]}${NC}"
|
|
if docker build "${build_args[@]}" 2>&1 | tail -20 | while read -r l; do echo -e " ${GRAY}${l}${NC}"; done; then
|
|
ok "${svc} → ${tag_sha}"
|
|
else
|
|
err "Build falló: ${svc}"
|
|
return 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
cmd_image_push() {
|
|
banner
|
|
_image_load_creds || return 1
|
|
local target="${1:-all}"
|
|
local services=()
|
|
if [[ "$target" == "all" ]]; then services=("${IMAGE_SERVICES[@]}"); else services=("$target"); fi
|
|
|
|
# Ensure logged in
|
|
echo "$GITEA_CI_TOKEN" | docker login "$GITEA_REGISTRY_URL" -u "$GITEA_CI_USER" --password-stdin >/dev/null 2>&1 \
|
|
|| { err "Login fallido"; return 1; }
|
|
|
|
for svc in "${services[@]}"; do
|
|
local dir sha tag_sha tag_latest
|
|
dir="$(_image_dir "$svc")" || continue
|
|
sha="$(_image_sha "$dir")"
|
|
tag_sha="$(_image_tag "$svc" "$sha")"
|
|
tag_latest="$(_image_tag "$svc" latest)"
|
|
|
|
step "IMAGE-PUSH" "${svc} → ${GITEA_REGISTRY_URL}/${GITEA_ORG}/${svc}"
|
|
if ! docker image inspect "$tag_sha" >/dev/null 2>&1; then
|
|
warn "Imagen local ausente: ${tag_sha} — corré 'image-build ${svc}' primero"
|
|
continue
|
|
fi
|
|
docker push "$tag_sha" 2>&1 | tail -5 | while read -r l; do echo -e " ${GRAY}${l}${NC}"; done
|
|
docker push "$tag_latest" 2>&1 | tail -5 | while read -r l; do echo -e " ${GRAY}${l}${NC}"; done
|
|
ok "${svc} pushed: ${sha} + latest"
|
|
done
|
|
}
|
|
|
|
cmd_image_pull() {
|
|
banner
|
|
_image_load_creds || return 1
|
|
local target="${1:-all}" tag_kind="${2:-latest}"
|
|
local services=()
|
|
if [[ "$target" == "all" ]]; then services=("${IMAGE_SERVICES[@]}"); else services=("$target"); fi
|
|
|
|
echo "$GITEA_CI_TOKEN" | docker login "$GITEA_REGISTRY_URL" -u "$GITEA_CI_USER" --password-stdin >/dev/null 2>&1 \
|
|
|| { err "Login fallido"; return 1; }
|
|
|
|
for svc in "${services[@]}"; do
|
|
local tag
|
|
tag="$(_image_tag "$svc" "$tag_kind")"
|
|
step "IMAGE-PULL" "${svc} ← ${tag}"
|
|
if docker pull "$tag" 2>&1 | tail -5 | while read -r l; do echo -e " ${GRAY}${l}${NC}"; done; then
|
|
# Re-tag to local alias expected by docker-compose
|
|
docker tag "$tag" "bdt-${svc}:latest"
|
|
ok "${svc} pulled → bdt-${svc}:latest"
|
|
else
|
|
err "Pull falló: ${svc}"
|
|
fi
|
|
done
|
|
}
|
|
|
|
cmd_image_deploy() {
|
|
banner
|
|
_image_load_creds || return 1
|
|
local target="${1:-all}" tag_kind="${2:-latest}"
|
|
local services=()
|
|
if [[ "$target" == "all" ]]; then services=("${IMAGE_SERVICES[@]}"); else services=("$target"); fi
|
|
|
|
step "IMAGE-DEPLOY" "Server-side deploy from ${GITEA_REGISTRY_URL}"
|
|
|
|
# 1) Pull nuevos
|
|
cmd_image_pull "$target" "$tag_kind"
|
|
|
|
# 2) Stop + rm contenedores viejos
|
|
cd "$INFRA_DIR"
|
|
for svc in "${services[@]}"; do
|
|
step "STOP" "bdt-${svc}"
|
|
$COMPOSE_CMD --profile apps stop "$svc" 2>/dev/null || true
|
|
$COMPOSE_CMD --profile apps rm -f "$svc" 2>/dev/null || true
|
|
done
|
|
|
|
# 3) Remove imágenes locales dangling (del build anterior)
|
|
docker image prune -f >/dev/null 2>&1 || true
|
|
ok "Dangling images purged"
|
|
|
|
# 4) Up con imagen nueva
|
|
step "UP" "Recreando servicios con imagen nueva"
|
|
$COMPOSE_CMD --profile apps up -d "${services[@]}" 2>&1 | while read -r l; do echo -e " ${GRAY}${l}${NC}"; done
|
|
|
|
# 5) Health check
|
|
cd "$BDT_ROOT"
|
|
echo ""
|
|
cmd_health
|
|
}
|
|
|
|
cmd_image_build_amd64() {
|
|
local script="${INFRA_DIR}/scripts/build-push-amd64.sh"
|
|
[[ ! -f "$script" ]] && { err "Script no encontrado: ${script}"; return 1; }
|
|
bash "$script" "$@"
|
|
}
|
|
|
|
cmd_server_deploy() {
|
|
local script="${INFRA_DIR}/scripts/server-deploy.sh"
|
|
[[ ! -f "$script" ]] && { err "Script no encontrado: ${script}"; return 1; }
|
|
_image_load_creds || return 1
|
|
|
|
# Servidor destino: configurar en ~/.bdt/config (no se versiona)
|
|
local server="${DEPLOY_SERVER:-}"
|
|
local server_user="${DEPLOY_USER:-}"
|
|
if [[ -z "$server" || -z "$server_user" ]]; then
|
|
err "Falta configurar el servidor destino"
|
|
echo -e " Agregá en ${GRAY}~/.bdt/config${NC}:"
|
|
echo -e " ${GRAY}DEPLOY_SERVER=<ip-del-servidor>${NC}"
|
|
echo -e " ${GRAY}DEPLOY_USER=<usuario-ssh>${NC}"
|
|
return 1
|
|
fi
|
|
local remote_script="/tmp/bdt-server-deploy.sh"
|
|
|
|
step "SCP" "Copiando script → ${server_user}@${server}"
|
|
scp "$script" "${server_user}@${server}:${remote_script}" || { err "SCP falló"; return 1; }
|
|
ok "Script copiado"
|
|
|
|
step "SSH" "Ejecutando deploy en ${server}"
|
|
ssh "${server_user}@${server}" \
|
|
"REGISTRY='${GITEA_REGISTRY_URL}' REGISTRY_USER='${GITEA_CI_USER}' REGISTRY_TOKEN='${GITEA_CI_TOKEN}' bash ${remote_script} $*"
|
|
}
|
|
|
|
#===============================================================================
|
|
# COMANDO: construir - Asistente: git banco → compilar → imagen Docker → up
|
|
#===============================================================================
|
|
|
|
svc_desc() {
|
|
case "$1" in
|
|
frontend) echo "Internet Banking (Next.js)" ;;
|
|
gateway) echo "API Gateway (Spring Boot)" ;;
|
|
service-bus) echo "Service Bus / ESB (Spring Boot)" ;;
|
|
canales-admin-web) echo "Canales Admin Web (pnpm)" ;;
|
|
canales-worker) echo "Canales Worker (pnpm)" ;;
|
|
esac
|
|
}
|
|
|
|
cmd_construir() {
|
|
banner
|
|
step "ASISTENTE" "Construir y desplegar un servicio (git banco → build → docker → up)"
|
|
echo ""
|
|
|
|
# 1. ¿Qué vas a construir?
|
|
local options=() i=1 s
|
|
for s in $APP_SERVICES; do
|
|
options+=("$s")
|
|
local cname st
|
|
cname="$(docker_name "$s")"
|
|
st="$(docker inspect --format='{{.State.Status}}' "$cname" 2>/dev/null | tr -d '[:space:]' || true)"
|
|
[[ -z "$st" ]] && st="sin contenedor"
|
|
echo -e " ${WHITE}${i}${NC}) ${WHITE}${s}${NC} — $(svc_desc "$s") ${GRAY}[rama: $(repo_branch "$s") | contenedor: ${st}]${NC}"
|
|
i=$((i+1))
|
|
done
|
|
echo ""
|
|
echo -ne " ${O3}¿Qué servicio vas a construir? (1-${#options[@]} o nombre, Enter=cancelar):${NC} "
|
|
read -r choice
|
|
[[ -z "$choice" ]] && { warn "Cancelado"; return 0; }
|
|
|
|
local svc=""
|
|
if [[ "$choice" =~ ^[0-9]+$ ]] && (( choice >= 1 && choice <= ${#options[@]} )); then
|
|
svc="${options[$((choice-1))]}"
|
|
else
|
|
for s in "${options[@]}"; do [[ "$s" == "$choice" ]] && svc="$s"; done
|
|
fi
|
|
[[ -z "$svc" ]] && { err "Opción inválida: ${choice}"; return 1; }
|
|
|
|
local dir repo def_branch
|
|
dir="$(repo_dir "$svc")"
|
|
repo="$(repo_url "$svc")"
|
|
def_branch="$(repo_branch "$svc")"
|
|
|
|
# 2. ¿Qué rama?
|
|
echo -ne " ${O3}Rama a construir [${def_branch}]:${NC} "
|
|
read -r branch
|
|
branch="${branch:-$def_branch}"
|
|
|
|
# 3. Resumen + confirmación
|
|
local dockerfile pre_build=""
|
|
dockerfile="$(_image_dockerfile "$svc")"
|
|
case "$svc" in gateway|service-bus) pre_build="gradle bootJar → " ;; esac
|
|
echo ""
|
|
echo -e " ${O2}${BOLD}Plan de ejecución:${NC}"
|
|
echo -e " Servicio: ${WHITE}${svc}${NC}"
|
|
echo -e " Repo banco: ${WHITE}${repo}${NC}"
|
|
echo -e " Rama: ${WHITE}${branch}${NC}"
|
|
echo -e " Directorio: ${GRAY}${dir}${NC}"
|
|
echo -e " Dockerfile: ${GRAY}${dir}/${dockerfile:-Dockerfile}${NC}"
|
|
echo -e " Pasos: ${GRAY}git pull → ${pre_build}docker build → up -d → health${NC}"
|
|
echo ""
|
|
echo -ne " ${O3}¿Continuar? (s/N):${NC} "
|
|
read -r confirm
|
|
[[ ! "$confirm" =~ ^[sSyY] ]] && { warn "Cancelado"; return 0; }
|
|
|
|
local start_time=$(date +%s)
|
|
|
|
# PASO 1: Git — clonar o actualizar desde el GitLab del banco
|
|
step "1/4 GIT" "Descargando rama ${branch} desde el GitLab del banco"
|
|
if [[ ! -d "$dir/.git" ]]; then
|
|
info "Repo no existe localmente, clonando..."
|
|
mkdir -p "$(dirname "$dir")"
|
|
git clone -b "$branch" "$repo" "$dir" || { err "Clone falló: ${repo} (¿VPN al banco activa?)"; return 1; }
|
|
ok "Clonado en ${dir} (${branch})"
|
|
else
|
|
local remote
|
|
remote="$(_bank_remote "$dir")"
|
|
if [[ -z "$remote" ]]; then
|
|
warn "Ningún remote apunta a ${GITLAB_URL} — uso 'origin'"
|
|
remote="origin"
|
|
fi
|
|
cd "$dir"
|
|
info "Remote banco: ${remote} ($(git remote get-url "$remote" 2>/dev/null))"
|
|
git fetch "$remote" --prune || { err "Fetch falló (¿VPN al banco activa?)"; cd "$BDT_ROOT"; return 1; }
|
|
|
|
if [[ -n "$(git status --porcelain 2>/dev/null | head -1)" ]]; then
|
|
warn "Hay cambios locales sin commitear en ${dir}"
|
|
echo -ne " ${O3}¿Guardar en stash y continuar? (s/N):${NC} "
|
|
read -r do_stash
|
|
if [[ "$do_stash" =~ ^[sSyY] ]]; then
|
|
git stash push -u -m "bdt-construir $(date '+%Y%m%d-%H%M%S')" && ok "Cambios guardados en stash"
|
|
else
|
|
err "Abortado para no pisar cambios locales"
|
|
cd "$BDT_ROOT"; return 1
|
|
fi
|
|
fi
|
|
|
|
git checkout "$branch" 2>/dev/null || git checkout -b "$branch" "${remote}/${branch}" 2>/dev/null || \
|
|
{ err "La rama '${branch}' no existe en ${remote}"; cd "$BDT_ROOT"; return 1; }
|
|
git pull "$remote" "$branch" && ok "Rama ${branch} @ $(git rev-parse --short HEAD)" || \
|
|
{ err "Pull falló"; cd "$BDT_ROOT"; return 1; }
|
|
cd "$BDT_ROOT"
|
|
fi
|
|
|
|
# PASO 2: Compilación previa (solo Java: el Dockerfile copia build/libs/*.jar)
|
|
case "$svc" in
|
|
gateway|service-bus)
|
|
step "2/4 GRADLE" "Compilando ${svc} (bootJar, sin tests)"
|
|
cd "$dir"
|
|
if ./gradlew clean bootJar -x test > "${LOG_DIR}/${svc}-construir-gradle.log" 2>&1; then
|
|
ok "JAR generado: $(ls "${dir}"/build/libs/*.jar 2>/dev/null | head -1)"
|
|
else
|
|
err "Gradle falló (ver ${LOG_DIR}/${svc}-construir-gradle.log)"
|
|
tail -15 "${LOG_DIR}/${svc}-construir-gradle.log" | while read -r l; do echo -e " ${GRAY}${l}${NC}"; done
|
|
cd "$BDT_ROOT"; return 1
|
|
fi
|
|
cd "$BDT_ROOT"
|
|
;;
|
|
*)
|
|
step "2/4 BUILD" "Compilación dentro del Docker build (multi-stage)"
|
|
ok "Nada que compilar fuera del Docker"
|
|
;;
|
|
esac
|
|
|
|
# PASO 3: Imagen Docker
|
|
step "3/4 DOCKER" "Construyendo imagen bdt-${svc}:latest"
|
|
_docker_build_local "$svc" || return 1
|
|
|
|
# PASO 4: Recrear contenedor + health
|
|
step "4/4 UP" "Recreando contenedor ${svc}"
|
|
cd "$INFRA_DIR"
|
|
$COMPOSE_CMD --profile apps up -d --force-recreate "$svc" 2>&1 | while read -r l; do echo -e " ${GRAY}${l}${NC}"; done
|
|
cd "$BDT_ROOT"
|
|
|
|
local url
|
|
url="$(svc_health_url "$svc")"
|
|
if [[ -n "$url" ]]; then
|
|
info "Esperando salud de ${svc} (hasta 120s)..."
|
|
local tries=0 code="000"
|
|
while (( tries < 24 )); do
|
|
code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 3 "$url" 2>/dev/null || echo "000")
|
|
[[ "$code" =~ ^(200|302|401)$ ]] && break
|
|
sleep 5; tries=$((tries+1))
|
|
done
|
|
if [[ "$code" =~ ^(200|302|401)$ ]]; then
|
|
ok "${svc} arriba y saludable (HTTP ${code} en ${url})"
|
|
else
|
|
err "${svc} no responde tras $((tries*5))s (HTTP ${code}) — revisá: bdt logs ${svc}"
|
|
fi
|
|
fi
|
|
|
|
local elapsed=$(( $(date +%s) - start_time ))
|
|
echo ""
|
|
ok "Asistente completado en ${elapsed}s — ${svc} @ ${branch}"
|
|
}
|
|
|
|
#===============================================================================
|
|
# COMANDO: publish - Sincronizar bdt.sh al repo público bdt-cli (Gitea)
|
|
#===============================================================================
|
|
|
|
cmd_publish() {
|
|
banner
|
|
step "PUBLISH" "Sincronizando bdt.sh → repo público bdt-cli"
|
|
|
|
# Ubicación del clon de bdt-cli: por defecto, al lado de la raíz del proyecto.
|
|
# Override en ~/.bdt/config: BDT_CLI_DIR=/ruta/al/clon
|
|
local cli_dir="${BDT_CLI_DIR:-$(dirname "$BDT_ROOT")/bdt-cli}"
|
|
|
|
if [[ ! -d "${cli_dir}/.git" ]]; then
|
|
err "No existe el clon de bdt-cli en ${cli_dir}"
|
|
echo -e " Clonalo: ${GRAY}git clone https://git.dcgeeks.net/BDT/bdt-cli.git ${cli_dir}${NC}"
|
|
echo -e " O definí ${GRAY}BDT_CLI_DIR=/ruta${NC} en ~/.bdt/config"
|
|
return 1
|
|
fi
|
|
|
|
cp "${BDT_ROOT}/bdt.sh" "${cli_dir}/bdt.sh"
|
|
chmod +x "${cli_dir}/bdt.sh"
|
|
|
|
cd "$cli_dir"
|
|
if git diff --quiet -- bdt.sh 2>/dev/null && [[ -z "$(git status --porcelain bdt.sh)" ]]; then
|
|
ok "Sin cambios: bdt-cli ya está al día (v${SCRIPT_VERSION})"
|
|
cd "$BDT_ROOT"
|
|
return 0
|
|
fi
|
|
|
|
local src_sha
|
|
src_sha="$(git -C "$BDT_ROOT" rev-parse --short HEAD 2>/dev/null || echo local)"
|
|
git add bdt.sh
|
|
git commit -q -m "chore: sync bdt.sh v${SCRIPT_VERSION} (monorepo @ ${src_sha})" && \
|
|
ok "Commit creado: v${SCRIPT_VERSION} @ ${src_sha}" || { err "Commit falló"; cd "$BDT_ROOT"; return 1; }
|
|
|
|
info "Pusheando a Gitea..."
|
|
if git push origin main 2>&1 | tail -2 | while read -r l; do echo -e " ${GRAY}${l}${NC}"; done; then
|
|
ok "Publicado: https://git.dcgeeks.net/BDT/bdt-cli"
|
|
else
|
|
err "Push falló — corré 'git push origin main' en ${cli_dir}"
|
|
cd "$BDT_ROOT"; return 1
|
|
fi
|
|
cd "$BDT_ROOT"
|
|
}
|
|
|
|
#===============================================================================
|
|
# AYUDA
|
|
#===============================================================================
|
|
|
|
cmd_help() {
|
|
banner
|
|
echo -e " ${O2}${BOLD}REPOSITORIOS${NC}"
|
|
echo -e " ${WHITE}clone${NC} [branch] Clonar todos los repos desde GitLab"
|
|
echo -e " ${WHITE}pull${NC} [branch] Actualizar todos los repos (git pull)"
|
|
echo ""
|
|
echo -e " ${O2}${BOLD}COMPILACIÓN${NC}"
|
|
echo -e " ${WHITE}install${NC} Instalar dependencias + compilar todo"
|
|
echo -e " ${WHITE}build${NC} [servicio|all] Construir imágenes Docker"
|
|
echo ""
|
|
echo -e " ${O2}${BOLD}SERVICIOS${NC}"
|
|
echo -e " ${WHITE}up${NC} [all|infra|apps|tools|nombre] Levantar servicios"
|
|
echo -e " ${WHITE}down${NC} [all|nombre] Detener servicios"
|
|
echo -e " ${WHITE}restart${NC} [all|nombre] Reiniciar servicios"
|
|
echo -e " ${WHITE}update${NC} [all|nombre] Pull + build + restart"
|
|
echo ""
|
|
echo -e " ${O2}${BOLD}MONITOREO${NC}"
|
|
echo -e " ${WHITE}status${NC} Estado de todos los servicios"
|
|
echo -e " ${WHITE}health${NC} Health check completo"
|
|
echo -e " ${WHITE}logs${NC} <servicio> [N|-f] Ver logs (N=líneas, -f=seguir)"
|
|
echo -e " ${WHITE}logs all${NC} Logs combinados de todos"
|
|
echo ""
|
|
echo -e " ${O2}${BOLD}VERIFICACIÓN${NC}"
|
|
echo -e " ${WHITE}verify-db${NC} Verificar base de datos"
|
|
echo -e " ${WHITE}verify-api${NC} Verificar endpoints API"
|
|
echo ""
|
|
echo -e " ${O2}${BOLD}DEPLOYMENT${NC}"
|
|
echo -e " ${WHITE}construir${NC} Asistente interactivo: elegir servicio + rama → git banco → build → docker → up"
|
|
echo -e " ${WHITE}deploy${NC} Pipeline completo (pull→build→docker→up→health)"
|
|
echo -e " ${WHITE}env${NC} [ambiente] Cambiar ambiente (desarrollo|calidad|demo|produccion)"
|
|
echo ""
|
|
echo -e " ${O2}${BOLD}DOCKER REGISTRY (Gitea)${NC}"
|
|
echo -e " ${WHITE}image-login${NC} Docker login en ${GRAY}git.dcgeeks.net${NC}"
|
|
echo -e " ${WHITE}image-build${NC} [svc|all] Build local (tags: \$SHA + latest) — sin Gradle"
|
|
echo -e " ${WHITE}image-push${NC} [svc|all] Push a Gitea Registry"
|
|
echo -e " ${WHITE}image-pull${NC} [svc|all] [tag] Pull desde Gitea Registry"
|
|
echo -e " ${WHITE}image-deploy${NC} [svc|all] [tag] Pull + down + rm + up + health (server)"
|
|
echo -e " ${WHITE}image-build-amd64${NC} [svc|all] Build linux/amd64 + push al registry — sin Gradle"
|
|
echo -e " ${WHITE}server-deploy${NC} [svc|all] SCP + ejecutar deploy en NEWIB01-DEV via SSH"
|
|
echo ""
|
|
echo -e " ${O3}${BOLD}JAR pre-compilado (image-build / image-build-amd64):${NC}"
|
|
echo -e " Gradle NO corre. Copiá el JAR compilado ANTES de buildear:"
|
|
echo -e " ${GRAY}~/.bdt/jars/gateway/ ← gateway-*.jar${NC}"
|
|
echo -e " ${GRAY}~/.bdt/jars/service-bus/ ← service-bus.jar${NC}"
|
|
echo -e " ${GRAY}~/.bdt/jars/channels/ ← channels-*.jar${NC}"
|
|
echo -e " Docker build corre con --no-cache."
|
|
echo ""
|
|
echo -e " ${O2}${BOLD}UTILIDADES${NC}"
|
|
echo -e " ${WHITE}git-auth${NC} [user] [pass] Configurar credenciales Git (no pide clave en cada pull)"
|
|
echo -e " ${WHITE}publish${NC} Sincronizar bdt.sh al repo público bdt-cli (Gitea)"
|
|
echo -e " ${WHITE}setup${NC} Instalar 'bdt' como comando global + alias + autocompletado"
|
|
echo -e " ${WHITE}menu${NC} Menu interactivo (panel de control)"
|
|
echo -e " ${WHITE}creds${NC} Mostrar credenciales"
|
|
echo -e " ${WHITE}clean${NC} Limpiar Docker (contenedores, imágenes)"
|
|
echo -e " ${WHITE}help${NC} Mostrar esta ayuda"
|
|
echo ""
|
|
echo -e " ${O3}${BOLD}EJEMPLOS:${NC}"
|
|
echo -e " ${GRAY}./bdt.sh deploy${NC} Deploy completo"
|
|
echo -e " ${GRAY}./bdt.sh up infra && ./bdt.sh up apps${NC} Levantar por partes"
|
|
echo -e " ${GRAY}./bdt.sh logs gateway -f${NC} Seguir logs del gateway"
|
|
echo -e " ${GRAY}./bdt.sh update gateway${NC} Actualizar solo gateway"
|
|
echo -e " ${GRAY}./bdt.sh clone calidad${NC} Clonar rama calidad"
|
|
echo ""
|
|
}
|
|
|
|
#===============================================================================
|
|
# MAIN
|
|
#===============================================================================
|
|
|
|
cmd="${1:-menu}"
|
|
shift 2>/dev/null || true
|
|
|
|
case "$cmd" in
|
|
clone) cmd_clone "$@" ;;
|
|
pull) cmd_pull "$@" ;;
|
|
install) cmd_install "$@" ;;
|
|
build) cmd_build "$@" ;;
|
|
up|start) cmd_up "$@" ;;
|
|
down|stop) cmd_down "$@" ;;
|
|
restart) cmd_restart "$@" ;;
|
|
status|st) cmd_status "$@" ;;
|
|
logs|log) cmd_logs "$@" ;;
|
|
health|hc) cmd_health "$@" ;;
|
|
verify-db) cmd_verify_db "$@" ;;
|
|
verify-api) cmd_verify_api "$@" ;;
|
|
env) cmd_env "$@" ;;
|
|
update) cmd_update "$@" ;;
|
|
deploy) cmd_deploy "$@" ;;
|
|
construir|wizard|asistente) cmd_construir "$@" ;;
|
|
publish) cmd_publish "$@" ;;
|
|
creds) cmd_creds "$@" ;;
|
|
clean) cmd_clean "$@" ;;
|
|
git-auth) cmd_git_auth "$@" ;;
|
|
setup) cmd_setup "$@" ;;
|
|
menu) cmd_menu "$@" ;;
|
|
image-login) cmd_image_login "$@" ;;
|
|
image-build) cmd_image_build "$@" ;;
|
|
image-push) cmd_image_push "$@" ;;
|
|
image-pull) cmd_image_pull "$@" ;;
|
|
image-deploy) cmd_image_deploy "$@" ;;
|
|
image-build-amd64) cmd_image_build_amd64 "$@" ;;
|
|
server-deploy) cmd_server_deploy "$@" ;;
|
|
help|-h|--help) cmd_help "$@" ;;
|
|
*)
|
|
err "Comando desconocido: ${cmd}"
|
|
echo ""
|
|
echo " Usa: ${GRAY}./bdt.sh help${NC}"
|
|
exit 1
|
|
;;
|
|
esac
|