84 lines
3.4 KiB
Python
84 lines
3.4 KiB
Python
|
|
"""L'ecriture du plan est ATOMIQUE : une panne en cours d'ecriture ne tronque rien.
|
||
|
|
|
||
|
|
POURQUOI CE TEST EXISTE. Jusqu'au 2026-09-08, treize sites du moteur ecrivaient les
|
||
|
|
registres par `path.open("w")` — une forme qui TRONQUE le fichier avant d'ecrire. Entre
|
||
|
|
les deux, il est vide. Une exception dans `yaml.safe_dump`, un disque plein, un Ctrl-C, et
|
||
|
|
`instance/plan/serveurs.yml` reste tronque.
|
||
|
|
|
||
|
|
L'asymetrie fait la gravite : `hosts.yml` se regenere d'un `make instancier-appliquer`, le
|
||
|
|
PLAN ne se regenere de rien. C'est la source unique de verite.
|
||
|
|
|
||
|
|
CE TEST PORTE SON PROPRE CONTROLE NEGATIF, et c'est le point. Il rejoue d'abord l'ANCIENNE
|
||
|
|
forme pour montrer qu'elle DETRUIT — sans quoi le succes de la nouvelle ne prouverait
|
||
|
|
rien. Une garantie qu'on n'a jamais vue echouer n'est pas une garantie, c'est une
|
||
|
|
habitude.
|
||
|
|
|
||
|
|
Aucun fichier reel n'est touche : tout se passe dans un dossier temporaire.
|
||
|
|
"""
|
||
|
|
import pathlib
|
||
|
|
import sys
|
||
|
|
import tempfile
|
||
|
|
|
||
|
|
sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[1]))
|
||
|
|
|
||
|
|
from inventory_rules import ecriture_atomique # noqa: E402
|
||
|
|
|
||
|
|
CONTENU = "serveurs:\n infra-pki-01:\n fonction: infra-pki\n"
|
||
|
|
|
||
|
|
|
||
|
|
def _neuf() -> pathlib.Path:
|
||
|
|
d = pathlib.Path(tempfile.mkdtemp(prefix="setops-atomique-"))
|
||
|
|
f = d / "serveurs.yml"
|
||
|
|
f.write_text(CONTENU, encoding="utf-8")
|
||
|
|
return f
|
||
|
|
|
||
|
|
|
||
|
|
# --- CONTROLE NEGATIF : l'ancienne forme detruit-elle vraiment ? -----------------------
|
||
|
|
f = _neuf()
|
||
|
|
try:
|
||
|
|
with f.open("w", encoding="utf-8") as fichier:
|
||
|
|
fichier.write("moitie...")
|
||
|
|
raise RuntimeError("panne simulee au milieu de l'ecriture")
|
||
|
|
except RuntimeError:
|
||
|
|
pass
|
||
|
|
perdu = f.read_text(encoding="utf-8")
|
||
|
|
print(f">>> ancienne forme, apres panne : {perdu!r}")
|
||
|
|
assert perdu != CONTENU, "LE CONTROLE NE CONTROLE RIEN : l'ancienne forme n'a rien casse"
|
||
|
|
print(">>> le controle mord : `open(\"w\")` laisse bien un fichier mutile")
|
||
|
|
|
||
|
|
# --- LA GARANTIE : la nouvelle forme survit-elle a la meme panne ? ---------------------
|
||
|
|
f = _neuf()
|
||
|
|
try:
|
||
|
|
with ecriture_atomique(f) as fichier:
|
||
|
|
fichier.write("moitie...")
|
||
|
|
raise RuntimeError("panne simulee au milieu de l'ecriture")
|
||
|
|
except RuntimeError:
|
||
|
|
pass
|
||
|
|
assert f.read_text(encoding="utf-8") == CONTENU, "LE FICHIER A ETE TRONQUE"
|
||
|
|
print(">>> apres la meme panne, le fichier est INTACT")
|
||
|
|
|
||
|
|
# Aucun residu : un `.serveurs.yml.xxxx.tmp` oublie finirait par etre committe.
|
||
|
|
restes = [p.name for p in f.parent.iterdir() if p.name != f.name]
|
||
|
|
assert not restes, f"RESIDU LAISSE DERRIERE : {restes}"
|
||
|
|
print(">>> aucun temporaire laisse dans le dossier")
|
||
|
|
|
||
|
|
# --- L'ecriture normale remplace bien le contenu ---------------------------------------
|
||
|
|
f = _neuf()
|
||
|
|
with ecriture_atomique(f) as fichier:
|
||
|
|
fichier.write("serveurs: {}\n")
|
||
|
|
assert f.read_text(encoding="utf-8") == "serveurs: {}\n", "L'ECRITURE NORMALE A ECHOUE"
|
||
|
|
print(">>> l'ecriture normale remplace le contenu")
|
||
|
|
|
||
|
|
# --- LES DROITS SURVIVENT ---------------------------------------------------------------
|
||
|
|
# `mkstemp` cree en 0600 ; le plan est en 0664, lisible par le groupe sur les runners.
|
||
|
|
# Sans report explicite des droits, le correctif rendait le plan illisible pour eux.
|
||
|
|
f = _neuf()
|
||
|
|
f.chmod(0o664)
|
||
|
|
with ecriture_atomique(f) as fichier:
|
||
|
|
fichier.write(CONTENU)
|
||
|
|
mode = f.stat().st_mode & 0o777
|
||
|
|
assert mode == 0o664, f"DROITS PERDUS : {oct(mode)} au lieu de 0o664"
|
||
|
|
print(">>> les droits du fichier sont conserves (0664)")
|
||
|
|
|
||
|
|
print("\n>>> l'ecriture du plan est atomique, eprouvee contre son propre controle.")
|