From 2a4757f880fa9a178c268a939196bf5476958675 Mon Sep 17 00:00:00 2001 From: Olivier Gayot Date: Wed, 25 Sep 2024 14:18:15 +0200 Subject: [PATCH 1/2] kvm-test: allow to reuse an existing image without overwriting it kvm-test has three new options (with only the third one being really new). * `--preserve-target` which is an explicit way to abort if the target image already exists (this is the default behavior) * `--recreate-target` which mimics what `-o` / `--overwrite` does (i.e., recreating the target image even if it already exists). * `--reuse-target` which is the new one. When the option is supplied, we will reuse the disk without recreating it (if it already exists). When using the --reuse-target option, the firmware will try to boot from the disk. To work around the issue, quickly hit ESC and select `Boot Manager -> UEFI QEMU DVD-ROM`. Signed-off-by: Olivier Gayot --- scripts/kvm-test.py | 46 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/scripts/kvm-test.py b/scripts/kvm-test.py index 952daf589..f7fd2ae19 100755 --- a/scripts/kvm-test.py +++ b/scripts/kvm-test.py @@ -2,7 +2,7 @@ '''kvm-test - boot a kvm with a test iso, possibly building that test iso first -kvm-test -q --install -o --boot +kvm-test -q --install --recreate-target --boot slimy build, install, overwrite existing image if it exists, and boot the result after install @@ -14,6 +14,7 @@ import copy import crypt import dataclasses +import enum import os import pathlib import shlex @@ -52,6 +53,15 @@ ''' +class TargetOverwrite(enum.Enum): + # Abort if the target already exists + PRESERVE = enum.auto() + # Recreate the target if it already exists + RECREATE = enum.auto() + # Reuse the target if it already exists + REUSE = enum.auto() + + @dataclasses.dataclass class Profile: name: str @@ -156,7 +166,7 @@ def load_config(self): Test isos and images written to /tmp/kvm-test Sample usage: - kvm-test --build -q --install -o -a --boot + kvm-test --build -q --install --recreate-target -a --boot slimy build, run install, overwrite existing image, use autoinstall, boot final resulting image @@ -204,8 +214,20 @@ def load_config(self): metavar="argument", help='pass custom -nic argument to QEMU' ' - overrides --nets') -parser.add_argument('-o', '--overwrite', default=False, action='store_true', - help='allow overwrite of the target image') +target_overwrite_group = parser.add_mutually_exclusive_group() +target_overwrite_group.add_argument('--preserve-target', + dest='target_overwrite', + action='store_const', const=TargetOverwrite.PRESERVE, + help='reuse the target image if it exists') +target_overwrite_group.add_argument('-o', '--overwrite', '--recreate-target', + dest='target_overwrite', + action='store_const', const=TargetOverwrite.RECREATE, + help='recreate the target disk if it already exists') +target_overwrite_group.add_argument('--reuse-target', + dest='target_overwrite', + action='store_const', const=TargetOverwrite.REUSE, + help='reuse the target image if it exists') +target_overwrite_group.set_defaults(target_overwrite=TargetOverwrite.PRESERVE) parser.add_argument('-q', '--quick', default=False, action='store_true', help='build iso with quick-test-this-branch') parser.add_argument('-r', '--release', action='store', help='target release') @@ -543,11 +565,15 @@ def get_initrd(mntdir): def install(ctx): if os.path.exists(ctx.target): - if ctx.args.overwrite: - os.remove(ctx.target) - else: - raise Exception('refusing to overwrite existing image, use the ' + - '-o option to allow overwriting') + match ctx.args.target_overwrite: + case TargetOverwrite.RECREATE: + os.remove(ctx.target) + case TargetOverwrite.PRESERVE: + raise Exception('refusing to overwrite existing image, use the ' + + '--reuse-target or --recreate-target option to ' + + 'allow overwriting') + case TargetOverwrite.REUSE: + pass # Only copy the files with secureboot, always overwrite on install if ctx.args.secureboot: @@ -589,7 +615,7 @@ def install(ctx): kvm.extend(('-device', 'nvme,drive=localdisk0,serial=deadbeef')) case interface: raise ValueError('unsupported disk interface', interface) - if not os.path.exists(ctx.target) or ctx.args.overwrite: + if not os.path.exists(ctx.target): disksize = ctx.args.disksize or ctx.default_disk_size run(f'qemu-img create -f qcow2 {ctx.target} {disksize}') From d0ae2dae4020ac9ae8542d8c0b7073185b21b64a Mon Sep 17 00:00:00 2001 From: Olivier Gayot Date: Wed, 25 Sep 2024 15:32:15 +0200 Subject: [PATCH 2/2] kvm-test: try to boot from the installation media even when --reuse-target Signed-off-by: Olivier Gayot --- scripts/kvm-test.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/scripts/kvm-test.py b/scripts/kvm-test.py index f7fd2ae19..c04ccabf0 100755 --- a/scripts/kvm-test.py +++ b/scripts/kvm-test.py @@ -564,6 +564,7 @@ def get_initrd(mntdir): def install(ctx): + boot_opts = ["order=d"] if os.path.exists(ctx.target): match ctx.args.target_overwrite: case TargetOverwrite.RECREATE: @@ -573,7 +574,18 @@ def install(ctx): '--reuse-target or --recreate-target option to ' + 'allow overwriting') case TargetOverwrite.REUSE: - pass + if not ctx.args.bios: + boot_opts.append("menu=on") + note = """ +NOTE: +---- +The option -boot order=d only works in legacy BIOS mode. +When reusing a target image in UEFI mode, QEMU will try to boot from the disk \ +first; rather than from the installation media. To workaround the issue, mash \ +the ESC button when the QEMU window opens. Then select "Device Manager" and \ +"UEFI QEMU DVD-ROM". +----""" + print(note, file=sys.stderr) # Only copy the files with secureboot, always overwrite on install if ctx.args.secureboot: @@ -597,7 +609,7 @@ def install(ctx): else: iso = ctx.iso - kvm.extend(('-cdrom', iso)) + kvm.extend(('-cdrom', iso, '-boot', ','.join(boot_opts))) if ctx.args.serial: kvm.append('-nographic')