[IMP] script todo: nb de VM dans le prompt parallèle + IDs de suivi (k/N)
Sur un gros parc (ex. 26 VM), on ne voyait ni combien de VM allaient être
déployées ni lesquelles étaient en cours (résultats parallèles dans le
désordre). Deux améliorations :
- Le prompt de parallélisme affiche le NOMBRE de VM à déployer :
« Déploiements en parallèle (défaut : 24, 26 VM) : ». Pour cela, la
séparation à-créer / déjà-existantes est faite AVANT le prompt (on connaît
le vrai compte).
- Chaque VM reçoit un ID « k/N » suivant l'ordre de préparation, affiché
dans les résultats de déploiement (« ✅ [3/26] nom ») et dans la résolution
d'IP (« [5/30] nom : ip »). L'ID reste stable même si les résultats
reviennent dans le désordre -> on suit lesquelles sont traitées.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
372aedb0eb
commit
a74b0c0c4c
2 changed files with 43 additions and 21 deletions
|
|
@ -1642,13 +1642,15 @@ class TODO:
|
|||
# Meilleur effort : le dernier bail (le plus récent) plutôt que le 1er.
|
||||
return cands[-1] if cands else None
|
||||
|
||||
def _qemu_resolve_ips(self, names):
|
||||
def _qemu_resolve_ips(self, names, labels=None):
|
||||
"""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}.
|
||||
`labels` : {nom: « k/N »} pour préfixer chaque ligne d'un ID de suivi.
|
||||
É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
|
||||
|
||||
labels = labels or {}
|
||||
print(f"\n{t('Resolving VM IPs (parallel, emulated boot is slow)...')}")
|
||||
result = {}
|
||||
workers = min(len(names), (os.cpu_count() or 4)) or 1
|
||||
|
|
@ -1661,7 +1663,8 @@ class TODO:
|
|||
except Exception:
|
||||
ip = None
|
||||
result[n] = ip
|
||||
print(f" {n}: {ip or t('no IP')}")
|
||||
prefix = f"[{labels[n]}] " if n in labels else ""
|
||||
print(f" {prefix}{n}: {ip or t('no IP')}")
|
||||
return result
|
||||
|
||||
def _qemu_vm_arch(self, name):
|
||||
|
|
@ -2256,37 +2259,48 @@ class TODO:
|
|||
input(t("Add each VM to ~/.ssh/config? (y/N): "))
|
||||
)
|
||||
|
||||
# Nombre de déploiements en parallèle. Défaut = nombre de CPU de
|
||||
# l'hôte (borné par le nombre de VM ; repli sur 4 si indéterminé).
|
||||
default_par = min(len(selected), os.cpu_count() or 4)
|
||||
# 5) Sépare les VM à CRÉER des déjà existantes AVANT de proposer le
|
||||
# parallélisme : on connaît alors le vrai nombre à déployer (affiché
|
||||
# dans le prompt) et on peut numéroter chaque tâche.
|
||||
pending = [] # (name, d, v, ram, disk, a)
|
||||
deployed = []
|
||||
for i, (d, v, ram, disk, a) in enumerate(selected):
|
||||
name = names[i]
|
||||
if self._qemu_domain_exists(name):
|
||||
print(f"⏭ {name}: {t('already exists, skipped.')}")
|
||||
deployed.append(name)
|
||||
else:
|
||||
pending.append((name, d, v, ram, disk, a))
|
||||
n_jobs = len(pending)
|
||||
|
||||
# Nombre de déploiements en parallèle. Défaut = nombre de CPU de l'hôte
|
||||
# (borné par le nombre de VM). On affiche aussi le NB DE VM à déployer.
|
||||
default_par = min(n_jobs, os.cpu_count() or 4) or 1
|
||||
raw = input(
|
||||
f"{t('Parallel deployments (default:')} {default_par}): "
|
||||
f"{t('Parallel deployments (default:')} {default_par}, "
|
||||
f"{n_jobs} {t('VMs')}): "
|
||||
).strip()
|
||||
try:
|
||||
parallelism = max(1, int(raw)) if raw else default_par
|
||||
except ValueError:
|
||||
parallelism = default_par
|
||||
|
||||
# 5) Confirmation puis déploiement (en parallèle).
|
||||
# Confirmation puis déploiement (en parallèle).
|
||||
ans = input(f"\n{t('Deploy these VMs now? (y/N): ')}")
|
||||
if not self._is_yes(ans):
|
||||
print(t("Cancelled."))
|
||||
return
|
||||
|
||||
deployed = []
|
||||
jobs = [] # (name, parts) des VM à créer
|
||||
for i, (d, v, ram, disk, a) in enumerate(selected):
|
||||
name = names[i]
|
||||
if self._qemu_domain_exists(name):
|
||||
print(f"⏭ {name}: {t('already exists, skipped.')}")
|
||||
deployed.append(name)
|
||||
continue
|
||||
# Jobs numérotés (k/N) : l'ID suit l'ORDRE de préparation, stable même
|
||||
# si les résultats reviennent dans le désordre (exécution parallèle).
|
||||
jobs = [] # (id, name, parts)
|
||||
for k, (name, d, v, ram, disk, a) in enumerate(pending, 1):
|
||||
eram, evcpus = eff_res(ram)
|
||||
parts = self._qemu_build_deploy_parts(
|
||||
d, v, a, name, eram, evcpus, disk,
|
||||
ssh_key, install_branch, dry_run=False,
|
||||
)
|
||||
jobs.append((name, parts))
|
||||
jobs.append((f"{k}/{n_jobs}", name, parts))
|
||||
|
||||
if jobs:
|
||||
from concurrent.futures import (
|
||||
|
|
@ -2301,17 +2315,17 @@ class TODO:
|
|||
)
|
||||
|
||||
def _run(job):
|
||||
jname, jparts = job
|
||||
jid, jname, jparts = job
|
||||
res = subprocess.run(jparts, capture_output=True, text=True)
|
||||
out = (res.stdout or "") + (res.stderr or "")
|
||||
return jname, res.returncode, out
|
||||
return jid, jname, res.returncode, out
|
||||
|
||||
with ThreadPoolExecutor(max_workers=workers) as pool:
|
||||
futures = [pool.submit(_run, j) for j in jobs]
|
||||
for fut in as_completed(futures):
|
||||
jname, rc, out = fut.result()
|
||||
jid, jname, rc, out = fut.result()
|
||||
mark = "✅" if rc == 0 else "❌"
|
||||
print(f"\n{mark} {jname} (rc={rc})")
|
||||
print(f"\n{mark} [{jid}] {jname} (rc={rc})")
|
||||
tail = [ln for ln in out.strip().splitlines() if ln][-4:]
|
||||
for ln in tail:
|
||||
print(f" {ln}")
|
||||
|
|
@ -2323,7 +2337,11 @@ class TODO:
|
|||
# é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)
|
||||
labels = {
|
||||
nm: f"{k}/{len(deployed)}"
|
||||
for k, nm in enumerate(deployed, 1)
|
||||
}
|
||||
ip_map = self._qemu_resolve_ips(deployed, labels)
|
||||
|
||||
if add_ssh_config:
|
||||
for name in deployed:
|
||||
|
|
|
|||
|
|
@ -1633,6 +1633,10 @@ TRANSLATIONS = {
|
|||
"fr": "Déploiements en parallèle (défaut :",
|
||||
"en": "Parallel deployments (default:",
|
||||
},
|
||||
"VMs": {
|
||||
"fr": "VM",
|
||||
"en": "VMs",
|
||||
},
|
||||
"Deploying": {
|
||||
"fr": "Déploiement de",
|
||||
"en": "Deploying",
|
||||
|
|
|
|||
Loading…
Reference in a new issue