client_unbound : survivre a la perte de connexion sans la masquer

Le deploiement s'interrompait autour du redemarrage d'Unbound (« banner
exchange »), et Ansible abandonnait alors TOUTES les couches suivantes de
l'hote — alors qu'il repondait de nouveau une minute plus tard.

Ma premiere explication etait fausse et je l'ai verifiee avant de coder :
sshd -T dit usedns no, il n'y a pas de resolution inverse. Et la cause reste
INCONNUE — j'avais ecrase le journal du deploiement rate en relancant. Faute
de methode, pas de raisonnement.

Ce que le depot sait de ce symptome est deja dans le Makefile : a travers la
frontiere le TCP s'etablit par proxy SYN, et l'echec se lit « banner exchange »
meme quand l'hote n'est pas la. Le message accuse SSH pour un probleme
d'accessibilite.

Corrige sans pretendre connaitre la cause : ignore_unreachable sur le handler,
puis wait_for_connection qui EXIGE le retour (180 s). Si l'hote ne revient
pas, la tache suivante echoue franchement — on ne masque rien.

Regle pour moi : ne plus ecraser le journal d'un echec avant de l'avoir lu.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Daniel Allaire 2026-08-09 11:55:41 -04:00
parent 9cdfcc5deb
commit 0de5294a20
4 changed files with 53 additions and 0 deletions

View file

@ -1,5 +1,34 @@
# CHANGELOG — Set-OPS # CHANGELOG — Set-OPS
## 2026-08-09 — `client_unbound` : survivre à la perte de connexion, sans la masquer
Le déploiement de `web-dorsal-01` s'était interrompu autour du redémarrage d'Unbound —
« Connection timed out during banner exchange ». Ansible marque alors l'hôte injoignable et
**abandonne toutes ses couches suivantes**, alors que la machine répondait de nouveau une
minute plus tard.
**Ma première explication était fausse, et je l'ai vérifiée avant de coder** : je pensais à
la résolution inverse de `sshd` au moment où le résolveur bascule. `sshd -T` répond
`usedns no` — elle n'a pas lieu. Et **la cause reste inconnue** : j'avais écrasé le journal
du déploiement raté en relançant, donc il n'est plus lisible. Faute de méthode, pas de
raisonnement.
Ce que le dépôt sait déjà de ce symptôme est consigné dans le `Makefile` (`_attendre-hote`) :
à travers la frontière, le TCP s'établit par proxy SYN, et l'échec se lit « banner
exchange » **même quand l'hôte n'est simplement pas là**. Le message accuse SSH pour un
problème d'accessibilité.
**Corrigé sans prétendre connaître la cause** : le handler de redémarrage tolère la perte
(`ignore_unreachable`), et une tâche **exige ensuite le retour** de l'hôte
(`wait_for_connection`, 180 s). On attend une condition, pas une durée.
Ce n'est **pas** masquer une panne : si l'hôte ne revient pas, la tâche suivante échoue
franchement. Ce qui change, c'est qu'une absence d'une minute n'annule plus une heure de
déploiement.
**Et une règle pour moi** : ne plus écraser le journal d'un échec avant de l'avoir lu. Le
diagnostic de cette course a été rendu impossible par un `rm -f` de confort.
## 2026-08-09 — Le plan bascule sur le gabarit recapturé, prouvé par une VM réelle ## 2026-08-09 — Le plan bascule sur le gabarit recapturé, prouvé par une VM réelle
`proxmox_clone_source_nom` / `proxmox_clone_vmid_modele` pointent désormais sur `proxmox_clone_source_nom` / `proxmox_clone_vmid_modele` pointent désormais sur

View file

@ -22,3 +22,7 @@ client_unbound_transitaires: []
client_unbound_apply: false client_unbound_apply: false
client_unbound_confirm: false client_unbound_confirm: false
client_unbound_resolv_conf: "/etc/resolv.conf" client_unbound_resolv_conf: "/etc/resolv.conf"
# Delai maximal pour que l'hote reponde apres le redemarrage d'Unbound. Depasser reste
# un ECHEC : on attend une machine qui revient, pas une panne qu'on tait.
client_unbound_attente_reconnexion: 180

View file

@ -1,6 +1,18 @@
--- ---
# `ignore_unreachable` : le redemarrage a deja fait perdre la connexion en cours de
# deploiement — « Connection timed out during banner exchange », le 2026-08-09 sur
# web-dorsal-01. La CAUSE n'est pas etablie : `usedns no` ecarte la resolution inverse
# de sshd, et le journal du deploiement rate a ete ecrase avant d'etre lu. Ce que le
# depot sait deja de ce symptome (Makefile, `_attendre-hote`) : a travers la frontiere,
# le TCP s'etablit par proxy SYN et l'echec se lit ainsi meme quand l'hote n'est
# simplement pas la.
#
# On ne masque donc pas une panne : une perte ICI n'abandonne plus les couches
# suivantes, et `wait_for_connection` exige que l'hote revienne pour de bon. S'il ne
# revient pas, la tache suivante echoue — franchement.
- name: Redémarrer unbound - name: Redémarrer unbound
ansible.builtin.systemd: ansible.builtin.systemd:
name: "{{ client_unbound_service }}" name: "{{ client_unbound_service }}"
state: restarted state: restarted
when: not ansible_check_mode when: not ansible_check_mode
ignore_unreachable: true

View file

@ -36,6 +36,14 @@
- name: Appliquer les redémarrages Unbound avant toute validation/bascule - name: Appliquer les redémarrages Unbound avant toute validation/bascule
ansible.builtin.meta: flush_handlers ansible.builtin.meta: flush_handlers
# Attendre une CONDITION — que l'hote reponde — et non une duree. Si la connexion a
# saute pendant le redemarrage, on la retablit ici ; sinon la tache passe aussitot.
- name: Exiger que l hote reponde avant de poursuivre
ansible.builtin.wait_for_connection:
timeout: "{{ client_unbound_attente_reconnexion }}"
sleep: 5
when: not ansible_check_mode
# --- Bascule du resolver : PROTÉGÉE + validée (ne casse jamais un nœud) --- # --- Bascule du resolver : PROTÉGÉE + validée (ne casse jamais un nœud) ---
- name: Refuser la bascule du resolver sans confirmation explicite - name: Refuser la bascule du resolver sans confirmation explicite
ansible.builtin.assert: ansible.builtin.assert: