Compare commits
11 Commits
7d51e8d012
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 1335ea1ebc | |||
| 91ff9dca9b | |||
| fc489c2115 | |||
| 71fe54b3e5 | |||
| 8ee3824dd7 | |||
| 1d7e14bb74 | |||
| 2152259140 | |||
| 529ba5e123 | |||
| 6a3d13cdfc | |||
| a9f1d79453 | |||
| dbc56955c9 |
@@ -14,8 +14,7 @@ Jenkins centralizado para el despliegue de software en terminales SCO (Self-Chec
|
|||||||
├── deploy/
|
├── deploy/
|
||||||
│ └── install.sh # Script desplegado en cada SCO
|
│ └── install.sh # Script desplegado en cada SCO
|
||||||
└── pipelines/
|
└── pipelines/
|
||||||
├── Jenkinsfile.ralph # Pipeline del cliente Ralph
|
└── Jenkinsfile.sco # Pipeline único de deploy (NODO + CLIENTE)
|
||||||
└── Jenkinsfile.lab # Pipeline del entorno de laboratorio
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Arquitectura
|
## 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`.
|
- **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`.
|
- **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`.
|
- **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
|
### Flujo de tráfico
|
||||||
|
|
||||||
@@ -57,16 +56,6 @@ cp .env.example .env
|
|||||||
# editar .env y setear CLOUDFLARE_TUNNEL_TOKEN=<token>
|
# editar .env y setear CLOUDFLARE_TUNNEL_TOKEN=<token>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Labels de agentes
|
|
||||||
|
|
||||||
Formato: `sco <cliente> <tienda>`
|
|
||||||
|
|
||||||
| Cliente | Tienda | Agentes |
|
|
||||||
|---|---|---|
|
|
||||||
| ralph | yabucoa | sco02–sco07 |
|
|
||||||
| ralph | san-lorenzo | sco03–sco06 |
|
|
||||||
| ralph | rio-grande | sco01–sco06 |
|
|
||||||
|
|
||||||
## Levantar el servidor
|
## Levantar el servidor
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
@@ -136,10 +125,16 @@ Configuración del proxy host para Jenkins:
|
|||||||
|
|
||||||
## Ejecutar un deploy
|
## 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**.
|
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`).
|
3. Completar **NODO** con el nombre exacto del agente a deployar (ej. `ralph-yabucoa-sco05`).
|
||||||
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.
|
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).
|
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/ \
|
java -jar jenkins-cli.jar -s https://jenkins.laoficina1782.com/ \
|
||||||
-auth TU_USUARIO:TU_API_TOKEN \
|
-auth TU_USUARIO:TU_API_TOKEN \
|
||||||
build deploy-lab -p TIENDA=oficina -s -v
|
build deploy-sco -p NODO=ralph-yabucoa-sco05 -p CLIENTE=mbs-ralphs -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
|
|
||||||
```
|
```
|
||||||
|
|
||||||
- `-s` espera a que termine el build; `-v` muestra el log en consola.
|
- `-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.
|
- 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`
|
## 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).
|
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. 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.
|
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/`.
|
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:
|
- **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).
|
||||||
```sh
|
- **Agregar un cliente**: agregar el nombre del bucket a la lista `choices` del parámetro `CLIENTE` en `data/jenkins/pipelines/Jenkinsfile.sco`.
|
||||||
chmod +x data/jenkins/scripts/*.sh
|
- 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.
|
> ⚠️ `data/jenkins/scripts/create-node.sh` y `create-client.sh` quedaron **obsoletos**: automatizan el esquema viejo (un Jenkinsfile y un label `sco <cliente> <tienda>` por cliente), que ya no existe. No usarlos hasta reescribirlos para el esquema de `deploy-sco`.
|
||||||
|
|
||||||
### create-node.sh — agregar un nodo a un cliente ya existente
|
|
||||||
|
|
||||||
```sh
|
|
||||||
data/jenkins/scripts/create-node.sh --cliente <cliente> --tienda <tienda> --numero <numero>
|
|
||||||
```
|
|
||||||
|
|
||||||
- Arma el nombre (`<cliente>-<tienda>-sco<numero>`, `numero` normalizado a 3 dígitos) y el label (`sco <cliente> <tienda>`) 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.<cliente>`) 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 <cliente> \
|
|
||||||
--tienda <nombre> [--tienda <nombre> ...] \
|
|
||||||
--nodo <tienda>:<numero> [--nodo <tienda>:<numero> ...]
|
|
||||||
```
|
|
||||||
|
|
||||||
- `--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 `<tienda>:<numero>`. 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.<cliente>` o ya hay un job `deploy-<cliente>` 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.<cliente>` (mismo esqueleto que `Jenkinsfile.ralph`, con el parámetro `NODO` opcional), agrega el job `deploy-<cliente>` 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 <cliente> <tienda>`.
|
|
||||||
2. Crear `data/jenkins/pipelines/Jenkinsfile.<cliente>` 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`.
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM jenkins/jenkins:2.541.3-jdk17
|
FROM jenkins/jenkins:2.541.3-jdk21
|
||||||
|
|
||||||
USER root
|
USER root
|
||||||
RUN apt-get update && apt-get install -y curl git && rm -rf /var/lib/apt/lists/*
|
RUN apt-get update && apt-get install -y curl git && rm -rf /var/lib/apt/lists/*
|
||||||
|
|||||||
@@ -1,16 +1,78 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
|
### DOWNLOAD MC
|
||||||
|
if [ ! -f /usr/local/bin/mc ]; then
|
||||||
|
curl -L https://dl.min.io/client/mc/release/linux-amd64/mc -o /usr/local/bin/mc
|
||||||
|
chmod +x /usr/local/bin/mc
|
||||||
|
fi
|
||||||
|
|
||||||
|
### UPDATE SOFTWARE
|
||||||
SERVER=minio-api.laoficina1782.com
|
SERVER=minio-api.laoficina1782.com
|
||||||
CUSTOMER=$1
|
CUSTOMER=$1
|
||||||
cat <<CONF > /tmp/rclone.conf
|
mc --config-dir /tmp/mc-config alias set minio https://minio-api.laoficina1782.com minioadmin LIGTNbUgQr
|
||||||
[minio]
|
mc --config-dir /tmp/mc-config mirror --remove --overwrite --exclude "backend/docker/data/**" minio/$CUSTOMER /opt/sco/
|
||||||
type = s3
|
find /opt/sco/ -type d -exec chmod 755 {} \;
|
||||||
provider = Minio
|
find /opt/sco/ -type f -exec chmod 644 {} \;
|
||||||
access_key_id = minioadmin
|
chmod -R 755 /opt/sco/frontend/
|
||||||
secret_access_key = LIGTNbUgQr
|
|
||||||
endpoint = https://minio-api.laoficina1782.com
|
### TMP FOLDER
|
||||||
region = us-east-1
|
cp /usr/lib/tmpfiles.d/fs-tmp.conf /etc/tmpfiles.d/
|
||||||
acl = private
|
echo "D /tmp 1777 root root -" > /etc/tmpfiles.d/fs-tmp.conf
|
||||||
force_path_style = true
|
|
||||||
CONF
|
### SERVICE
|
||||||
rclone --config /tmp/rclone.conf sync minio:$CUSTOMER /opt/sco/ --exclude "backend/docker/data/**" --s3-sign-accept-encoding=false --multi-thread-streams=0 --progress --verbose
|
find /opt/sco/resources/services/ -type f -exec sh -c 'cp "$1" "/etc/systemd/system/$(basename "$1")"' _ {} \;
|
||||||
|
find /opt/sco/resources/services/ -type f -exec sh -c 'systemctl enable "$(basename "$1")"' _ {} \;
|
||||||
|
systemctl daemon-reload
|
||||||
|
|
||||||
|
### AUTOSTART
|
||||||
|
rsync -a --delete /opt/sco/resources/autostart/ /home/sco/.config/autostart/
|
||||||
|
chown -R sco:users /home/sco/.config/autostart/*
|
||||||
|
chmod -R 644 /home/sco/.config/autostart/*
|
||||||
|
|
||||||
|
### CRONTAB
|
||||||
|
crontab -u root /opt/sco/resources/crontab/root.txt
|
||||||
|
crontab -u sco /opt/sco/resources/crontab/sco.txt
|
||||||
|
|
||||||
|
### PYTHON
|
||||||
|
find /opt/sco/resources/python/ -type d -iname "packages" | while read packages_dir; do
|
||||||
|
parent_dir=$(dirname "$packages_dir")
|
||||||
|
req_file="$parent_dir/requirements.txt"
|
||||||
|
if [ -f "$req_file" ]; then
|
||||||
|
pip install -q --no-index --find-links="$packages_dir" -r "$req_file"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
### DOCKER IMAGES
|
||||||
|
mkdir -p /tmp/images/
|
||||||
|
find /opt/sco/resources/images/ -type f -name '*.gz' -exec sh -c 'gunzip -c "$1" > /tmp/images/"$(basename "${1%.gz}")"' _ {} \;
|
||||||
|
find /tmp/images/ -type f -iname "*.tar" -exec docker load -i {} \;
|
||||||
|
|
||||||
|
### INIT CPI-SERVER DATABASES AND LOGS FOLDERS
|
||||||
|
mkdir -p /opt/sco/backend/docker/data/cpi-server/database
|
||||||
|
mkdir -p /opt/sco/backend/docker/data/cpi-server/logs/devices
|
||||||
|
mkdir -p /opt/sco/backend/docker/data/cpi-server/logs/service
|
||||||
|
touch /opt/sco/backend/docker/data/cpi-server/database/configuration.db
|
||||||
|
touch /opt/sco/backend/docker/data/cpi-server/database/connectivity.db
|
||||||
|
touch /opt/sco/backend/docker/data/cpi-server/database/Identity.db
|
||||||
|
touch /opt/sco/backend/docker/data/cpi-server/database/transaction.db
|
||||||
|
touch /opt/sco/backend/docker/data/cpi-server/database/trialdata.db
|
||||||
|
|
||||||
|
### INIT SYMETRIC CONFIGURATION FILE
|
||||||
|
mkdir -p /opt/sco/backend/docker/data/symmetric
|
||||||
|
if [ ! -f /opt/sco/backend/docker/data/symmetric/engine.properties ]; then
|
||||||
|
LOCAL_NODE=$(hostname)
|
||||||
|
LOCAL_IP=$(ip route get 1.1.1.1 | grep -oP '(?<=src\s)\d+(\.\d+){3}')
|
||||||
|
cat <<EOF > /opt/sco/backend/docker/data/symmetric/engine.properties
|
||||||
|
engine.name=$LOCAL_NODE
|
||||||
|
group.id=fullmesh
|
||||||
|
external.id=$LOCAL_NODE
|
||||||
|
db.driver=com.mysql.cj.jdbc.Driver
|
||||||
|
db.url=jdbc:mysql://$LOCAL_IP:3306/sco
|
||||||
|
db.user=root
|
||||||
|
db.password=U2qs&U6LA9U2
|
||||||
|
registration.url=
|
||||||
|
sync.url=http://$LOCAL_IP:31415/sync/$LOCAL_NODE
|
||||||
|
start.pulled.job=true
|
||||||
|
job.purge.period.time.ms=7200000
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
+22
-36
@@ -20,14 +20,12 @@ jenkins:
|
|||||||
users:
|
users:
|
||||||
- id: admin
|
- id: admin
|
||||||
password: H0l4mund0!
|
password: H0l4mund0!
|
||||||
|
|
||||||
# Agentes permanentes (WebSocket): cada SCO conecta outbound a Jenkins via wss://.
|
# Agentes permanentes (WebSocket): cada SCO conecta outbound a Jenkins via wss://.
|
||||||
# Nombre = identificador en Jenkins. Label "sco" agrupa todos los SCOs,
|
# El deploy (Jenkinsfile.sco) targetea por nombre exacto de nodo (parámetro NODO),
|
||||||
# luego cliente (ralph) y tienda (yabucoa / san-lorenzo / rio-grande).
|
# no por label, por eso los nodos no llevan labelString.
|
||||||
nodes:
|
nodes:
|
||||||
- permanent:
|
- permanent:
|
||||||
name: "ralph-yabucoa-sco02"
|
name: "ralph-yabucoa-sco02"
|
||||||
labelString: "sco ralph yabucoa"
|
|
||||||
remoteFS: "/opt/jenkins-agent"
|
remoteFS: "/opt/jenkins-agent"
|
||||||
numExecutors: 1
|
numExecutors: 1
|
||||||
retentionStrategy: "always"
|
retentionStrategy: "always"
|
||||||
@@ -36,7 +34,6 @@ jenkins:
|
|||||||
webSocket: true
|
webSocket: true
|
||||||
- permanent:
|
- permanent:
|
||||||
name: "ralph-yabucoa-sco03"
|
name: "ralph-yabucoa-sco03"
|
||||||
labelString: "sco ralph yabucoa"
|
|
||||||
remoteFS: "/opt/jenkins-agent"
|
remoteFS: "/opt/jenkins-agent"
|
||||||
numExecutors: 1
|
numExecutors: 1
|
||||||
retentionStrategy: "always"
|
retentionStrategy: "always"
|
||||||
@@ -45,7 +42,6 @@ jenkins:
|
|||||||
webSocket: true
|
webSocket: true
|
||||||
- permanent:
|
- permanent:
|
||||||
name: "ralph-yabucoa-sco04"
|
name: "ralph-yabucoa-sco04"
|
||||||
labelString: "sco ralph yabucoa"
|
|
||||||
remoteFS: "/opt/jenkins-agent"
|
remoteFS: "/opt/jenkins-agent"
|
||||||
numExecutors: 1
|
numExecutors: 1
|
||||||
retentionStrategy: "always"
|
retentionStrategy: "always"
|
||||||
@@ -54,7 +50,6 @@ jenkins:
|
|||||||
webSocket: true
|
webSocket: true
|
||||||
- permanent:
|
- permanent:
|
||||||
name: "ralph-yabucoa-sco05"
|
name: "ralph-yabucoa-sco05"
|
||||||
labelString: "sco ralph yabucoa"
|
|
||||||
remoteFS: "/opt/jenkins-agent"
|
remoteFS: "/opt/jenkins-agent"
|
||||||
numExecutors: 1
|
numExecutors: 1
|
||||||
retentionStrategy: "always"
|
retentionStrategy: "always"
|
||||||
@@ -63,7 +58,6 @@ jenkins:
|
|||||||
webSocket: true
|
webSocket: true
|
||||||
- permanent:
|
- permanent:
|
||||||
name: "ralph-yabucoa-sco06"
|
name: "ralph-yabucoa-sco06"
|
||||||
labelString: "sco ralph yabucoa"
|
|
||||||
remoteFS: "/opt/jenkins-agent"
|
remoteFS: "/opt/jenkins-agent"
|
||||||
numExecutors: 1
|
numExecutors: 1
|
||||||
retentionStrategy: "always"
|
retentionStrategy: "always"
|
||||||
@@ -72,7 +66,6 @@ jenkins:
|
|||||||
webSocket: true
|
webSocket: true
|
||||||
- permanent:
|
- permanent:
|
||||||
name: "ralph-yabucoa-sco07"
|
name: "ralph-yabucoa-sco07"
|
||||||
labelString: "sco ralph yabucoa"
|
|
||||||
remoteFS: "/opt/jenkins-agent"
|
remoteFS: "/opt/jenkins-agent"
|
||||||
numExecutors: 1
|
numExecutors: 1
|
||||||
retentionStrategy: "always"
|
retentionStrategy: "always"
|
||||||
@@ -81,7 +74,6 @@ jenkins:
|
|||||||
webSocket: true
|
webSocket: true
|
||||||
- permanent:
|
- permanent:
|
||||||
name: "ralph-san-lorenzo-sco03"
|
name: "ralph-san-lorenzo-sco03"
|
||||||
labelString: "sco ralph san-lorenzo"
|
|
||||||
remoteFS: "/opt/jenkins-agent"
|
remoteFS: "/opt/jenkins-agent"
|
||||||
numExecutors: 1
|
numExecutors: 1
|
||||||
retentionStrategy: "always"
|
retentionStrategy: "always"
|
||||||
@@ -90,7 +82,6 @@ jenkins:
|
|||||||
webSocket: true
|
webSocket: true
|
||||||
- permanent:
|
- permanent:
|
||||||
name: "ralph-san-lorenzo-sco04"
|
name: "ralph-san-lorenzo-sco04"
|
||||||
labelString: "sco ralph san-lorenzo"
|
|
||||||
remoteFS: "/opt/jenkins-agent"
|
remoteFS: "/opt/jenkins-agent"
|
||||||
numExecutors: 1
|
numExecutors: 1
|
||||||
retentionStrategy: "always"
|
retentionStrategy: "always"
|
||||||
@@ -99,7 +90,6 @@ jenkins:
|
|||||||
webSocket: true
|
webSocket: true
|
||||||
- permanent:
|
- permanent:
|
||||||
name: "ralph-san-lorenzo-sco05"
|
name: "ralph-san-lorenzo-sco05"
|
||||||
labelString: "sco ralph san-lorenzo"
|
|
||||||
remoteFS: "/opt/jenkins-agent"
|
remoteFS: "/opt/jenkins-agent"
|
||||||
numExecutors: 1
|
numExecutors: 1
|
||||||
retentionStrategy: "always"
|
retentionStrategy: "always"
|
||||||
@@ -108,7 +98,6 @@ jenkins:
|
|||||||
webSocket: true
|
webSocket: true
|
||||||
- permanent:
|
- permanent:
|
||||||
name: "ralph-san-lorenzo-sco06"
|
name: "ralph-san-lorenzo-sco06"
|
||||||
labelString: "sco ralph san-lorenzo"
|
|
||||||
remoteFS: "/opt/jenkins-agent"
|
remoteFS: "/opt/jenkins-agent"
|
||||||
numExecutors: 1
|
numExecutors: 1
|
||||||
retentionStrategy: "always"
|
retentionStrategy: "always"
|
||||||
@@ -117,7 +106,6 @@ jenkins:
|
|||||||
webSocket: true
|
webSocket: true
|
||||||
- permanent:
|
- permanent:
|
||||||
name: "ralph-rio-grande-sco01"
|
name: "ralph-rio-grande-sco01"
|
||||||
labelString: "sco ralph rio-grande"
|
|
||||||
remoteFS: "/opt/jenkins-agent"
|
remoteFS: "/opt/jenkins-agent"
|
||||||
numExecutors: 1
|
numExecutors: 1
|
||||||
retentionStrategy: "always"
|
retentionStrategy: "always"
|
||||||
@@ -126,7 +114,6 @@ jenkins:
|
|||||||
webSocket: true
|
webSocket: true
|
||||||
- permanent:
|
- permanent:
|
||||||
name: "ralph-rio-grande-sco02"
|
name: "ralph-rio-grande-sco02"
|
||||||
labelString: "sco ralph rio-grande"
|
|
||||||
remoteFS: "/opt/jenkins-agent"
|
remoteFS: "/opt/jenkins-agent"
|
||||||
numExecutors: 1
|
numExecutors: 1
|
||||||
retentionStrategy: "always"
|
retentionStrategy: "always"
|
||||||
@@ -135,7 +122,6 @@ jenkins:
|
|||||||
webSocket: true
|
webSocket: true
|
||||||
- permanent:
|
- permanent:
|
||||||
name: "ralph-rio-grande-sco03"
|
name: "ralph-rio-grande-sco03"
|
||||||
labelString: "sco ralph rio-grande"
|
|
||||||
remoteFS: "/opt/jenkins-agent"
|
remoteFS: "/opt/jenkins-agent"
|
||||||
numExecutors: 1
|
numExecutors: 1
|
||||||
retentionStrategy: "always"
|
retentionStrategy: "always"
|
||||||
@@ -144,7 +130,6 @@ jenkins:
|
|||||||
webSocket: true
|
webSocket: true
|
||||||
- permanent:
|
- permanent:
|
||||||
name: "ralph-rio-grande-sco04"
|
name: "ralph-rio-grande-sco04"
|
||||||
labelString: "sco ralph rio-grande"
|
|
||||||
remoteFS: "/opt/jenkins-agent"
|
remoteFS: "/opt/jenkins-agent"
|
||||||
numExecutors: 1
|
numExecutors: 1
|
||||||
retentionStrategy: "always"
|
retentionStrategy: "always"
|
||||||
@@ -153,7 +138,6 @@ jenkins:
|
|||||||
webSocket: true
|
webSocket: true
|
||||||
- permanent:
|
- permanent:
|
||||||
name: "ralph-rio-grande-sco05"
|
name: "ralph-rio-grande-sco05"
|
||||||
labelString: "sco ralph rio-grande"
|
|
||||||
remoteFS: "/opt/jenkins-agent"
|
remoteFS: "/opt/jenkins-agent"
|
||||||
numExecutors: 1
|
numExecutors: 1
|
||||||
retentionStrategy: "always"
|
retentionStrategy: "always"
|
||||||
@@ -162,7 +146,6 @@ jenkins:
|
|||||||
webSocket: true
|
webSocket: true
|
||||||
- permanent:
|
- permanent:
|
||||||
name: "ralph-rio-grande-sco06"
|
name: "ralph-rio-grande-sco06"
|
||||||
labelString: "sco ralph rio-grande"
|
|
||||||
remoteFS: "/opt/jenkins-agent"
|
remoteFS: "/opt/jenkins-agent"
|
||||||
numExecutors: 1
|
numExecutors: 1
|
||||||
retentionStrategy: "always"
|
retentionStrategy: "always"
|
||||||
@@ -170,8 +153,23 @@ jenkins:
|
|||||||
inbound:
|
inbound:
|
||||||
webSocket: true
|
webSocket: true
|
||||||
- permanent:
|
- permanent:
|
||||||
name: "lab-oficina-sco-77"
|
name: "laboratorio-girboy-sco81"
|
||||||
labelString: "sco lab oficina"
|
remoteFS: "/opt/jenkins-agent"
|
||||||
|
numExecutors: 1
|
||||||
|
retentionStrategy: "always"
|
||||||
|
launcher:
|
||||||
|
inbound:
|
||||||
|
webSocket: true
|
||||||
|
- permanent:
|
||||||
|
name: "laboratorio-girboy-sco82"
|
||||||
|
remoteFS: "/opt/jenkins-agent"
|
||||||
|
numExecutors: 1
|
||||||
|
retentionStrategy: "always"
|
||||||
|
launcher:
|
||||||
|
inbound:
|
||||||
|
webSocket: true
|
||||||
|
- permanent:
|
||||||
|
name: "laboratorio-girboy-sco83"
|
||||||
remoteFS: "/opt/jenkins-agent"
|
remoteFS: "/opt/jenkins-agent"
|
||||||
numExecutors: 1
|
numExecutors: 1
|
||||||
retentionStrategy: "always"
|
retentionStrategy: "always"
|
||||||
@@ -182,28 +180,16 @@ jenkins:
|
|||||||
unclassified:
|
unclassified:
|
||||||
location:
|
location:
|
||||||
url: https://jenkins.laoficina1782.com/
|
url: https://jenkins.laoficina1782.com/
|
||||||
|
|
||||||
security:
|
security:
|
||||||
globalJobDslSecurityConfiguration:
|
globalJobDslSecurityConfiguration:
|
||||||
useScriptSecurity: false
|
useScriptSecurity: false
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
- script: |
|
- script: |
|
||||||
pipelineJob('deploy-ralph') {
|
pipelineJob('deploy-sco') {
|
||||||
description('Deploy de install.sh a los SCOs de Ralph en la tienda seleccionada.')
|
description('Deploy de install.sh a un nodo SCO puntual, para el cliente seleccionado.')
|
||||||
definition {
|
definition {
|
||||||
cps {
|
cps {
|
||||||
script(new File('/opt/jenkins/Jenkinsfile.ralph').text)
|
script(new File('/opt/jenkins/Jenkinsfile.sco').text)
|
||||||
sandbox(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
- script: |
|
|
||||||
pipelineJob('deploy-lab') {
|
|
||||||
description('Deploy de install.sh a los SCOs de Deploy Lab en la tienda seleccionada.')
|
|
||||||
definition {
|
|
||||||
cps {
|
|
||||||
script(new File('/opt/jenkins/Jenkinsfile.lab').text)
|
|
||||||
sandbox(true)
|
sandbox(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
pipeline {
|
|
||||||
agent none
|
|
||||||
|
|
||||||
parameters {
|
|
||||||
choice(
|
|
||||||
name: 'TIENDA',
|
|
||||||
choices: ['oficina'],
|
|
||||||
description: 'Tienda destino'
|
|
||||||
)
|
|
||||||
string(
|
|
||||||
name: 'NODO',
|
|
||||||
defaultValue: '',
|
|
||||||
description: 'Nombre exacto del nodo a deployar (vacío = toda la tienda)'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
stages {
|
|
||||||
stage('Preparar scripts') {
|
|
||||||
agent { label 'built-in' }
|
|
||||||
steps {
|
|
||||||
sh 'cp /opt/deploy/install.sh .'
|
|
||||||
stash name: 'scripts', includes: 'install.sh'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Deploy') {
|
|
||||||
agent { label 'built-in' }
|
|
||||||
steps {
|
|
||||||
script {
|
|
||||||
def labelExpr = "lab && ${params.TIENDA}"
|
|
||||||
def nodes = nodesByLabel(label: labelExpr, offline: false)
|
|
||||||
if (params.NODO?.trim()) {
|
|
||||||
def target = params.NODO.trim()
|
|
||||||
if (!nodes.contains(target)) {
|
|
||||||
error "El nodo '${target}' no está online o no pertenece al label: ${labelExpr}"
|
|
||||||
}
|
|
||||||
nodes = [target]
|
|
||||||
}
|
|
||||||
if (nodes.isEmpty()) {
|
|
||||||
error "No hay nodos online con el label: ${labelExpr}"
|
|
||||||
}
|
|
||||||
def deployStages = nodes.collectEntries { nodeName ->
|
|
||||||
["Deploy ${nodeName}": {
|
|
||||||
node(nodeName) {
|
|
||||||
unstash 'scripts'
|
|
||||||
sh "bash install.sh 'lab'"
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
parallel deployStages
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
pipeline {
|
|
||||||
agent none
|
|
||||||
|
|
||||||
parameters {
|
|
||||||
choice(
|
|
||||||
name: 'TIENDA',
|
|
||||||
choices: ['yabucoa', 'san-lorenzo', 'rio-grande'],
|
|
||||||
description: 'Tienda destino'
|
|
||||||
)
|
|
||||||
string(
|
|
||||||
name: 'NODO',
|
|
||||||
defaultValue: '',
|
|
||||||
description: 'Nombre exacto del nodo a deployar (vacío = toda la tienda)'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
stages {
|
|
||||||
stage('Preparar scripts') {
|
|
||||||
agent { label 'built-in' }
|
|
||||||
steps {
|
|
||||||
sh 'cp /opt/deploy/install.sh .'
|
|
||||||
stash name: 'scripts', includes: 'install.sh'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Deploy') {
|
|
||||||
agent { label 'built-in' }
|
|
||||||
steps {
|
|
||||||
script {
|
|
||||||
def labelExpr = "ralph && ${params.TIENDA}"
|
|
||||||
def nodes = nodesByLabel(label: labelExpr, offline: false)
|
|
||||||
if (params.NODO?.trim()) {
|
|
||||||
def target = params.NODO.trim()
|
|
||||||
if (!nodes.contains(target)) {
|
|
||||||
error "El nodo '${target}' no está online o no pertenece al label: ${labelExpr}"
|
|
||||||
}
|
|
||||||
nodes = [target]
|
|
||||||
}
|
|
||||||
if (nodes.isEmpty()) {
|
|
||||||
error "No hay nodos online con el label: ${labelExpr}"
|
|
||||||
}
|
|
||||||
def deployStages = nodes.collectEntries { nodeName ->
|
|
||||||
["Deploy ${nodeName}": {
|
|
||||||
node(nodeName) {
|
|
||||||
unstash 'scripts'
|
|
||||||
sh "bash install.sh 'ralph'"
|
|
||||||
sh 'cat ~/sco-app/installed.txt'
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
parallel deployStages
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
pipeline {
|
||||||
|
agent none
|
||||||
|
parameters {
|
||||||
|
string(
|
||||||
|
name: 'NODO',
|
||||||
|
defaultValue: '',
|
||||||
|
description: 'Nombre exacto del nodo a deployar'
|
||||||
|
)
|
||||||
|
choice(
|
||||||
|
name: 'CLIENTE',
|
||||||
|
choices: [
|
||||||
|
'SELECCIONAR_CLIENTE',
|
||||||
|
'cencosud-jumbo',
|
||||||
|
'censosud-staisabel',
|
||||||
|
'changomas-hiper',
|
||||||
|
'changomas-super',
|
||||||
|
'dibal',
|
||||||
|
'hisense',
|
||||||
|
'lsco',
|
||||||
|
'mbs-econo',
|
||||||
|
'mbs-famcoop',
|
||||||
|
'mbs-ralphs',
|
||||||
|
'mbs-supermax',
|
||||||
|
'modatelas',
|
||||||
|
'walmart-chile-acuenta',
|
||||||
|
'walmart-chile-lider',
|
||||||
|
'wm-mexico-bodega',
|
||||||
|
'wm-mexico-walmart'
|
||||||
|
],
|
||||||
|
description: 'Cliente para el cual se ejecuta el deploy'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
stages {
|
||||||
|
stage('Registro de parámetros') {
|
||||||
|
agent none
|
||||||
|
when { expression { params.CLIENTE == null } }
|
||||||
|
steps {
|
||||||
|
echo 'Primer build: Jenkins está registrando los parámetros de este Jenkinsfile. No se ejecuta ningún deploy. Volvé a correr el job con "Build with Parameters".'
|
||||||
|
script { currentBuild.result = 'NOT_BUILT' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Preparar scripts') {
|
||||||
|
agent { label 'built-in' }
|
||||||
|
when { expression { params.CLIENTE != null } }
|
||||||
|
steps {
|
||||||
|
sh 'cp /opt/deploy/install.sh .'
|
||||||
|
stash name: 'scripts', includes: 'install.sh'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Deploy') {
|
||||||
|
agent { label 'built-in' }
|
||||||
|
when { expression { params.CLIENTE != null } }
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
if (!params.NODO?.trim()) {
|
||||||
|
error "El parámetro NODO es obligatorio"
|
||||||
|
}
|
||||||
|
if (params.CLIENTE == 'SELECCIONAR_CLIENTE') {
|
||||||
|
error "El parámetro CLIENTE es obligatorio"
|
||||||
|
}
|
||||||
|
def target = params.NODO.trim()
|
||||||
|
node(target) {
|
||||||
|
unstash 'scripts'
|
||||||
|
sh "bash install.sh '${params.CLIENTE.trim()}'"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-6
@@ -27,11 +27,10 @@ services:
|
|||||||
expose:
|
expose:
|
||||||
- "8080"
|
- "8080"
|
||||||
volumes:
|
volumes:
|
||||||
- jenkins_home:/var/jenkins_home
|
- ./data/jenkins_home:/var/jenkins_home
|
||||||
- ./data/jenkins/jenkins.yaml:/usr/share/jenkins/ref/jenkins.yaml:ro
|
- ./data/jenkins/jenkins.yaml:/usr/share/jenkins/ref/jenkins.yaml:ro
|
||||||
- ./data/jenkins/deploy:/opt/deploy:ro
|
- ./data/jenkins/deploy:/opt/deploy:ro
|
||||||
- ./data/jenkins/pipelines/Jenkinsfile.ralph:/opt/jenkins/Jenkinsfile.ralph:ro
|
- ./data/jenkins/pipelines/Jenkinsfile.sco:/opt/jenkins/Jenkinsfile.sco:ro
|
||||||
- ./data/jenkins/pipelines/Jenkinsfile.lab:/opt/jenkins/Jenkinsfile.lab:ro
|
|
||||||
networks:
|
networks:
|
||||||
- proxy
|
- proxy
|
||||||
|
|
||||||
@@ -62,6 +61,3 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
proxy:
|
proxy:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
|
|
||||||
volumes:
|
|
||||||
jenkins_home:
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SRC_DIR=/opt/server/data
|
||||||
|
BACKUP_DIR=/opt/server/backups/jenkins_home
|
||||||
|
KEEP=4
|
||||||
|
|
||||||
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
|
||||||
|
STAMP=$(date +%Y%m%d)
|
||||||
|
tar czf "$BACKUP_DIR/jenkins_home_$STAMP.tar.gz" -C "$SRC_DIR" jenkins_home
|
||||||
|
|
||||||
|
ls -1t "$BACKUP_DIR"/jenkins_home_*.tar.gz | tail -n +$((KEEP + 1)) | xargs -r rm --
|
||||||
Reference in New Issue
Block a user