GUI : persister les journaux d'exécution
Chaque action (creer-vm/verifier/deployer) écrit un journal horodaté <instance>/logs/<hote>-<action>-<date>.log en plus du streaming live. Si le navigateur se déconnecte, l'exécution continue et le log est capturé jusqu'au bout (au lieu d'être interrompue). node --check OK, serveur HTTP 200. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
55847b6df0
commit
b4ca67289a
2 changed files with 26 additions and 3 deletions
|
|
@ -3,6 +3,11 @@
|
|||
## 2026-07-07 (soir)
|
||||
|
||||
### Ajouté
|
||||
- **GUI : persistance des journaux d'exécution.** Chaque action lancée depuis l'interface
|
||||
(créer-vm / vérifier / déployer) écrit désormais, **en plus du streaming live**, un journal
|
||||
horodaté `<instance>/logs/<hôte>-<action>-<date>.log` (gitignoré). Bonus : si le navigateur se
|
||||
déconnecte, l'exécution **continue** et le journal est capturé jusqu'au bout (au lieu d'être
|
||||
interrompue) — utile pour un déploiement qu'on ne veut pas voir avorter à la fermeture d'un onglet.
|
||||
- **GUI : vues « Flux » et « Couches » (lecture seule).** Deux nouveaux onglets rendent visibles
|
||||
dans l'interface deux registres jusque-là en ligne de commande seulement : **Flux** = la matrice
|
||||
d'audit réseau (rôle · sens · port · pair · chiffrement coloré · raison, depuis les `meta/flux.yml`),
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import secrets
|
|||
import socket
|
||||
import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
import threading
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from pathlib import Path
|
||||
|
|
@ -2053,6 +2054,7 @@ class Gestionnaire(BaseHTTPRequestHandler):
|
|||
self.repondre_json(409, {"erreur": "Une execution est deja en cours."})
|
||||
return
|
||||
fichier_vault = None
|
||||
journal = None
|
||||
try:
|
||||
cible = {"deployer": "deployer", "pousser": "deployer",
|
||||
"creer": "creer-vm"}.get(mode, "verifier-deploiement")
|
||||
|
|
@ -2066,7 +2068,14 @@ class Gestionnaire(BaseHTTPRequestHandler):
|
|||
self.send_header("Content-Type", "text/plain; charset=utf-8")
|
||||
self.send_header("Cache-Control", "no-cache")
|
||||
self.end_headers()
|
||||
self._ecrire_flux(f"$ make {cible} HOTE={hote}\n\n")
|
||||
# Persistance : un journal horodaté par exécution, en plus du streaming live.
|
||||
dossier_logs = self.inventaire.parents[2] / "logs"
|
||||
dossier_logs.mkdir(parents=True, exist_ok=True)
|
||||
chemin_log = dossier_logs / f"{hote}-{cible}-{time.strftime('%Y%m%dT%H%M%S')}.log"
|
||||
journal = open(chemin_log, "w", encoding="utf-8")
|
||||
entete = f"$ make {cible} HOTE={hote}\n\n"
|
||||
journal.write(entete)
|
||||
self._ecrire_flux(entete)
|
||||
proc = subprocess.Popen(
|
||||
["make", cible, f"HOTE={hote}"],
|
||||
cwd=str(RACINE), env=env,
|
||||
|
|
@ -2075,8 +2084,11 @@ class Gestionnaire(BaseHTTPRequestHandler):
|
|||
)
|
||||
try:
|
||||
for ligne in proc.stdout:
|
||||
journal.write(ligne)
|
||||
if not self._ecrire_flux(ligne):
|
||||
proc.terminate()
|
||||
# Navigateur déconnecté : on continue à journaliser jusqu'au bout.
|
||||
for reste in proc.stdout:
|
||||
journal.write(reste)
|
||||
break
|
||||
finally:
|
||||
rc = proc.wait()
|
||||
|
|
@ -2091,8 +2103,14 @@ class Gestionnaire(BaseHTTPRequestHandler):
|
|||
marquer_serveur_actif(hote)
|
||||
except Exception:
|
||||
pass
|
||||
self._ecrire_flux(f"\n__FIN__ rc={rc}\n")
|
||||
journal.write(f"\n__FIN__ rc={rc}\n")
|
||||
self._ecrire_flux(f"\n[journal : {os.path.relpath(chemin_log, RACINE)}]\n__FIN__ rc={rc}\n")
|
||||
finally:
|
||||
if journal:
|
||||
try:
|
||||
journal.close()
|
||||
except OSError:
|
||||
pass
|
||||
if fichier_vault:
|
||||
try:
|
||||
os.remove(fichier_vault)
|
||||
|
|
|
|||
Loading…
Reference in a new issue