2026-06-30 18:05:42 -04:00
|
|
|
---
|
2026-08-24 15:50:37 -04:00
|
|
|
# CLOUD-INIT REECRIT /etc/hosts A CHAQUE DEMARRAGE (2026-08-24).
|
|
|
|
|
#
|
|
|
|
|
# Le gabarit dore laisse `manage_etc_hosts: true`. A chaque boot, cloud-init regenere
|
|
|
|
|
# /etc/hosts depuis son propre modele — et efface le plancher de resolution que ce role
|
|
|
|
|
# vient de poser. La machine perd alors la seule facon qu'elle a de nommer ses voisines
|
|
|
|
|
# sans DNS, et personne ne le voit : rien n'echoue tant qu'on ne demande pas un nom.
|
|
|
|
|
#
|
|
|
|
|
# CONSTATE SUR infra-dns-01 : redemarre a 18h53 lors d'un deplacement de disque, il a
|
|
|
|
|
# perdu ses six entrees de flotte. Le defaut est apparu deux jours plus tard, sous la
|
|
|
|
|
# forme d'un `apt update` qui n'arrivait plus a resoudre le cache d'artefacts — un
|
|
|
|
|
# message qui ne parlait pas du tout du vrai probleme.
|
|
|
|
|
#
|
|
|
|
|
# On le desactive par un fragment plutot qu'en editant cloud.cfg : le gabarit reste
|
|
|
|
|
# intact, et `apt purge cloud-init` ou une remise a zero rend la machine a son etat
|
|
|
|
|
# d'origine.
|
site : le plancher survit au redemarrage, et la zone dit les vraies adresses
Le decoupage du site en quatre zones a deplace cinq machines. Ni le plancher
/etc/hosts ni la zone DNS n'avaient suivi. Quatre defauts, tous dans le moteur.
LE PLANCHER ETAIT EFFACE A CHAQUE DEMARRAGE — ET LE PREMIER CORRECTIF N'EN
ETAIT PAS UN.
`hosts_statiques` posait `99-setops-hosts.cfg` avec `manage_etc_hosts: false`,
pendant que `cloud_init` posait `99_setops.cfg` avec `true`. Dans `cloud.cfg.d`
l'ordre est LEXICAL et le dernier gagne : `-` vaut 0x2D, `_` vaut 0x5F. On a
donc retire la cle de `cloud_init` — le role qui POSSEDE le fichier decide —
puis renomme notre fragment `zz-` pour passer apres le `99_chezlepro.cfg` du
gabarit dore.
Et ca ne suffisait toujours pas. Redemarrage d'epreuve : plancher encore efface.
La cause reelle est ailleurs — Proxmox inscrit `manage_etc_hosts: true` dans la
USER-DATA de son lecteur cloud-init, et la user-data prime sur `cloud.cfg.d`
tout entier. Aucun fragment ne pouvait gagner ; renommer pour parler en dernier
ne servait a rien, le dernier mot n'appartenant pas a ce repertoire.
Ce que cloud-init regenere, il le regenere depuis `hosts.debian.tmpl` — le
gabarit le documente lui-meme. `hosts_statiques` le pose desormais avec le MEME
contenu que /etc/hosts, et une garde compare les deux a chaque passage.
Redemarrage d'epreuve : les neuf entrees sont la.
La garde precedente affirmait « conforme » en mesurant l'ordre lexical — vrai,
et sans rapport avec ce qui se passait. Une garde qui mesure la mauvaise chose
est pire qu'aucune.
LA ZONE DNS NE PUBLIAIT PAS LES NOMS DE SERVICE.
`forge.genese.internal` et `pki.genese.internal` — des noms que les certificats
portent et que les clients appellent — n'avaient aucun enregistrement. Seul le
plancher savait les resoudre. Trois causes empilees :
- le plan du site coupait `serveur_powerdns_publier_expositions`, au motif que
« le site n'a pas d'edge » : ca confondait PUBLIC et EXPOSE ;
- `expositions_des_applications` rendait `domaine: None` faute de
`domaines.yml`, et le modele de zone ecarte les expositions dont le domaine
n'est pas la zone. Repli ajoute, symetrique de celui deja ecrit pour `edge` :
sans domaine public declare, le domaine est celui que porte le FQDN ;
- `serveur_powerdns` exigeait les deux registres et echouait si `domaines.yml`
manquait — le meme tout-ou-rien que `hosts_statiques` a corrige le meme jour.
Puis `named-checkzone` a refuse la zone : `dns.genese.internal` heritait d'un
CNAME par defaut du role ET d'un A par exposition. La garde a bien joue son role
— elle a arrete une zone cassee avant qu'elle soit servie. Le plan l'emporte
desormais sur le defaut du role.
Un service ne doit pas dependre d'un plancher pour etre joignable : le plancher
est un filet, pas le sol.
VERIFICATION. Les huit noms — cinq machines, trois services — resolvent vers les
bonnes adresses depuis les cinq hotes, par le plancher ET par le DNS, et le
plancher survit au redemarrage.
P46 refuse desormais deux choses : plus d'un role ecrivant `manage_etc_hosts`,
et l'absence du gabarit maitre. Controle negatif verifie.
RESTE NOMME, PAS CORRIGE : la zone INVERSE. `serveur_powerdns_zone_inverse`
derive d'un supernet /16 — la forme d'un tenant. Un site declare plusieurs /24
et n'a pas de supernet unique : aucune zone inverse n'est generee.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 20:31:01 -04:00
|
|
|
#
|
|
|
|
|
# `zz-` ET NON `99-` (2026-08-25). Cloud-init lit `cloud.cfg.d` dans l'ordre LEXICAL, et
|
|
|
|
|
# le DERNIER a parler gagne. Notre fragment s'appelait `99-setops-hosts.cfg` ; le gabarit
|
|
|
|
|
# dore en porte un autre, `99_chezlepro.cfg`, qui pose `manage_etc_hosts: true`. Or `-`
|
|
|
|
|
# vaut 0x2D et `_` vaut 0x5F : le fragment du gabarit etait lu APRES le notre, et gagnait.
|
|
|
|
|
#
|
|
|
|
|
# Mesure du 2026-08-25 : les cinq machines du site redemarrees avaient perdu tout leur
|
|
|
|
|
# plancher malgre notre fragment — il etait bien la, simplement sans effet. Un fichier
|
|
|
|
|
# present et ignore est le pire des deux mondes : il rassure sans rien garantir.
|
|
|
|
|
#
|
|
|
|
|
# `zz-` passe apres tout prefixe numerique ET apres `_`. On ne cherche donc plus a
|
|
|
|
|
# connaitre les fragments des autres : on parle en dernier, quels qu'ils soient. La garde
|
|
|
|
|
# plus bas verifie que c'est encore vrai sur la machine.
|
2026-08-24 15:50:37 -04:00
|
|
|
- name: Empêcher cloud-init de réécrire le plancher à chaque démarrage
|
|
|
|
|
ansible.builtin.copy:
|
site : le plancher survit au redemarrage, et la zone dit les vraies adresses
Le decoupage du site en quatre zones a deplace cinq machines. Ni le plancher
/etc/hosts ni la zone DNS n'avaient suivi. Quatre defauts, tous dans le moteur.
LE PLANCHER ETAIT EFFACE A CHAQUE DEMARRAGE — ET LE PREMIER CORRECTIF N'EN
ETAIT PAS UN.
`hosts_statiques` posait `99-setops-hosts.cfg` avec `manage_etc_hosts: false`,
pendant que `cloud_init` posait `99_setops.cfg` avec `true`. Dans `cloud.cfg.d`
l'ordre est LEXICAL et le dernier gagne : `-` vaut 0x2D, `_` vaut 0x5F. On a
donc retire la cle de `cloud_init` — le role qui POSSEDE le fichier decide —
puis renomme notre fragment `zz-` pour passer apres le `99_chezlepro.cfg` du
gabarit dore.
Et ca ne suffisait toujours pas. Redemarrage d'epreuve : plancher encore efface.
La cause reelle est ailleurs — Proxmox inscrit `manage_etc_hosts: true` dans la
USER-DATA de son lecteur cloud-init, et la user-data prime sur `cloud.cfg.d`
tout entier. Aucun fragment ne pouvait gagner ; renommer pour parler en dernier
ne servait a rien, le dernier mot n'appartenant pas a ce repertoire.
Ce que cloud-init regenere, il le regenere depuis `hosts.debian.tmpl` — le
gabarit le documente lui-meme. `hosts_statiques` le pose desormais avec le MEME
contenu que /etc/hosts, et une garde compare les deux a chaque passage.
Redemarrage d'epreuve : les neuf entrees sont la.
La garde precedente affirmait « conforme » en mesurant l'ordre lexical — vrai,
et sans rapport avec ce qui se passait. Une garde qui mesure la mauvaise chose
est pire qu'aucune.
LA ZONE DNS NE PUBLIAIT PAS LES NOMS DE SERVICE.
`forge.genese.internal` et `pki.genese.internal` — des noms que les certificats
portent et que les clients appellent — n'avaient aucun enregistrement. Seul le
plancher savait les resoudre. Trois causes empilees :
- le plan du site coupait `serveur_powerdns_publier_expositions`, au motif que
« le site n'a pas d'edge » : ca confondait PUBLIC et EXPOSE ;
- `expositions_des_applications` rendait `domaine: None` faute de
`domaines.yml`, et le modele de zone ecarte les expositions dont le domaine
n'est pas la zone. Repli ajoute, symetrique de celui deja ecrit pour `edge` :
sans domaine public declare, le domaine est celui que porte le FQDN ;
- `serveur_powerdns` exigeait les deux registres et echouait si `domaines.yml`
manquait — le meme tout-ou-rien que `hosts_statiques` a corrige le meme jour.
Puis `named-checkzone` a refuse la zone : `dns.genese.internal` heritait d'un
CNAME par defaut du role ET d'un A par exposition. La garde a bien joue son role
— elle a arrete une zone cassee avant qu'elle soit servie. Le plan l'emporte
desormais sur le defaut du role.
Un service ne doit pas dependre d'un plancher pour etre joignable : le plancher
est un filet, pas le sol.
VERIFICATION. Les huit noms — cinq machines, trois services — resolvent vers les
bonnes adresses depuis les cinq hotes, par le plancher ET par le DNS, et le
plancher survit au redemarrage.
P46 refuse desormais deux choses : plus d'un role ecrivant `manage_etc_hosts`,
et l'absence du gabarit maitre. Controle negatif verifie.
RESTE NOMME, PAS CORRIGE : la zone INVERSE. `serveur_powerdns_zone_inverse`
derive d'un supernet /16 — la forme d'un tenant. Un site declare plusieurs /24
et n'a pas de supernet unique : aucune zone inverse n'est generee.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 20:31:01 -04:00
|
|
|
dest: /etc/cloud/cloud.cfg.d/zz-setops-hosts.cfg
|
2026-08-24 15:50:37 -04:00
|
|
|
content: |
|
|
|
|
|
# GÉNÉRÉ par Set-OPS (rôle hosts_statiques). NE PAS éditer à la main.
|
|
|
|
|
# /etc/hosts est le PLANCHER DE RÉSOLUTION de l'écosystème, dérivé de l'inventaire.
|
|
|
|
|
# Laisser cloud-init le régénérer au démarrage l'effacerait en silence.
|
|
|
|
|
manage_etc_hosts: false
|
|
|
|
|
owner: root
|
|
|
|
|
group: root
|
|
|
|
|
mode: "0644"
|
|
|
|
|
when: hosts_statiques_actif | bool
|
|
|
|
|
|
site : le plancher survit au redemarrage, et la zone dit les vraies adresses
Le decoupage du site en quatre zones a deplace cinq machines. Ni le plancher
/etc/hosts ni la zone DNS n'avaient suivi. Quatre defauts, tous dans le moteur.
LE PLANCHER ETAIT EFFACE A CHAQUE DEMARRAGE — ET LE PREMIER CORRECTIF N'EN
ETAIT PAS UN.
`hosts_statiques` posait `99-setops-hosts.cfg` avec `manage_etc_hosts: false`,
pendant que `cloud_init` posait `99_setops.cfg` avec `true`. Dans `cloud.cfg.d`
l'ordre est LEXICAL et le dernier gagne : `-` vaut 0x2D, `_` vaut 0x5F. On a
donc retire la cle de `cloud_init` — le role qui POSSEDE le fichier decide —
puis renomme notre fragment `zz-` pour passer apres le `99_chezlepro.cfg` du
gabarit dore.
Et ca ne suffisait toujours pas. Redemarrage d'epreuve : plancher encore efface.
La cause reelle est ailleurs — Proxmox inscrit `manage_etc_hosts: true` dans la
USER-DATA de son lecteur cloud-init, et la user-data prime sur `cloud.cfg.d`
tout entier. Aucun fragment ne pouvait gagner ; renommer pour parler en dernier
ne servait a rien, le dernier mot n'appartenant pas a ce repertoire.
Ce que cloud-init regenere, il le regenere depuis `hosts.debian.tmpl` — le
gabarit le documente lui-meme. `hosts_statiques` le pose desormais avec le MEME
contenu que /etc/hosts, et une garde compare les deux a chaque passage.
Redemarrage d'epreuve : les neuf entrees sont la.
La garde precedente affirmait « conforme » en mesurant l'ordre lexical — vrai,
et sans rapport avec ce qui se passait. Une garde qui mesure la mauvaise chose
est pire qu'aucune.
LA ZONE DNS NE PUBLIAIT PAS LES NOMS DE SERVICE.
`forge.genese.internal` et `pki.genese.internal` — des noms que les certificats
portent et que les clients appellent — n'avaient aucun enregistrement. Seul le
plancher savait les resoudre. Trois causes empilees :
- le plan du site coupait `serveur_powerdns_publier_expositions`, au motif que
« le site n'a pas d'edge » : ca confondait PUBLIC et EXPOSE ;
- `expositions_des_applications` rendait `domaine: None` faute de
`domaines.yml`, et le modele de zone ecarte les expositions dont le domaine
n'est pas la zone. Repli ajoute, symetrique de celui deja ecrit pour `edge` :
sans domaine public declare, le domaine est celui que porte le FQDN ;
- `serveur_powerdns` exigeait les deux registres et echouait si `domaines.yml`
manquait — le meme tout-ou-rien que `hosts_statiques` a corrige le meme jour.
Puis `named-checkzone` a refuse la zone : `dns.genese.internal` heritait d'un
CNAME par defaut du role ET d'un A par exposition. La garde a bien joue son role
— elle a arrete une zone cassee avant qu'elle soit servie. Le plan l'emporte
desormais sur le defaut du role.
Un service ne doit pas dependre d'un plancher pour etre joignable : le plancher
est un filet, pas le sol.
VERIFICATION. Les huit noms — cinq machines, trois services — resolvent vers les
bonnes adresses depuis les cinq hotes, par le plancher ET par le DNS, et le
plancher survit au redemarrage.
P46 refuse desormais deux choses : plus d'un role ecrivant `manage_etc_hosts`,
et l'absence du gabarit maitre. Controle negatif verifie.
RESTE NOMME, PAS CORRIGE : la zone INVERSE. `serveur_powerdns_zone_inverse`
derive d'un supernet /16 — la forme d'un tenant. Un site declare plusieurs /24
et n'a pas de supernet unique : aucune zone inverse n'est generee.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 20:31:01 -04:00
|
|
|
# CE FRAGMENT EST DESORMAIS LE SEUL A DECIDER (2026-08-25).
|
|
|
|
|
#
|
|
|
|
|
# `cloud_init` en ecrivait un second (`99_setops.cfg`) qui posait `manage_etc_hosts: true`.
|
|
|
|
|
# Dans `cloud.cfg.d` l'ordre est LEXICAL : `-` (0x2D) passe avant `_` (0x5F), donc le
|
|
|
|
|
# fragment de `cloud_init` etait lu EN DERNIER et gagnait. Le plancher etait efface a
|
|
|
|
|
# chaque demarrage, et ca ne se voyait qu'au redemarrage suivant — sous la forme d'un
|
|
|
|
|
# `apt update` qui ne resolvait plus, ou d'un nom de service qui ne pointait nulle part.
|
|
|
|
|
#
|
|
|
|
|
# LE RETRAIT DOIT ETRE AUSSI EXPLICITE QUE LA POSE. Sans la tache ci-dessous, desactiver
|
|
|
|
|
# `hosts_statiques` laissait le fragment en place : la machine gardait un /etc/hosts fige
|
|
|
|
|
# que plus personne ne tenait a jour, et cloud-init n'avait plus le droit de le reprendre.
|
|
|
|
|
# Un etat que ni l'un ni l'autre n'assume.
|
|
|
|
|
- name: Rendre /etc/hosts à cloud-init quand le plancher est désactivé
|
|
|
|
|
ansible.builtin.file:
|
|
|
|
|
path: /etc/cloud/cloud.cfg.d/zz-setops-hosts.cfg
|
|
|
|
|
state: absent
|
|
|
|
|
when: not (hosts_statiques_actif | bool)
|
|
|
|
|
|
|
|
|
|
# L'ancien nom, qui ne parlait pas en dernier. Le laisser en place n'aurait rien casse,
|
|
|
|
|
# mais deux fichiers disant la meme chose sont un desaccord qui attend son heure.
|
|
|
|
|
- name: Retirer l'ancien fragment, qui ne parlait pas en dernier
|
|
|
|
|
ansible.builtin.file:
|
|
|
|
|
path: /etc/cloud/cloud.cfg.d/99-setops-hosts.cfg
|
|
|
|
|
state: absent
|
|
|
|
|
|
2026-07-03 14:14:34 -04:00
|
|
|
# Alias d'exposition (best-effort) : dérivés du plan si celui-ci est disponible.
|
|
|
|
|
- name: Vérifier la présence des registres du plan (sur le nœud de contrôle)
|
|
|
|
|
ansible.builtin.stat:
|
|
|
|
|
path: "{{ item }}"
|
|
|
|
|
register: hosts_statiques_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:
|
|
|
|
|
- hosts_statiques_actif | bool
|
|
|
|
|
- hosts_statiques_publier_expositions | bool
|
|
|
|
|
- setops_plan_dir is defined
|
|
|
|
|
|
site : un SITE a bien un plan — et huit defauts que lui seul pouvait reveler
J'ai repete toute la journee qu'un SITE n'est pas un plan. C'etait faux : j'en
reconstruisais un morceau par morceau dans underlay.yml sans le nommer. Ce qui est vrai,
c'est qu'un site ne DERIVE pas — il declare ses adresses parce qu'il EST le terrain — et
ne passe donc pas par `instancier`. Mais ne pas deriver n'est pas ne pas avoir de plan.
SITE-Chezlepro/plan/{10-intrants,serveurs,applications}.yml ; underlay.yml ne garde que
la fabric. Ce qui est MESURE d'un cote, ce qui est VOULU de l'autre. Les groupes viennent
du registre des applications, les gardes ont suivi le plan (4 controles negatifs).
Huit defauts, tous invisibles chez un tenant parce qu'il a toujours tout :
- client_pki codait `infra-pki-01` EN DUR — vrai par coincidence de nomenclature ;
- aucun moyen pour un service non-root de lire la cle (Forgejo tourne en `git`) ;
- le certificat, PUBLIC par nature, restait en 0600 ;
- l'unite Forgejo n'avait pas d'ExecReload : un cert renouvele aurait ete servi perime ;
- le role ne savait pas servir TLS lui-meme (il y avait toujours un edge) ;
- le cert ne couvrait pas le nom de SERVICE, faute d'`expose:` ;
- les registres se chargeaient en tout-ou-rien : sans domaines.yml, plancher vide ;
- le flux declarait 3000 en dur.
Le message accusait presque toujours autre chose : le DNS quand c'etait un nom faux, une
permission de fichier quand c'etait un port privilegie, rien du tout quand le plancher
s'ecrivait vide.
ROOT_URL est gravee dans les URL de clonage : la forge sert desormais sur 443, avec
CAP_NET_BIND_SERVICE, et son URL n'a plus de port.
Verifie depuis le reseau : Verify return code 0, https://forge.genese.internal/ -> 200.
42 preuves vertes, flux coherents (34 roles, 92 flux).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 13:15:34 -04:00
|
|
|
# CHAQUE REGISTRE EST CHARGÉ POUR LUI-MÊME (2026-08-25).
|
|
|
|
|
#
|
|
|
|
|
# La condition exigeait que les DEUX fichiers existent (`length == 2`). Un tout-ou-rien
|
|
|
|
|
# sans raison : `domaines.yml` déclare les domaines PUBLICS, et un écosystème peut
|
|
|
|
|
# légitimement n'en avoir aucun — c'est le cas du SITE, dont tous les services sont
|
|
|
|
|
# internes.
|
|
|
|
|
#
|
|
|
|
|
# Conséquence : `applications.yml` n'était pas chargé non plus, la dérivation rendait une
|
|
|
|
|
# liste vide, et le plancher s'écrivait SANS AUCUN ALIAS — sans erreur. Le certificat de
|
|
|
|
|
# la forge portait `forge.genese.internal` et ce nom ne résolvait nulle part.
|
|
|
|
|
#
|
|
|
|
|
# On charge donc ce qui existe, fichier par fichier. Un registre absent n'est pas une
|
|
|
|
|
# faute ; il est simplement absent.
|
2026-07-03 14:14:34 -04:00
|
|
|
- name: Charger les registres applications et domaines (si présents)
|
|
|
|
|
ansible.builtin.include_vars:
|
site : un SITE a bien un plan — et huit defauts que lui seul pouvait reveler
J'ai repete toute la journee qu'un SITE n'est pas un plan. C'etait faux : j'en
reconstruisais un morceau par morceau dans underlay.yml sans le nommer. Ce qui est vrai,
c'est qu'un site ne DERIVE pas — il declare ses adresses parce qu'il EST le terrain — et
ne passe donc pas par `instancier`. Mais ne pas deriver n'est pas ne pas avoir de plan.
SITE-Chezlepro/plan/{10-intrants,serveurs,applications}.yml ; underlay.yml ne garde que
la fabric. Ce qui est MESURE d'un cote, ce qui est VOULU de l'autre. Les groupes viennent
du registre des applications, les gardes ont suivi le plan (4 controles negatifs).
Huit defauts, tous invisibles chez un tenant parce qu'il a toujours tout :
- client_pki codait `infra-pki-01` EN DUR — vrai par coincidence de nomenclature ;
- aucun moyen pour un service non-root de lire la cle (Forgejo tourne en `git`) ;
- le certificat, PUBLIC par nature, restait en 0600 ;
- l'unite Forgejo n'avait pas d'ExecReload : un cert renouvele aurait ete servi perime ;
- le role ne savait pas servir TLS lui-meme (il y avait toujours un edge) ;
- le cert ne couvrait pas le nom de SERVICE, faute d'`expose:` ;
- les registres se chargeaient en tout-ou-rien : sans domaines.yml, plancher vide ;
- le flux declarait 3000 en dur.
Le message accusait presque toujours autre chose : le DNS quand c'etait un nom faux, une
permission de fichier quand c'etait un port privilegie, rien du tout quand le plancher
s'ecrivait vide.
ROOT_URL est gravee dans les URL de clonage : la forge sert desormais sur 443, avec
CAP_NET_BIND_SERVICE, et son URL n'a plus de port.
Verifie depuis le reseau : Verify return code 0, https://forge.genese.internal/ -> 200.
42 preuves vertes, flux coherents (34 roles, 92 flux).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 13:15:34 -04:00
|
|
|
file: "{{ item.item }}"
|
|
|
|
|
loop: "{{ hosts_statiques_plan.results | default([]) }}"
|
2026-07-03 14:14:34 -04:00
|
|
|
loop_control:
|
site : un SITE a bien un plan — et huit defauts que lui seul pouvait reveler
J'ai repete toute la journee qu'un SITE n'est pas un plan. C'etait faux : j'en
reconstruisais un morceau par morceau dans underlay.yml sans le nommer. Ce qui est vrai,
c'est qu'un site ne DERIVE pas — il declare ses adresses parce qu'il EST le terrain — et
ne passe donc pas par `instancier`. Mais ne pas deriver n'est pas ne pas avoir de plan.
SITE-Chezlepro/plan/{10-intrants,serveurs,applications}.yml ; underlay.yml ne garde que
la fabric. Ce qui est MESURE d'un cote, ce qui est VOULU de l'autre. Les groupes viennent
du registre des applications, les gardes ont suivi le plan (4 controles negatifs).
Huit defauts, tous invisibles chez un tenant parce qu'il a toujours tout :
- client_pki codait `infra-pki-01` EN DUR — vrai par coincidence de nomenclature ;
- aucun moyen pour un service non-root de lire la cle (Forgejo tourne en `git`) ;
- le certificat, PUBLIC par nature, restait en 0600 ;
- l'unite Forgejo n'avait pas d'ExecReload : un cert renouvele aurait ete servi perime ;
- le role ne savait pas servir TLS lui-meme (il y avait toujours un edge) ;
- le cert ne couvrait pas le nom de SERVICE, faute d'`expose:` ;
- les registres se chargeaient en tout-ou-rien : sans domaines.yml, plancher vide ;
- le flux declarait 3000 en dur.
Le message accusait presque toujours autre chose : le DNS quand c'etait un nom faux, une
permission de fichier quand c'etait un port privilegie, rien du tout quand le plancher
s'ecrivait vide.
ROOT_URL est gravee dans les URL de clonage : la forge sert desormais sur 443, avec
CAP_NET_BIND_SERVICE, et son URL n'a plus de port.
Verifie depuis le reseau : Verify return code 0, https://forge.genese.internal/ -> 200.
42 preuves vertes, flux coherents (34 roles, 92 flux).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 13:15:34 -04:00
|
|
|
label: "{{ item.item | basename }}"
|
2026-07-03 14:14:34 -04:00
|
|
|
when:
|
|
|
|
|
- hosts_statiques_actif | bool
|
|
|
|
|
- hosts_statiques_publier_expositions | bool
|
site : un SITE a bien un plan — et huit defauts que lui seul pouvait reveler
J'ai repete toute la journee qu'un SITE n'est pas un plan. C'etait faux : j'en
reconstruisais un morceau par morceau dans underlay.yml sans le nommer. Ce qui est vrai,
c'est qu'un site ne DERIVE pas — il declare ses adresses parce qu'il EST le terrain — et
ne passe donc pas par `instancier`. Mais ne pas deriver n'est pas ne pas avoir de plan.
SITE-Chezlepro/plan/{10-intrants,serveurs,applications}.yml ; underlay.yml ne garde que
la fabric. Ce qui est MESURE d'un cote, ce qui est VOULU de l'autre. Les groupes viennent
du registre des applications, les gardes ont suivi le plan (4 controles negatifs).
Huit defauts, tous invisibles chez un tenant parce qu'il a toujours tout :
- client_pki codait `infra-pki-01` EN DUR — vrai par coincidence de nomenclature ;
- aucun moyen pour un service non-root de lire la cle (Forgejo tourne en `git`) ;
- le certificat, PUBLIC par nature, restait en 0600 ;
- l'unite Forgejo n'avait pas d'ExecReload : un cert renouvele aurait ete servi perime ;
- le role ne savait pas servir TLS lui-meme (il y avait toujours un edge) ;
- le cert ne couvrait pas le nom de SERVICE, faute d'`expose:` ;
- les registres se chargeaient en tout-ou-rien : sans domaines.yml, plancher vide ;
- le flux declarait 3000 en dur.
Le message accusait presque toujours autre chose : le DNS quand c'etait un nom faux, une
permission de fichier quand c'etait un port privilegie, rien du tout quand le plancher
s'ecrivait vide.
ROOT_URL est gravee dans les URL de clonage : la forge sert desormais sur 443, avec
CAP_NET_BIND_SERVICE, et son URL n'a plus de port.
Verifie depuis le reseau : Verify return code 0, https://forge.genese.internal/ -> 200.
42 preuves vertes, flux coherents (34 roles, 92 flux).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 13:15:34 -04:00
|
|
|
- item.stat.exists | default(false)
|
2026-07-03 14:14:34 -04:00
|
|
|
|
|
|
|
|
- name: Dériver les alias d'exposition (FQDN exposés → edge qui les sert)
|
|
|
|
|
ansible.builtin.set_fact:
|
|
|
|
|
hosts_statiques_expositions: >-
|
|
|
|
|
{{ {'applications': applications | default({})}
|
|
|
|
|
| expositions_des_applications({'domaines_publics': domaines_publics | default({})}) }}
|
|
|
|
|
when:
|
|
|
|
|
- hosts_statiques_actif | bool
|
|
|
|
|
- hosts_statiques_publier_expositions | bool
|
|
|
|
|
|
2026-06-30 18:05:42 -04:00
|
|
|
- name: Générer /etc/hosts depuis l'inventaire (plancher de résolution, indépendant du DNS)
|
|
|
|
|
ansible.builtin.template:
|
|
|
|
|
src: hosts.j2
|
|
|
|
|
dest: /etc/hosts
|
|
|
|
|
owner: root
|
|
|
|
|
group: root
|
|
|
|
|
mode: "0644"
|
|
|
|
|
when: hosts_statiques_actif | bool
|
site : le plancher survit au redemarrage, et la zone dit les vraies adresses
Le decoupage du site en quatre zones a deplace cinq machines. Ni le plancher
/etc/hosts ni la zone DNS n'avaient suivi. Quatre defauts, tous dans le moteur.
LE PLANCHER ETAIT EFFACE A CHAQUE DEMARRAGE — ET LE PREMIER CORRECTIF N'EN
ETAIT PAS UN.
`hosts_statiques` posait `99-setops-hosts.cfg` avec `manage_etc_hosts: false`,
pendant que `cloud_init` posait `99_setops.cfg` avec `true`. Dans `cloud.cfg.d`
l'ordre est LEXICAL et le dernier gagne : `-` vaut 0x2D, `_` vaut 0x5F. On a
donc retire la cle de `cloud_init` — le role qui POSSEDE le fichier decide —
puis renomme notre fragment `zz-` pour passer apres le `99_chezlepro.cfg` du
gabarit dore.
Et ca ne suffisait toujours pas. Redemarrage d'epreuve : plancher encore efface.
La cause reelle est ailleurs — Proxmox inscrit `manage_etc_hosts: true` dans la
USER-DATA de son lecteur cloud-init, et la user-data prime sur `cloud.cfg.d`
tout entier. Aucun fragment ne pouvait gagner ; renommer pour parler en dernier
ne servait a rien, le dernier mot n'appartenant pas a ce repertoire.
Ce que cloud-init regenere, il le regenere depuis `hosts.debian.tmpl` — le
gabarit le documente lui-meme. `hosts_statiques` le pose desormais avec le MEME
contenu que /etc/hosts, et une garde compare les deux a chaque passage.
Redemarrage d'epreuve : les neuf entrees sont la.
La garde precedente affirmait « conforme » en mesurant l'ordre lexical — vrai,
et sans rapport avec ce qui se passait. Une garde qui mesure la mauvaise chose
est pire qu'aucune.
LA ZONE DNS NE PUBLIAIT PAS LES NOMS DE SERVICE.
`forge.genese.internal` et `pki.genese.internal` — des noms que les certificats
portent et que les clients appellent — n'avaient aucun enregistrement. Seul le
plancher savait les resoudre. Trois causes empilees :
- le plan du site coupait `serveur_powerdns_publier_expositions`, au motif que
« le site n'a pas d'edge » : ca confondait PUBLIC et EXPOSE ;
- `expositions_des_applications` rendait `domaine: None` faute de
`domaines.yml`, et le modele de zone ecarte les expositions dont le domaine
n'est pas la zone. Repli ajoute, symetrique de celui deja ecrit pour `edge` :
sans domaine public declare, le domaine est celui que porte le FQDN ;
- `serveur_powerdns` exigeait les deux registres et echouait si `domaines.yml`
manquait — le meme tout-ou-rien que `hosts_statiques` a corrige le meme jour.
Puis `named-checkzone` a refuse la zone : `dns.genese.internal` heritait d'un
CNAME par defaut du role ET d'un A par exposition. La garde a bien joue son role
— elle a arrete une zone cassee avant qu'elle soit servie. Le plan l'emporte
desormais sur le defaut du role.
Un service ne doit pas dependre d'un plancher pour etre joignable : le plancher
est un filet, pas le sol.
VERIFICATION. Les huit noms — cinq machines, trois services — resolvent vers les
bonnes adresses depuis les cinq hotes, par le plancher ET par le DNS, et le
plancher survit au redemarrage.
P46 refuse desormais deux choses : plus d'un role ecrivant `manage_etc_hosts`,
et l'absence du gabarit maitre. Controle negatif verifie.
RESTE NOMME, PAS CORRIGE : la zone INVERSE. `serveur_powerdns_zone_inverse`
derive d'un supernet /16 — la forme d'un tenant. Un site declare plusieurs /24
et n'a pas de supernet unique : aucune zone inverse n'est generee.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 20:31:01 -04:00
|
|
|
|
|
|
|
|
# LE SEUL ENDROIT QUI TIENNE AU REDEMARRAGE (2026-08-25).
|
|
|
|
|
#
|
|
|
|
|
# Le fragment `cloud.cfg.d` ne suffit pas, et c'est mesure : Proxmox inscrit
|
|
|
|
|
# `manage_etc_hosts: true` dans la USER-DATA de son lecteur cloud-init, et la user-data
|
|
|
|
|
# prime sur tout fragment de `/etc/cloud/cloud.cfg.d`. Le plancher etait donc efface a
|
|
|
|
|
# chaque demarrage malgre le fragment — d'abord `99-setops-hosts.cfg`, puis son
|
|
|
|
|
# remplacant `zz-` : renommer pour parler en dernier ne changeait rien, puisque le dernier
|
|
|
|
|
# mot n'appartenait pas a ce repertoire.
|
|
|
|
|
#
|
|
|
|
|
# Ce que cloud-init regenere, il le regenere DEPUIS CE GABARIT. On le pose donc avec le
|
|
|
|
|
# meme contenu que /etc/hosts : le fichier de la machine et le gabarit qui le reecrira
|
|
|
|
|
# disent la meme chose, quelle que soit la valeur de `manage_etc_hosts`.
|
|
|
|
|
#
|
|
|
|
|
# Le gabarit d'origine le documente lui-meme : « make changes to the master file in
|
|
|
|
|
# /etc/cloud/templates/hosts.debian.tmpl ».
|
2026-09-10 13:29:25 -04:00
|
|
|
# ... MAIS SEULEMENT TANT QUE CLOUD-INIT EST LA (2026-09-10).
|
|
|
|
|
#
|
|
|
|
|
# D-85 fait RETIRER cloud-init par `serveur_durci`. Le repertoire des gabarits maitres
|
|
|
|
|
# part avec lui, et cette tache echoue alors sur :
|
|
|
|
|
#
|
|
|
|
|
# Destination directory /etc/cloud/templates does not exist
|
|
|
|
|
#
|
|
|
|
|
# Or l'echec n'a aucun sens : ce gabarit ne sert qu'a une chose, survivre a la reecriture
|
|
|
|
|
# de `/etc/hosts` par cloud-init au demarrage. Plus de cloud-init, plus de reecriture —
|
|
|
|
|
# le plancher tient tout seul, ce qui EST le resultat recherche par D-85.
|
|
|
|
|
#
|
|
|
|
|
# CE QUE CA A COUTE (reconstruction du 2026-09-10). `_amorcer-socle` monte `infra-pki-01`
|
|
|
|
|
# et `infra-dns-01` EN ENTIER d'abord, durcissement compris : cloud-init y est donc deja
|
|
|
|
|
# parti quand la flotte rejoue `hosts_statiques`. La tache echouait, l'hote sortait du
|
|
|
|
|
# play — et TOUT ce qui suivait dans ce play n'etait jamais pose, dont `icinga-ca.crt`.
|
|
|
|
|
# Leur porteur de sante tournait ensuite normalement et chaque rapport echouait sur
|
|
|
|
|
# `curl: (77)`, en silence. Deux machines ont supervise dans le vide sans que rien ne le
|
|
|
|
|
# dise : un echec bruyant au bon endroit avait produit une panne muette ailleurs.
|
|
|
|
|
- name: Le gabarit maître de cloud-init existe-t-il encore ?
|
|
|
|
|
ansible.builtin.stat:
|
|
|
|
|
path: /etc/cloud/templates
|
|
|
|
|
register: hosts_statiques_gabarits_cloud_init
|
|
|
|
|
when: hosts_statiques_actif | bool
|
|
|
|
|
|
site : le plancher survit au redemarrage, et la zone dit les vraies adresses
Le decoupage du site en quatre zones a deplace cinq machines. Ni le plancher
/etc/hosts ni la zone DNS n'avaient suivi. Quatre defauts, tous dans le moteur.
LE PLANCHER ETAIT EFFACE A CHAQUE DEMARRAGE — ET LE PREMIER CORRECTIF N'EN
ETAIT PAS UN.
`hosts_statiques` posait `99-setops-hosts.cfg` avec `manage_etc_hosts: false`,
pendant que `cloud_init` posait `99_setops.cfg` avec `true`. Dans `cloud.cfg.d`
l'ordre est LEXICAL et le dernier gagne : `-` vaut 0x2D, `_` vaut 0x5F. On a
donc retire la cle de `cloud_init` — le role qui POSSEDE le fichier decide —
puis renomme notre fragment `zz-` pour passer apres le `99_chezlepro.cfg` du
gabarit dore.
Et ca ne suffisait toujours pas. Redemarrage d'epreuve : plancher encore efface.
La cause reelle est ailleurs — Proxmox inscrit `manage_etc_hosts: true` dans la
USER-DATA de son lecteur cloud-init, et la user-data prime sur `cloud.cfg.d`
tout entier. Aucun fragment ne pouvait gagner ; renommer pour parler en dernier
ne servait a rien, le dernier mot n'appartenant pas a ce repertoire.
Ce que cloud-init regenere, il le regenere depuis `hosts.debian.tmpl` — le
gabarit le documente lui-meme. `hosts_statiques` le pose desormais avec le MEME
contenu que /etc/hosts, et une garde compare les deux a chaque passage.
Redemarrage d'epreuve : les neuf entrees sont la.
La garde precedente affirmait « conforme » en mesurant l'ordre lexical — vrai,
et sans rapport avec ce qui se passait. Une garde qui mesure la mauvaise chose
est pire qu'aucune.
LA ZONE DNS NE PUBLIAIT PAS LES NOMS DE SERVICE.
`forge.genese.internal` et `pki.genese.internal` — des noms que les certificats
portent et que les clients appellent — n'avaient aucun enregistrement. Seul le
plancher savait les resoudre. Trois causes empilees :
- le plan du site coupait `serveur_powerdns_publier_expositions`, au motif que
« le site n'a pas d'edge » : ca confondait PUBLIC et EXPOSE ;
- `expositions_des_applications` rendait `domaine: None` faute de
`domaines.yml`, et le modele de zone ecarte les expositions dont le domaine
n'est pas la zone. Repli ajoute, symetrique de celui deja ecrit pour `edge` :
sans domaine public declare, le domaine est celui que porte le FQDN ;
- `serveur_powerdns` exigeait les deux registres et echouait si `domaines.yml`
manquait — le meme tout-ou-rien que `hosts_statiques` a corrige le meme jour.
Puis `named-checkzone` a refuse la zone : `dns.genese.internal` heritait d'un
CNAME par defaut du role ET d'un A par exposition. La garde a bien joue son role
— elle a arrete une zone cassee avant qu'elle soit servie. Le plan l'emporte
desormais sur le defaut du role.
Un service ne doit pas dependre d'un plancher pour etre joignable : le plancher
est un filet, pas le sol.
VERIFICATION. Les huit noms — cinq machines, trois services — resolvent vers les
bonnes adresses depuis les cinq hotes, par le plancher ET par le DNS, et le
plancher survit au redemarrage.
P46 refuse desormais deux choses : plus d'un role ecrivant `manage_etc_hosts`,
et l'absence du gabarit maitre. Controle negatif verifie.
RESTE NOMME, PAS CORRIGE : la zone INVERSE. `serveur_powerdns_zone_inverse`
derive d'un supernet /16 — la forme d'un tenant. Un site declare plusieurs /24
et n'a pas de supernet unique : aucune zone inverse n'est generee.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 20:31:01 -04:00
|
|
|
- name: Poser le plancher dans le gabarit maître de cloud-init (il survit au démarrage)
|
|
|
|
|
ansible.builtin.template:
|
|
|
|
|
src: hosts.debian.tmpl.j2
|
|
|
|
|
dest: /etc/cloud/templates/hosts.debian.tmpl
|
|
|
|
|
owner: root
|
|
|
|
|
group: root
|
|
|
|
|
mode: "0644"
|
|
|
|
|
when:
|
|
|
|
|
- hosts_statiques_actif | bool
|
|
|
|
|
- ansible_facts.os_family | default('') == 'Debian'
|
2026-09-10 13:29:25 -04:00
|
|
|
- hosts_statiques_gabarits_cloud_init.stat.isdir | default(false)
|
site : le plancher survit au redemarrage, et la zone dit les vraies adresses
Le decoupage du site en quatre zones a deplace cinq machines. Ni le plancher
/etc/hosts ni la zone DNS n'avaient suivi. Quatre defauts, tous dans le moteur.
LE PLANCHER ETAIT EFFACE A CHAQUE DEMARRAGE — ET LE PREMIER CORRECTIF N'EN
ETAIT PAS UN.
`hosts_statiques` posait `99-setops-hosts.cfg` avec `manage_etc_hosts: false`,
pendant que `cloud_init` posait `99_setops.cfg` avec `true`. Dans `cloud.cfg.d`
l'ordre est LEXICAL et le dernier gagne : `-` vaut 0x2D, `_` vaut 0x5F. On a
donc retire la cle de `cloud_init` — le role qui POSSEDE le fichier decide —
puis renomme notre fragment `zz-` pour passer apres le `99_chezlepro.cfg` du
gabarit dore.
Et ca ne suffisait toujours pas. Redemarrage d'epreuve : plancher encore efface.
La cause reelle est ailleurs — Proxmox inscrit `manage_etc_hosts: true` dans la
USER-DATA de son lecteur cloud-init, et la user-data prime sur `cloud.cfg.d`
tout entier. Aucun fragment ne pouvait gagner ; renommer pour parler en dernier
ne servait a rien, le dernier mot n'appartenant pas a ce repertoire.
Ce que cloud-init regenere, il le regenere depuis `hosts.debian.tmpl` — le
gabarit le documente lui-meme. `hosts_statiques` le pose desormais avec le MEME
contenu que /etc/hosts, et une garde compare les deux a chaque passage.
Redemarrage d'epreuve : les neuf entrees sont la.
La garde precedente affirmait « conforme » en mesurant l'ordre lexical — vrai,
et sans rapport avec ce qui se passait. Une garde qui mesure la mauvaise chose
est pire qu'aucune.
LA ZONE DNS NE PUBLIAIT PAS LES NOMS DE SERVICE.
`forge.genese.internal` et `pki.genese.internal` — des noms que les certificats
portent et que les clients appellent — n'avaient aucun enregistrement. Seul le
plancher savait les resoudre. Trois causes empilees :
- le plan du site coupait `serveur_powerdns_publier_expositions`, au motif que
« le site n'a pas d'edge » : ca confondait PUBLIC et EXPOSE ;
- `expositions_des_applications` rendait `domaine: None` faute de
`domaines.yml`, et le modele de zone ecarte les expositions dont le domaine
n'est pas la zone. Repli ajoute, symetrique de celui deja ecrit pour `edge` :
sans domaine public declare, le domaine est celui que porte le FQDN ;
- `serveur_powerdns` exigeait les deux registres et echouait si `domaines.yml`
manquait — le meme tout-ou-rien que `hosts_statiques` a corrige le meme jour.
Puis `named-checkzone` a refuse la zone : `dns.genese.internal` heritait d'un
CNAME par defaut du role ET d'un A par exposition. La garde a bien joue son role
— elle a arrete une zone cassee avant qu'elle soit servie. Le plan l'emporte
desormais sur le defaut du role.
Un service ne doit pas dependre d'un plancher pour etre joignable : le plancher
est un filet, pas le sol.
VERIFICATION. Les huit noms — cinq machines, trois services — resolvent vers les
bonnes adresses depuis les cinq hotes, par le plancher ET par le DNS, et le
plancher survit au redemarrage.
P46 refuse desormais deux choses : plus d'un role ecrivant `manage_etc_hosts`,
et l'absence du gabarit maitre. Controle negatif verifie.
RESTE NOMME, PAS CORRIGE : la zone INVERSE. `serveur_powerdns_zone_inverse`
derive d'un supernet /16 — la forme d'un tenant. Un site declare plusieurs /24
et n'a pas de supernet unique : aucune zone inverse n'est generee.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 20:31:01 -04:00
|
|
|
|
|
|
|
|
# LA GARDE MESURE LE FAIT QUI COMPTE (2026-08-25).
|
|
|
|
|
#
|
|
|
|
|
# La garde precedente verifiait que notre fragment `cloud.cfg.d` parlait en dernier. C'est
|
|
|
|
|
# vrai — et sans effet, puisque la user-data de la source de donnees prime sur ce
|
|
|
|
|
# repertoire tout entier. Une garde qui mesure la mauvaise chose est pire qu'aucune : elle
|
|
|
|
|
# affirme « conforme » pendant que le defaut opere.
|
|
|
|
|
#
|
|
|
|
|
# Ce qui compte est que le fichier ET le gabarit qui le reecrira portent les MEMES
|
|
|
|
|
# entrees. On les compare donc, ligne d'adresse par ligne d'adresse.
|
|
|
|
|
- name: Relever les entrées du plancher et celles du gabarit maître
|
|
|
|
|
ansible.builtin.shell:
|
|
|
|
|
cmd: >-
|
|
|
|
|
set -o pipefail;
|
|
|
|
|
for f in /etc/hosts /etc/cloud/templates/hosts.debian.tmpl; do
|
|
|
|
|
printf '%s=' "$f";
|
|
|
|
|
grep -cE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+[[:space:]]' "$f" 2>/dev/null || printf '0';
|
|
|
|
|
printf '\n';
|
|
|
|
|
done
|
|
|
|
|
executable: /bin/bash
|
|
|
|
|
register: hosts_statiques_accord
|
|
|
|
|
changed_when: false
|
2026-09-14 11:02:37 -04:00
|
|
|
# LIRE N'EST PAS CHANGER, ET `--check` NE DOIT PAS RENDRE LA GARDE FOLLE (2026-09-14).
|
|
|
|
|
#
|
|
|
|
|
# Sans `check_mode: false`, cette commande est SAUTEE en mode idempotent. La garde qui
|
|
|
|
|
# suit compare alors du VIDE et refuse, sur les sept machines a la fois :
|
|
|
|
|
#
|
|
|
|
|
# ne portent pas le meme nombre d'entrees ()
|
|
|
|
|
#
|
|
|
|
|
# Les parentheses vides sont tout le diagnostic — il n'y avait aucun compte a comparer.
|
|
|
|
|
# Le Makefile CONSEILLE pourtant ce mode (« tester d abord en idempotent »), donc un
|
|
|
|
|
# essai a blanc rendait sept faux echecs a qui suivait le conseil.
|
|
|
|
|
#
|
|
|
|
|
# Cette tache ne fait que LIRE deux fichiers et compter des lignes. La faire tourner en
|
|
|
|
|
# `--check` ne modifie rien et rend au mode idempotent ce qu'il promet : dire ce qui
|
|
|
|
|
# changerait, pas inventer des pannes.
|
|
|
|
|
check_mode: false
|
site : le plancher survit au redemarrage, et la zone dit les vraies adresses
Le decoupage du site en quatre zones a deplace cinq machines. Ni le plancher
/etc/hosts ni la zone DNS n'avaient suivi. Quatre defauts, tous dans le moteur.
LE PLANCHER ETAIT EFFACE A CHAQUE DEMARRAGE — ET LE PREMIER CORRECTIF N'EN
ETAIT PAS UN.
`hosts_statiques` posait `99-setops-hosts.cfg` avec `manage_etc_hosts: false`,
pendant que `cloud_init` posait `99_setops.cfg` avec `true`. Dans `cloud.cfg.d`
l'ordre est LEXICAL et le dernier gagne : `-` vaut 0x2D, `_` vaut 0x5F. On a
donc retire la cle de `cloud_init` — le role qui POSSEDE le fichier decide —
puis renomme notre fragment `zz-` pour passer apres le `99_chezlepro.cfg` du
gabarit dore.
Et ca ne suffisait toujours pas. Redemarrage d'epreuve : plancher encore efface.
La cause reelle est ailleurs — Proxmox inscrit `manage_etc_hosts: true` dans la
USER-DATA de son lecteur cloud-init, et la user-data prime sur `cloud.cfg.d`
tout entier. Aucun fragment ne pouvait gagner ; renommer pour parler en dernier
ne servait a rien, le dernier mot n'appartenant pas a ce repertoire.
Ce que cloud-init regenere, il le regenere depuis `hosts.debian.tmpl` — le
gabarit le documente lui-meme. `hosts_statiques` le pose desormais avec le MEME
contenu que /etc/hosts, et une garde compare les deux a chaque passage.
Redemarrage d'epreuve : les neuf entrees sont la.
La garde precedente affirmait « conforme » en mesurant l'ordre lexical — vrai,
et sans rapport avec ce qui se passait. Une garde qui mesure la mauvaise chose
est pire qu'aucune.
LA ZONE DNS NE PUBLIAIT PAS LES NOMS DE SERVICE.
`forge.genese.internal` et `pki.genese.internal` — des noms que les certificats
portent et que les clients appellent — n'avaient aucun enregistrement. Seul le
plancher savait les resoudre. Trois causes empilees :
- le plan du site coupait `serveur_powerdns_publier_expositions`, au motif que
« le site n'a pas d'edge » : ca confondait PUBLIC et EXPOSE ;
- `expositions_des_applications` rendait `domaine: None` faute de
`domaines.yml`, et le modele de zone ecarte les expositions dont le domaine
n'est pas la zone. Repli ajoute, symetrique de celui deja ecrit pour `edge` :
sans domaine public declare, le domaine est celui que porte le FQDN ;
- `serveur_powerdns` exigeait les deux registres et echouait si `domaines.yml`
manquait — le meme tout-ou-rien que `hosts_statiques` a corrige le meme jour.
Puis `named-checkzone` a refuse la zone : `dns.genese.internal` heritait d'un
CNAME par defaut du role ET d'un A par exposition. La garde a bien joue son role
— elle a arrete une zone cassee avant qu'elle soit servie. Le plan l'emporte
desormais sur le defaut du role.
Un service ne doit pas dependre d'un plancher pour etre joignable : le plancher
est un filet, pas le sol.
VERIFICATION. Les huit noms — cinq machines, trois services — resolvent vers les
bonnes adresses depuis les cinq hotes, par le plancher ET par le DNS, et le
plancher survit au redemarrage.
P46 refuse desormais deux choses : plus d'un role ecrivant `manage_etc_hosts`,
et l'absence du gabarit maitre. Controle negatif verifie.
RESTE NOMME, PAS CORRIGE : la zone INVERSE. `serveur_powerdns_zone_inverse`
derive d'un supernet /16 — la forme d'un tenant. Un site declare plusieurs /24
et n'a pas de supernet unique : aucune zone inverse n'est generee.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 20:31:01 -04:00
|
|
|
when:
|
|
|
|
|
- hosts_statiques_actif | bool
|
|
|
|
|
- ansible_facts.os_family | default('') == 'Debian'
|
2026-09-10 13:29:25 -04:00
|
|
|
# Rien a relever quand le gabarit maitre n'existe plus (cloud-init retire, D-85).
|
|
|
|
|
- hosts_statiques_gabarits_cloud_init.stat.isdir | default(false)
|
site : le plancher survit au redemarrage, et la zone dit les vraies adresses
Le decoupage du site en quatre zones a deplace cinq machines. Ni le plancher
/etc/hosts ni la zone DNS n'avaient suivi. Quatre defauts, tous dans le moteur.
LE PLANCHER ETAIT EFFACE A CHAQUE DEMARRAGE — ET LE PREMIER CORRECTIF N'EN
ETAIT PAS UN.
`hosts_statiques` posait `99-setops-hosts.cfg` avec `manage_etc_hosts: false`,
pendant que `cloud_init` posait `99_setops.cfg` avec `true`. Dans `cloud.cfg.d`
l'ordre est LEXICAL et le dernier gagne : `-` vaut 0x2D, `_` vaut 0x5F. On a
donc retire la cle de `cloud_init` — le role qui POSSEDE le fichier decide —
puis renomme notre fragment `zz-` pour passer apres le `99_chezlepro.cfg` du
gabarit dore.
Et ca ne suffisait toujours pas. Redemarrage d'epreuve : plancher encore efface.
La cause reelle est ailleurs — Proxmox inscrit `manage_etc_hosts: true` dans la
USER-DATA de son lecteur cloud-init, et la user-data prime sur `cloud.cfg.d`
tout entier. Aucun fragment ne pouvait gagner ; renommer pour parler en dernier
ne servait a rien, le dernier mot n'appartenant pas a ce repertoire.
Ce que cloud-init regenere, il le regenere depuis `hosts.debian.tmpl` — le
gabarit le documente lui-meme. `hosts_statiques` le pose desormais avec le MEME
contenu que /etc/hosts, et une garde compare les deux a chaque passage.
Redemarrage d'epreuve : les neuf entrees sont la.
La garde precedente affirmait « conforme » en mesurant l'ordre lexical — vrai,
et sans rapport avec ce qui se passait. Une garde qui mesure la mauvaise chose
est pire qu'aucune.
LA ZONE DNS NE PUBLIAIT PAS LES NOMS DE SERVICE.
`forge.genese.internal` et `pki.genese.internal` — des noms que les certificats
portent et que les clients appellent — n'avaient aucun enregistrement. Seul le
plancher savait les resoudre. Trois causes empilees :
- le plan du site coupait `serveur_powerdns_publier_expositions`, au motif que
« le site n'a pas d'edge » : ca confondait PUBLIC et EXPOSE ;
- `expositions_des_applications` rendait `domaine: None` faute de
`domaines.yml`, et le modele de zone ecarte les expositions dont le domaine
n'est pas la zone. Repli ajoute, symetrique de celui deja ecrit pour `edge` :
sans domaine public declare, le domaine est celui que porte le FQDN ;
- `serveur_powerdns` exigeait les deux registres et echouait si `domaines.yml`
manquait — le meme tout-ou-rien que `hosts_statiques` a corrige le meme jour.
Puis `named-checkzone` a refuse la zone : `dns.genese.internal` heritait d'un
CNAME par defaut du role ET d'un A par exposition. La garde a bien joue son role
— elle a arrete une zone cassee avant qu'elle soit servie. Le plan l'emporte
desormais sur le defaut du role.
Un service ne doit pas dependre d'un plancher pour etre joignable : le plancher
est un filet, pas le sol.
VERIFICATION. Les huit noms — cinq machines, trois services — resolvent vers les
bonnes adresses depuis les cinq hotes, par le plancher ET par le DNS, et le
plancher survit au redemarrage.
P46 refuse desormais deux choses : plus d'un role ecrivant `manage_etc_hosts`,
et l'absence du gabarit maitre. Controle negatif verifie.
RESTE NOMME, PAS CORRIGE : la zone INVERSE. `serveur_powerdns_zone_inverse`
derive d'un supernet /16 — la forme d'un tenant. Un site declare plusieurs /24
et n'a pas de supernet unique : aucune zone inverse n'est generee.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 20:31:01 -04:00
|
|
|
|
|
|
|
|
- name: Refuser que le plancher et son gabarit maître divergent
|
|
|
|
|
ansible.builtin.assert:
|
|
|
|
|
that:
|
|
|
|
|
- (hosts_statiques_accord.stdout_lines | select('search', '^/etc/hosts=')
|
|
|
|
|
| first | default('=0')).split('=')[1] | int > 1
|
|
|
|
|
- (hosts_statiques_accord.stdout_lines | select('search', '^/etc/hosts=')
|
|
|
|
|
| first | default('=0')).split('=')[1]
|
|
|
|
|
== (hosts_statiques_accord.stdout_lines | select('search', 'hosts.debian.tmpl=')
|
|
|
|
|
| first | default('=-1')).split('=')[1]
|
|
|
|
|
fail_msg: >-
|
|
|
|
|
Le plancher et le gabarit maître de cloud-init ne portent pas le même nombre
|
|
|
|
|
d'entrées ({{ hosts_statiques_accord.stdout_lines | default([]) | join(' | ') }}).
|
|
|
|
|
Cloud-init régénère /etc/hosts depuis le gabarit à chaque démarrage : la divergence
|
|
|
|
|
ne se verrait qu'au prochain redémarrage, et se manifesterait ailleurs — un `apt`
|
|
|
|
|
qui ne résout plus, un certificat dont le nom ne pointe nulle part.
|
|
|
|
|
success_msg: >-
|
|
|
|
|
Plancher et gabarit maître d'accord
|
|
|
|
|
({{ hosts_statiques_accord.stdout_lines | default([]) | join(' | ') }}).
|
|
|
|
|
when:
|
|
|
|
|
- hosts_statiques_actif | bool
|
|
|
|
|
- ansible_facts.os_family | default('') == 'Debian'
|
2026-09-10 13:29:25 -04:00
|
|
|
# LA GARDE SUIT SON OBJET. Elle protege le plancher d'une REECRITURE par cloud-init ;
|
|
|
|
|
# sans cloud-init, il n'y a plus de reecriture et plus de gabarit a comparer. La
|
|
|
|
|
# laisser tourner ferait echouer sur « 34 contre 0 » — c'est-a-dire accuser une
|
|
|
|
|
# divergence la ou il n'y a plus qu'un seul fichier. Une garde qui survit a ce qu'elle
|
|
|
|
|
# gardait ne mesure plus rien : elle invente.
|
|
|
|
|
- hosts_statiques_gabarits_cloud_init.stat.isdir | default(false)
|
2026-09-14 11:02:37 -04:00
|
|
|
# NI EN MODE IDEMPOTENT, POUR LA MEME RAISON (2026-09-14). Cette garde compare l'etat
|
|
|
|
|
# que la tache « Poser le plancher dans le gabarit maitre » vient d'etablir vingt
|
|
|
|
|
# lignes plus haut. En `--check`, cette ecriture est SIMULEE : le gabarit sur disque
|
|
|
|
|
# porte encore l'etat d'AVANT, et la garde compare donc l'avant a l'apres.
|
|
|
|
|
#
|
|
|
|
|
# /etc/hosts=13 | /etc/cloud/templates/hosts.debian.tmpl=2
|
|
|
|
|
#
|
|
|
|
|
# Sept machines en echec sur un essai a blanc, alors que le deploiement reel passe.
|
|
|
|
|
# Le Makefile CONSEILLE ce mode — « tester d abord en idempotent » — donc suivre le
|
|
|
|
|
# conseil fabriquait sept fausses pannes.
|
|
|
|
|
#
|
|
|
|
|
# Une assertion qui porte sur une post-condition de son propre play n'a rien a dire
|
|
|
|
|
# tant que ce play n'a rien ecrit.
|
|
|
|
|
- not ansible_check_mode
|