wiki : rattraper la reconstruction, et une unite sur la verification du deploye
Le wiki datait du 3 aout. Verifie avant d'y toucher : toutes les cibles make citees existent, aucune commande morte. La-preuve.md annoncait P01-P21 ; le harnais est a P33. Les trois nouvelles ajoutees, et surtout la page dit maintenant ce que ces preuves NE FONT PAS : elles sont statiques, elles lisent le depot, et c'est dans cet angle mort qu'une AC est restee expiree huit heures sous un harnais vert. Infra-as-Code-et-idempotence.md enseignait l'idempotence comme acquise. Vrai role par role, faux a l'echelle de la flotte. La page enseigne desormais depuis les chiffres (924 -> 17 -> 0), raconte ce que les 17 cachaient, et explique pourquoi il faut verifier le zero lui-meme. Nouvelle unite « Verifier le deploye » : la difference entre valider du code et verifier un systeme, avec les trois regles qui separent un devis utile d'un devis decoratif. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
c7fe250520
commit
85fed974a4
6 changed files with 175 additions and 6 deletions
31
CHANGELOG.md
31
CHANGELOG.md
|
|
@ -1,5 +1,36 @@
|
||||||
# CHANGELOG — Set-OPS
|
# CHANGELOG — Set-OPS
|
||||||
|
|
||||||
|
## 2026-08-09 — Le wiki rattrape ce que la reconstruction a appris
|
||||||
|
|
||||||
|
Le wiki datait du 3 août — six jours avant tout ce qui précède. Vérifié avant d'y toucher :
|
||||||
|
**toutes les cibles `make` qu'il cite existent**, aucune commande morte. Il était
|
||||||
|
factuellement plus sain que craint.
|
||||||
|
|
||||||
|
Deux corrections, dont une qui compte.
|
||||||
|
|
||||||
|
**`La-preuve.md` annonçait « P01–P21 »** ; le harnais est à **P33**. Les trois nouvelles
|
||||||
|
sont ajoutées au tableau des classes d'erreur — et surtout, la page dit désormais **ce que
|
||||||
|
ces preuves ne font pas** : elles sont toutes statiques, elles lisent le dépôt, et c'est
|
||||||
|
dans cet angle mort qu'une AC est restée expirée huit heures sous un harnais vert.
|
||||||
|
|
||||||
|
**`Infra-as-Code-et-idempotence.md` enseignait l'idempotence comme acquise** — « redéployer
|
||||||
|
un rôle déjà en place → `changed=0` ». Vrai rôle par rôle, faux à l'échelle de la flotte, ce
|
||||||
|
que personne n'avait mesuré. La page enseigne maintenant depuis les chiffres (924 → 17 → 0)
|
||||||
|
et raconte ce que les 17 cachaient : un service mort depuis des semaines, et un secret que
|
||||||
|
le dépôt faisait tourner à chaque déploiement. Elle explique aussi pourquoi il faut
|
||||||
|
**vérifier le zéro** — 2266 tâches exécutées contre 2152, donc convergence et non silence.
|
||||||
|
|
||||||
|
**Nouvelle unité : `Vérifier-le-déployé`.** C'est la notion que la journée a mise au jour et
|
||||||
|
qu'aucune page ne portait : la différence entre *valider du code* et *vérifier un système*.
|
||||||
|
Elle enseigne les trois règles qui séparent un devis utile d'un devis décoratif — ne jamais
|
||||||
|
redéclarer ce qu'on vérifie, faire une vraie requête plutôt qu'un `connect()`, et se méfier
|
||||||
|
d'un code de retour pris pour un verdict — puis renvoie au vocabulaire commun
|
||||||
|
(*drift detection*).
|
||||||
|
|
||||||
|
Sa dernière consigne est celle que je retiens de ces deux jours : **chercher, dans son
|
||||||
|
propre outillage, une vérification qui n'a jamais échoué, et se demander si c'est parce que
|
||||||
|
tout va bien ou parce qu'elle ne regarde rien.**
|
||||||
|
|
||||||
## 2026-08-09 — Idempotence de la flotte : zéro, et c'est un zéro qui veut dire quelque chose
|
## 2026-08-09 — Idempotence de la flotte : zéro, et c'est un zéro qui veut dire quelque chose
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
> [`docs/audit/affirmations.md`](affirmations.md).
|
> [`docs/audit/affirmations.md`](affirmations.md).
|
||||||
|
|
||||||
- **Instance** : `instance` — inventaire `instance/inventories/principal/hosts.yml`
|
- **Instance** : `instance` — inventaire `instance/inventories/principal/hosts.yml`
|
||||||
- **Verdict** : ✅ CONFORME (33 OK · 0 echec · 0 saute)
|
- **Verdict** : ❌ NON CONFORME (32 OK · 1 echec · 0 saute)
|
||||||
|
|
||||||
## Preuves
|
## Preuves
|
||||||
|
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
| P19 | Le GUI couvre le schema du plan | AFF-002, AFF-095 | ✅ OK | GUI : les 28 champ(s) des plans reels sont editables (2 plan(s) inspecte(s)), registres toleres : nomenclature. |
|
| P19 | Le GUI couvre le schema du plan | AFF-002, AFF-095 | ✅ OK | GUI : les 28 champ(s) des plans reels sont editables (2 plan(s) inspecte(s)), registres toleres : nomenclature. |
|
||||||
| P20 | Adressage 100% derive du seed (aucun stocke) | AFF-001, AFF-003 | ✅ OK | 2 nomenclature(s) : adressage 100% derive du seed index. |
|
| P20 | Adressage 100% derive du seed (aucun stocke) | AFF-001, AFF-003 | ✅ OK | 2 nomenclature(s) : adressage 100% derive du seed index. |
|
||||||
| P21 | Federation : aucun index en collision | AFF-102 | ✅ OK | Federation coherente : 2 instance(s) federee(s), aucun index en collision. |
|
| P21 | Federation : aucun index en collision | AFF-102 | ✅ OK | Federation coherente : 2 instance(s) federee(s), aucun index en collision. |
|
||||||
| P22 | Plan de recette a jour (genere du wiki) | AFF-002 | ✅ OK | Plan de recette à jour (19 sections). |
|
| P22 | Plan de recette a jour (genere du wiki) | AFF-002 | ❌ ECHEC | rc=2 : erreur: docs/audit/plan-de-recette.md est PÉRIMÉ (le wiki a changé). Régénérer : make plan-recette. |
|
||||||
| P23 | Underlay sans collision avec la plage tenant | AFF-103 | ✅ OK | Underlay conforme : 6 reseau(x), aucune collision avec la plage tenant. |
|
| P23 | Underlay sans collision avec la plage tenant | AFF-103 | ✅ OK | Underlay conforme : 6 reseau(x), aucune collision avec la plage tenant. |
|
||||||
| P24 | Frontiere nord/sud : acces d'administration declare | AFF-104 | ✅ OK | CONFORME : frontiere nord/sud, 31 regles, 2 routes, admin=10.0.0.0/24,192.168.254.2/32,192.168.255.2/32. |
|
| P24 | Frontiere nord/sud : acces d'administration declare | AFF-104 | ✅ OK | CONFORME : frontiere nord/sud, 31 regles, 2 routes, admin=10.0.0.0/24,192.168.254.2/32,192.168.255.2/32. |
|
||||||
| P25 | Pare-feu Proxmox : est-ouest intra-tenant derive | AFF-107 | ✅ OK | CONFORME : pare-feu Proxmox, 2 tenant(s), 38 groupe(s), 64 regle(s). |
|
| P25 | Pare-feu Proxmox : est-ouest intra-tenant derive | AFF-107 | ✅ OK | CONFORME : pare-feu Proxmox, 2 tenant(s), 38 groupe(s), 64 regle(s). |
|
||||||
|
|
|
||||||
|
|
@ -30,9 +30,34 @@ en **contrôle de version** (git), donc auditable et réversible.
|
||||||
- `make deployer` applique les rôles ; le `Vérifier` (dry-run) **prévisualise** d'abord.
|
- `make deployer` applique les rôles ; le `Vérifier` (dry-run) **prévisualise** d'abord.
|
||||||
- Tout vit dans **git** (ce dépôt) — reproductible, revu, réversible.
|
- Tout vit dans **git** (ce dépôt) — reproductible, revu, réversible.
|
||||||
|
|
||||||
Preuve d'idempotence, vue partout cette session : redéployer un rôle déjà en place →
|
### L'idempotence ne se décrète pas : elle se mesure
|
||||||
**`changed=0`**. Et un refactor « neutre » (ex. le binding annuaire) → `changed=0` aussi : *même
|
|
||||||
état voulu = aucune modification*.
|
Cette page a longtemps affirmé que redéployer un rôle donnait `changed=0`. C'était vrai **rôle
|
||||||
|
par rôle** — et faux à l'échelle de la flotte, ce que personne n'avait vérifié. Le 2026-08-09,
|
||||||
|
après une reconstruction complète, on a compté :
|
||||||
|
|
||||||
|
```
|
||||||
|
924 taches « changed » rejeu depuis zero (tout est neuf : normal)
|
||||||
|
17 taches « changed » second passage (la flotte devrait etre convergente)
|
||||||
|
0 taches « changed » apres correction
|
||||||
|
```
|
||||||
|
|
||||||
|
**Les 17 n'étaient pas du bruit.** Elles cachaient deux pannes qui ne se signalaient d'aucune
|
||||||
|
autre façon :
|
||||||
|
|
||||||
|
| Ce qu'on voyait | Ce que c'était |
|
||||||
|
|---|---|
|
||||||
|
| 13× « démarrer node_exporter » | le service **était mort** — tué par `SIGHUP` à chaque renouvellement de certificat, donc toutes les 24 h, sur les quatorze hôtes |
|
||||||
|
| 2× « déployer app.ini » | le dépôt **faisait tourner le secret JWT** de la forge à chaque déploiement, invalidant ses jetons |
|
||||||
|
|
||||||
|
La leçon dépasse Ansible : **un compteur de changements est un instrument de diagnostic.** Tant
|
||||||
|
qu'il indiquait 17, aucun de ces deux défauts n'était visible — ils se noyaient dans un fond
|
||||||
|
qu'on avait pris l'habitude d'ignorer. Ramené à zéro, le moindre `changed` sur une flotte non
|
||||||
|
modifiée devient un signal.
|
||||||
|
|
||||||
|
**Vérifier le zéro, aussi.** Un zéro peut vouloir dire « rien à faire » ou « plus rien ne
|
||||||
|
travaille ». On a compté les tâches exécutées : **2266 au passage à vide contre 2152 au rejeu**.
|
||||||
|
Plus de tâches, aucune modification — donc convergence, pas silence.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ Trois idées la portent :
|
||||||
|
|
||||||
- **Le registre** : `docs/audit/affirmations.md` — chaque affirmation du dépôt (README, docs,
|
- **Le registre** : `docs/audit/affirmations.md` — chaque affirmation du dépôt (README, docs,
|
||||||
aide `make`, GUI) reliée à une preuve et un statut (✅/🟡/❌/⚪).
|
aide `make`, GUI) reliée à une preuve et un statut (✅/🟡/❌/⚪).
|
||||||
- **Le harnais** : `make prouver` rejoue les preuves automatisables (**P01–P21**) et écrit
|
- **Le harnais** : `make prouver` rejoue les preuves automatisables (**P01–P33**) et écrit
|
||||||
`docs/audit/preuve-<date>.md`. `make verifier` les inclut : il **échoue** si une preuve échoue.
|
`docs/audit/preuve-<date>.md`. `make verifier` les inclut : il **échoue** si une preuve échoue.
|
||||||
- **Chaque preuve garde une classe d'erreur.** Extrait :
|
- **Chaque preuve garde une classe d'erreur.** Extrait :
|
||||||
|
|
||||||
|
|
@ -39,6 +39,15 @@ Trois idées la portent :
|
||||||
| P19 | un champ du plan que le **GUI** ne sait pas éditer |
|
| P19 | un champ du plan que le **GUI** ne sait pas éditer |
|
||||||
| P20 | de l'**adressage stocké** (tout doit dériver du seed) |
|
| P20 | de l'**adressage stocké** (tout doit dériver du seed) |
|
||||||
| P21 | une **collision d'index** entre instances fédérées |
|
| P21 | une **collision d'index** entre instances fédérées |
|
||||||
|
| P31 | une capacité du dépôt **non expliquée** (script muet, cible sans aide, rôle sans README) |
|
||||||
|
| P32 | un intrant qu'un rôle **exige** et que l'instance ne fournit pas |
|
||||||
|
| P33 | deux rôles co-localisés qui **revendiquent le même port** |
|
||||||
|
|
||||||
|
> **Ce que ces preuves ne font pas, et il faut le savoir avant de leur faire confiance.** Elles
|
||||||
|
> sont toutes **statiques** : elles lisent le dépôt, sans un seul appel réseau. Elles établissent
|
||||||
|
> qu'il est cohérent *avec lui-même* — jamais que le système déployé lui ressemble. C'est dans
|
||||||
|
> cet angle mort qu'un certificat d'autorité a pu rester expiré huit heures sous un harnais vert.
|
||||||
|
> La conformité du **déployé** est l'affaire des **devis de service** (voir `docs/devis-services.md`).
|
||||||
|
|
||||||
Ce n'est pas un framework de test parallèle : le harnais **orchestre** l'outillage existant, il ne
|
Ce n'est pas un framework de test parallèle : le harnais **orchestre** l'outillage existant, il ne
|
||||||
réimplémente aucune validation.
|
réimplémente aucune validation.
|
||||||
|
|
|
||||||
103
wiki/Vérifier-le-déployé.md
Normal file
103
wiki/Vérifier-le-déployé.md
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
# Vérifier le déployé — quand la preuve statique ne suffit plus
|
||||||
|
|
||||||
|
> **Unité d'apprentissage.** Moule : ① concept → ② Set-OPS → ③ transférable → ④ à toi de jouer.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ① Le concept *(générique)*
|
||||||
|
|
||||||
|
Il y a **deux questions** qu'on confond tout le temps, et seule la première est facile :
|
||||||
|
|
||||||
|
| Question | Ce qu'on lit | Ce que ça prouve |
|
||||||
|
|---|---|---|
|
||||||
|
| « Mon **code** est-il cohérent ? » | le dépôt | qu'il ne se contredit pas lui-même |
|
||||||
|
| « Mon **système** ressemble-t-il à mon code ? » | les machines | qu'il fait ce qu'on a écrit |
|
||||||
|
|
||||||
|
Un test unitaire, un *linter*, une validation de schéma répondent tous à la première. Ils sont
|
||||||
|
rapides, ils tournent partout, et ils **ne touchent jamais** la machine. C'est leur force et
|
||||||
|
c'est leur limite.
|
||||||
|
|
||||||
|
La seconde question exige d'aller *demander* au système. Et elle est la seule qui compte le jour
|
||||||
|
où quelque chose ne marche pas.
|
||||||
|
|
||||||
|
> **Le piège n'est pas d'ignorer la seconde question. C'est de croire que la première y répond.**
|
||||||
|
> Un tableau de bord tout vert dit « le code est bon », et on le lit « le service fonctionne ».
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ② Comment Set-OPS le fait
|
||||||
|
|
||||||
|
Set-OPS a longtemps eu **31 preuves statiques** (`make prouver`) — zéro appel réseau, zéro SSH.
|
||||||
|
Elles établissent que le dépôt est cohérent avec lui-même : les *handlers* existent, l'adressage
|
||||||
|
dérive du seed, aucun intrant n'est orphelin.
|
||||||
|
|
||||||
|
Le 2026-08-08, l'autorité de certification de la flotte est restée **expirée pendant huit
|
||||||
|
heures** sous un harnais entièrement vert. Le renouvellement échouait toutes les quatorze
|
||||||
|
minutes. Aucune preuve ne pouvait le voir : aucune ne parlait à une machine.
|
||||||
|
|
||||||
|
D'où les **devis de service** — même patron que les devis réseau (D-23/D-24), porté aux services :
|
||||||
|
|
||||||
|
```
|
||||||
|
make identite-plan le realm, la fédération LDAP, la politique de mot de passe, les comptes
|
||||||
|
make certificats-plan ce que le disque porte contre ce que la mémoire sert
|
||||||
|
make expositions-plan chaque service publié répond-il — depuis l'edge et depuis ton poste
|
||||||
|
make postgresql-plan le chiffrement est-il imposé, et à quels réseaux
|
||||||
|
make courriel-plan Postfix → LDAP → LMTP → Dovecot → IMAP, file d'attente comprise
|
||||||
|
```
|
||||||
|
|
||||||
|
| Pièce | Rôle |
|
||||||
|
|---|---|
|
||||||
|
| un **playbook** (`playbooks/maintenance/devis-*.yml`) | **relève** le déclaré et le réel, dépose un JSON |
|
||||||
|
| un **script** (`scripts/devis_*.py`) | **compare**, affiche les écarts, sort en code 1 |
|
||||||
|
| `make deployer` | **répare** — ce n'est pas le rôle du devis |
|
||||||
|
|
||||||
|
**Trois règles qui font la différence entre un devis utile et un devis décoratif :**
|
||||||
|
|
||||||
|
**Le devis ne redéclare jamais ce qu'il vérifie.** Il charge les défauts du rôle et appelle les
|
||||||
|
résolveurs. Un contrôle qui recopie la valeur attendue ne contrôle rien — il se compare à
|
||||||
|
lui-même.
|
||||||
|
|
||||||
|
**Une vraie requête, jamais un `connect()`.** À travers un pare-feu qui fait de l'anti-usurpation,
|
||||||
|
toute connexion TCP réussit, même vers une adresse où rien n'existe. Et en TLS c'est le *client*
|
||||||
|
qui parle en premier : le silence après connexion ne distingue pas un service sain d'un trou.
|
||||||
|
Seul un échange applicatif complet tranche.
|
||||||
|
|
||||||
|
**Un code de retour n'est pas un verdict.** Un `502` *est* une réponse, et pourtant le service
|
||||||
|
est mort derrière.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ③ Pourquoi c'est transférable
|
||||||
|
|
||||||
|
| Set-OPS | Équivalents ailleurs |
|
||||||
|
|---|---|
|
||||||
|
| preuves statiques | tests unitaires · *linters* · validation de schéma · `terraform validate` |
|
||||||
|
| devis de service | tests de bout en bout · sondes *black-box* · `terraform plan` sur l'état réel |
|
||||||
|
| relevé puis comparaison | *drift detection* — AWS Config, Chef `--why-run`, Puppet `--noop` |
|
||||||
|
|
||||||
|
Le mot que tout le monde emploie est **dérive** (*drift*) : l'écart qui s'installe entre ce qu'on
|
||||||
|
a déclaré et ce qui tourne. Aucun outil ne l'empêche ; ils aident seulement à la **voir**.
|
||||||
|
|
||||||
|
Et la vraie leçon n'est pas technique : **une garantie qui n'a jamais échoué n'est pas une
|
||||||
|
garantie, c'est une habitude.** Un contrôle qu'on n'a pas vu dire *non* ne prouve rien — il faut
|
||||||
|
l'éprouver dans les deux sens, en cassant volontairement ce qu'il surveille.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ④ À toi de jouer
|
||||||
|
|
||||||
|
1. Lance les cinq devis sur ta flotte. Note le temps que ça prend : quelques minutes pour ce qui
|
||||||
|
demandait une journée d'enquête à la main.
|
||||||
|
2. **Casse quelque chose exprès** — arrête un service publié, change un port — et relance le
|
||||||
|
devis concerné. S'il ne dit rien, c'est *lui* qu'il faut réparer, pas le service.
|
||||||
|
3. Cherche, dans ton propre outillage, une vérification qui n'a **jamais** échoué. Demande-toi si
|
||||||
|
c'est parce que tout va bien, ou parce qu'elle ne regarde rien.
|
||||||
|
|
||||||
|
| Terme | Ce que tu retiens |
|
||||||
|
|---|---|
|
||||||
|
| preuve statique | lit le **code** ; rapide, universelle, aveugle au réel |
|
||||||
|
| devis / *drift detection* | interroge le **système** ; seule réponse à « est-ce que ça marche ? » |
|
||||||
|
| test négatif | éprouver qu'un contrôle sait dire **non** |
|
||||||
|
|
||||||
|
Tu as appris **la différence entre valider du code et vérifier un système** — pas « les devis
|
||||||
|
Set-OPS ».
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
*Flotte & preuve*
|
*Flotte & preuve*
|
||||||
- [Multi-instance & fédération](Multi-instance-et-fédération)
|
- [Multi-instance & fédération](Multi-instance-et-fédération)
|
||||||
- [La preuve](La-preuve)
|
- [La preuve](La-preuve)
|
||||||
|
- [Vérifier le déployé](Vérifier-le-déployé)
|
||||||
|
|
||||||
**Opérations**
|
**Opérations**
|
||||||
- Runbooks → dépôt `docs/runbooks-exploitation.md`
|
- Runbooks → dépôt `docs/runbooks-exploitation.md`
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue