diff --git a/CHANGELOG.md b/CHANGELOG.md index aefffde..ea65af2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,43 @@ # CHANGELOG — Set-OPS +## 2026-09-14 (6) — Le site avait l'orchestration, pas le moyen de la lancer + +`playbooks/site.yml` est genere par `orchestrer.py` et ordonne les couches pour +**n'importe quelle** instance — son en-tete le dit. Mais `deployer-tout` ne vise que +l'inventaire d'un LOCATAIRE, et le site n'avait que `site-appliquer GROUPE=`. + +Le site ne se deployait donc que **groupe par groupe, a la main**, dans un ordre qu'il +fallait se rappeler. Un hebergeur qu'on ne peut remonter qu'en enchainant onze groupes de +memoire n'est pas reconstructible : il est reparable par quelqu'un qui se souvient. C'est +nommement l'une des trois limites du jalon de reconstruction autonome — *« le SITE jamais +reconstruit »*. + +`site-deployer-tout` comble le manque. Trois differences avec son equivalent locataire, +aucune cosmetique : l'inventaire est un **script** (un site se derive de son underlay, il +ne se fige pas dans un `hosts.yml`), la voute vit **a cote de la carte** +(`underlay.vault.yml`, hors depot), et le perimetre reste `hotes_actifs` — les +hyperviseurs et la frontiere sont dans l'inventaire mais ne se deploient pas. + +### Quatre gardes que `--check` rendait folles + +Le Makefile CONSEILLE l'essai a blanc — *« tester d'abord en idempotent »*. Suivre ce +conseil rendait **sept machines en echec** sur un site parfaitement sain. Quatre causes, +une seule famille : **une garde qui compare contre ce qu'une tache du meme play vient de +produire n'a rien a dire tant que rien n'a ete ecrit.** + +| role | ce que `--check` cassait | remede | +|---|---|---| +| `hosts_statiques` | la lecture des deux fichiers etait sautee : `ne portent pas le meme nombre d'entrees ()` | `check_mode: false` sur la lecture | +| `hosts_statiques` | l'assertion comparait l'AVANT a l'APRES : `/etc/hosts=13 \| tmpl=2` | `not ansible_check_mode` sur l'assertion | +| `serveur_icinga` | le telechargement simule, l'installation cherchait un fichier absent | `check_mode: false` sur `get_url` | +| `serveur_ops` | la version du controleur non lue : `Le controleur tourne Python ` | `check_mode: false` sur la lecture | + +**Les parentheses vides et l'espace apres « Python » sont tout le diagnostic** : il n'y +avait rien a comparer. Un essai a blanc qui ment est pire qu'aucun — il apprend a ne plus +le lancer. + +Apres correction : **7/7, 0 echec**, de 174 a 309 taches par machine. + ## 2026-09-14 (5) — Le site ne savait pas se configurer lui-meme Parti pour eprouver une sonde, arrive sur un defaut structurel : **le runner du SITE ne diff --git a/Makefile b/Makefile index 73f416d..c6217a8 100644 --- a/Makefile +++ b/Makefile @@ -1054,6 +1054,45 @@ site-appliquer: ## Applique un role aux machines du site — GROUPE=`. + @# + @# CE QUE CA COUTAIT : le site ne se DEPLOYAIT que groupe par groupe, a la main, dans + @# un ordre qu'il fallait se rappeler. Un hebergeur qu'on ne peut remonter qu'en + @# enchainant onze groupes de memoire n'est pas reconstructible — il est reparable par + @# quelqu'un qui se souvient. C'est nommement l'une des trois limites du jalon de + @# reconstruction autonome : « le SITE jamais reconstruit ». + @# + @# TROIS DIFFERENCES AVEC `deployer-tout`, ET AUCUNE N'EST COSMETIQUE : + @# + @# l'inventaire est un SCRIPT (`site_inventaire.py`), pas un fichier : un site se + @# derive de son underlay, il ne se fige pas dans un `hosts.yml`. + @# la voute vit a cote de la carte (`underlay.vault.yml`), hors depot, et non + @# dans `group_vars/all`. Sans le `-e @`, les roles partages echouent + @# sur une assertion qui ne dit pas qu'il manque un FICHIER. + @# le perimetre est `hotes_actifs`, comme chez un locataire — les hyperviseurs et + @# la frontiere sont dans l'inventaire mais ne se deploient pas. + @set -e; \ + if [[ "$(CONFIRMER)" != "true" ]]; then \ + printf '%s\n' 'Refus: deploiement ORCHESTRE de TOUT le site (action impactante).'; \ + printf '%s\n' 'Relancer avec CONFIRMER=true. Astuce: tester d abord en idempotent avec MODE_CHECK=1.'; \ + exit 2; \ + fi; \ + python3 scripts/verifier_genome_a_jour.py || exit 2; \ + python3 scripts/orchestrer.py verifier; \ + python3 scripts/orchestrer.py ecrire; \ + voute="$$(dirname "$$(readlink -f underlay.yml)")/underlay.vault.yml"; \ + supp=(); [[ -f "$$voute" ]] && supp+=( -e "@$$voute" ); \ + mode="$$([[ -n "$(MODE_CHECK)" ]] && printf -- '--check --diff' || true)"; \ + ansible-playbook -i scripts/site_inventaire.py playbooks/site.yml \ + --limit "$(GROUPE_HOTES_ACTIFS)" "$${supp[@]}" $$mode $(ARGS) + # --- LE GENOME REMONTE SUR LA FORGE DU SITE ----------------------------------- # # La forge du genome vit DANS le site, sur un reseau que le poste de l'exploitant ne route diff --git a/docs/audit/preuve-2026-09-14.md b/docs/audit/preuve-2026-09-14.md index 5fe8eb4..9da4129 100644 --- a/docs/audit/preuve-2026-09-14.md +++ b/docs/audit/preuve-2026-09-14.md @@ -43,7 +43,7 @@ | P28 | Pools Proxmox : un par tenant, sans collision | AFF-110 | ✅ OK | CONFORME : 5 pool(s) Proxmox, 44 VM placee(s), aucun nom ni VMID en collision. | | P29 | Authentification : chaque role declare sa position | AFF-111 | ✅ OK | 33 role(s) serveur declares (interne-sans-auth 2, ldap-direct 2, sans-auth-humaine 22, socle-identite 2, web-sso 5) ; 2 lacune(s) nommee(s) : serveur_loki, serv | | P30 | SDN EVPN : zones, VNets et sous-reseaux derives | AFF-112 | ✅ OK | CONFORME : SDN EVPN, 3 zone(s), 15 VNet(s), 15 sous-reseau(x), aucune collision. | -| P31 | Documentation : tout ce que le depot FAIT est nomme | — | ✅ OK | 65 scripts expliques et atteignables, 121 cibles make documentees, 68 roles avec README. | +| P31 | Documentation : tout ce que le depot FAIT est nomme | — | ✅ OK | 65 scripts expliques et atteignables, 122 cibles make documentees, 68 roles avec README. | | P32 | Intrants exiges par les roles : tous fournis | — | ✅ OK | CONFORME : 38 exigence(s) de role, toutes satisfaites (149 cle(s) declaree(s) par l'instance). | | P33 | Aucune collision de port entre roles co-localises | — | ✅ OK | CONFORME : 34 revendication(s) de port, aucune collision entre roles co-localises (36 groupes). | | P34 | Chaque document declare son lecteur | — | ✅ OK | 45 document(s) declarent leur lecteur (40 genere(s) exempte(s)). | diff --git a/roles/hosts_statiques/tasks/main.yml b/roles/hosts_statiques/tasks/main.yml index 4836287..206438f 100644 --- a/roles/hosts_statiques/tasks/main.yml +++ b/roles/hosts_statiques/tasks/main.yml @@ -196,6 +196,21 @@ executable: /bin/bash register: hosts_statiques_accord changed_when: false + # 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 when: - hosts_statiques_actif | bool - ansible_facts.os_family | default('') == 'Debian' @@ -229,3 +244,17 @@ # 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) + # 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 diff --git a/roles/serveur_icinga/tasks/main.yml b/roles/serveur_icinga/tasks/main.yml index 9fd9453..a07a6bb 100644 --- a/roles/serveur_icinga/tasks/main.yml +++ b/roles/serveur_icinga/tasks/main.yml @@ -37,6 +37,22 @@ url: "{{ serveur_icinga_keyring_url }}" dest: "/tmp/icinga-archive-keyring.deb" mode: "0644" + # RECUPERER N'EST PAS INSTALLER, ET `--check` CASSAIT LA PAIRE (2026-09-14). + # + # Sans `check_mode: false`, ce telechargement est SIMULE en mode idempotent — et la + # tache qui suit cherche alors un fichier qui n'existe pas : + # + # Unable to install package: E:Could not open file + # /tmp/icinga-archive-keyring.deb - open (2: No such file or directory) + # + # Un essai a blanc rendait donc un echec sur la machine de supervision, alors que le + # deploiement reel passe. Le Makefile conseille ce mode : suivre le conseil fabriquait + # une fausse panne, et c'est la troisieme de cette famille dans le meme essai. + # + # Ce que ce `check_mode: false` autorise reellement : deposer un fichier dans `/tmp`. + # Rien du systeme gere n'en depend, et c'est ce qui permet a l'installation d'ETRE + # evaluee — donc au mode idempotent de dire ce qu'il promet. + check_mode: false # LA CLE PASSE PAR LE CACHE, ELLE AUSSI (mesure du 2026-09-10). # # `get_url` ignore la configuration d'apt : le mandataire pose dans diff --git a/roles/serveur_ops/tasks/main.yml b/roles/serveur_ops/tasks/main.yml index fe47c11..8e54ec4 100644 --- a/roles/serveur_ops/tasks/main.yml +++ b/roles/serveur_ops/tasks/main.yml @@ -122,6 +122,16 @@ become: false run_once: true changed_when: false + # LIRE UNE VERSION N'EST PAS CHANGER, ET `--check` RENDAIT LA GARDE MUETTE (2026-09-14). + # + # Sans `check_mode: false`, cette commande est sautee en mode idempotent : la garde qui + # suit compare alors contre du VIDE et refuse. + # + # Le controleur tourne Python et site-ops-01 tourne Python 3.13 + # + # L'espace apres « Python » est tout le diagnostic — il n'y avait rien a comparer. Un + # essai a blanc rendait donc un echec sur le runner, alors que le deploiement reel passe. + check_mode: false register: serveur_ops_python_controleur - name: Exiger que le controleur et la cible partagent leur version de Python