Set-OPS-Public/scripts/ma_forge.py

107 lines
4.8 KiB
Python
Raw Permalink Normal View History

#!/usr/bin/env python3
"""L'adresse du wiki de la forge QUI PORTE MON GENOME.
CHAQUE RUNNER PUBLIE POUR SA FORGE (decide le 2026-09-14).
La premiere idee etait qu'un controleur pousse vers plusieurs forges, avec un temoin
portant une liste. Elle CENTRALISAIT : un seul poste aurait eu besoin d'un acces sur
chaque forge, et le temoin serait devenu un fait global que personne ne detient.
Le modele retenu suit la ligne du reste du systeme — les voutes, les runners, les
sauvegardes : **chacun sert les siens**. Le runner du site publie sur la forge du site ;
celui d'un locataire sur la forge de ce locataire. Un employe de TechnoLibre lit la forge
de TechnoLibre, pas celle de son hebergeur.
DEUX NOTIONS A NE PAS CONFONDRE, et c'est ce qui a rendu le sujet trouble :
la forge AMONT (`serveur_ops_forge_amont`) ou je LIS le genome
MA forge (derivee ici) ou je SERS les miens
Le runner d'un locataire lit sur la forge du SITE et sert sur la SIENNE. Les deux adresses
different, et le wiki appartient a la seconde.
LE WIKI SUIT LE GENOME (decide le 2026-09-14). Un locataire ne porte PAS le moteur : il le
lit sur la forge de son hebergeur, comme il y prend ses paquets et son gabarit. Lui faire
publier la documentation du moteur sur SA forge reviendrait a l'en rendre depositaire —
donc a lui imposer l'organisation, les depots, le miroir a tenir synchrone et la preuve
qu'il ne derive pas. Pour un service qu'il ne rend a personne.
LE SIGNAL EST DEJA AU PLAN : `serveur_ops_forge_externe: true` dit « je lis mon genome
ailleurs ». Un ecosysteme qui le declare ne publie pas — il consulte, la ou le genome vit.
CE QUI RESTE VRAI D'UNE FORGE DE LOCATAIRE : elle peut exister, et servir LE CODE DE SES
GENS — depots, tickets, revues. C'est l'offre « Atelier ». Ce n'est simplement pas
l'endroit ou vit le moteur.
CE QUI N'EST PAS DERIVABLE, ET C'EST DIT PLUTOT QUE DEVINE : le poste du mainteneur n'est
le runner d'aucun ecosysteme. Il publie vers le domicile PUBLIC du projet, qui n'est la
forge d'aucun plan. La, `WIKI_REMOTE` reste explicite — et il l'emporte toujours.
"""
from __future__ import annotations
import sys
from pathlib import Path
RACINE = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(RACINE / "scripts"))
def ma_forge() -> tuple[str | None, str]:
"""(url du wiki, explication). `None` quand rien n'est derivable."""
try:
from inventory_rules import charger_applications, instance_courante
except Exception as e:
return None, f"moteur illisible ({e.__class__.__name__})"
inst = instance_courante()
if not inst:
return None, "aucune instance montee"
# `charger_applications` VEUT UN CHEMIN, pas rien. L'appeler sans argument levait un
# `TypeError` que le `except` transformait en « plan illisible » — un message poli pour
# une faute de programmation. Le voila nomme.
try:
apps = (charger_applications(Path(inst) / "plan" / "applications.yml")
or {}).get("applications") or {}
except (OSError, ValueError) as e:
return None, f"plan illisible ({e.__class__.__name__})"
# UN ECOSYSTEME QUI LIT SON GENOME AILLEURS NE LE PUBLIE PAS. Le wiki suit le genome :
# il vit la ou le moteur vit, et un locataire n'est pas son depositaire.
gv = Path(inst) / "inventories" / "principal" / "group_vars" / "serveur_ops.yml"
if gv.is_file():
try:
import yaml
d = yaml.safe_load(gv.read_text(encoding="utf-8")) or {}
except (OSError, yaml.YAMLError):
d = {}
if d.get("serveur_ops_forge_externe"):
amont = d.get("serveur_ops_forge_amont") or "sa forge amont"
return None, (f"{Path(inst).resolve().name} lit son genome sur {amont} — "
"le wiki s'y consulte, il ne s'y republie pas d'ici")
# LE NOM DU SERVICE, PAS CELUI DE LA MACHINE. Un FQDN expose survit au demenagement du
# service ; `forge-01` non. C'est la meme regle que partout ailleurs dans ce depot.
for nom, app in (apps.items() if isinstance(apps, dict) else []):
if str((app or {}).get("groupe")) != "serveur_forgejo":
continue
exposes = (app or {}).get("expose") or []
if not exposes:
return None, "`serveur_forgejo` est au plan mais n'expose aucun nom"
fqdn = str(exposes[0])
depot = RACINE.name.lower()
return (f"ssh://git@{fqdn}/genome/{depot}.wiki.git",
f"forge de l'ecosysteme monte ({Path(inst).resolve().name}), exposee en {fqdn}")
return None, f"{Path(inst).resolve().name} ne declare aucun `serveur_forgejo`"
if __name__ == "__main__":
url, pourquoi = ma_forge()
if url:
print(url)
print(f"note : {pourquoi}", file=sys.stderr)
raise SystemExit(0)
print(f"note : pas de forge derivable — {pourquoi}", file=sys.stderr)
raise SystemExit(1)