[IMP] script todo: deploy the ERPLibre infra in parallel
The infra fleet was deployed one VM at a time, each blocking up to 90s waiting for its DHCP lease. Deploys now run concurrently through a ThreadPoolExecutor (default min(count, 4), promptable), with each job's output captured and printed per VM as it finishes (no interleaving). VMs are created with --no-wait-ip so workers return quickly; IPs are then collected once for the ~/.ssh/config step. Preferred over shelling out to GNU parallel: no external dependency, grouped output, and it stays integrated with the ssh-config and ERPLibre-clone steps. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4b988bbe46
commit
19e3801d2c
2 changed files with 66 additions and 11 deletions
|
|
@ -1433,7 +1433,17 @@ class TODO:
|
||||||
input(t("Add each VM to ~/.ssh/config? (y/N): "))
|
input(t("Add each VM to ~/.ssh/config? (y/N): "))
|
||||||
)
|
)
|
||||||
|
|
||||||
# 5) Confirmation puis déploiement séquentiel.
|
# Nombre de déploiements en parallèle (défaut : min(nb VM, 4)).
|
||||||
|
default_par = min(len(selected), 4)
|
||||||
|
raw = input(
|
||||||
|
f"{t('Parallel deployments (default:')} {default_par}): "
|
||||||
|
).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).
|
||||||
ans = input(f"\n{t('Deploy these VMs now? (y/N): ')}")
|
ans = input(f"\n{t('Deploy these VMs now? (y/N): ')}")
|
||||||
if not self._is_yes(ans):
|
if not self._is_yes(ans):
|
||||||
print(t("Cancelled."))
|
print(t("Cancelled."))
|
||||||
|
|
@ -1441,10 +1451,11 @@ class TODO:
|
||||||
|
|
||||||
script_path = self._qemu_script_path()
|
script_path = self._qemu_script_path()
|
||||||
deployed = []
|
deployed = []
|
||||||
|
jobs = [] # (name, parts) des VM à créer
|
||||||
for d, v, _ram, _disk in selected:
|
for d, v, _ram, _disk in selected:
|
||||||
name = self._qemu_infra_name(d, v)
|
name = self._qemu_infra_name(d, v)
|
||||||
if self._qemu_domain_exists(name):
|
if self._qemu_domain_exists(name):
|
||||||
print(f"\n⏭ {name}: {t('already exists, skipped.')}")
|
print(f"⏭ {name}: {t('already exists, skipped.')}")
|
||||||
deployed.append(name)
|
deployed.append(name)
|
||||||
continue
|
continue
|
||||||
parts = [
|
parts = [
|
||||||
|
|
@ -1456,25 +1467,57 @@ class TODO:
|
||||||
v,
|
v,
|
||||||
"--name",
|
"--name",
|
||||||
name,
|
name,
|
||||||
|
# Mot de passe console « erplibre » (+ clé SSH). --no-wait-ip :
|
||||||
|
# ne bloque pas 90s par VM, l'IP est collectée après coup.
|
||||||
|
"--password",
|
||||||
|
"erplibre",
|
||||||
|
"--no-wait-ip",
|
||||||
]
|
]
|
||||||
if ssh_key:
|
if ssh_key:
|
||||||
parts += ["--ssh-key", ssh_key]
|
parts += ["--ssh-key", ssh_key]
|
||||||
# Mot de passe console par défaut « erplibre » (login virsh
|
|
||||||
# console + SSH par mot de passe), en plus de la clé.
|
|
||||||
parts += ["--password", "erplibre"]
|
|
||||||
if install_branch:
|
if install_branch:
|
||||||
parts += ["--package", "git"]
|
parts += ["--package", "git"]
|
||||||
parts.append("-y")
|
parts.append("-y")
|
||||||
cmd = " ".join(shlex.quote(p) for p in parts)
|
jobs.append((name, parts))
|
||||||
print(f"\n▶ {name}: {cmd}")
|
|
||||||
self.execute.exec_command_live(cmd, source_erplibre=False)
|
if jobs:
|
||||||
deployed.append(name)
|
from concurrent.futures import (
|
||||||
if add_ssh_config:
|
ThreadPoolExecutor,
|
||||||
|
as_completed,
|
||||||
|
)
|
||||||
|
|
||||||
|
workers = min(parallelism, len(jobs))
|
||||||
|
print(
|
||||||
|
f"\n{t('Deploying')} {len(jobs)} VM "
|
||||||
|
f"({t('parallel jobs:')} {workers})…"
|
||||||
|
)
|
||||||
|
|
||||||
|
def _run(job):
|
||||||
|
jname, jparts = job
|
||||||
|
res = subprocess.run(jparts, capture_output=True, text=True)
|
||||||
|
out = (res.stdout or "") + (res.stderr or "")
|
||||||
|
return 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()
|
||||||
|
mark = "✅" if rc == 0 else "❌"
|
||||||
|
print(f"\n{mark} {jname} (rc={rc})")
|
||||||
|
tail = [ln for ln in out.strip().splitlines() if ln][-4:]
|
||||||
|
for ln in tail:
|
||||||
|
print(f" {ln}")
|
||||||
|
if rc == 0:
|
||||||
|
deployed.append(jname)
|
||||||
|
|
||||||
|
# 6) ~/.ssh/config (une fois les VM démarrées et l'IP attribuée).
|
||||||
|
if add_ssh_config:
|
||||||
|
for name in deployed:
|
||||||
ip = self._qemu_vm_ip(name)
|
ip = self._qemu_vm_ip(name)
|
||||||
if ip:
|
if ip:
|
||||||
self._write_ssh_config_entry(name, "erplibre", ip)
|
self._write_ssh_config_entry(name, "erplibre", ip)
|
||||||
|
|
||||||
# 6) Installation ERPLibre (clone) si demandée.
|
# 7) Installation ERPLibre (clone) si demandée.
|
||||||
if install_branch:
|
if install_branch:
|
||||||
print(f"\n{t('Cloning ERPLibre on each VM')} ({install_branch})…")
|
print(f"\n{t('Cloning ERPLibre on each VM')} ({install_branch})…")
|
||||||
for name in deployed:
|
for name in deployed:
|
||||||
|
|
|
||||||
|
|
@ -1287,6 +1287,18 @@ TRANSLATIONS = {
|
||||||
"fr": "Clonage d'ERPLibre sur chaque VM",
|
"fr": "Clonage d'ERPLibre sur chaque VM",
|
||||||
"en": "Cloning ERPLibre on each VM",
|
"en": "Cloning ERPLibre on each VM",
|
||||||
},
|
},
|
||||||
|
"Parallel deployments (default:": {
|
||||||
|
"fr": "Déploiements en parallèle (défaut :",
|
||||||
|
"en": "Parallel deployments (default:",
|
||||||
|
},
|
||||||
|
"Deploying": {
|
||||||
|
"fr": "Déploiement de",
|
||||||
|
"en": "Deploying",
|
||||||
|
},
|
||||||
|
"parallel jobs:": {
|
||||||
|
"fr": "tâches parallèles :",
|
||||||
|
"en": "parallel jobs:",
|
||||||
|
},
|
||||||
"ERPLibre infra deployment done.": {
|
"ERPLibre infra deployment done.": {
|
||||||
"fr": "Déploiement de l'infra ERPLibre terminé.",
|
"fr": "Déploiement de l'infra ERPLibre terminé.",
|
||||||
"en": "ERPLibre infra deployment done.",
|
"en": "ERPLibre infra deployment done.",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue