[FIX] script todo: résolution d'IP en parallèle (dashboard ne s'ouvrait jamais)
Après un déploiement infra, la résolution d'IP tournait EN SÉRIE (boucle ssh_config puis install), jusqu'à 10 min par VM émulée, SANS aucune sortie : le dashboard « n'ouvrait jamais » (impression de blocage), d'autant qu'une VM qui ne boote pas (IP jamais attribuée) bloquait tout le reste. Fix : _qemu_resolve_ips résout les IP de toutes les VM EN PARALLÈLE, avec progression affichée par VM, une seule fois, réutilisée pour ~/.ssh/config ET l'installation (plus de double résolution). _qemu_install_erplibre_* acceptent une IP/ip_map déjà résolue. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
7bd44d21a9
commit
b49e107b83
1 changed files with 44 additions and 11 deletions
|
|
@ -1763,6 +1763,28 @@ class TODO:
|
||||||
# Meilleur effort : le dernier bail (le plus récent) plutôt que le 1er.
|
# Meilleur effort : le dernier bail (le plus récent) plutôt que le 1er.
|
||||||
return cands[-1] if cands else None
|
return cands[-1] if cands else None
|
||||||
|
|
||||||
|
def _qemu_resolve_ips(self, names):
|
||||||
|
"""Résout les IP de plusieurs VM EN PARALLÈLE (le boot émulé est lent),
|
||||||
|
en affichant la progression au fur et à mesure. Renvoie {nom: ip|None}.
|
||||||
|
Évite l'attente EN SÉRIE et SANS sortie qui donnait l'impression d'un
|
||||||
|
blocage (dashboard qui « n'ouvre jamais »)."""
|
||||||
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||||
|
|
||||||
|
print(f"\n{t('Resolving VM IPs (parallel, emulated boot is slow)...')}")
|
||||||
|
result = {}
|
||||||
|
workers = min(len(names), (os.cpu_count() or 4)) or 1
|
||||||
|
with ThreadPoolExecutor(max_workers=workers) as pool:
|
||||||
|
futs = {pool.submit(self._qemu_vm_ip, n): n for n in names}
|
||||||
|
for fut in as_completed(futs):
|
||||||
|
n = futs[fut]
|
||||||
|
try:
|
||||||
|
ip = fut.result()
|
||||||
|
except Exception:
|
||||||
|
ip = None
|
||||||
|
result[n] = ip
|
||||||
|
print(f" {n}: {ip or t('no IP')}")
|
||||||
|
return result
|
||||||
|
|
||||||
def _qemu_vm_arch(self, name):
|
def _qemu_vm_arch(self, name):
|
||||||
"""Architecture d'une VM (jeton amd64/arm64/s390x) via virsh dumpxml."""
|
"""Architecture d'une VM (jeton amd64/arm64/s390x) via virsh dumpxml."""
|
||||||
try:
|
try:
|
||||||
|
|
@ -1952,10 +1974,10 @@ class TODO:
|
||||||
f"make {self.ERPLIBRE_ODOO_TARGET}"
|
f"make {self.ERPLIBRE_ODOO_TARGET}"
|
||||||
)
|
)
|
||||||
|
|
||||||
def _qemu_install_erplibre_monitored(self, names, branch):
|
def _qemu_install_erplibre_monitored(self, names, branch, ip_map=None):
|
||||||
"""Lance l'install ERPLibre en parallèle DÉTACHÉE sur les VM et ouvre
|
"""Lance l'install ERPLibre en parallèle DÉTACHÉE sur les VM et ouvre
|
||||||
le dashboard Textual. Quitter le dashboard n'arrête pas les installs.
|
le dashboard Textual. Quitter le dashboard n'arrête pas les installs.
|
||||||
"""
|
`ip_map` : IP déjà résolues (sinon on résout ici, EN PARALLÈLE)."""
|
||||||
from script.todo.qemu_install_monitor import (
|
from script.todo.qemu_install_monitor import (
|
||||||
launch_installs,
|
launch_installs,
|
||||||
run_monitor,
|
run_monitor,
|
||||||
|
|
@ -1966,10 +1988,11 @@ class TODO:
|
||||||
mod = self._qemu_import_module()
|
mod = self._qemu_import_module()
|
||||||
except Exception:
|
except Exception:
|
||||||
mod = None
|
mod = None
|
||||||
|
if ip_map is None:
|
||||||
|
ip_map = self._qemu_resolve_ips(names)
|
||||||
vms = []
|
vms = []
|
||||||
for name in names:
|
for name in names:
|
||||||
print(f" {name}: {t('resolving IP...')}")
|
ip = ip_map.get(name)
|
||||||
ip = self._qemu_vm_ip(name)
|
|
||||||
if ip:
|
if ip:
|
||||||
d, v, a = (
|
d, v, a = (
|
||||||
self._qemu_vm_meta(name, mod)
|
self._qemu_vm_meta(name, mod)
|
||||||
|
|
@ -2012,10 +2035,12 @@ class TODO:
|
||||||
# Commande prête à copier pour relire/partager tous les logs.
|
# Commande prête à copier pour relire/partager tous les logs.
|
||||||
print(f" {t('Read the logs:')} tail -n +1 {logdir}/*.log")
|
print(f" {t('Read the logs:')} tail -n +1 {logdir}/*.log")
|
||||||
|
|
||||||
def _qemu_install_erplibre_vm(self, name, ssh_key, branch):
|
def _qemu_install_erplibre_vm(self, name, ssh_key, branch, ip=None):
|
||||||
"""Clone ERPLibre (branche donnée) dans ~/git/erplibre de la VM puis
|
"""Clone ERPLibre (branche donnée) dans ~/git/erplibre de la VM puis
|
||||||
exécute « make install_os » et « make install_odoo_18 » (streamé)."""
|
exécute « make install_os » et « make install_odoo_18 » (streamé).
|
||||||
ip = self._qemu_vm_ip(name)
|
`ip` : IP déjà résolue (sinon on la résout ici)."""
|
||||||
|
if ip is None:
|
||||||
|
ip = self._qemu_vm_ip(name)
|
||||||
if not ip:
|
if not ip:
|
||||||
print(
|
print(
|
||||||
f" {name}: {t('no IP obtained, ERPLibre install skipped.')}"
|
f" {name}: {t('no IP obtained, ERPLibre install skipped.')}"
|
||||||
|
|
@ -2316,10 +2341,16 @@ class TODO:
|
||||||
if rc == 0:
|
if rc == 0:
|
||||||
deployed.append(jname)
|
deployed.append(jname)
|
||||||
|
|
||||||
# 6) ~/.ssh/config (une fois les VM démarrées et l'IP attribuée).
|
# 6) Résolution des IP EN PARALLÈLE (réutilisée pour ssh_config +
|
||||||
|
# install) : une boucle EN SÉRIE bloquait plusieurs minutes par VM
|
||||||
|
# émulée SANS sortie -> le dashboard « n'ouvrait jamais ».
|
||||||
|
ip_map = {}
|
||||||
|
if deployed and (add_ssh_config or install_branch):
|
||||||
|
ip_map = self._qemu_resolve_ips(deployed)
|
||||||
|
|
||||||
if add_ssh_config:
|
if add_ssh_config:
|
||||||
for name in deployed:
|
for name in deployed:
|
||||||
ip = self._qemu_vm_ip(name)
|
ip = ip_map.get(name)
|
||||||
if ip:
|
if ip:
|
||||||
self._write_ssh_config_entry(name, "erplibre", ip)
|
self._write_ssh_config_entry(name, "erplibre", ip)
|
||||||
|
|
||||||
|
|
@ -2327,7 +2358,9 @@ class TODO:
|
||||||
if install_branch:
|
if install_branch:
|
||||||
if install_monitor:
|
if install_monitor:
|
||||||
# Installs détachées en parallèle + dashboard Textual.
|
# Installs détachées en parallèle + dashboard Textual.
|
||||||
self._qemu_install_erplibre_monitored(deployed, install_branch)
|
self._qemu_install_erplibre_monitored(
|
||||||
|
deployed, install_branch, ip_map
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
print(
|
print(
|
||||||
f"\n{t('Installing ERPLibre on each VM')} "
|
f"\n{t('Installing ERPLibre on each VM')} "
|
||||||
|
|
@ -2335,7 +2368,7 @@ class TODO:
|
||||||
)
|
)
|
||||||
for name in deployed:
|
for name in deployed:
|
||||||
self._qemu_install_erplibre_vm(
|
self._qemu_install_erplibre_vm(
|
||||||
name, ssh_key, install_branch
|
name, ssh_key, install_branch, ip_map.get(name)
|
||||||
)
|
)
|
||||||
|
|
||||||
print(f"\n✅ {t('ERPLibre infra deployment done.')}")
|
print(f"\n✅ {t('ERPLibre infra deployment done.')}")
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue