From fc489c2115ad043a637a2edd975e059c63e33a7d Mon Sep 17 00:00:00 2001 From: aagusfernandez02 Date: Mon, 20 Jul 2026 10:03:57 -0300 Subject: [PATCH] docs: update README for the single deploy-sco job scheme Reflect the move from per-client Jenkinsfiles/labels to one parameterized job (NODO + CLIENTE), the mc-based install.sh, and flag create-node.sh / create-client.sh as obsolete until they're rewritten for this scheme. Co-Authored-By: Claude Sonnet 5 --- README.md | 118 +++++++++++------------------------------------------- 1 file changed, 23 insertions(+), 95 deletions(-) diff --git a/README.md b/README.md index f7fdfcc..a1704d9 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,7 @@ Jenkins centralizado para el despliegue de software en terminales SCO (Self-Chec ├── deploy/ │ └── install.sh # Script desplegado en cada SCO └── pipelines/ - ├── Jenkinsfile.ralph # Pipeline del cliente Ralph - └── Jenkinsfile.lab # Pipeline del entorno de laboratorio + └── Jenkinsfile.sco # Pipeline único de deploy (NODO + CLIENTE) ``` ## Arquitectura @@ -24,7 +23,7 @@ Jenkins centralizado para el despliegue de software en terminales SCO (Self-Chec - **Nginx Proxy Manager (NPM)**: reverse proxy interno que resuelve el hostname `jenkins.laoficina1782.com` y hace forward hacia `jenkins-server:8080`. Corre en el mismo servidor, red `proxy`. - **Cloudflare Tunnel (`cloudflared`)**: es el único punto de entrada desde internet. El contenedor `cloudflared` abre una conexión saliente hacia el edge de Cloudflare (autenticada con `TUNNEL_TOKEN`), por lo que **no hace falta abrir puertos entrantes en el firewall/router** del servidor. El tunnel está configurado del lado de Cloudflare para enrutar el hostname público hacia `http://npm:80` dentro de la red `proxy`. - **Agentes (SCOs)**: cada terminal SCO conecta al master vía WebSocket (no JNLP), outbound hacia `wss://jenkins.laoficina1782.com/`. El proceso del agente corre como `root`. -- **Storage**: Minio almacena el software de cada cliente en buckets separados (ej: bucket `ralph`). +- **Storage**: Minio almacena el software de cada cliente en buckets separados. El nombre del bucket es el mismo valor que se selecciona en el parámetro `CLIENTE` del deploy (ej: bucket `mbs-ralphs`). ### Flujo de tráfico @@ -57,16 +56,6 @@ cp .env.example .env # editar .env y setear CLOUDFLARE_TUNNEL_TOKEN= ``` -### Labels de agentes - -Formato: `sco ` - -| Cliente | Tienda | Agentes | -|---|---|---| -| ralph | yabucoa | sco02–sco07 | -| ralph | san-lorenzo | sco03–sco06 | -| ralph | rio-grande | sco01–sco06 | - ## Levantar el servidor ```sh @@ -136,10 +125,16 @@ Configuración del proxy host para Jenkins: ## Ejecutar un deploy -1. En Jenkins, abrir el job `deploy-ralph` (o `deploy-lab` para el entorno de laboratorio). +Hay un único job, `deploy-sco`, que despliega a **un nodo puntual** (no a una tienda entera). + +1. En Jenkins, abrir el job `deploy-sco`. 2. Click en **Build with Parameters**. -3. Seleccionar la **tienda** destino en el dropdown (yabucoa / san-lorenzo / rio-grande para `deploy-ralph`; oficina para `deploy-lab`). -4. Opcionalmente, completar **NODO** con el nombre exacto de un SCO (ej. `ralph-yabucoa-sco05`) para deployar solo en ese nodo. Si se deja vacío, despliega en paralelo en todos los SCOs online de la tienda seleccionada. +3. Completar **NODO** con el nombre exacto del agente a deployar (ej. `ralph-yabucoa-sco05`). +4. Seleccionar **CLIENTE** en el dropdown — es el nombre del bucket de Minio que se sincroniza en ese nodo. + +Ambos parámetros son obligatorios: si `NODO` queda vacío o `CLIENTE` queda en `SELECCIONAR_CLIENTE` (el placeholder inicial), el build falla explícitamente en vez de deployar por accidente. Para desplegar a varios nodos (ej. toda una tienda) hay que correr el job una vez por nodo. + +> Nota: el **primer build** de este job (o de cualquier job parametrizado nuevo) corre antes de que Jenkins conozca los parámetros declarados en el Jenkinsfile — es una limitación de cómo Jenkins descubre los parámetros la primera vez. El pipeline lo detecta (`params.CLIENTE == null`) y termina como `NOT_BUILT` sin deployar nada; alcanza con volver a correr el job con **Build with Parameters** normalmente. También se puede disparar desde consola con el Jenkins CLI o `curl`, ver [Ejecutar un job desde consola](#ejecutar-un-job-desde-consola). @@ -150,96 +145,29 @@ curl -O https://jenkins.laoficina1782.com/jnlpJars/jenkins-cli.jar java -jar jenkins-cli.jar -s https://jenkins.laoficina1782.com/ \ -auth TU_USUARIO:TU_API_TOKEN \ - build deploy-lab -p TIENDA=oficina -s -v - -# Deploy a un solo nodo de la tienda -java -jar jenkins-cli.jar -s https://jenkins.laoficina1782.com/ \ - -auth TU_USUARIO:TU_API_TOKEN \ - build deploy-lab -p TIENDA=oficina -p NODO=lab-oficina-sco-77 -s -v + build deploy-sco -p NODO=ralph-yabucoa-sco05 -p CLIENTE=mbs-ralphs -s -v ``` - `-s` espera a que termine el build; `-v` muestra el log en consola. - El API Token se genera en el usuario de Jenkins → Configure → API Token. -- Alternativa sin el CLI: `curl -X POST https://jenkins.laoficina1782.com/job/deploy-lab/buildWithParameters --user TU_USUARIO:TU_API_TOKEN --data-urlencode "TIENDA=oficina"`. +- Alternativa sin el CLI: `curl -X POST https://jenkins.laoficina1782.com/job/deploy-sco/buildWithParameters --user TU_USUARIO:TU_API_TOKEN --data-urlencode "NODO=ralph-yabucoa-sco05" --data-urlencode "CLIENTE=mbs-ralphs"`. +- Si se dispara por CLI/`curl` **omitiendo** `-p CLIENTE=...`, Jenkins no manda un valor vacío: rellena el parámetro con su default, que es `SELECCIONAR_CLIENTE` (el placeholder es a propósito el primer valor de la lista, para que un `CLIENTE` faltante falle en vez de deployar silenciosamente al primer cliente real de la lista). ## Qué hace `install.sh` -Recibe el nombre del cliente como argumento (`$1`): +Recibe el nombre del cliente como argumento (`$1`), que es el mismo valor que se selecciona en el parámetro `CLIENTE` del deploy: -1. Genera config de rclone apuntando a Minio a través del hostname público `https://minio-api.laoficina1782.com` (antes apuntaba directo a la IP del servidor por el puerto `9000`; ahora pasa por el mismo túnel/proxy que Jenkins, con `force_path_style = true` porque el endpoint ya no es un bucket-subdominio). -2. Sincroniza el bucket `$CUSTOMER` desde Minio hacia `/opt/sco/` en el SCO (excluyendo datos persistentes del backend), con `--s3-sign-accept-encoding=false --multi-thread-streams=0` para evitar problemas de firma/concurrencia a través del proxy. +1. Da de alta (o reutiliza) un alias `mc` apuntando a Minio a través del hostname público `https://minio-api.laoficina1782.com`. +2. Mirrorea el bucket `$CUSTOMER` desde Minio hacia `/opt/sco/` en el SCO (excluyendo datos persistentes del backend), con `--remove --overwrite` para dejar el destino idéntico al bucket. Los pasos de instalación local (permisos, servicios systemd, autostart, crontabs, paquetes Python, imágenes Docker, inicialización de bases de datos del cpi-server, `engine.properties` de SymmetricDS) ya no están en este script — quedaron fuera del alcance actual de `install.sh`, que hoy solo se ocupa de traer el software del cliente a `/opt/sco/`. -## Scripts de alta (create-node.sh / create-client.sh) +## Agregar un nodo o un cliente nuevo -`data/jenkins/scripts/` tiene dos scripts para no tener que editar `jenkins.yaml`, los Jenkinsfiles y `docker-compose.yml` a mano. +Desde que el deploy pasó a un job único (`deploy-sco`, con `NODO` + `CLIENTE` como parámetros en vez de un Jenkinsfile/label por cliente), dar de alta algo nuevo es mucho más simple y **ya no requiere tocar `docker-compose.yml` ni crear Jenkinsfiles**: -**Prerequisito**: [`yq`](https://github.com/mikefarah/yq) (la versión de Go, **no** la de Python — son incompatibles, ver más abajo) y que los scripts tengan permiso de ejecución: -```sh -chmod +x data/jenkins/scripts/*.sh -``` +- **Agregar un nodo** (a un cliente existente o nuevo): agregar una entrada `permanent` en `.jenkins.nodes` de `data/jenkins/jenkins.yaml` con el nombre del agente (no hace falta `labelString`, el deploy targetea por nombre exacto de nodo). Después conectar el agente físico siguiendo [Conectar un agente SCO](#conectar-un-agente-sco). +- **Agregar un cliente**: agregar el nombre del bucket a la lista `choices` del parámetro `CLIENTE` en `data/jenkins/pipelines/Jenkinsfile.sco`. +- En ambos casos, aplicar el cambio con `docker compose up -d --build` (el contenedor de Jenkins re-lee `jenkins.yaml` vía JCasC). -Ambos **solo editan archivos** — no hacen `docker compose up -d --build` ni commits. Después de correrlos, revisá con `git diff` y aplicá el rebuild vos mismo. - -### create-node.sh — agregar un nodo a un cliente ya existente - -```sh -data/jenkins/scripts/create-node.sh --cliente --tienda --numero -``` - -- Arma el nombre (`--sco`, `numero` normalizado a 3 dígitos) y el label (`sco `) siguiendo la convención existente, y agrega el nodo al principio de `.jenkins.nodes` en `jenkins.yaml`. -- `cliente` y `tienda` deben ser minúsculas, números y guiones (`^[a-z0-9-]+$`) — nada de mayúsculas ni espacios. -- Valida que el cliente ya esté dado de alta (que exista `Jenkinsfile.`) y que la tienda esté en su dropdown de `TIENDA`. Si falla cualquiera de las dos, corta sin tocar `jenkins.yaml`. -- Detecta nodos duplicados (mismo nombre final) y corta sin duplicar. -- `--skip-checks` salta las validaciones de cliente/tienda existentes — lo usa `create-client.sh` internamente al dar de alta un cliente nuevo (en ese momento el Jenkinsfile todavía no existe). - -Ejemplo: -```sh -data/jenkins/scripts/create-node.sh --cliente ralph --tienda yabucoa --numero 8 -# -> nodo "ralph-yabucoa-sco008", label "sco ralph yabucoa" -``` - -### create-client.sh — dar de alta un cliente nuevo completo - -```sh -data/jenkins/scripts/create-client.sh --cliente \ - --tienda [--tienda ...] \ - --nodo : [--nodo : ...] -``` - -- `--tienda` es repetible: declara cada tienda que va a aparecer en el dropdown del Jenkinsfile (se deduplica automáticamente si se repite). -- `--nodo` es repetible: uno por cada SCO a crear, en formato `:`. Cada `tienda` referenciada en un `--nodo` tiene que haber sido declarada con algún `--tienda`. -- Corta antes de tocar nada si el cliente ya existe (ya hay `Jenkinsfile.` o ya hay un job `deploy-` en `jenkins.yaml`). -- Si falla la creación de algún nodo a mitad del loop (ej. `--nodo` repetido), revierte automáticamente los nodos ya creados en esa misma corrida antes de cortar — no deja nodos huérfanos. -- Al terminar, genera `data/jenkins/pipelines/Jenkinsfile.` (mismo esqueleto que `Jenkinsfile.ralph`, con el parámetro `NODO` opcional), agrega el job `deploy-` a `jenkins.yaml` y el volumen correspondiente a `docker-compose.yml`. - -Ejemplo: -```sh -data/jenkins/scripts/create-client.sh --cliente econo-mbs \ - --tienda yabucoa --tienda san-lorenzo \ - --nodo yabucoa:1 --nodo yabucoa:2 --nodo yabucoa:3 \ - --nodo san-lorenzo:3 --nodo san-lorenzo:4 -``` - -### Troubleshooting - -- **`usage: yq [-h] [--yaml-output] ...` / `yq: error: argument files: can't open '.jenkins...'`**: tenés instalado el `yq` de Python (kislyuk/yq), que usa sintaxis de `jq` y es incompatible. Desinstalalo (`pip uninstall yq`) e instalá el de Go: - ```sh - wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/local/bin/yq - chmod +x /usr/local/bin/yq - hash -r # si ya habías corrido "yq" antes en esa misma terminal, bash puede tener cacheada la ruta vieja - yq --version # debe decir "yq (https://github.com/mikefarah/yq/) version v4..." - ``` -- **`Permission denied` al correr un script**: falta el bit de ejecución — `chmod +x data/jenkins/scripts/*.sh`. -- **`printf: NNN: invalid octal number`**: no debería pasar (ya está resuelto), pero si aparece es porque un `--numero` con cero a la izquierda se está interpretando como octal en vez de decimal. - -## Agregar un nuevo cliente - -Con los scripts (recomendado, ver arriba), o a mano siguiendo estos pasos: - -1. Agregar los nodos del cliente en `data/jenkins/jenkins.yaml` con el label `sco `. -2. Crear `data/jenkins/pipelines/Jenkinsfile.` con el dropdown de tiendas. -3. Agregar el job en la sección `jobs` de `jenkins.yaml`. -4. Montar el nuevo Jenkinsfile en `docker-compose.yml`. -5. Recrear el contenedor: `docker compose up -d --build`. +> ⚠️ `data/jenkins/scripts/create-node.sh` y `create-client.sh` quedaron **obsoletos**: automatizan el esquema viejo (un Jenkinsfile y un label `sco ` por cliente), que ya no existe. No usarlos hasta reescribirlos para el esquema de `deploy-sco`.