phase 4.5: diun deploye, prisme pose sur J5040, 3 bugs chaine alerte corriges, compose du kit versionnes
This commit is contained in:
@@ -10,28 +10,29 @@
|
||||
>
|
||||
> Couverture backup : g9=restic (sources /data /home/folzo /etc, cron 03:30) ; j5040=non (à couvrir Phase 5)
|
||||
|
||||
<!-- GÉNÉRÉ PAR scripts/11-registry.sh — ne pas éditer à la main. ts=2026-10-12 14:48 UTC ; 21 conteneurs -->
|
||||
<!-- GÉNÉRÉ PAR scripts/11-registry.sh — ne pas éditer à la main. ts=2026-10-12 17:05 UTC ; 22 conteneurs -->
|
||||
|
||||
| Machine | Conteneur | Projet / service (compose) | Image | État | Épinglée | Watchtower | Type | Dans le kit | Endpoint (Caddy) |
|
||||
|---|---|---|---|---|---|---|---|---|---|
|
||||
| g9 | `collabora` | nextcloud / collabora | `collabora/code:26.04.5.1.1` | running | oui | false | stateful | oui | — |
|
||||
| g9 | `couchdb` | g9-queue / couchdb | `couchdb:3.3` | running | oui | false | stateful | NON | — |
|
||||
| g9 | `couchdb` | g9-queue / couchdb | `couchdb:3.3` | running | oui | false | stateful | oui | — |
|
||||
| g9 | `diun` | diun / diun | `e324b793eb32` | running | oui (digest) | false | stateful | oui | — |
|
||||
| g9 | `edge` | edge / edge | `caddy:2` | running | oui | true | stateless | oui | — |
|
||||
| g9 | `element` | matrix / element | `vectorim/element-web:latest` | running | non (latest) | false | stateful | NON | — |
|
||||
| g9 | `element` | matrix / element | `vectorim/element-web:latest` | running | non (latest) | false | stateful | oui | — |
|
||||
| g9 | `gitea` | gitea / gitea | `gitea/gitea:1.27.3` | running | oui | false | stateful | oui | git.folzocorp.fr |
|
||||
| g9 | `gitea-db` | gitea / gitea-db | `postgres:16` | running | oui | false | stateful | oui | — |
|
||||
| g9 | `jellyfin` | jellyfin / jellyfin | `jellyfin/jellyfin:10.9` | running | oui | false | stateful | oui | media.folzocorp.fr |
|
||||
| g9 | `n8n` | g9-queue / n8n | `docker.n8n.io/n8nio/n8n:latest` | running | non (latest) | false | stateful | NON | n8n.folzocorp.fr |
|
||||
| g9 | `n8n` | g9-queue / n8n | `docker.n8n.io/n8nio/n8n:latest` | running | non (latest) | false | stateful | oui | n8n.folzocorp.fr |
|
||||
| g9 | `nextcloud` | nextcloud / nextcloud | `nextcloud:35.0.1` | running | oui | false | stateful | oui | cloud.folzocorp.fr |
|
||||
| g9 | `nextcloud_db` | nextcloud / db | `mariadb:10.11` | running | oui | false | stateful | oui | — |
|
||||
| g9 | `nextcloud_redis` | nextcloud / redis | `redis:7` | running | oui | false | stateful | oui | — |
|
||||
| g9 | `obsidian` | g9-queue / obsidian | `lscr.io/linuxserver/obsidian:latest` | running | non (latest) | false | stateful | NON | — |
|
||||
| g9 | `obsidian` | g9-queue / obsidian | `lscr.io/linuxserver/obsidian:latest` | running | non (latest) | false | stateful | oui | — |
|
||||
| g9 | `photoprism` | photoprism / photoprism | `photoprism/photoprism:260919` | running | oui | false | stateful | oui | photos.folzocorp.fr |
|
||||
| g9 | `photoprism_db` | photoprism / db | `mariadb:10.11` | running | oui | false | stateful | oui | — |
|
||||
| g9 | `synapse` | matrix / synapse | `matrixdotorg/synapse:latest` | running | non (latest) | false | stateful | NON | matrix.folzocorp.fr |
|
||||
| g9 | `synapse` | matrix / synapse | `matrixdotorg/synapse:latest` | running | non (latest) | false | stateful | oui | matrix.folzocorp.fr |
|
||||
| g9 | `valheim` | compose / valheim | `valheim-pterodactyl:1` | running | oui | false | stateful | NON | — |
|
||||
| g9 | `vaultwarden` | vaultwarden / vaultwarden | `vaultwarden/server:1.37.4` | running | oui | false | stateful | oui | pass.folzocorp.fr |
|
||||
| g9 | `watchtower` | g9-queue / watchtower | `45b54f6dc152` | running | oui (digest) | true | stateless | NON | — |
|
||||
| g9 | `watchtower` | g9-queue / watchtower | `45b54f6dc152` | running | oui (digest) | true | stateless | oui | — |
|
||||
| j5040 | `adguard` | adguard / adguard | `aba9e3bf0613` | running | oui (digest) | true | stateless | oui | — |
|
||||
| j5040 | `caddy` | edge-j5040 / caddy | `502996b5b60a` | running | oui (digest) | true | stateless | oui | — |
|
||||
| j5040 | `sweet_feynman` | - / - | `437a490f7afc` | running | oui (digest) | ABSENT | stateless | NON | — |
|
||||
@@ -40,15 +41,9 @@
|
||||
|
||||
- g9/valheim: conteneur réel non déclaré dans le kit (compose)
|
||||
- g9/n8n: image non épinglée (docker.n8n.io/n8nio/n8n:latest) — S11.4 pinning
|
||||
- g9/n8n: conteneur réel non déclaré dans le kit (compose)
|
||||
- g9/element: image non épinglée (vectorim/element-web:latest) — S11.4 pinning
|
||||
- g9/element: conteneur réel non déclaré dans le kit (compose)
|
||||
- g9/synapse: image non épinglée (matrixdotorg/synapse:latest) — S11.4 pinning
|
||||
- g9/synapse: conteneur réel non déclaré dans le kit (compose)
|
||||
- g9/watchtower: conteneur réel non déclaré dans le kit (compose)
|
||||
- g9/couchdb: conteneur réel non déclaré dans le kit (compose)
|
||||
- g9/obsidian: image non épinglée (lscr.io/linuxserver/obsidian:latest) — S11.4 pinning
|
||||
- g9/obsidian: conteneur réel non déclaré dans le kit (compose)
|
||||
- j5040/sweet_feynman: label watchtower absent — S11.4 sélectivité
|
||||
- j5040/sweet_feynman: conteneur réel non déclaré dans le kit (compose)
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
watch:
|
||||
workers: 10
|
||||
schedule: "0 6 * * 1"
|
||||
firstCheckNotif: false
|
||||
|
||||
providers:
|
||||
docker:
|
||||
watchByDefault: true
|
||||
watchStopped: false
|
||||
@@ -0,0 +1,21 @@
|
||||
# Diun — notification des nouvelles versions SANS appliquer (C-AP4).
|
||||
# Image épinglée par digest ; stateful (DB d'état dans /data/docker/diun/data) ;
|
||||
# label watchtower volontairement absent : Watchtower ne scanne pas cette brique.
|
||||
name: diun
|
||||
|
||||
services:
|
||||
diun:
|
||||
image: crazymax/diun@sha256:e324b793eb32dfb7f74d3a39421ebf090141caaadee69b8f78da63112408ee25
|
||||
container_name: diun
|
||||
command: serve
|
||||
volumes:
|
||||
- /data/docker/diun/data:/data
|
||||
- ./diun.yml:/diun.yml:ro
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
environment:
|
||||
- "TZ=Europe/Paris"
|
||||
- "LOG_LEVEL=info"
|
||||
- "LOG_JSON=true"
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=false"
|
||||
@@ -0,0 +1,85 @@
|
||||
name: g9-queue
|
||||
services:
|
||||
n8n:
|
||||
image: docker.n8n.io/n8nio/n8n:latest
|
||||
container_name: n8n
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "5678:5678"
|
||||
labels:
|
||||
com.centurylinklabs.watchtower.enable: "false"
|
||||
environment:
|
||||
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
|
||||
- N8N_BASIC_AUTH_ACTIVE=false
|
||||
- N8N_BASIC_AUTH_USER=${N8N_USER}
|
||||
- N8N_BASIC_AUTH_PASSWORD=${N8N_PASSWORD}
|
||||
- N8N_SECURE_COOKIE=false
|
||||
- N8N_HOST=192.168.1.24
|
||||
- N8N_PROTOCOL=http
|
||||
- DB_TYPE=sqlite
|
||||
- DB_SQLITE_VACUUM_ON_ISSUE=true
|
||||
- N8N_RUNNERS_ENABLED=true
|
||||
- GENERIC_TIMEZONE=Europe/Paris
|
||||
- TZ=Europe/Paris
|
||||
volumes:
|
||||
- ./n8n/n8n-data:/home/node/.n8n
|
||||
networks:
|
||||
- default
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
|
||||
couchdb:
|
||||
image: couchdb:3.3
|
||||
container_name: couchdb
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "5984:5984"
|
||||
labels:
|
||||
com.centurylinklabs.watchtower.enable: "false"
|
||||
environment:
|
||||
- COUCHDB_USER=thib
|
||||
- COUCHDB_PASSWORD=${COUCHDB_PASSWORD}
|
||||
volumes:
|
||||
- ./couchdb-data:/opt/couchdb/data
|
||||
networks:
|
||||
- default
|
||||
|
||||
obsidian:
|
||||
image: lscr.io/linuxserver/obsidian:latest
|
||||
container_name: obsidian
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "3100:3000"
|
||||
labels:
|
||||
com.centurylinklabs.watchtower.enable: "false"
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=Europe/Paris
|
||||
volumes:
|
||||
- ./obsidian-vault:/vault
|
||||
- ./config:/config
|
||||
networks:
|
||||
- default
|
||||
|
||||
watchtower:
|
||||
image: nickfedor/watchtower@sha256:45b54f6dc15227cfb38dbb826f2881aa0f56aaf0c255cdbb38bd80e598bdca9a
|
||||
container_name: watchtower
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
com.centurylinklabs.watchtower.enable: "true"
|
||||
environment:
|
||||
- WATCHTOWER_CLEANUP=false
|
||||
- WATCHTOWER_INCLUDE_STOPPED=false
|
||||
- WATCHTOWER_POLL_INTERVAL=3600
|
||||
- WATCHTOWER_LABEL_ENABLE=true
|
||||
- WATCHTOWER_NOTIFICATION_URL=generic+http://n8n:5678/webhook/watchtower
|
||||
- N8N_BASIC_AUTH_PASSWORD=${N8N_PASSWORD}
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- ./watchtower/notify.sh:/scripts/notify.sh:ro
|
||||
- ./watchtower/log:/data
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: g9-queue
|
||||
@@ -0,0 +1,24 @@
|
||||
services:
|
||||
synapse:
|
||||
image: matrixdotorg/synapse:latest
|
||||
container_name: synapse
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
com.centurylinklabs.watchtower.enable: "false"
|
||||
ports:
|
||||
- "8008:8008"
|
||||
environment:
|
||||
- SYNAPSE_SERVER_NAME=192.168.1.24
|
||||
- SYNAPSE_REPORT_STATS=no
|
||||
volumes:
|
||||
- ./data:/data
|
||||
element:
|
||||
image: vectorim/element-web:latest
|
||||
container_name: element
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
com.centurylinklabs.watchtower.enable: "false"
|
||||
ports:
|
||||
- "8009:80"
|
||||
volumes:
|
||||
- ./config.json:/app/config.json:ro
|
||||
@@ -0,0 +1,34 @@
|
||||
services:
|
||||
valheim:
|
||||
image: valheim-pterodactyl:1
|
||||
container_name: valheim
|
||||
user: "1000:1000"
|
||||
ports:
|
||||
- "2456-2458:2456-2458/tcp"
|
||||
- "2456-2458:2456-2458/udp"
|
||||
environment:
|
||||
- TZ=Europe/Paris
|
||||
- STARTUP=true
|
||||
- SERVER_MEMORY=2048
|
||||
- SERVER_IP=192.168.1.24
|
||||
- SERVER_PORT=2456
|
||||
- PUBLIC=1
|
||||
- NAME=LesBifleurs
|
||||
- WORLD=LeRepaireDuGrandFrak
|
||||
- SAVE_LOCATION=/home/container/save
|
||||
- PASSWORD=${VALHEIM_PASSWORD}
|
||||
- SAVE_INTERVAL=1800
|
||||
- AUTO_BACKUP=1
|
||||
- AUTO_BACKUP_DAYS_TO_LIVE=3
|
||||
- AUTO_UPDATE=0
|
||||
- AUTO_UPDATE_SCHEDULE=
|
||||
- SCHEDULED_RESTART=0
|
||||
- P_SERVER_LOCATION=g9
|
||||
- P_SERVER_UUID=aff5199c-a215-4f18-a601-3f8dda1702ea
|
||||
- P_SERVER_ALLOCATION_LIMIT=0.000000
|
||||
volumes:
|
||||
- ../data:/home/container
|
||||
mem_limit: 2048m
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
com.centurylinklabs.watchtower.enable: "false"
|
||||
@@ -142,3 +142,7 @@
|
||||
| 2026-10-12 16:20 | 4.5 | **backup 3-2-1 mesuré + restauration photos prouvée** (`10-verify-restore-photo.sh` rc=0) | C-P5 : périmètre, coffres, photos, restauration | `restic snapshots` (repo `rclone:freeboxftp:Freebox/backup/g9`) = **5 snapshots**, dernier `06a7e3b8` 2026-10-12 12:05, **541.393 GiB**, sources `/data /home/folzo /etc`. Présence dans le snapshot `latest` (607 284 entrées) : vaultwarden **630**, gitea **5 599**, `gitea/db` (Postgres) **2 162**, nextcloud **88 017**, `nextcloud/db` (MariaDB) **844**, photoprism originals **505 836**, edge/Caddy 52, `/home/folzo` 5 054 (n8n, synapse, couchdb, valheim, obsidian = montages bind `/home/folzo/*` → **inclus**). **Médias 15 To + 5,5 To exclus par construction** : ils vivent sur le NAS `.25`, le périmètre du G9 ne contient que 564 Go (`/data/docker` + `/data/famille`). Restauration : sha256 restauré **identique** à la source `.25` | aucune écriture sur les snapshots (`snapshots`/`ls`/`restore` vers `/tmp`), `rm -rf /tmp/restore-photo-test` sur le G9 |
|
||||
| 2026-10-12 16:30 | 4.5 | `PHOTOS-DOUBLE-RUN.md` : double-run **mesuré**, 2 écarts de nommage identifiés | C-PH1 : totaux source vs G9 + endpoints mesurés | copie **433 941 fichiers == 433 941 fichiers** (source `.25 /volume1/photo` 567 416 508 104 octets vs G9 `/data/docker/photoprism/originals` 567 394 253 738, écart 0,0039 % = vignettes `@eaDir`) ; RAM `photoprism` **1,104 GiB** + `photoprism_db` 183,5 MiB (enveloppe 2-3 Go tenue) ; indexation **39 294 / 433 941 fichiers = 9,1 %** (photos 36 254, albums 681, faces 37, **37 erreurs**, 3 utilisateurs) ; endpoints : `prisme.folzocorp.fr` DNS OK mais **0 route Caddy → 000**, `photos.folzocorp.fr` route J5040 → **`192.168.1.24:2342` = PhotoPrism** (307) au lieu du NAS, web DSM `.25` **5000/5001 = 000** (445/222 ouverts) | document seul ; **aucune modification du Caddyfile** — la pose de `prisme.` et le repointage de `photos.` sont des actions L3 (G11/G6) **soumises à validation** |
|
||||
| 2026-10-12 16:35 | 4.5 | n8n mesuré en lecture seule | C-ID9 (partie mesurable par l'IA) : `curl http://192.168.1.24:5678/healthz` = **200** ; données n8n = `/home/folzo/n8n/n8n-data` → **dans le périmètre restic** ; n8n **exclu du SSO** (fonction payante) consigné au registre. L'appel API avec la clé dédiée, la 2FA de l'owner et le compte local de secours restent **côté humain** (création de clé = L3) | aucune écriture n8n |
|
||||
| 2026-10-12 17:10 | 4.5 | **Diun déployé sur le G9** (GO utilisateur) | C-AP4 : notifier les nouvelles versions **sans appliquer** | `compose/diun/docker-compose.yml` + `diun.yml` (kit) → `providers.docker.watchByDefault: true`, `watchStopped: false`, schedule `0 6 * * 1`, `firstCheckNotif: false` ; image **épinglée par digest** `crazymax/diun@sha256:e324b793eb32dfb7f74d3a39421ebf090141caaadee69b8f78da63112408ee25` (le nom `crazy-max/diun` est refusé par le registre, c'est `crazymax/diun`) ; label `com.centurylinklabs.watchtower.enable=false` (stateful, Watchtower ne le scanne pas) ; **19 images analysées** au premier passage ; `g9-diun-notify.sh` (parse les lignes JSON `New version found` + curseur anti-répétition `/var/lib/g9-probes/diun.cursor`) installé en `/usr/local/bin` + cron `20 6 * * *` ; `--selftest` → `NOTIFY_OK 200`. **Aucune image modifiée** : `docker inspect` de tous les conteneurs avant/après = identique, la seule entrée nouvelle est Diun lui-même (18 → 19 conteneurs) | `cd /home/folzo/g9-migration/compose/diun && docker compose down` ; `sudo crontab -l \| grep -v g9-diun-notify \| sudo crontab -` ; `sudo rm -f /usr/local/bin/g9-diun-notify.sh` ; `sudo rm -rf /data/docker/diun` |
|
||||
| 2026-10-12 17:15 | 4.5 | **`prisme.folzocorp.fr` posé sur le J5040** (GO utilisateur) | C-PH1 (volet endpoint) : PhotoPrism accessible par son nom | `Caddyfile` du J5040 monté dans le conteneur `caddy` : bloc `prisme.folzocorp.fr { import folzocorp; reverse_proxy 192.168.1.24:2342 }` ajouté **au-dessus** de `photos.` ; sauvegarde `Caddyfile.bak-20261012-1643` ; `caddy validate` = `Valid configuration` puis `caddy reload` = OK ; mesure depuis le pilot : **`https://prisme.folzocorp.fr/` = 200** (certificat Let's Encrypt émis par ACME DNS-01 OVH, `curl` **sans** `-k`). **`photos.` non repointé** (GO partiel) : il sert encore PhotoPrism → l'écart de nommage reste documenté dans `PHOTOS-DOUBLE-RUN.md` | `cp /home/folzo/g9-migration/compose/edge-j5040/Caddyfile.bak-20261012-1643 /home/folzo/g9-migration/compose/edge-j5040/Caddyfile && docker exec caddy caddy reload --config /etc/caddy/Caddyfile` |
|
||||
| 2026-10-12 17:20 | 4.5 | **3 bugs corrigés dans la chaîne d'alerte** (digest et payloads invisibles) | C-AP2, C-AP4 : le digest doit arriver, les payloads doivent être relisibles | (1) `--digest` forçait `QUIET=1` et `notify()` sortait en quiet → **le digest n'était jamais envoyé** → ajout de `notify_force()` ; (2) `summary=$(grep '^KO' …)` avec `set -o pipefail` = **rc=1 silencieux** : le script mourait avant le digest → `\| true` ajouté ; (3) `g9-notify.py` publiait en type **`m.text`** (type hérité) alors que `g9-verify-alert.py` ne lisait que `m.room.message` → payloads **envoyés (200) et invisibles** ; type unifié en `m.room.message` + listing acceptant les deux. Ajout `g9-verify-alert.py --list N` (event_ids). Mesuré : **`payloads JSON conformes: 5`** (2 digest, selftest, dérive registre, diun) + 1 non conforme = mon message de debug | `git checkout scripts/12-probes.sh scripts/g9-notify.py scripts/g9-verify-alert.py` + `sudo install` de l'ancien ; messages conservés dans le salon |
|
||||
| 2026-10-12 17:25 | 4.5 | **compose du kit versionnés** : les briques déclarées hors git sont rentrées dans le dépôt | C-ID1 (fiabilité du registre), C-ID5 : la colonne « kit » était fausse (9 conteneurs marqués hors kit) | import dans `g9-migration/compose/` des définitions réelles qui vivaient hors kit : `matrix/` (`/home/folzo/matrix`), `g9-queue/` (`/home/folzo/docker-compose.yml` : n8n, watchtower, couchdb, obsidian), `valheim/`, `diun/`, + `edge-j5040/Caddyfile` ; **0 secret importé** (les `secrets/` du G9 sont en 700 root, les compose ne contiennent que des `${VAR}` et des chemins `secrets_file`) ; les fichiers du kit déjà versionnés **ne sont pas écrasés** (la copie live n'écrase pas le kit : la dérive doit rester visible). Constats automatiques **14 → 7** ; restent 7 vrais constats : 4 images `:latest` non épinglées (n8n, element, synapse, obsidian), `g9/valheim` dont le projet compose s'appelle `compose`, `j5040/sweet_feynman` sans projet compose et sans label watchtower | `git rm -r g9-migration/compose/{matrix,g9-queue,valheim,diun}` (aucun conteneur touché) |
|
||||
|
||||
@@ -65,7 +65,14 @@ mkdir -p "$STATE_DIR"
|
||||
notify() {
|
||||
local payload="$1"
|
||||
if [[ "$QUIET" == "1" ]]; then return 0; fi
|
||||
REGISTRY_B64="$(printf '%s' "$payload" | base64 -w0)" python3 /usr/local/bin/g9-notify.py
|
||||
python3 /usr/local/bin/g9-notify.py "$(printf '%s' "$payload" | base64 -w0)"
|
||||
}
|
||||
|
||||
# Le digest doit TOUJOURS être envoyé, même en mode quiet (QUIET coupe les alertes
|
||||
# de sonde, pas le message quotidien).
|
||||
notify_force() {
|
||||
local payload="$1"
|
||||
python3 /usr/local/bin/g9-notify.py "$(printf '%s' "$payload" | base64 -w0)"
|
||||
}
|
||||
|
||||
alert() {
|
||||
@@ -156,10 +163,10 @@ nb_ok="$(grep -c '^OK' "$results" || true)"
|
||||
nb_ko="$(grep -c '^KO' "$results" || true)"
|
||||
|
||||
if [[ "$MODE" == "digest" ]]; then
|
||||
summary="$(grep '^KO' "$results" | sed 's/^KO //' | head -8 | tr '\n' '; ')"
|
||||
summary="$(grep '^KO' "$results" | sed 's/^KO //' | head -8 | tr '\n' '; ' || true)"
|
||||
ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
payload="$(python3 -c 'import json,sys; print(json.dumps({"ts":sys.argv[1],"source":"12-probes","brique":"digest","host":sys.argv[2],"check":"daily","http_code":0,"severite":"info","message":f"{sys.argv[3]} OK / {sys.argv[4]} KO — {sys.argv[5]}","runbook":"RUNBOOKS/digest.md"},ensure_ascii=False))' "$ts" "$HOST" "$nb_ok" "$nb_ko" "${summary:-tout OK}")"
|
||||
notify "$payload"
|
||||
notify_force "$payload"
|
||||
fi
|
||||
echo "sonde : $nb_ok OK / $nb_ko KO"
|
||||
rm -f "$results"
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env bash
|
||||
# g9-diun-notify.sh — notifie les NOUVELLES VERSIONS signalées par Diun, sans rien appliquer (C-AP4).
|
||||
# Diun ne fait que lire les registres : aucune image n'est tirée, aucune image n'est remplacée.
|
||||
# Usage : g9-diun-notify.sh [--selftest] [--dry]
|
||||
# Anti-bruit : un curseur horodaté évite de renvoyer la même ligne à chaque passage.
|
||||
set -uo pipefail
|
||||
|
||||
DIUN_CTN="${DIUN_CTN:-diun}"
|
||||
STATE="${STATE:-/var/lib/g9-probes}"
|
||||
CURSOR="$STATE/diun.cursor"
|
||||
SELFTEST=0
|
||||
DRY=0
|
||||
for a in "$@"; do
|
||||
if [[ "$a" == "--selftest" ]]; then SELFTEST=1; fi
|
||||
if [[ "$a" == "--dry" ]]; then DRY=1; fi
|
||||
done
|
||||
mkdir -p "$STATE"
|
||||
|
||||
parse() {
|
||||
# Lignes JSON de Diun -> "image|version courante|version la plus récente"
|
||||
python3 -c '
|
||||
import sys, json
|
||||
out = []
|
||||
for line in sys.stdin:
|
||||
line = line.strip()
|
||||
if not line.startswith("{"):
|
||||
continue
|
||||
try:
|
||||
d = json.loads(line)
|
||||
except Exception:
|
||||
continue
|
||||
if d.get("message") not in ("New version found", "New image version found"):
|
||||
continue
|
||||
out.append("%s -> %s" % (d.get("image", "?"), d.get("latest", d.get("version", "?"))))
|
||||
print("\n".join(sorted(set(out))))
|
||||
'
|
||||
}
|
||||
|
||||
payload_from() {
|
||||
local listed="$1" ts
|
||||
ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
python3 -c 'import json,sys; print(json.dumps({"ts":sys.argv[1],"source":"diun","brique":"versions","host":"g9","check":"new-image-versions","http_code":0,"severite":"info","message":sys.argv[2],"runbook":"RUNBOOKS/digest.md"},ensure_ascii=False))' "$ts" "$listed"
|
||||
}
|
||||
|
||||
send() {
|
||||
local payload="$1" b64
|
||||
b64="$(printf '%s' "$payload" | base64 -w0)"
|
||||
if [ -x /usr/local/bin/g9-notify.py ]; then
|
||||
python3 /usr/local/bin/g9-notify.py "$b64"
|
||||
else
|
||||
source "$(dirname "$0")/lib-notify.sh"
|
||||
notify_json "$payload"
|
||||
fi
|
||||
}
|
||||
|
||||
if [[ "$SELFTEST" == 1 ]]; then
|
||||
sample='{"level":"warn","provider":"docker","image":"docker.io/library/redis:7","latest":"docker.io/library/redis:7.2.4","time":"2026-10-12T06:20:00+02:00","message":"New version found"}'
|
||||
listed="$(printf '%s\n' "$sample" | parse)"
|
||||
if [[ -z "$listed" ]]; then
|
||||
echo "DIUN_KO parse"
|
||||
exit 1
|
||||
fi
|
||||
payload="$(payload_from "selftest — $listed")"
|
||||
if [[ "$DRY" == 1 ]]; then
|
||||
echo "$payload"
|
||||
exit 0
|
||||
fi
|
||||
send "$payload"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! docker ps --format '{{.Names}}' | grep -qx "$DIUN_CTN"; then
|
||||
echo "DIUN_KO conteneur $DIUN_CTN absent"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
since="$(cat "$CURSOR" 2>/dev/null)"
|
||||
if [[ -z "$since" ]]; then
|
||||
since="$(date -u -d '24 hours ago' +%Y-%m-%dT%H:%M:%SZ)"
|
||||
fi
|
||||
now="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
|
||||
listed="$(docker logs --since "$since" "$DIUN_CTN" 2>&1 | parse)"
|
||||
if [[ -z "$listed" ]]; then
|
||||
echo "DIUN_OK aucune nouvelle version depuis $since"
|
||||
printf '%s' "$now" > "$CURSOR"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
nb="$(printf '%s\n' "$listed" | grep -c .)"
|
||||
payload="$(payload_from "$nb version(s) plus récente(s) signalée(s) : $(printf '%s; ' $listed) — Diun n'applique rien, dry-run Watchtower = scanned/2")"
|
||||
if [[ "$DRY" == 1 ]]; then
|
||||
echo "$payload"
|
||||
exit 0
|
||||
fi
|
||||
send "$payload"
|
||||
printf '%s' "$now" > "$CURSOR"
|
||||
@@ -27,8 +27,12 @@ def load_env():
|
||||
|
||||
|
||||
def main():
|
||||
import sys
|
||||
|
||||
env = load_env()
|
||||
raw = os.environ.get("REGISTRY_B64", "")
|
||||
# sudo ne transmet pas l'environnement (sudoers sans SETENV) : le payload passe
|
||||
# en argument, l'env reste accepté pour les appels cron.
|
||||
raw = sys.argv[1] if len(sys.argv) > 1 else os.environ.get("REGISTRY_B64", "")
|
||||
if not raw:
|
||||
print("NOTIFY_KO no-payload")
|
||||
return
|
||||
|
||||
@@ -38,7 +38,7 @@ def fetch(limit):
|
||||
def main():
|
||||
if len(sys.argv) > 2 and sys.argv[1] == "--list":
|
||||
for ev in fetch(int(sys.argv[2])).get("chunk", []):
|
||||
if ev.get("type") != "m.room.message":
|
||||
if ev.get("type") not in ("m.room.message", "m.text"):
|
||||
continue
|
||||
body = ev.get("content", {}).get("body", "").replace("\n", " ")
|
||||
print(f"{ev.get('event_id')} {body[:170]}")
|
||||
@@ -54,7 +54,7 @@ def main():
|
||||
bad = 0
|
||||
seen = []
|
||||
for ev in data.get("chunk", []):
|
||||
if ev.get("type") != "m.room.message":
|
||||
if ev.get("type") not in ("m.room.message", "m.text"):
|
||||
continue
|
||||
body = ev.get("content", {}).get("body", "")
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user