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 <noreply@anthropic.com>
187 lines
7.5 KiB
YAML
187 lines
7.5 KiB
YAML
---
|
|
- name: Installer PowerDNS Authoritative
|
|
ansible.builtin.apt:
|
|
name: "{{ serveur_powerdns_packages }}"
|
|
state: present
|
|
update_cache: true
|
|
cache_valid_time: 3600
|
|
|
|
- name: Créer le répertoire des zones PowerDNS
|
|
ansible.builtin.file:
|
|
path: "{{ serveur_powerdns_zone_directory }}"
|
|
state: directory
|
|
owner: root
|
|
group: root
|
|
mode: "0755"
|
|
|
|
- name: Déployer la configuration du backend BIND
|
|
ansible.builtin.template:
|
|
src: setops-bind.conf.j2
|
|
dest: /etc/powerdns/pdns.d/setops-bind.conf
|
|
owner: root
|
|
group: root
|
|
mode: "0644"
|
|
notify: Validate and reload PowerDNS
|
|
|
|
- name: Déployer l'index des zones PowerDNS
|
|
ansible.builtin.template:
|
|
src: bindbackend.conf.j2
|
|
dest: "{{ serveur_powerdns_bind_config }}"
|
|
owner: root
|
|
group: root
|
|
mode: "0644"
|
|
notify: Validate and reload PowerDNS
|
|
|
|
# CHAQUE REGISTRE EST CHARGE POUR LUI-MEME (2026-08-25).
|
|
#
|
|
# Ce `include_vars` listait les deux fichiers en dur et echouait si l'un manquait.
|
|
# `domaines.yml` declare les domaines PUBLICS, et un ecosysteme peut legitimement n'en
|
|
# avoir aucun — c'est le cas du SITE, dont tous les services sont internes.
|
|
#
|
|
# Le defaut est reste invisible tant que le site gardait `publier_expositions: false` ;
|
|
# il est apparu a la seconde ou on a voulu publier ses noms de service. C'est le MEME
|
|
# defaut que `hosts_statiques` a corrige le meme jour, dans les memes termes : un registre
|
|
# absent n'est pas une faute, il est simplement absent.
|
|
- name: Vérifier la présence des registres du plan (sur le nœud de contrôle)
|
|
ansible.builtin.stat:
|
|
path: "{{ item }}"
|
|
register: serveur_powerdns_plan
|
|
delegate_to: localhost # les registres du plan vivent sur le nœud de contrôle
|
|
become: false # lire un fichier ne nécessite pas de privilèges
|
|
loop:
|
|
- "{{ setops_plan_dir }}/applications.yml"
|
|
- "{{ setops_plan_dir }}/domaines.yml"
|
|
loop_control:
|
|
label: "{{ item | basename }}"
|
|
when: serveur_powerdns_publier_expositions | bool
|
|
|
|
- name: Charger les registres applications et domaines (si présents)
|
|
ansible.builtin.include_vars:
|
|
file: "{{ item.item }}"
|
|
loop: "{{ serveur_powerdns_plan.results | default([]) }}"
|
|
loop_control:
|
|
label: "{{ item.item | basename }}"
|
|
when:
|
|
- serveur_powerdns_publier_expositions | bool
|
|
- item.stat.exists | default(false)
|
|
|
|
- name: Dériver les A d'exposition (FQDN publics -> edge qui les sert)
|
|
ansible.builtin.set_fact:
|
|
serveur_powerdns_expositions: >-
|
|
{{ {'applications': applications | default({})}
|
|
| expositions_des_applications({'domaines_publics': domaines_publics | default({})}) }}
|
|
when: serveur_powerdns_publier_expositions | bool
|
|
|
|
- name: Générer la zone DNS interne depuis l'inventaire
|
|
ansible.builtin.template:
|
|
src: zone.db.j2
|
|
dest: "{{ serveur_powerdns_zone_directory }}/{{ serveur_powerdns_zone }}.zone"
|
|
owner: root
|
|
group: root
|
|
mode: "0644"
|
|
notify: Validate and reload PowerDNS
|
|
|
|
# Meme source que la zone directe : `hotes_actifs` et son `ansible_host`. Deux zones
|
|
# alimentees par une seule verite — l'endroit ou elles divergeraient n'existe pas.
|
|
- name: Générer les zones DNS inverses depuis l'inventaire
|
|
ansible.builtin.template:
|
|
src: zone-inverse.db.j2
|
|
dest: "{{ serveur_powerdns_zone_directory }}/{{ zone_inverse }}.zone"
|
|
owner: root
|
|
group: root
|
|
mode: "0644"
|
|
loop: "{{ serveur_powerdns_zones_inverses | default([]) }}"
|
|
loop_control:
|
|
loop_var: zone_inverse
|
|
notify: Validate and reload PowerDNS
|
|
|
|
# UNE ZONE INVERSE QUI N'EST PLUS REVENDIQUEE DOIT DISPARAITRE. Sans ce retrait, un
|
|
# ecosysteme qui abandonne un reseau laisserait derriere lui un fichier que le backend ne
|
|
# declare plus mais que le repertoire garde — et le prochain lecteur croirait la zone
|
|
# servie.
|
|
- name: Relever les zones inverses présentes sur la machine
|
|
ansible.builtin.find:
|
|
paths: "{{ serveur_powerdns_zone_directory }}"
|
|
patterns: "*.in-addr.arpa.zone"
|
|
register: serveur_powerdns_inverses_presentes
|
|
|
|
- name: Retirer les zones inverses que l'écosystème ne revendique plus
|
|
ansible.builtin.file:
|
|
path: "{{ item.path }}"
|
|
state: absent
|
|
loop: "{{ serveur_powerdns_inverses_presentes.files | default([]) }}"
|
|
loop_control:
|
|
label: "{{ item.path | basename }}"
|
|
when: >-
|
|
(item.path | basename | regex_replace('\.zone$', ''))
|
|
not in (serveur_powerdns_zones_inverses | default([]))
|
|
notify: Validate and reload PowerDNS
|
|
|
|
# LES ZONES PUBLIQUES, DANS LEUR PROPRE INSTANCE — seulement si le site a un serveur
|
|
# public pour les tirer. Sans lui, publier une zone n'aurait personne pour la servir.
|
|
- name: Publier les zones primaire-cache
|
|
ansible.builtin.include_tasks: zones-publiques.yml
|
|
when: serveur_powerdns_dns_public_site | length > 0
|
|
|
|
- name: Activer et démarrer PowerDNS
|
|
ansible.builtin.systemd:
|
|
name: "{{ serveur_powerdns_service_name }}"
|
|
enabled: true
|
|
state: started
|
|
# Dry-run (--check) : le paquet n'est pas reellement installe, donc le service
|
|
# n'existe pas encore et systemd echouerait. On saute en mode check seulement ;
|
|
# 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.
|
|
- name: Assurer le repertoire des sondes de supervision
|
|
ansible.builtin.file:
|
|
path: /usr/local/lib/setops/sondes
|
|
state: directory
|
|
owner: root
|
|
group: root
|
|
mode: "0755"
|
|
|
|
- name: Deposer la sonde « zones »
|
|
ansible.builtin.template:
|
|
src: sonde-zones.sh.j2
|
|
dest: /usr/local/lib/setops/sondes/zones.sh
|
|
owner: root
|
|
group: root
|
|
mode: "0750"
|