[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:
parent
b395e7c3ed
commit
939e26ba83
3 changed files with 87 additions and 4 deletions
|
|
@ -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:
|
def launch_installs(vms: list[dict], branch: str, remote_cmd: str) -> str:
|
||||||
"""vms : [{name, ip}]. Lance chaque install détachée, écrit un manifeste
|
"""vms : [{name, ip, distro?, version?, arch?}]. Lance chaque install
|
||||||
et retourne son chemin. remote_cmd : script exécuté dans chaque VM."""
|
détachée, écrit un manifeste et retourne son chemin. remote_cmd : script
|
||||||
|
exécuté dans chaque VM."""
|
||||||
sdir = session_dir()
|
sdir = session_dir()
|
||||||
stamp = time.strftime("%Y%m%d-%H%M%S")
|
stamp = time.strftime("%Y%m%d-%H%M%S")
|
||||||
|
when = time.strftime("%Y-%m-%d %H:%M:%S")
|
||||||
logdir = sdir / stamp
|
logdir = sdir / stamp
|
||||||
logdir.mkdir(parents=True, exist_ok=True)
|
logdir.mkdir(parents=True, exist_ok=True)
|
||||||
entries = []
|
entries = []
|
||||||
for vm in vms:
|
for vm in vms:
|
||||||
log_path = str(logdir / f"{vm['name']}.log")
|
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)
|
_launch_one(vm["ip"], remote_cmd, log_path)
|
||||||
entries.append(
|
entries.append(
|
||||||
{
|
{
|
||||||
"name": vm["name"],
|
"name": vm["name"],
|
||||||
"ip": vm["ip"],
|
"ip": vm["ip"],
|
||||||
|
"distro": vm.get("distro"),
|
||||||
|
"version": vm.get("version"),
|
||||||
|
"arch": vm.get("arch"),
|
||||||
"log": log_path,
|
"log": log_path,
|
||||||
"ssh": f"ssh erplibre@{vm['ip']}",
|
"ssh": f"ssh erplibre@{vm['ip']}",
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1763,6 +1763,40 @@ 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_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):
|
def _qemu_pick_branch(self):
|
||||||
"""Liste les branches distantes d'ERPLibre et en fait choisir une."""
|
"""Liste les branches distantes d'ERPLibre et en fait choisir une."""
|
||||||
print(f"\n{t('Fetching ERPLibre branch list...')}")
|
print(f"\n{t('Fetching ERPLibre branch list...')}")
|
||||||
|
|
@ -1928,12 +1962,29 @@ class TODO:
|
||||||
)
|
)
|
||||||
|
|
||||||
remote = self._qemu_erplibre_remote_cmd(branch)
|
remote = self._qemu_erplibre_remote_cmd(branch)
|
||||||
|
try:
|
||||||
|
mod = self._qemu_import_module()
|
||||||
|
except Exception:
|
||||||
|
mod = None
|
||||||
vms = []
|
vms = []
|
||||||
for name in names:
|
for name in names:
|
||||||
print(f" {name}: {t('resolving IP...')}")
|
print(f" {name}: {t('resolving IP...')}")
|
||||||
ip = self._qemu_vm_ip(name)
|
ip = self._qemu_vm_ip(name)
|
||||||
if ip:
|
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:
|
else:
|
||||||
print(f" {name}: {t('no IP, skipped.')}")
|
print(f" {name}: {t('no IP, skipped.')}")
|
||||||
if not vms:
|
if not vms:
|
||||||
|
|
|
||||||
|
|
@ -1201,6 +1201,10 @@ TRANSLATIONS = {
|
||||||
"fr": "Toutes les architectures supportées",
|
"fr": "Toutes les architectures supportées",
|
||||||
"en": "All supported architectures",
|
"en": "All supported architectures",
|
||||||
},
|
},
|
||||||
|
"installation": {
|
||||||
|
"fr": "installation",
|
||||||
|
"en": "installation",
|
||||||
|
},
|
||||||
"(includes emulated architectures — some VMs are slow)": {
|
"(includes emulated architectures — some VMs are slow)": {
|
||||||
"fr": "(inclut des architectures émulées — certaines VM sont lentes)",
|
"fr": "(inclut des architectures émulées — certaines VM sont lentes)",
|
||||||
"en": "(includes emulated architectures — some VMs are slow)",
|
"en": "(includes emulated architectures — some VMs are slow)",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue