[ADD] script qemu: support architecture s390x (IBM Z, Ubuntu)
Ajoute --arch s390x au déploiement QEMU. Réalité constatée (juillet 2026) : seul Ubuntu publie des images cloud s390x (cloud-images.ubuntu.com : OK) ; Debian et Fedora n'en publient pas (404), Arch ne cible que x86_64/aarch64. s390x est donc scopé à Ubuntu et rejeté proprement pour les autres distros. deploy_qemu.py : - FOREIGN_ARCHES / S390X_DISTROS : s390x n'est valide que pour Ubuntu. - virt_install : sur s390x -> --arch s390x, --machine s390-ccw-virtio, --virt-type qemu (émulation TCG, pas de KVM sur hôte x86), console SCLP (pas de série ISA), amorçage IPL/zipl (aucun --boot UEFI/BIOS). Les disques/réseau bus=virtio sont mappés en virtio-ccw par libvirt. - ensure_s390x_emulator : installe qemu-system-s390x au besoin (apt: qemu-system-misc, dnf: qemu-system-s390x, pacman: qemu-emulators-full, zypper: qemu-s390). - Avertit que s390x est ÉMULÉ (lent) sur un hôte x86. todo.py : le menu « Déployer une VM » demande l'architecture (s390x proposé uniquement pour Ubuntu, avec avertissement lenteur) et passe --arch. install_debian_dependency.sh : wkhtmltopdf n'a pas de build s390x -> skip best-effort au lieu d'avorter l'install (la branche s390x rust-all existait déjà pour compiler les wheels). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
deddaeb6a9
commit
37a999b911
4 changed files with 165 additions and 11 deletions
|
|
@ -187,7 +187,11 @@ fi
|
||||||
#--------------------------------------------------
|
#--------------------------------------------------
|
||||||
# Install Wkhtmltopdf if needed
|
# Install Wkhtmltopdf if needed
|
||||||
#--------------------------------------------------
|
#--------------------------------------------------
|
||||||
if [ ${EL_INSTALL_WKHTMLTOPDF} = "True" ]; then
|
if [ "$(uname -m)" = "s390x" ]; then
|
||||||
|
# wkhtmltopdf ne publie pas de build s390x (WKHTMLTOX_X64 est de l'amd64).
|
||||||
|
# On saute proprement plutôt que d'avorter tout l'install.
|
||||||
|
echo "wkhtmltopdf : pas de build s390x, ignoré (optionnel)."
|
||||||
|
elif [ ${EL_INSTALL_WKHTMLTOPDF} = "True" ]; then
|
||||||
echo -e "\n---- Installing wkhtml ----"
|
echo -e "\n---- Installing wkhtml ----"
|
||||||
INSTALLED=$(dpkg -s wkhtmltox | grep installed)
|
INSTALLED=$(dpkg -s wkhtmltox | grep installed)
|
||||||
if [ "" == "${INSTALLED}" ]; then
|
if [ "" == "${INSTALLED}" ]; then
|
||||||
|
|
|
||||||
|
|
@ -104,11 +104,22 @@ DISTROS: dict[str, tuple[dict[str, tuple[str, str, int, str]], str]] = {
|
||||||
}
|
}
|
||||||
|
|
||||||
# Traduction de l'arch générique (amd64/arm64) vers le nom propre à la distro.
|
# Traduction de l'arch générique (amd64/arm64) vers le nom propre à la distro.
|
||||||
|
# s390x s'écrit « s390x » partout (identité), donc aucune entrée n'est requise.
|
||||||
ARCH_ALIASES: dict[str, dict[str, str]] = {
|
ARCH_ALIASES: dict[str, dict[str, str]] = {
|
||||||
"fedora": {"amd64": "x86_64", "arm64": "aarch64"},
|
"fedora": {"amd64": "x86_64", "arm64": "aarch64"},
|
||||||
"arch": {"amd64": "x86_64", "arm64": "aarch64"},
|
"arch": {"amd64": "x86_64", "arm64": "aarch64"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Architectures « étrangères » à un hôte x86 : émulées en TCG (pas de KVM),
|
||||||
|
# donc LENTES, avec une machine et un amorçage spécifiques (voir virt_install).
|
||||||
|
FOREIGN_ARCHES: tuple[str, ...] = ("s390x",)
|
||||||
|
|
||||||
|
# Distros publiant des images cloud s390x (IBM Z). Seul Ubuntu en publie :
|
||||||
|
# Debian et Fedora n'ont pas de qcow2 cloud s390x ; Arch ne cible que
|
||||||
|
# x86_64/aarch64. Vérifié en juillet 2026 (cloud-images.ubuntu.com : OK ;
|
||||||
|
# cloud.debian.org & fedora-secondary : 404).
|
||||||
|
S390X_DISTROS: tuple[str, ...] = ("ubuntu",)
|
||||||
|
|
||||||
ARCH_CLOUD_BASE = "https://geo.mirror.pkgbuild.com/images/latest"
|
ARCH_CLOUD_BASE = "https://geo.mirror.pkgbuild.com/images/latest"
|
||||||
|
|
||||||
CLOUD_IMG_BASE = "https://cloud-images.ubuntu.com"
|
CLOUD_IMG_BASE = "https://cloud-images.ubuntu.com"
|
||||||
|
|
@ -388,6 +399,17 @@ DAEMON_PACKAGES: dict[str, list[str]] = {
|
||||||
"brew": [],
|
"brew": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Émulateur QEMU système s390x (IBM Z). Requis UNIQUEMENT pour --arch s390x sur
|
||||||
|
# un hôte non-s390x : virt-install a besoin du binaire qemu-system-s390x. Sur
|
||||||
|
# apt, qemu-system-misc fournit tous les émulateurs non-x86 (dont s390x).
|
||||||
|
S390X_EMULATOR_PACKAGES: dict[str, list[str]] = {
|
||||||
|
"apt": ["qemu-system-misc"],
|
||||||
|
"dnf": ["qemu-system-s390x"],
|
||||||
|
"pacman": ["qemu-emulators-full"],
|
||||||
|
"zypper": ["qemu-s390"],
|
||||||
|
"brew": [],
|
||||||
|
}
|
||||||
|
|
||||||
# Gestionnaires de paquets, dans l'ordre de préférence :
|
# Gestionnaires de paquets, dans l'ordre de préférence :
|
||||||
# (clé TOOL_PACKAGES, binaire à détecter, commande d'installation, sudo, refresh)
|
# (clé TOOL_PACKAGES, binaire à détecter, commande d'installation, sudo, refresh)
|
||||||
PKG_MANAGERS: tuple[
|
PKG_MANAGERS: tuple[
|
||||||
|
|
@ -596,6 +618,52 @@ def ensure_tools(runner: Runner, assume_yes: bool, no_install: bool) -> None:
|
||||||
ensure_libvirt_service(runner)
|
ensure_libvirt_service(runner)
|
||||||
|
|
||||||
|
|
||||||
|
def ensure_s390x_emulator(
|
||||||
|
runner: Runner, assume_yes: bool, no_install: bool
|
||||||
|
) -> None:
|
||||||
|
"""Vérifie que qemu-system-s390x est présent (requis pour --arch s390x sur
|
||||||
|
un hôte x86) ; l'installe au besoin via le gestionnaire de paquets."""
|
||||||
|
if shutil.which("qemu-system-s390x"):
|
||||||
|
return
|
||||||
|
pm = detect_pkg_manager()
|
||||||
|
if pm is None:
|
||||||
|
sys.exit(
|
||||||
|
" Émulateur s390x introuvable (qemu-system-s390x) et gestionnaire "
|
||||||
|
"de paquets non reconnu.\n Installez-le manuellement."
|
||||||
|
)
|
||||||
|
pm_key, install_cmd, use_sudo, refresh = pm
|
||||||
|
packages = S390X_EMULATOR_PACKAGES.get(pm_key, [])
|
||||||
|
if not packages:
|
||||||
|
sys.exit(
|
||||||
|
" Émulateur s390x introuvable (qemu-system-s390x) : installez le "
|
||||||
|
"paquet QEMU système s390x de votre distribution."
|
||||||
|
)
|
||||||
|
full_cmd = install_cmd + packages
|
||||||
|
printable = ("sudo " if use_sudo and runner.use_sudo else "") + " ".join(
|
||||||
|
full_cmd
|
||||||
|
)
|
||||||
|
print(" Émulateur s390x manquant (qemu-system-s390x).")
|
||||||
|
print(f" Commande d'installation : {printable}")
|
||||||
|
if no_install:
|
||||||
|
sys.exit(
|
||||||
|
" Installation automatique désactivée (--no-install-deps).\n"
|
||||||
|
" Installez manuellement : " + printable
|
||||||
|
)
|
||||||
|
if not assume_yes and not prompt_yes_no(
|
||||||
|
" Installer l'émulateur s390x maintenant ?"
|
||||||
|
):
|
||||||
|
sys.exit(" Installation refusée.\n Commande manuelle : " + printable)
|
||||||
|
if refresh:
|
||||||
|
runner.run(refresh, privileged=use_sudo, check=False)
|
||||||
|
runner.run(full_cmd, privileged=use_sudo)
|
||||||
|
if not shutil.which("qemu-system-s390x"):
|
||||||
|
sys.exit(
|
||||||
|
" qemu-system-s390x toujours absent après installation.\n"
|
||||||
|
f" Essayez manuellement : {printable}"
|
||||||
|
)
|
||||||
|
print(" Émulateur s390x installé avec succès.")
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------- #
|
# --------------------------------------------------------------------------- #
|
||||||
# Étapes
|
# Étapes
|
||||||
# --------------------------------------------------------------------------- #
|
# --------------------------------------------------------------------------- #
|
||||||
|
|
@ -977,6 +1045,10 @@ def virt_install(
|
||||||
osinfo: str,
|
osinfo: str,
|
||||||
runner: Runner,
|
runner: Runner,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
foreign = args.arch in FOREIGN_ARCHES
|
||||||
|
# s390x n'a pas de port série ISA : la console est SCLP (ttysclp0), et non
|
||||||
|
# ttyS0. Ailleurs (x86), console série classique.
|
||||||
|
console_target = "sclp" if foreign else "serial"
|
||||||
cmd = [
|
cmd = [
|
||||||
"virt-install",
|
"virt-install",
|
||||||
"--name",
|
"--name",
|
||||||
|
|
@ -993,6 +1065,7 @@ def virt_install(
|
||||||
# volume « cidata » est visible dès init-local et cloud-init le lit.
|
# volume « cidata » est visible dès init-local et cloud-init le lit.
|
||||||
# En CD-ROM, l'initramfs Debian ne charge pas sr_mod à temps -> le
|
# En CD-ROM, l'initramfs Debian ne charge pas sr_mod à temps -> le
|
||||||
# seed n'est pas vu et rien ne s'applique (Ubuntu, lui, tolère le CD).
|
# seed n'est pas vu et rien ne s'applique (Ubuntu, lui, tolère le CD).
|
||||||
|
# Sur s390x, bus=virtio est mappé en virtio-ccw par libvirt.
|
||||||
"--disk",
|
"--disk",
|
||||||
f"path={seed},readonly=on,bus=virtio",
|
f"path={seed},readonly=on,bus=virtio",
|
||||||
"--osinfo",
|
"--osinfo",
|
||||||
|
|
@ -1002,16 +1075,28 @@ def virt_install(
|
||||||
"--graphics",
|
"--graphics",
|
||||||
args.graphics,
|
args.graphics,
|
||||||
"--console",
|
"--console",
|
||||||
"pty,target_type=serial",
|
f"pty,target_type={console_target}",
|
||||||
]
|
]
|
||||||
# Boot UEFI par défaut : Debian 13 (trixie) et les images cloud récentes
|
if foreign:
|
||||||
# n'embarquent plus le chargeur BIOS/GRUB-pc et partent en boucle
|
# s390x (IBM Z) sur hôte x86 : émulation TCG (--virt-type qemu, pas de
|
||||||
# « Booting... » en SeaBIOS. UEFI (OVMF) fonctionne pour Ubuntu/Debian/
|
# KVM), machine s390-ccw-virtio, amorçage IPL/zipl depuis le disque
|
||||||
# Fedora. --bios force l'ancien BIOS si OVMF est indisponible.
|
# (ni BIOS ni UEFI/OVMF -> aucun --boot). LENT (émulation logicielle).
|
||||||
# Secure Boot DÉSACTIVÉ : le chargeur d'Arch (GRUB) n'est pas signé et
|
cmd += [
|
||||||
# OVMF Secure Boot le refuse (« Access Denied » -> pas de boot). Ubuntu/
|
"--arch",
|
||||||
# Debian/Fedora bootent aussi sans Secure Boot (shim signé non requis).
|
"s390x",
|
||||||
if not args.bios:
|
"--machine",
|
||||||
|
"s390-ccw-virtio",
|
||||||
|
"--virt-type",
|
||||||
|
"qemu",
|
||||||
|
]
|
||||||
|
elif not args.bios:
|
||||||
|
# Boot UEFI par défaut : Debian 13 (trixie) et les images cloud
|
||||||
|
# récentes n'embarquent plus le chargeur BIOS/GRUB-pc et partent en
|
||||||
|
# boucle « Booting... » en SeaBIOS. UEFI (OVMF) fonctionne pour
|
||||||
|
# Ubuntu/Debian/Fedora. --bios force l'ancien BIOS si OVMF est absent.
|
||||||
|
# Secure Boot DÉSACTIVÉ : le chargeur d'Arch (GRUB) n'est pas signé et
|
||||||
|
# OVMF Secure Boot le refuse (« Access Denied » -> pas de boot).
|
||||||
|
# Ubuntu/Debian/Fedora bootent aussi sans Secure Boot.
|
||||||
cmd += [
|
cmd += [
|
||||||
"--boot",
|
"--boot",
|
||||||
"uefi,firmware.feature0.name=secure-boot,"
|
"uefi,firmware.feature0.name=secure-boot,"
|
||||||
|
|
@ -1097,7 +1182,8 @@ def build_parser() -> argparse.ArgumentParser:
|
||||||
g_img.add_argument(
|
g_img.add_argument(
|
||||||
"--arch",
|
"--arch",
|
||||||
default="amd64",
|
default="amd64",
|
||||||
help="Architecture de l'image (défaut : amd64).",
|
help="Architecture de l'image (défaut : amd64). s390x (IBM Z) n'est "
|
||||||
|
"disponible que pour Ubuntu et est ÉMULÉ (lent) sur un hôte x86.",
|
||||||
)
|
)
|
||||||
g_img.add_argument(
|
g_img.add_argument(
|
||||||
"--image-dir",
|
"--image-dir",
|
||||||
|
|
@ -1333,6 +1419,14 @@ def main() -> None:
|
||||||
f"Version {args.version!r} inconnue pour {args.distro}. "
|
f"Version {args.version!r} inconnue pour {args.distro}. "
|
||||||
f"Choix : {', '.join(versions)} (voir --list-images)."
|
f"Choix : {', '.join(versions)} (voir --list-images)."
|
||||||
)
|
)
|
||||||
|
# s390x n'est publié en image cloud que par Ubuntu (voir S390X_DISTROS).
|
||||||
|
if args.arch == "s390x" and args.distro not in S390X_DISTROS:
|
||||||
|
sys.exit(
|
||||||
|
f"Architecture s390x indisponible pour {args.distro!r} : seul "
|
||||||
|
f"Ubuntu publie des images cloud s390x ({', '.join(S390X_DISTROS)})."
|
||||||
|
"\n Debian/Fedora n'en publient pas ; Arch ne cible que "
|
||||||
|
"x86_64/aarch64."
|
||||||
|
)
|
||||||
code, default_osinfo, min_ram, min_disk = versions[args.version]
|
code, default_osinfo, min_ram, min_disk = versions[args.version]
|
||||||
if args.codename:
|
if args.codename:
|
||||||
code = args.codename
|
code = args.codename
|
||||||
|
|
@ -1404,6 +1498,14 @@ def main() -> None:
|
||||||
|
|
||||||
if not args.dry_run:
|
if not args.dry_run:
|
||||||
ensure_tools(runner, args.assume_yes, args.no_install_deps)
|
ensure_tools(runner, args.assume_yes, args.no_install_deps)
|
||||||
|
if args.arch in FOREIGN_ARCHES:
|
||||||
|
ensure_s390x_emulator(
|
||||||
|
runner, args.assume_yes, args.no_install_deps
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
" Note : s390x est ÉMULÉ (TCG) sur cet hôte — le boot et "
|
||||||
|
"l'installation seront nettement plus lents que x86."
|
||||||
|
)
|
||||||
|
|
||||||
print(f"\n== 1/5 Image cloud ({args.distro} {args.version} / {code}) ==")
|
print(f"\n== 1/5 Image cloud ({args.distro} {args.version} / {code}) ==")
|
||||||
download_image(urls, args.image_path, args.dry_run)
|
download_image(urls, args.image_path, args.dry_run)
|
||||||
|
|
|
||||||
|
|
@ -854,6 +854,32 @@ class TODO:
|
||||||
print(f"{t('Invalid selection, using')} {default}")
|
print(f"{t('Invalid selection, using')} {default}")
|
||||||
return default
|
return default
|
||||||
|
|
||||||
|
# Distros publiant des images cloud s390x (IBM Z). Seul Ubuntu en publie
|
||||||
|
# (cohérent avec S390X_DISTROS de deploy_qemu.py).
|
||||||
|
_QEMU_S390X_DISTROS = ("ubuntu",)
|
||||||
|
|
||||||
|
def _qemu_prompt_arch(self, distro):
|
||||||
|
"""Demande l'architecture. s390x n'est proposé que pour les distros qui
|
||||||
|
publient des images s390x (Ubuntu) ; il est ÉMULÉ (lent) sur x86."""
|
||||||
|
if distro not in self._QEMU_S390X_DISTROS:
|
||||||
|
return "amd64"
|
||||||
|
print(f"\n{t('Architecture:')}")
|
||||||
|
print(f" [1] amd64 *")
|
||||||
|
print(f" [2] s390x ({t('IBM Z — emulated, slow on x86')})")
|
||||||
|
sel = (
|
||||||
|
input(f"{t('Choice (number or name, blank = amd64):')} ")
|
||||||
|
.strip()
|
||||||
|
.lower()
|
||||||
|
)
|
||||||
|
if sel in ("2", "s390x"):
|
||||||
|
warn = t(
|
||||||
|
"s390x is emulated (TCG): boot and install are much "
|
||||||
|
"slower than x86."
|
||||||
|
)
|
||||||
|
print(f"⚠ {warn}")
|
||||||
|
return "s390x"
|
||||||
|
return "amd64"
|
||||||
|
|
||||||
def _qemu_list_images(self):
|
def _qemu_list_images(self):
|
||||||
"""Affiche la liste des distros/versions et leurs specs."""
|
"""Affiche la liste des distros/versions et leurs specs."""
|
||||||
cmd = f"{self._qemu_script_path()} --list-images"
|
cmd = f"{self._qemu_script_path()} --list-images"
|
||||||
|
|
@ -948,6 +974,7 @@ class TODO:
|
||||||
# Distro + version d'abord : permet de proposer un nom par défaut.
|
# Distro + version d'abord : permet de proposer un nom par défaut.
|
||||||
distro = self._qemu_prompt_distro()
|
distro = self._qemu_prompt_distro()
|
||||||
version = self._qemu_prompt_version(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)
|
||||||
name = (
|
name = (
|
||||||
input(f"{t('VM name (default: ')}{default_name}): ").strip()
|
input(f"{t('VM name (default: ')}{default_name}): ").strip()
|
||||||
|
|
@ -991,6 +1018,8 @@ class TODO:
|
||||||
parts.append("sudo")
|
parts.append("sudo")
|
||||||
parts.append(script_path)
|
parts.append(script_path)
|
||||||
parts += ["--name", name, "--distro", distro, "--version", version]
|
parts += ["--name", name, "--distro", distro, "--version", version]
|
||||||
|
if arch and arch != "amd64":
|
||||||
|
parts += ["--arch", arch]
|
||||||
if memory:
|
if memory:
|
||||||
parts += ["--memory", memory]
|
parts += ["--memory", memory]
|
||||||
if vcpus:
|
if vcpus:
|
||||||
|
|
|
||||||
|
|
@ -1162,6 +1162,25 @@ TRANSLATIONS = {
|
||||||
"fr": "Version pour",
|
"fr": "Version pour",
|
||||||
"en": "Version for",
|
"en": "Version for",
|
||||||
},
|
},
|
||||||
|
"Architecture:": {
|
||||||
|
"fr": "Architecture :",
|
||||||
|
"en": "Architecture:",
|
||||||
|
},
|
||||||
|
"IBM Z — emulated, slow on x86": {
|
||||||
|
"fr": "IBM Z — émulé, lent sur x86",
|
||||||
|
"en": "IBM Z — emulated, slow on x86",
|
||||||
|
},
|
||||||
|
"Choice (number or name, blank = amd64):": {
|
||||||
|
"fr": "Choix (numéro ou nom, vide = amd64) :",
|
||||||
|
"en": "Choice (number or name, blank = amd64):",
|
||||||
|
},
|
||||||
|
"s390x is emulated (TCG): boot and install are much "
|
||||||
|
"slower than x86.": {
|
||||||
|
"fr": "s390x est émulé (TCG) : le boot et l'installation sont bien "
|
||||||
|
"plus lents que x86.",
|
||||||
|
"en": "s390x is emulated (TCG): boot and install are much "
|
||||||
|
"slower than x86.",
|
||||||
|
},
|
||||||
"Choice (number or version, blank = default):": {
|
"Choice (number or version, blank = default):": {
|
||||||
"fr": "Choix (numéro ou version, vide = défaut) :",
|
"fr": "Choix (numéro ou version, vide = défaut) :",
|
||||||
"en": "Choice (number or version, blank = default):",
|
"en": "Choice (number or version, blank = default):",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue