temoins : toutes les bases, modeles compris (template1 dite perdue a tort)

Premier essai reel sur Technolibre : pg_dumpall --clean recree template1, et
les bases vivantes etaient lues sans les modeles. Le test reproduit le filtre.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Daniel Allaire 2026-10-07 12:55:53 -04:00
parent 11b5bb5733
commit 543791e859
3 changed files with 23 additions and 6 deletions

View file

@ -57,9 +57,21 @@ restauré. Je m'y suis trompé un moment.
- `shellcheck` des deux scripts rendus : rien, avant comme après. - `shellcheck` des deux scripts rendus : rien, avant comme après.
- `make verifier` conforme, **94/94**. - `make verifier` conforme, **94/94**.
**Reste** : déployer `client_backup` sur les deux locataires (les nœuds de Chezlepro n'ont pas **Déployé** : `client_backup` sur les deux locataires, simulé d'abord (`--check --diff`) :
la nouvelle unité : `sauvegarder-maintenant` y refuserait), puis reconstruire Chezlepro avec 4 changements par nœud détenteur d'état (script, outil, comparateur, unité), 2 ailleurs,
des témoins pris pour de vrai, puis étiqueter la release. 0 échec ; l'application a fait exactement cela.
**Premier essai réel**, Technolibre, contre l'instantané de la veille (`SOURCE=candidat` :
celui de 11:34 n'existe plus). Nextcloud identique (268 fichiers, `instanceid` compris) ;
annuaire identique (12 entrées, `sysadmin` compris) ; clés et certificats de l'AC
inchangés, seule sa base `db/` a bougé ; DKIM inchangée ; aucun courriel perdu ; Keycloak a
quelques sessions et événements de plus. **Un faux écart**, du comparateur : `template1`
« perdue », parce que les bases vivantes étaient lues sans les modèles alors que
`pg_dumpall --clean` recrée `template1`. Corrigé (toutes les bases) ; le test reproduit le
filtre de PostgreSQL, et l'ancienne requête le fait échouer.
**Reste** : reconstruire Chezlepro avec des témoins pris pour de vrai, puis étiqueter la
release.
## 2026-10-07 (100) — Pré-vol de M4 : la face tient devant le cluster, deux en-têtes disaient faux ## 2026-10-07 (100) — Pré-vol de M4 : la face tient devant le cluster, deux en-têtes disaient faux

View file

@ -252,7 +252,9 @@ def jeu_postgresql(dump: Path, interroger=psql) -> Rapport:
r.ecarts.append(f"l'instantane n'emporte pas de dump ({dump.name})") r.ecarts.append(f"l'instantane n'emporte pas de dump ({dump.name})")
return r return r
bases, roles, lignes = lire_dump(dump.read_text(errors="replace")) bases, roles, lignes = lire_dump(dump.read_text(errors="replace"))
vivantes = set(interroger("postgres", "select datname from pg_database where not datistemplate") or []) # TOUTES les bases, modeles compris : `pg_dumpall --clean` recree `template1`, et le
# premier essai reel (Technolibre, 2026-10-07) l'a dite « perdue » faute de la chercher.
vivantes = set(interroger("postgres", "select datname from pg_database") or [])
roles_vivants = set(interroger("postgres", "select rolname from pg_roles") or []) roles_vivants = set(interroger("postgres", "select rolname from pg_roles") or [])
r.compte = len(lignes) r.compte = len(lignes)
for b in sorted(bases - vivantes): for b in sorted(bases - vivantes):

View file

@ -65,6 +65,7 @@ mail: marie@exemple.internal
DUMP = r"""CREATE ROLE keycloak; DUMP = r"""CREATE ROLE keycloak;
CREATE ROLE postgres; CREATE ROLE postgres;
CREATE DATABASE template1 WITH TEMPLATE = template0 ENCODING = 'UTF8';
CREATE DATABASE keycloak WITH TEMPLATE = template0 ENCODING = 'UTF8'; CREATE DATABASE keycloak WITH TEMPLATE = template0 ENCODING = 'UTF8';
\connect keycloak \connect keycloak
COPY public.realm (id, name) FROM stdin; COPY public.realm (id, name) FROM stdin;
@ -189,12 +190,14 @@ def postgresql() -> None:
argv = ["--avant", str(d / "avant"), "--instantane", "x", "--jeu", "postgresql=/var/backups/setops/postgresql", argv = ["--avant", str(d / "avant"), "--instantane", "x", "--jeu", "postgresql=/var/backups/setops/postgresql",
"--dump", "/var/backups/setops/postgresql/toutes-bases.sql"] "--dump", "/var/backups/setops/postgresql/toutes-bases.sql"]
def cluster(bases=("postgres", "keycloak"), roles=("postgres", "keycloak"), comptes=None): def cluster(bases=("postgres", "template1", "keycloak"), roles=("postgres", "keycloak"), comptes=None):
comptes = comptes if comptes is not None else {"public.realm": "2", "public.user_session": "1"} comptes = comptes if comptes is not None else {"public.realm": "2", "public.user_session": "1"}
def interroger(base: str, sql: str): def interroger(base: str, sql: str):
if "pg_database" in sql: if "pg_database" in sql:
return list(bases) # Comme PostgreSQL : `template1` est un modele, qu'un filtre sur
# `datistemplate` ecarterait (le faux « base perdue » du premier essai reel).
return [b for b in bases if not ("datistemplate" in sql and b == "template1")]
if "pg_roles" in sql: if "pg_roles" in sql:
return list(roles) return list(roles)
table = sql.rsplit(" ", 1)[-1] table = sql.rsplit(" ", 1)[-1]