Machinerie d'exposition : SAN auto-dérivés + vhost WebSocket-aware
Élimine 3 gotchas du spike Nextcloud/Collabora : - instancier dérive sans_exposition par edge (FQDN exposés du plan) → le cert edge (client_pki_sans) se met à jour tout seul, plus de liste manuelle en group_vars ; - champ 'websocket' sur une application → le vhost d'exposition ajoute la map $http_upgrade + en-têtes Upgrade/Connection + timeout long (Collabora, éditeurs live) ; - (plancher /etc/hosts : le mécanisme d'alias existait déjà, publier_expositions=true). Prouvé sur le lab : cert edge couvre les 6 expositions, bureau 200 en WebSocket. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
da4976aa98
commit
0d2bc2c2e9
3 changed files with 26 additions and 1 deletions
|
|
@ -6,6 +6,10 @@
|
|||
# amont = http://<IP interne de l'hote de l'application>:<port>. Une exposition
|
||||
# non resolvable (application sans hote actif, ou sans port) est listee mais
|
||||
# NON publiee (binding declare, pas encore cablable).
|
||||
{% if serveur_nginx_expositions | default([]) | selectattr('websocket', 'defined') | selectattr('websocket') | list | length > 0 %}
|
||||
# Une exposition au moins est WebSocket-aware (ex. Collabora) : map d'upgrade.
|
||||
map $http_upgrade $connection_upgrade { default upgrade; "" close; }
|
||||
{% endif %}
|
||||
{% for expo in serveur_nginx_expositions | default([]) %}
|
||||
{% set ns = namespace(amont='') %}
|
||||
{% if expo.hote in hostvars and hostvars[expo.hote].ansible_host is defined and expo.port %}
|
||||
|
|
@ -37,6 +41,13 @@ server {
|
|||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
{% if expo.websocket | default(false) %}
|
||||
# Collabora & co : editeur en direct via WebSocket (upgrade + longue tenue).
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_read_timeout 3600s;
|
||||
{% endif %}
|
||||
}
|
||||
}
|
||||
{% else %}
|
||||
|
|
|
|||
|
|
@ -27,10 +27,12 @@ import yaml
|
|||
|
||||
from inventory_rules import (
|
||||
charger_applications,
|
||||
charger_domaines,
|
||||
charger_nomenclature,
|
||||
charger_serveurs,
|
||||
deriver_nomenclature,
|
||||
deriver_ressources,
|
||||
expositions_des_applications,
|
||||
fonction_seq,
|
||||
)
|
||||
|
||||
|
|
@ -55,6 +57,7 @@ GENERE = INVENTAIRE.with_name("hosts.genere.yml")
|
|||
FICHIER_SERVEURS = INSTANCE / "plan/serveurs.yml"
|
||||
FICHIER_APPLICATIONS = INSTANCE / "plan/applications.yml"
|
||||
FICHIER_NOMENCLATURE = INSTANCE / "plan/nomenclature.yml"
|
||||
FICHIER_DOMAINES = INSTANCE / "plan/domaines.yml"
|
||||
|
||||
GROUPES_SOCLE = ["serveur_debian", "serveur_durci"]
|
||||
PLACEMENT = [("noeud", "proxmox_noeud"), ("stockage", "proxmox_stockage"),
|
||||
|
|
@ -151,6 +154,9 @@ def generer() -> dict:
|
|||
apps = charger_applications(FICHIER_APPLICATIONS).get("applications", {})
|
||||
nomenclature = charger_nomenclature(FICHIER_NOMENCLATURE)
|
||||
injections = resoudre_liens(apps, serveurs, nomenclature)
|
||||
# Expositions du plan (champ 'expose') -> pour deriver les SANs de chaque edge.
|
||||
domaines = charger_domaines(FICHIER_DOMAINES)
|
||||
expositions = expositions_des_applications({"applications": apps}, domaines)
|
||||
|
||||
services_par_hote: dict = {}
|
||||
for app in apps.values():
|
||||
|
|
@ -184,9 +190,14 @@ def generer() -> dict:
|
|||
# Variables derivees des liens (bindings) declares par les applications.
|
||||
for var, val in injections.get(nom, {}).items():
|
||||
hostvars[var] = val
|
||||
groupes = set(GROUPES_SOCLE) | services_par_hote.get(nom, set()) | set(srv.get("integrations") or [])
|
||||
# SANs d'exposition : les FQDN que cet edge sert (derives du plan) -> cert edge
|
||||
# (client_pki_sans), au lieu d'une liste manuelle. Vide si l'hote n'est pas un edge.
|
||||
sans = sorted({e["fqdn"] for e in expositions if e.get("edge") in groupes})
|
||||
if sans:
|
||||
hostvars["sans_exposition"] = sans
|
||||
etat = "hotes_actifs" if srv.get("etat") == "actif" else "hotes_planifies"
|
||||
children[etat]["hosts"][nom] = hostvars
|
||||
groupes = set(GROUPES_SOCLE) | services_par_hote.get(nom, set()) | set(srv.get("integrations") or [])
|
||||
for groupe in sorted(groupes):
|
||||
children.setdefault(groupe, {"hosts": {}})["hosts"][nom] = None
|
||||
return {"all": {"children": children}}
|
||||
|
|
|
|||
|
|
@ -200,6 +200,9 @@ def expositions_des_applications(applications: dict, domaines: dict, edge: str |
|
|||
"fqdn": fqdn, "application": app_id, "groupe": app.get("groupe"),
|
||||
"hote": app.get("hote"), "port": app.get("port"),
|
||||
"edge": edge_dom, "domaine": dom,
|
||||
# Exposition WebSocket-aware (ex. Collabora) : le vhost ajoute
|
||||
# alors l'upgrade Upgrade/Connection. Declare par l'app (websocket: true).
|
||||
"websocket": bool(app.get("websocket")),
|
||||
})
|
||||
return resultat
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue