[IMP] script todo: suffixe d'arch dans le nom + log d'install non vide
1) Nommage : _qemu_infra_name ajoute un suffixe d'architecture quand elle diffère de la native de l'hôte -> déployer un s390x sur un hôte amd64 donne « erplibre-ubuntu-2604-s390x » (au lieu de « erplibre-ubuntu-2604 »). Évite les collisions de noms entre archis et rend l'archi visible. Passé dans les 3 appelants (VM unique + plan + jobs de l'infra). 2) Log d'installation vide : sur une archi ÉMULÉE (s390x/arm64 sur x86) le boot prend plusieurs minutes ; pendant ce temps l'attente n'écrivait rien -> le log restait VIDE et paraissait « bloqué ». _launch_one écrit désormais un en-tête d'attente immédiat + un battement toutes les ~30 s, et l'attente sshd/cloud-init passe de ~12 à ~20 min (boot émulé lent). _qemu_wait_ssh (chemin streamé) : timeout porté à 20 min également. Validé : nommage (amd64/natif sans suffixe, s390x/arm64 suffixés) ; le log se remplit dès le départ (en-tête + « ... 30s »). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
88dc1d5409
commit
0930f30cd3
3 changed files with 51 additions and 13 deletions
|
|
@ -20,6 +20,14 @@ import subprocess
|
|||
import time
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
from script.todo.todo_i18n import t
|
||||
except Exception: # pragma: no cover - repli si i18n indisponible
|
||||
|
||||
def t(key: str) -> str:
|
||||
return key
|
||||
|
||||
|
||||
EXIT_MARKER = "__ERPLIBRE_EXIT__"
|
||||
SSH_OPTS = (
|
||||
"-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "
|
||||
|
|
@ -38,7 +46,8 @@ def _launch_one(ip: str, remote_cmd: str, log_path: str) -> None:
|
|||
"""Lance une install SSH DÉTACHÉE : attend le sshd, exécute, journalise
|
||||
la sortie puis écrit le marqueur de fin avec le code de sortie."""
|
||||
# Sonde de disponibilité : on attend que sshd réponde ET que cloud-init
|
||||
# soit TERMINÉ, via des connexions COURTES successives (jusqu'à ~12 min).
|
||||
# soit TERMINÉ, via des connexions COURTES successives (jusqu'à ~20 min :
|
||||
# une architecture ÉMULÉE, s390x/arm64 sur hôte x86, boote lentement).
|
||||
# Au 1er boot, cloud-init régénère les clés d'hôte et REDÉMARRE sshd : une
|
||||
# session SSH longue (ex. « cloud-init status --wait ») serait alors tuée
|
||||
# (« Connection closed by remote host », exit 255 — cas Fedora). Chaque
|
||||
|
|
@ -49,16 +58,27 @@ def _launch_one(ip: str, remote_cmd: str, log_path: str) -> None:
|
|||
"if command -v cloud-init >/dev/null 2>&1; then "
|
||||
"cloud-init status 2>/dev/null || true; else echo nocloudinit; fi"
|
||||
)
|
||||
log_q = shlex.quote(log_path)
|
||||
# On écrit un message d'attente + un battement toutes les ~30 s : sinon le
|
||||
# log reste VIDE pendant tout le boot émulé et paraît « bloqué ».
|
||||
msg_wait = t("Waiting for the VM to start (boot + cloud-init)")
|
||||
msg_slow = t("(an emulated architecture can be slow; this is normal)")
|
||||
msg_ready = t("VM ready - starting the ERPLibre install")
|
||||
wrapper = (
|
||||
f"for i in $(seq 1 144); do "
|
||||
f"echo {shlex.quote('== ' + msg_wait + ' ==')} >> {log_q}; "
|
||||
f"echo {shlex.quote(' ' + msg_slow)} >> {log_q}; "
|
||||
f"for i in $(seq 1 240); do "
|
||||
f"st=$(ssh {SSH_OPTS} -o BatchMode=yes erplibre@{ip} "
|
||||
f"{shlex.quote(ci_probe)} 2>/dev/null); "
|
||||
f'case "$st" in '
|
||||
f"*done*|*disabled*|*error*|*degraded*|*nocloudinit*) break;; "
|
||||
f"esac; sleep 5; done; "
|
||||
f"esac; "
|
||||
f'if [ $((i % 6)) -eq 0 ]; then echo " ... $((i*5))s" >> {log_q}; fi; '
|
||||
f"sleep 5; done; "
|
||||
f"echo {shlex.quote('== ' + msg_ready + ' ==')} >> {log_q}; "
|
||||
f"ssh {SSH_OPTS} erplibre@{ip} {shlex.quote(remote_cmd)} "
|
||||
f"> {shlex.quote(log_path)} 2>&1; "
|
||||
f'echo "{EXIT_MARKER} $?" >> {shlex.quote(log_path)}'
|
||||
f">> {log_q} 2>&1; "
|
||||
f'echo "{EXIT_MARKER} $?" >> {log_q}'
|
||||
)
|
||||
# setsid -f : le process survit à la fermeture du menu / du dashboard.
|
||||
subprocess.Popen(
|
||||
|
|
|
|||
|
|
@ -1041,7 +1041,7 @@ class TODO:
|
|||
distro = self._qemu_prompt_distro()
|
||||
version = self._qemu_prompt_version(distro)
|
||||
arch = self._qemu_prompt_arch(distro)
|
||||
default_name = self._qemu_infra_name(distro, version)
|
||||
default_name = self._qemu_infra_name(distro, version, arch)
|
||||
name = (
|
||||
input(f"{t('VM name (default: ')}{default_name}): ").strip()
|
||||
or default_name
|
||||
|
|
@ -1608,10 +1608,16 @@ class TODO:
|
|||
spec.loader.exec_module(mod)
|
||||
return mod
|
||||
|
||||
@staticmethod
|
||||
def _qemu_infra_name(distro, version):
|
||||
"""Nom de VM stable pour le parc, ex. erplibre-ubuntu-2404."""
|
||||
return f"erplibre-{distro}-{version.replace('.', '')}"
|
||||
@classmethod
|
||||
def _qemu_infra_name(cls, distro, version, arch=None):
|
||||
"""Nom de VM stable pour le parc, ex. erplibre-ubuntu-2404. Ajoute un
|
||||
suffixe d'architecture quand elle diffère de la native de l'hôte (ex.
|
||||
erplibre-ubuntu-2604-s390x sur un hôte amd64) pour éviter les collisions
|
||||
de noms entre archis et rendre l'archi visible."""
|
||||
base = f"erplibre-{distro}-{version.replace('.', '')}"
|
||||
if arch and arch != cls._native_arch():
|
||||
base += f"-{arch}"
|
||||
return base
|
||||
|
||||
@staticmethod
|
||||
def _parse_disk_gb(size):
|
||||
|
|
@ -1743,7 +1749,7 @@ class TODO:
|
|||
ERPLIBRE_EXTRA_DISK_GB = 5
|
||||
|
||||
@staticmethod
|
||||
def _qemu_wait_ssh(ip, user="erplibre", timeout=720):
|
||||
def _qemu_wait_ssh(ip, user="erplibre", timeout=1200):
|
||||
"""Attend que sshd réponde ET que cloud-init soit TERMINÉ, via des
|
||||
connexions COURTES successives. Au 1er boot, cloud-init régénère les
|
||||
clés d'hôte et REDÉMARRE sshd : attendre la fin de cloud-init AVANT de
|
||||
|
|
@ -2049,7 +2055,7 @@ class TODO:
|
|||
free_ram = self._host_free_ram_mb()
|
||||
print(f"\n{t('Deployment plan')} ({len(selected)} VM) :")
|
||||
for d, v, ram, disk in selected:
|
||||
name = self._qemu_infra_name(d, v)
|
||||
name = self._qemu_infra_name(d, v, arch)
|
||||
print(f" - {name:<26} {d} {v:<7} RAM {ram}Mo {t('disk')} {disk}")
|
||||
print(f"\n {t('Total RAM (all running):')} {total_ram} Mo")
|
||||
print(f" {t('Total virtual disk (thin qcow2):')} ~{total_disk} G")
|
||||
|
|
@ -2108,7 +2114,7 @@ class TODO:
|
|||
deployed = []
|
||||
jobs = [] # (name, parts) des VM à créer
|
||||
for d, v, _ram, disk in selected:
|
||||
name = self._qemu_infra_name(d, v)
|
||||
name = self._qemu_infra_name(d, v, arch)
|
||||
if self._qemu_domain_exists(name):
|
||||
print(f"⏭ {name}: {t('already exists, skipped.')}")
|
||||
deployed.append(name)
|
||||
|
|
|
|||
|
|
@ -1197,6 +1197,18 @@ TRANSLATIONS = {
|
|||
"fr": "images pour cette architecture disponibles seulement pour :",
|
||||
"en": "images for this arch only exist for:",
|
||||
},
|
||||
"Waiting for the VM to start (boot + cloud-init)": {
|
||||
"fr": "En attente du démarrage de la VM (boot + cloud-init)",
|
||||
"en": "Waiting for the VM to start (boot + cloud-init)",
|
||||
},
|
||||
"(an emulated architecture can be slow; this is normal)": {
|
||||
"fr": "(une architecture émulée peut être lente ; c'est normal)",
|
||||
"en": "(an emulated architecture can be slow; this is normal)",
|
||||
},
|
||||
"VM ready - starting the ERPLibre install": {
|
||||
"fr": "VM prête — installation ERPLibre en cours",
|
||||
"en": "VM ready - starting the ERPLibre install",
|
||||
},
|
||||
"Choice (number or name, blank = native):": {
|
||||
"fr": "Choix (numéro ou nom, vide = native) :",
|
||||
"en": "Choice (number or name, blank = native):",
|
||||
|
|
|
|||
Loading…
Reference in a new issue