[IMP] script todo: en-tête d'install (date, distro, version, archi) dans le log

Le log d'installation commence désormais par un en-tête identifiant
l'installation : date, VM, distribution + version, architecture, branche, IP.
Écrit dès la création du log (plus jamais vide au démarrage).

_qemu_install_erplibre_monitored déduit distro/version/arch de chaque VM
(nom via _qemu_infra_name + arch via virsh dumpxml) et les passe à
launch_installs, qui écrit l'en-tête et les stocke dans le manifeste.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Mathieu Benoit 2026-07-28 08:57:36 +00:00
parent b395e7c3ed
commit 939e26ba83
3 changed files with 87 additions and 4 deletions

View file

@ -89,22 +89,50 @@ def _launch_one(ip: str, remote_cmd: str, log_path: str) -> None:
)
def _log_header(vm: dict, branch: str, when: str) -> str:
"""En-tête du log : date, VM, distribution, version, architecture, branche.
Permet d'identifier l'installation d'un coup d'œil (et de ne jamais laisser
le log vide pendant l'attente du boot)."""
distro = vm.get("distro") or "?"
version = vm.get("version") or ""
arch = vm.get("arch") or "?"
bar = "=" * 64
return (
f"{bar}\n"
f" ERPLibre — {t('installation')}\n"
f" Date : {when}\n"
f" VM : {vm['name']}\n"
f" Distribution : {distro} {version}\n"
f" Architecture : {arch}\n"
f" Branche : {branch}\n"
f" IP : {vm['ip']}\n"
f"{bar}\n\n"
)
def launch_installs(vms: list[dict], branch: str, remote_cmd: str) -> str:
"""vms : [{name, ip}]. Lance chaque install détachée, écrit un manifeste
et retourne son chemin. remote_cmd : script exécuté dans chaque VM."""
"""vms : [{name, ip, distro?, version?, arch?}]. Lance chaque install
détachée, écrit un manifeste et retourne son chemin. remote_cmd : script
exécuté dans chaque VM."""
sdir = session_dir()
stamp = time.strftime("%Y%m%d-%H%M%S")
when = time.strftime("%Y-%m-%d %H:%M:%S")
logdir = sdir / stamp
logdir.mkdir(parents=True, exist_ok=True)
entries = []
for vm in vms:
log_path = str(logdir / f"{vm['name']}.log")
Path(log_path).write_text("") # log vide = état « en attente »
# En-tête d'emblée (date/distro/version/arch) : le log n'est jamais
# vide, l'utilisateur voit tout de suite QUOI s'installe.
Path(log_path).write_text(_log_header(vm, branch, when))
_launch_one(vm["ip"], remote_cmd, log_path)
entries.append(
{
"name": vm["name"],
"ip": vm["ip"],
"distro": vm.get("distro"),
"version": vm.get("version"),
"arch": vm.get("arch"),
"log": log_path,
"ssh": f"ssh erplibre@{vm['ip']}",
}

View file

@ -1763,6 +1763,40 @@ 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_vm_arch(self, name):
"""Architecture d'une VM (jeton amd64/arm64/s390x) via virsh dumpxml."""
try:
res = subprocess.run(
["sudo", "virsh", "dumpxml", name],
capture_output=True,
text=True,
timeout=15,
)
except (OSError, subprocess.SubprocessError):
return None
m = re.search(r"<type[^>]*\barch='([^']+)'", res.stdout)
if not m:
return None
return {
"x86_64": "amd64",
"aarch64": "arm64",
"s390x": "s390x",
}.get(m.group(1), m.group(1))
def _qemu_vm_meta(self, name, mod):
"""(distro, version, arch) d'une VM déduits de son nom + son arch. Le
nom suit _qemu_infra_name(distro, version, arch) : on retrouve donc
(distro, version) en testant les combinaisons du catalogue."""
arch = self._qemu_vm_arch(name) or "amd64"
try:
for d, (versions, _default) in mod.DISTROS.items():
for v in versions:
if self._qemu_infra_name(d, v, arch) == name:
return d, v, arch
except Exception:
pass
return None, None, arch
def _qemu_pick_branch(self):
"""Liste les branches distantes d'ERPLibre et en fait choisir une."""
print(f"\n{t('Fetching ERPLibre branch list...')}")
@ -1928,12 +1962,29 @@ class TODO:
)
remote = self._qemu_erplibre_remote_cmd(branch)
try:
mod = self._qemu_import_module()
except Exception:
mod = None
vms = []
for name in names:
print(f" {name}: {t('resolving IP...')}")
ip = self._qemu_vm_ip(name)
if ip:
vms.append({"name": name, "ip": ip})
d, v, a = (
self._qemu_vm_meta(name, mod)
if mod
else (None, None, None)
)
vms.append(
{
"name": name,
"ip": ip,
"distro": d,
"version": v,
"arch": a,
}
)
else:
print(f" {name}: {t('no IP, skipped.')}")
if not vms:

View file

@ -1201,6 +1201,10 @@ TRANSLATIONS = {
"fr": "Toutes les architectures supportées",
"en": "All supported architectures",
},
"installation": {
"fr": "installation",
"en": "installation",
},
"(includes emulated architectures — some VMs are slow)": {
"fr": "(inclut des architectures émulées — certaines VM sont lentes)",
"en": "(includes emulated architectures — some VMs are slow)",