seulement_si dans meta/supervision.yml, lu par le gabarit Icinga des sondes ; garde test_sondes_conditionnelles. journaux-frontiere ne rougit plus a vie chez les locataires ; Technolibre sans critique. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
92 lines
3.8 KiB
Python
92 lines
3.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Une sonde posee sous condition est declaree sous la MEME condition.
|
|
|
|
UNE LISTE QUI EN SUIT UNE AUTRE PREND DU RETARD (2026-09-28). Un role pose sa sonde dans
|
|
`/usr/local/lib/setops/sondes/` avec ses taches ; Icinga l'attend d'apres
|
|
`meta/supervision.yml`. Quand le depot est conditionnel (`when:`) et la declaration ne
|
|
l'est pas, Icinga attend une sonde qui n'existera jamais : `journaux-frontiere` a ete
|
|
rouge a vie chez chaque locataire, dont la frontiere appartient au site.
|
|
|
|
Trois regles :
|
|
1. toute sonde deposee sous `when:` est declaree avec `seulement_si` ;
|
|
2. la variable de `seulement_si` figure dans ce `when:` ;
|
|
3. elle a une valeur par defaut LITTERALE dans le role qui la definit — Icinga la lit
|
|
telle quelle, il ne rend pas le Jinja d'un autre role.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import yaml
|
|
|
|
ROLES = Path(__file__).resolve().parents[2] / "roles"
|
|
|
|
|
|
def depots_conditionnels() -> dict[str, str]:
|
|
"""{nom de sonde : texte du `when:`} pour chaque sonde deposee sous condition."""
|
|
out = {}
|
|
for f in sorted(ROLES.glob("*/tasks/*.yml")):
|
|
try:
|
|
taches = yaml.safe_load(f.read_text(encoding="utf-8")) or []
|
|
except yaml.YAMLError:
|
|
continue
|
|
for t in taches if isinstance(taches, list) else []:
|
|
if not isinstance(t, dict):
|
|
continue
|
|
module = next((v for v in t.values() if isinstance(v, dict) and "dest" in v), None)
|
|
dest = str((module or {}).get("dest", ""))
|
|
if "/setops/sondes/" in dest and t.get("when"):
|
|
quand = t["when"] if isinstance(t["when"], str) else " ".join(map(str, t["when"]))
|
|
out[dest.rsplit("/", 1)[-1].removesuffix(".sh")] = quand
|
|
return out
|
|
|
|
|
|
def declarations() -> dict[str, tuple[str, dict]]:
|
|
"""{nom de sonde : (role declarant, declaration)}."""
|
|
out = {}
|
|
for f in sorted(ROLES.glob("*/meta/supervision.yml")):
|
|
for s in (yaml.safe_load(f.read_text(encoding="utf-8")) or {}).get("sondes") or []:
|
|
out[s["nom"]] = (f.parents[1].name, s)
|
|
return out
|
|
|
|
|
|
def main() -> int:
|
|
depots, decl = depots_conditionnels(), declarations()
|
|
echecs = 0
|
|
for nom, quand in sorted(depots.items()):
|
|
role, s = decl.get(nom, (None, {}))
|
|
var = s.get("seulement_si")
|
|
if not var:
|
|
print(f"ECHEC « {nom} » est posee sous `when: {quand}` mais declaree sans "
|
|
f"`seulement_si` : Icinga l'attendrait la ou elle n'existe pas")
|
|
echecs += 1
|
|
continue
|
|
if var not in quand:
|
|
print(f"ECHEC « {nom} » : `seulement_si: {var}` n'est pas la condition du depot "
|
|
f"(`when: {quand}`)")
|
|
echecs += 1
|
|
continue
|
|
definisseur = s.get("defini_par") or role
|
|
defauts = yaml.safe_load((ROLES / definisseur / "defaults" / "main.yml")
|
|
.read_text(encoding="utf-8")) or {}
|
|
val = defauts.get(var, "<absente>")
|
|
if val == "<absente>" or (isinstance(val, str) and "{{" in val):
|
|
print(f"ECHEC « {nom} » : `{var}` doit avoir un defaut LITTERAL dans "
|
|
f"`{definisseur}/defaults/main.yml` (trouve : {val!r})")
|
|
echecs += 1
|
|
continue
|
|
print(f"ok {nom:<20} seulement_si {var} (defaut {val!r}, {definisseur})")
|
|
for nom, (role, s) in sorted(decl.items()):
|
|
if s.get("seulement_si") and nom not in depots:
|
|
print(f"ECHEC « {nom} » ({role}) declare `seulement_si` sans depot conditionnel")
|
|
echecs += 1
|
|
if echecs:
|
|
print(f"\n{echecs} echec(s).")
|
|
return 1
|
|
print("OK — chaque sonde conditionnelle est attendue sous sa propre condition.")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|