2026-09-14 14:26:29 -04:00
|
|
|
#!/usr/bin/env python3
|
2026-09-14 14:41:23 -04:00
|
|
|
"""L'adresse du wiki de la forge QUI PORTE MON GENOME.
|
2026-09-14 14:26:29 -04:00
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
2026-09-14 14:41:23 -04:00
|
|
|
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.
|
|
|
|
|
|
2026-09-14 14:26:29 -04:00
|
|
|
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__})"
|
|
|
|
|
|
2026-09-14 14:41:23 -04:00
|
|
|
# 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")
|
|
|
|
|
|
2026-09-14 14:26:29 -04:00
|
|
|
# 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)
|