From 7bd44d21a97410dbe4919b3a62dc3595c4a3ece7 Mon Sep 17 00:00:00 2001 From: Mathieu Benoit Date: Tue, 28 Jul 2026 09:22:46 +0000 Subject: [PATCH] =?UTF-8?q?[FIX]=20script=20qemu:=20t=C3=A9l=C3=A9chargeme?= =?UTF-8?q?nt=20complet=20v=C3=A9rifi=C3=A9=20+=20arm64=20sans=20Secure=20?= =?UTF-8?q?Boot?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Une VM arm64 (Fedora aarch64 émulée) restait FIGÉE au firmware (CPU ~2 %, aucune IP, seed non appliqué). Deux causes : 1) Téléchargement tronqué non détecté. _download_one ne vérifiait pas que le nombre d'octets reçus == Content-Length. Une connexion coupée en cours laissait un .part TRONQUÉ, validé comme « complet » (tmp.replace) : un qcow2 valide mais VIDE (128 Kio, juste l'en-tête, 5 Gio virtuels) -> disque sans OS -> pas de boot. Pire, ce cache corrompu était réutilisé. Fix : contrôle de complétude (done < total -> exception -> miroir suivant ou échec net, jamais de commit d'un fichier tronqué). 2) arm64 : « --boot uefi » simple laissait libvirt choisir l'AAVMF « secure » (clés Microsoft enrôlées) -> pas de boot. On désactive Secure Boot comme pour x86 (secure-boot=no -> AAVMF_CODE.no-secboot.fd). Validé : redéploiement Fedora 42 aarch64 avec image complète + firmware non-SB -> CPU 111 % (boot actif), IP en ~80 s, SSH OK (erplibre, aarch64, Fedora 42 Cloud, sudo OK). Co-Authored-By: Claude Opus 4.8 (1M context) --- script/qemu/deploy_qemu.py | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/script/qemu/deploy_qemu.py b/script/qemu/deploy_qemu.py index fe5cfae..01f49ae 100755 --- a/script/qemu/deploy_qemu.py +++ b/script/qemu/deploy_qemu.py @@ -766,6 +766,15 @@ def _download_one(url: str, tmp: Path, timeout: int) -> None: print(f" {pct:3d}%", flush=True) if is_tty: print() + # Vérifie la COMPLÉTUDE : si le serveur a annoncé une taille et qu'on a + # reçu moins (connexion coupée), le .part est TRONQUÉ. Sans ce contrôle, + # il était validé comme « complet » -> qcow2 valide mais VIDE (juste + # l'en-tête) -> VM qui ne boote pas, et cache empoisonné réutilisé ensuite. + if total > 0 and done < total: + raise OSError( + f"téléchargement incomplet : {done}/{total} octets reçus " + "(connexion interrompue)" + ) def download_image( @@ -1145,10 +1154,20 @@ def virt_install( # disque (ni BIOS ni UEFI/OVMF -> aucun --boot). cmd += ["--arch", "s390x", "--machine", "s390-ccw-virtio"] elif args.arch == "arm64": - # arm64/aarch64 : machine « virt » + UEFI (firmware AAVMF résolu par - # libvirt d'après --arch aarch64). Les images cloud arm64 n'ont pas de - # BIOS -> UEFI obligatoire. - cmd += ["--arch", "aarch64", "--machine", "virt", "--boot", "uefi"] + # arm64/aarch64 : machine « virt » + UEFI (firmware AAVMF). Les images + # cloud arm64 n'ont pas de BIOS -> UEFI obligatoire. Secure Boot + # DÉSACTIVÉ (comme x86) : sinon libvirt sélectionne l'AAVMF « secure » + # à clés Microsoft enrôlées et la VM RESTE FIGÉE au firmware (aucun + # boot, aucune IP). secure-boot=no -> AAVMF non-SB, boot OK. + cmd += [ + "--arch", + "aarch64", + "--machine", + "virt", + "--boot", + "uefi,firmware.feature0.name=secure-boot," + "firmware.feature0.enabled=no", + ] elif not args.bios: # Boot UEFI par défaut (x86) : Debian 13 (trixie) et les images cloud # récentes n'embarquent plus le chargeur BIOS/GRUB-pc et partent en