From ba2020d4861bc0efe93c0c11a0c25b44a97d875a Mon Sep 17 00:00:00 2001 From: Daniel Allaire Date: Tue, 29 Sep 2026 05:29:45 -0400 Subject: [PATCH] powerdns : une zone plus recente que sa version servie est rechargee ; zones le voit PowerDNS servait chez les deux locataires une zone anterieure a son fichier (console absente) : le handler de rechargement avait ete abandonne. Reconciliation a chaque passage (bind-reload-now) et controle dans la sonde zones. Plancher /etc/hosts rejoue sur les deux locataires ; console se resout depuis les edges. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 42 +++++++++++++++++++ roles/serveur_powerdns/defaults/main.yml | 4 ++ roles/serveur_powerdns/tasks/main.yml | 34 +++++++++++++++ .../templates/sonde-zones.sh.j2 | 20 ++++++++- 4 files changed, 99 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ce7afe..cdcacc3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,47 @@ # CHANGELOG — Set-OPS +## 2026-09-29 (30) — `console` ne se résolvait pas : un plancher périmé et une zone jamais rechargée + +**Constat.** Depuis l'edge de chaque locataire, `console.` ne se résolvait pas, +alors que l'edge la sert. Les autres expositions se résolvaient. + +**Première cause : le plancher `/etc/hosts` n'avait pas été rejoué.** Il dérive du plan +(inventaire + `expose`), mais n'est posé que par le socle (`serveur_debian`). La console a +été ajoutée au plan après le dernier passage du socle ; seul `ops-01`, redéployé depuis, +la portait. Rejoué seul (`hosts_statiques`, sans `common_packages` et sa mise à jour +complète) sur les 26 machines des deux locataires, après simulation : `console` ajoutée, +`forge-01` et `forge` retirées (l'ancienne forge des locataires, sortie du plan). + +**Seconde cause, plus grave : PowerDNS servait une zone antérieure à son fichier.** Le +fichier de zone, réécrit le 16 septembre, portait `console` ; PowerDNS servait la version +chargée à son démarrage (13 septembre chez Chezlepro, 14 chez Technolibre). Le rechargement +ne passait que par un handler, et un handler en attente est abandonné quand une tâche échoue +plus loin dans le même passage ; aux passages suivants, le fichier ne change plus et rien ne +le redemande. La sonde `zones` comptait les zones servies, pas leur fraîcheur : verte. + +- **Rôle `serveur_powerdns`** : à chaque passage, chaque zone (interne et publique) dont le + fichier est plus récent que son chargement (`bind-domain-status`) est rechargée + (`bind-reload-now`). Ce qui est à jour n'est pas touché. +- **Sonde `zones`** : critique si une zone servie est plus ancienne que son fichier + au-delà de `serveur_powerdns_sonde_tolerance` (900 s), en nommant les zones. Mise en + défaut par ce paramètre : critique. +- **Posé sur les trois** (Chezlepro, Technolibre, site) : deux zones rechargées chez chaque + locataire ; au site, la zone et une zone inverse réécrites (le DNS public `site-dnspub-01` + n'y était pas encore). `zones` au vert partout, « chacune conforme à son fichier ». + `console` se résout depuis les deux edges, par le plancher et par PowerDNS. + +**Une erreur de ma part, rattrapée par la garde de syntaxe.** `${#tableau[@]}` dans une sonde +ouvre un commentaire Jinja. `test_sondes_syntaxe.py` l'a vu ; mais j'avais enchaîné le +déploiement de Technolibre sans attendre le test, et la pose de la sonde y a échoué (la +réconciliation, elle, était passée). Corrigé et redéployé ; la configuration publique +réécrite pendant ce passage raté ne différait que par des commentaires. + +**Ce qui n'est pas traité ici.** Les machines des locataires interrogent le résolveur du +site, qui répond NXDOMAIN pour leurs noms internes : leur résolution repose entièrement sur +le plancher. C'est l'état voulu tant que le basculement vers leur résolveur +(`client_resolveur_apply`) n'est pas confirmé. Et rien ne signale encore qu'un plancher est +en retard sur le plan : il suit le plan au déploiement, pas en continu. + ## 2026-09-29 (29) — `passerelle` fait le trajet d'un visiteur jusqu'à la page de connexion ; fin de la revue des sondes Cinquième et dernière des sondes « répond » de la revue (25). diff --git a/roles/serveur_powerdns/defaults/main.yml b/roles/serveur_powerdns/defaults/main.yml index 0156b8c..259e762 100644 --- a/roles/serveur_powerdns/defaults/main.yml +++ b/roles/serveur_powerdns/defaults/main.yml @@ -84,6 +84,10 @@ serveur_powerdns_zones_inverses: >- # --- Sonde de supervision ----------------------------------------------------------- # La zone souveraine et son inverse : deux au minimum. serveur_powerdns_sonde_minimum: 2 +# Ecart tolere (secondes) entre la date d'un fichier de zone et son chargement par +# PowerDNS : le temps qu'un deploiement ecrive puis recharge. Au-dela, la zone servie +# n'est pas celle du disque. Mise en defaut PAR PARAMETRE : une valeur tres negative. +serveur_powerdns_sonde_tolerance: 900 # --- ZONES PUBLIQUES : `autorite: primaire-cache` (tasks/zones-publiques.yml) --------- # diff --git a/roles/serveur_powerdns/tasks/main.yml b/roles/serveur_powerdns/tasks/main.yml index b5df2bc..9264cba 100644 --- a/roles/serveur_powerdns/tasks/main.yml +++ b/roles/serveur_powerdns/tasks/main.yml @@ -133,6 +133,40 @@ # en vrai deploiement, la tache s'execute normalement. when: not ansible_check_mode +# LE FICHIER SUR DISQUE N'EST PAS LA ZONE SERVIE (2026-09-29). Le rechargement passait +# seulement par un handler. Or un handler en attente est ABANDONNE si une tache echoue plus +# loin dans le meme passage — et aux passages suivants le fichier ne change plus, donc plus +# rien ne le redemande. Constate chez les deux locataires : zone reecrite le 16 septembre +# (ajout de `console`), PowerDNS la servait telle que chargee le 13 ou le 14. Treize jours +# de NXDOMAIN sur un nom que le fichier portait, et aucune sonde ne le voyait. +# +# On compare donc a chaque passage, zone par zone, la date du fichier a celle ou PowerDNS +# l'a chargee, et on recharge ce qui est en retard. Ce qui est juste n'est pas touche. +- name: Recharger toute zone dont le fichier est plus recent que la version servie + ansible.builtin.shell: + executable: /bin/bash + cmd: | + set -uo pipefail + verifier() { # $1 = option d'instance ("" ou --config-name=public), $2 = repertoire + local f z charge + for f in "$2"/*.zone; do + [[ -e "${f}" ]] || continue + z=$(basename "${f}" .zone) + charge=$(pdns_control $1 bind-domain-status "${z}" 2>/dev/null \ + | grep -oP 'parsed into memory at \K.*') + if [[ -z "${charge}" ]] || (( $(date -r "${f}" +%s) > $(date -d "${charge}" +%s) )); then + pdns_control $1 bind-reload-now "${z}" >/dev/null && echo "RECHARGEE ${z}" + fi + done + } + verifier "" "{{ serveur_powerdns_zone_directory }}" + {% if serveur_powerdns_dns_public_site | length > 0 %} + verifier "--config-name=public" "{{ serveur_powerdns_public_zones_dir }}" + {% endif %} + register: serveur_powerdns_reconciliation + changed_when: "'RECHARGEE' in serveur_powerdns_reconciliation.stdout" + when: not ansible_check_mode + # --- Sonde de supervision (docs/supervision-conception.md) -------------------------- # Le role qui possede la verite depose sa propre sonde ; le porteur (`client_sante`) la # fait tourner et pousse le verdict, sans savoir ce qu'elle mesure. diff --git a/roles/serveur_powerdns/templates/sonde-zones.sh.j2 b/roles/serveur_powerdns/templates/sonde-zones.sh.j2 index 90cf7ef..a37cd09 100644 --- a/roles/serveur_powerdns/templates/sonde-zones.sh.j2 +++ b/roles/serveur_powerdns/templates/sonde-zones.sh.j2 @@ -8,6 +8,7 @@ set -uo pipefail MINIMUM={{ serveur_powerdns_sonde_minimum }} +TOLERANCE={{ serveur_powerdns_sonde_tolerance }} systemctl is-active --quiet pdns || { echo "L'autoritatif (pdns) n'est pas actif."; exit 2; } [[ "$(pdns_control rping 2>&1 | head -1)" == "PONG" ]] \ @@ -21,4 +22,21 @@ if (( n < MINIMUM )); then echo "L'autoritatif ne sert que ${n} zone(s), moins que ${MINIMUM} — la resolution interne repondra NXDOMAIN.|zones=${n};${MINIMUM};;0;" exit 2 fi -echo "Autoritatif : ${n} zone(s) servie(s).|zones=${n};${MINIMUM};;0;" +# LA ZONE SERVIE EST-ELLE CELLE DU DISQUE ? (2026-09-29) Compter les zones ne dit pas +# lesquelles sont a jour : chez les deux locataires, PowerDNS a servi pendant treize jours +# une zone anterieure a son fichier — `console` y manquait — et cette sonde restait verte. +# `bind-domain-status` donne l'heure de chargement ; on la compare a celle du fichier. +retard=() +for f in {{ serveur_powerdns_zone_directory }}/*.zone; do + [[ -e "${f}" ]] || continue + z=$(basename "${f}" .zone) + charge=$(pdns_control bind-domain-status "${z}" 2>/dev/null | grep -oP 'parsed into memory at \K.*') + if [[ -z "${charge}" ]]; then retard+=("${z}=jamais chargee"); continue; fi + ecart=$(( $(date -r "${f}" +%s) - $(date -d "${charge}" +%s) )) + (( ecart > TOLERANCE )) && retard+=("${z}=fichier plus recent de $(( ecart / 3600 )) h") +done +if [[ -n "${retard[*]}" ]]; then # (le compteur de tableau de bash ouvrirait un commentaire Jinja) + echo "L'autoritatif sert ${n} zone(s), mais PAS celles du disque : ${retard[*]} — les noms ajoutes depuis repondent NXDOMAIN. Redeployer serveur_powerdns.|zones=${n};${MINIMUM};;0;" + exit 2 +fi +echo "Autoritatif : ${n} zone(s) servie(s), chacune conforme a son fichier.|zones=${n};${MINIMUM};;0;"