From ade7349711520aafe3b7307137a3687263e6cc2f Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Fri, 27 Dec 2024 12:07:56 +0100 Subject: [PATCH] Rename various [Runtime] options and rename mkosi qemu to mkosi vm - Let's get rid of the "Qemu" prefix for runtime options as they apply both to the qemu and vmspawn verbs. - Let's rename QemuGui= to Console= and make it take all the options that are accepted by vmspawn's --console= option. - Let's rename the various runtime options to the corresponding vmspawn option where applicable. - Let's rename mkosi qemu to mkosi vm as well while we're at it. --- .github/workflows/ci.yml | 2 +- docs/distribution-policy.md | 2 +- mkosi.conf | 2 +- mkosi.conf.d/15-memory.conf | 2 +- mkosi/__init__.py | 3 +- mkosi/config.py | 197 ++++++++++++++++++++------------- mkosi/qemu.py | 127 +++++++++++---------- mkosi/resources/man/mkosi.1.md | 182 +++++++++++++++--------------- mkosi/vmspawn.py | 34 +++--- tests/__init__.py | 14 +-- tests/test_boot.py | 12 +- tests/test_config.py | 7 +- tests/test_initrd.py | 12 +- tests/test_json.py | 148 ++++++++++++------------- 14 files changed, 389 insertions(+), 355 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4a8f7f83d..ee0c62dff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -178,7 +178,7 @@ jobs: Environment=SYSTEMD_REPART_MKFS_OPTIONS_EROFS="--quiet" [Runtime] - QemuKvm=yes + KVM=yes EOF # TODO: Remove once all distros have recent enough systemd that knows systemd.default_device_timeout_sec. diff --git a/docs/distribution-policy.md b/docs/distribution-policy.md index bc1604eb9..07a678b63 100644 --- a/docs/distribution-policy.md +++ b/docs/distribution-policy.md @@ -57,4 +57,4 @@ used: another existing distribution, update the `[Match]` blocks for the existing distribution to also match against the new distribution. To test whether all necessary changes were made, you can run - `mkosi -d --tools-tree -t disk -f qemu`. + `mkosi -d --tools-tree -t disk -f vm`. diff --git a/mkosi.conf b/mkosi.conf index 8e62fb3d7..03e43b75c 100644 --- a/mkosi.conf +++ b/mkosi.conf @@ -50,4 +50,4 @@ KernelModulesInitrdExclude=.* KernelModulesInitrdInclude=default [Runtime] -QemuMem=4G +RAM=4G diff --git a/mkosi.conf.d/15-memory.conf b/mkosi.conf.d/15-memory.conf index 6db5bb1e4..958fca11f 100644 --- a/mkosi.conf.d/15-memory.conf +++ b/mkosi.conf.d/15-memory.conf @@ -6,4 +6,4 @@ Format=|uki Format=|cpio [Runtime] -QemuMem=8G +RAM=8G diff --git a/mkosi/__init__.py b/mkosi/__init__.py index 5207a033d..e09e7c1f4 100644 --- a/mkosi/__init__.py +++ b/mkosi/__init__.py @@ -2623,7 +2623,7 @@ def check_tools(config: Config, verb: Verb) -> None: if verb == Verb.boot: check_systemd_tool(config, "systemd-nspawn", version="254", reason="boot images") - if verb == Verb.qemu and config.vmm == Vmm.vmspawn: + if verb in (Verb.vm, Verb.qemu) and config.vmm == Vmm.vmspawn: check_systemd_tool(config, "systemd-vmspawn", version="256", reason="boot images with vmspawn") if verb == Verb.sysupdate: @@ -4809,6 +4809,7 @@ def run_verb(args: Args, images: Sequence[Config], *, resources: Path) -> None: { Verb.shell: run_shell, Verb.boot: run_shell, + Verb.vm: run_vm, Verb.qemu: run_vm, Verb.serve: run_serve, Verb.burn: run_burn, diff --git a/mkosi/config.py b/mkosi/config.py index 9e976ec29..99a09a619 100644 --- a/mkosi/config.py +++ b/mkosi/config.py @@ -64,6 +64,7 @@ class Verb(StrEnum): cat_config = enum.auto() shell = enum.auto() boot = enum.auto() + vm = enum.auto() qemu = enum.auto() ssh = enum.auto() serve = enum.auto() @@ -84,6 +85,7 @@ def supports_cmdline(self) -> bool: Verb.build, Verb.shell, Verb.boot, + Verb.vm, Verb.qemu, Verb.ssh, Verb.journalctl, @@ -100,6 +102,7 @@ def needs_build(self) -> bool: Verb.build, Verb.shell, Verb.boot, + Verb.vm, Verb.qemu, Verb.serve, Verb.burn, @@ -145,7 +148,7 @@ def __str__(self) -> str: @dataclasses.dataclass(frozen=True) -class QemuDrive: +class Drive: id: str size: int directory: Optional[Path] @@ -155,16 +158,16 @@ class QemuDrive: # We use negative numbers for specifying special constants # for VSock CIDs since they're not valid CIDs anyway. -class QemuVsockCID(enum.IntEnum): +class VsockCID(enum.IntEnum): auto = -1 hash = -2 @classmethod def format(cls, cid: int) -> str: - if cid == QemuVsockCID.auto: + if cid == VsockCID.auto: return "auto" - if cid == QemuVsockCID.hash: + if cid == VsockCID.hash: return "hash" return str(cid) @@ -297,7 +300,7 @@ class Cacheonly(StrEnum): never = enum.auto() -class QemuFirmware(StrEnum): +class Firmware(StrEnum): auto = enum.auto() linux = enum.auto() uefi = enum.auto() @@ -305,7 +308,14 @@ class QemuFirmware(StrEnum): bios = enum.auto() def is_uefi(self) -> bool: - return self in (QemuFirmware.uefi, QemuFirmware.uefi_secure_boot) + return self in (Firmware.uefi, Firmware.uefi_secure_boot) + + +class ConsoleMode(StrEnum): + interactive = enum.auto() + read_only = enum.auto() + native = enum.auto() + gui = enum.auto() class Network(StrEnum): @@ -458,7 +468,7 @@ def to_oci(self) -> str: return a - def supports_smbios(self, firmware: QemuFirmware) -> bool: + def supports_smbios(self, firmware: Firmware) -> bool: if self.is_x86_variant(): return True @@ -1243,7 +1253,7 @@ def parse_profile(value: str) -> str: return value -def parse_drive(value: str) -> QemuDrive: +def parse_drive(value: str) -> Drive: parts = value.split(":", maxsplit=3) if not parts or not parts[0]: die(f"No ID specified for drive '{value}'") @@ -1264,7 +1274,7 @@ def parse_drive(value: str) -> QemuDrive: options = parts[3] if len(parts) > 3 and parts[3] else None file_id = parts[4] if len(parts) > 4 and parts[4] else id - return QemuDrive(id=id, size=size, directory=directory, options=options, file_id=file_id) + return Drive(id=id, size=size, directory=directory, options=options, file_id=file_id) def config_parse_sector_size(value: Optional[str], old: Optional[int]) -> Optional[int]: @@ -1290,10 +1300,10 @@ def config_parse_vsock_cid(value: Optional[str], old: Optional[int]) -> Optional return None if value == "auto": - return QemuVsockCID.auto + return VsockCID.auto if value == "hash": - return QemuVsockCID.hash + return VsockCID.hash try: cid = int(value) @@ -1874,22 +1884,21 @@ class Config: ssh_certificate: Optional[Path] machine: Optional[str] forward_journal: Optional[Path] - vmm: Vmm - # QEMU-specific options - qemu_gui: bool - qemu_smp: int - qemu_mem: int - qemu_kvm: ConfigFeature - qemu_vsock: ConfigFeature - qemu_vsock_cid: int - qemu_swtpm: ConfigFeature - qemu_cdrom: bool - qemu_removable: bool - qemu_firmware: QemuFirmware - qemu_firmware_variables: Optional[Path] - qemu_kernel: Optional[Path] - qemu_drives: list[QemuDrive] + vmm: Vmm + console: ConsoleMode + cpus: int + ram: int + kvm: ConfigFeature + vsock: ConfigFeature + vsock_cid: int + tpm: ConfigFeature + cdrom: bool + removable: bool + firmware: Firmware + firmware_variables: Optional[Path] + linux: Optional[Path] + drives: list[Drive] qemu_args: list[str] image: Optional[str] @@ -3425,7 +3434,7 @@ def parse_ini(path: Path, only_sections: Collection[str] = ()) -> Iterator[tuple metavar="NAME=VALUE", section="Runtime", parse=config_make_dict_parser(delimiter=" ", parse=parse_key_value, allow_paths=True, unescape=True), - help="Pass a systemd credential to systemd-nspawn or qemu", + help="Pass a systemd credential to a systemd-nspawn container or a virtual machine", paths=("mkosi.credentials",), ), ConfigSetting( @@ -3510,7 +3519,7 @@ def parse_ini(path: Path, only_sections: Collection[str] = ()) -> Iterator[tuple choices=Vmm.choices(), parse=config_make_enum_parser(Vmm), default=Vmm.qemu, - help="Set the virtual machine monitor to use for mkosi qemu", + help="Set the virtual machine monitor to use for mkosi vm", ), ConfigSetting( dest="machine", @@ -3537,108 +3546,137 @@ def parse_ini(path: Path, only_sections: Collection[str] = ()) -> Iterator[tuple help="Directory containing systemd-sysupdate transfer definitions", ), ConfigSetting( - dest="qemu_gui", - metavar="BOOL", + dest="console", + metavar="MODE", nargs="?", section="Runtime", - parse=config_parse_boolean, - help="Start QEMU in graphical mode", + parse=config_make_enum_parser(ConsoleMode), + help="Configure the virtual machine console mode to use", + default=ConsoleMode.native, ), ConfigSetting( - dest="qemu_smp", - metavar="SMP", + dest="cpus", + name="CPUs", + metavar="CPUS", section="Runtime", parse=config_parse_number, default=1, - help="Configure guest's SMP settings", + help="Configure number of CPUs in virtual machine", + compat_longs=("--qemu-smp",), + compat_names=("QemuSmp",), ), ConfigSetting( - dest="qemu_mem", - metavar="MEM", + dest="ram", + name="RAM", + metavar="BYTES", section="Runtime", parse=config_parse_bytes, default=parse_bytes("2G"), help="Configure guest's RAM size", + compat_longs=("--qemu-mem",), + compat_names=("QemuMem",), ), ConfigSetting( - dest="qemu_kvm", + dest="kvm", + name="KVM", metavar="FEATURE", nargs="?", section="Runtime", parse=config_parse_feature, help="Configure whether to use KVM or not", + compat_longs=("--qemu-kvm",), + compat_names=("QemuKvm",), ), ConfigSetting( - dest="qemu_vsock", + dest="vsock", metavar="FEATURE", nargs="?", section="Runtime", parse=config_parse_feature, - help="Configure whether to use qemu with a vsock or not", + help="Configure whether to use vsock or not", + compat_longs=("--qemu-vsock",), + compat_names=("QemuVsock",), ), ConfigSetting( - dest="qemu_vsock_cid", - name="QemuVsockConnectionId", - long="--qemu-vsock-cid", + dest="vsock_cid", + name="VsockConnectionId", + long="--vsock-cid", metavar="NUMBER|auto|hash", section="Runtime", parse=config_parse_vsock_cid, - default=QemuVsockCID.auto, - help="Specify the VSock connection ID to use", + default=VsockCID.auto, + help="Specify the vsock connection ID to use", + compat_longs=("--qemu-vsock-cid",), + compat_names=("QemuVsockConnectionId",), ), ConfigSetting( - dest="qemu_swtpm", + dest="tpm", + name="TPM", metavar="FEATURE", nargs="?", section="Runtime", parse=config_parse_feature, - help="Configure whether to use qemu with swtpm or not", + help="Configure whether to use a virtual tpm or not", + compat_longs=("--qemu-swtpm",), + compat_names=("QemuSwtpm",), ), ConfigSetting( - dest="qemu_cdrom", + dest="cdrom", metavar="BOOLEAN", nargs="?", section="Runtime", parse=config_parse_boolean, help="Attach the image as a CD-ROM to the virtual machine", + compat_longs=("--qemu-cdrom",), + compat_names=("QemuCdrom",), ), ConfigSetting( - dest="qemu_removable", + dest="removable", metavar="BOOLEAN", nargs="?", section="Runtime", parse=config_parse_boolean, help="Attach the image as a removable drive to the virtual machine", + compat_longs=("--qemu-removable",), + compat_names=("QemuRemovable",), ), ConfigSetting( - dest="qemu_firmware", + dest="firmware", section="Runtime", - parse=config_make_enum_parser(QemuFirmware), - default=QemuFirmware.auto, - help="Set qemu firmware to use", - choices=QemuFirmware.choices(), + parse=config_make_enum_parser(Firmware), + default=Firmware.auto, + help="Select the virtual machine firmware to use", + choices=Firmware.choices(), + compat_longs=("--qemu-firmware",), + compat_names=("QemuFirmware",), ), ConfigSetting( - dest="qemu_firmware_variables", + dest="firmware_variables", metavar="PATH", section="Runtime", parse=config_make_path_parser(constants=("custom", "microsoft")), - help="Set the path to the qemu firmware variables file to use", + help="Set the path to the firmware variables file to use", + compat_longs=("--qemu-firmware-variables",), + compat_names=("QemuFirmwareVariables",), ), ConfigSetting( - dest="qemu_kernel", + dest="linux", metavar="PATH", section="Runtime", parse=config_make_path_parser(), - help="Specify the kernel to use for qemu direct kernel boot", + help="Specify the kernel to use for direct kernel boot", + compat_longs=("--qemu-kernel",), + compat_names=("QemuKernel",), ), ConfigSetting( - dest="qemu_drives", - long="--qemu-drive", + dest="drives", + long="--drive", metavar="DRIVE", section="Runtime", parse=config_make_list_parser(delimiter=" ", parse=parse_drive), - help="Specify a qemu drive that mkosi should create and pass to qemu", + help="Specify drive that mkosi should create and pass to the virtual machine", + compat_longs=("--qemu-drive",), + compat_names=("QemuDrives",), ), ConfigSetting( dest="qemu_args", @@ -3725,7 +3763,7 @@ def create_argument_parser(chdir: bool = True) -> argparse.ArgumentParser: mkosi [options…] {b}build{e} [command line…] mkosi [options…] {b}shell{e} [command line…] mkosi [options…] {b}boot{e} [nspawn settings…] - mkosi [options…] {b}qemu{e} [qemu parameters…] + mkosi [options…] {b}vm{e} [vmm parameters…] mkosi [options…] {b}ssh{e} [command line…] mkosi [options…] {b}journalctl{e} [command line…] mkosi [options…] {b}coredumpctl{e} [command line…] @@ -4411,7 +4449,7 @@ def parse_config( hint="Build with -f to generate a new history file from scratch", ) - # If we're operating on a previously built image (qemu, boot, shell, ...), we're not rebuilding the + # If we're operating on a previously built image (vm, boot, shell, ...), we're not rebuilding the # image and the configuration of the latest build is available, we load the config that was used to # build the previous image from there instead of parsing configuration files, except for the Host # section settings which we allow changing without requiring a rebuild of the image. @@ -4899,17 +4937,17 @@ def summary(config: Config) -> str: Register guest with machined: {yes_no(config.register)} Virtual Machine Monitor: {config.vmm} - QEMU GUI: {yes_no(config.qemu_gui)} - QEMU CPU Cores: {config.qemu_smp} - QEMU Memory: {config.qemu_mem} - QEMU Use KVM: {config.qemu_kvm} - QEMU Use VSock: {config.qemu_vsock} - QEMU VSock Connection ID: {QemuVsockCID.format(config.qemu_vsock_cid)} - QEMU Use Swtpm: {config.qemu_swtpm} - QEMU Use CD-ROM: {yes_no(config.qemu_cdrom)} - QEMU Firmware: {config.qemu_firmware} - QEMU Firmware Variables: {none_to_none(config.qemu_firmware_variables)} - QEMU Kernel: {none_to_none(config.qemu_kernel)} + Console: {config.console} + CPU Cores: {config.cpus} + RAM: {format_bytes(config.ram)} + KVM: {config.kvm} + VSock: {config.vsock} + VSock Connection ID: {VsockCID.format(config.vsock_cid)} + TPM: {config.tpm} + CD-ROM: {yes_no(config.cdrom)} + Firmware: {config.firmware} + Firmware Variables: {none_to_none(config.firmware_variables)} + Linux: {none_to_none(config.linux)} QEMU Extra Arguments: {line_join_list(config.qemu_args)} """ @@ -4987,9 +5025,7 @@ def enum_list_transformer(enumlist: list[str], fieldtype: type[list[E]]) -> list enumtype = fieldtype.__args__[0] # type: ignore return [enumtype[e] for e in enumlist] - def config_drive_transformer( - drives: list[dict[str, Any]], fieldtype: type[QemuDrive] - ) -> list[QemuDrive]: + def config_drive_transformer(drives: list[dict[str, Any]], fieldtype: type[Drive]) -> list[Drive]: # TODO: exchange for TypeGuard and list comprehension once on 3.10 ret = [] @@ -4997,7 +5033,7 @@ def config_drive_transformer( assert "Id" in d assert "Size" in d ret.append( - QemuDrive( + Drive( id=d["Id"], size=d["Size"] if isinstance(d["Size"], int) else parse_bytes(d["Size"]), directory=Path(d["Directory"]) if d.get("Directory") else None, @@ -5059,14 +5095,14 @@ def uki_profile_transformer( ConfigFeature: enum_transformer, Distribution: enum_transformer, OutputFormat: enum_transformer, - QemuFirmware: enum_transformer, + Firmware: enum_transformer, SecureBootSignTool: enum_transformer, Incremental: enum_transformer, Optional[Distribution]: optional_enum_transformer, list[ManifestFormat]: enum_list_transformer, Verb: enum_transformer, DocFormat: enum_transformer, - list[QemuDrive]: config_drive_transformer, + list[Drive]: config_drive_transformer, GenericVersion: generic_version_transformer, Cacheonly: enum_transformer, Network: enum_transformer, @@ -5075,6 +5111,7 @@ def uki_profile_transformer( list[UKIProfile]: uki_profile_transformer, list[ArtifactOutput]: enum_list_transformer, CertificateSource: certificate_source_transformer, + ConsoleMode: enum_transformer, } def json_transformer(key: str, val: Any) -> Any: diff --git a/mkosi/qemu.py b/mkosi/qemu.py index c00afe388..25c1339e9 100644 --- a/mkosi/qemu.py +++ b/mkosi/qemu.py @@ -28,11 +28,12 @@ Args, Config, ConfigFeature, + ConsoleMode, + Drive, + Firmware, Network, OutputFormat, - QemuDrive, - QemuFirmware, - QemuVsockCID, + VsockCID, finalize_term, format_bytes, systemd_tool_version, @@ -67,8 +68,8 @@ def description(self) -> str: def feature(self, config: Config) -> ConfigFeature: return { - QemuDeviceNode.kvm: config.qemu_kvm, - QemuDeviceNode.vhost_vsock: config.qemu_vsock, + QemuDeviceNode.kvm: config.kvm, + QemuDeviceNode.vhost_vsock: config.vsock, }[self] def open(self) -> int: @@ -178,7 +179,7 @@ class OvmfConfig: vars_format: str -def find_ovmf_firmware(config: Config, firmware: QemuFirmware) -> Optional[OvmfConfig]: +def find_ovmf_firmware(config: Config, firmware: Firmware) -> Optional[OvmfConfig]: if not firmware.is_uefi(): return None @@ -214,19 +215,19 @@ def find_ovmf_firmware(config: Config, firmware: QemuFirmware) -> Optional[OvmfC ) continue - if firmware == QemuFirmware.uefi_secure_boot and "secure-boot" not in j["features"]: + if firmware == Firmware.uefi_secure_boot and "secure-boot" not in j["features"]: logging.debug(f"{p.name} firmware description does not include secure boot, skipping") continue - if firmware != QemuFirmware.uefi_secure_boot and "secure-boot" in j["features"]: + if firmware != Firmware.uefi_secure_boot and "secure-boot" in j["features"]: logging.debug(f"{p.name} firmware description includes secure boot, skipping") continue - if config.qemu_firmware_variables == Path("microsoft") and "enrolled-keys" not in j["features"]: + if config.firmware_variables == Path("microsoft") and "enrolled-keys" not in j["features"]: logging.debug(f"{p.name} firmware description does not have enrolled Microsoft keys, skipping") continue - if config.qemu_firmware_variables != Path("microsoft") and "enrolled-keys" in j["features"]: + if config.firmware_variables != Path("microsoft") and "enrolled-keys" in j["features"]: logging.debug(f"{p.name} firmware description has enrolled Microsoft keys, skipping") continue @@ -322,7 +323,7 @@ def start_virtiofsd( ) -> Iterator[Path]: virtiofsd = find_virtiofsd(root=config.tools(), extra=config.extra_search_paths) if virtiofsd is None: - die("virtiofsd must be installed to boot directory images or use RuntimeTrees= with mkosi qemu") + die("virtiofsd must be installed to boot directory images or use RuntimeTrees= with mkosi vm") cmdline: list[PathString] = [ virtiofsd, @@ -369,7 +370,7 @@ def start_virtiofsd( cmdline += ["--fd", str(SD_LISTEN_FDS_START)] - # We want RuntimeBuildSources= and RuntimeTrees= to do the right thing even when running mkosi qemu + # We want RuntimeBuildSources= and RuntimeTrees= to do the right thing even when running mkosi vm # as root without the source directories necessarily being owned by root. We achieve this by running # virtiofsd as the owner of the source directory and then mapping that uid to root. if not name: @@ -645,28 +646,28 @@ def generate_scratch_fs(config: Config) -> Iterator[Path]: yield Path(scratch.name) -def finalize_qemu_firmware(config: Config, kernel: Optional[Path]) -> QemuFirmware: - if config.qemu_firmware != QemuFirmware.auto: - return config.qemu_firmware +def finalize_firmware(config: Config, kernel: Optional[Path]) -> Firmware: + if config.firmware != Firmware.auto: + return config.firmware if kernel: if KernelType.identify(config, kernel) != KernelType.unknown: - return QemuFirmware.uefi_secure_boot + return Firmware.uefi_secure_boot - return QemuFirmware.linux + return Firmware.linux if ( config.output_format in (OutputFormat.cpio, OutputFormat.directory) or config.architecture.to_efi() is None ): - return QemuFirmware.linux + return Firmware.linux # At the moment there are no qemu firmware descriptions for non-x86 architectures that advertise # secure-boot support so let's default to no secure boot for non-x86 architectures. if config.architecture.is_x86_variant(): - return QemuFirmware.uefi_secure_boot + return Firmware.uefi_secure_boot - return QemuFirmware.uefi + return Firmware.uefi def finalize_firmware_variables( @@ -676,12 +677,12 @@ def finalize_firmware_variables( stack: contextlib.ExitStack, ) -> tuple[Path, str]: ovmf_vars = stack.enter_context(tempfile.NamedTemporaryFile(prefix="mkosi-ovmf-vars-")) - if config.qemu_firmware_variables in (None, Path("custom"), Path("microsoft")): + if config.firmware_variables in (None, Path("custom"), Path("microsoft")): ovmf_vars_format = ovmf.vars_format else: ovmf_vars_format = "raw" - if config.qemu_firmware_variables == Path("custom"): + if config.firmware_variables == Path("custom"): assert config.secure_boot_certificate run( [ @@ -705,8 +706,8 @@ def finalize_firmware_variables( else: vars = ( config.tools() / ovmf.vars.relative_to("/") - if config.qemu_firmware_variables == Path("microsoft") or not config.qemu_firmware_variables - else config.qemu_firmware_variables + if config.firmware_variables == Path("microsoft") or not config.firmware_variables + else config.firmware_variables ) shutil.copy2(vars, Path(ovmf_vars.name)) @@ -733,7 +734,7 @@ def apply_runtime_size(config: Config, image: Path) -> None: @contextlib.contextmanager -def finalize_drive(config: Config, drive: QemuDrive) -> Iterator[Path]: +def finalize_drive(config: Config, drive: Drive) -> Iterator[Path]: with tempfile.NamedTemporaryFile( dir=drive.directory or "/var/tmp", prefix=f"mkosi-drive-{drive.id}", @@ -802,11 +803,11 @@ def finalize_kernel_command_line_extra(config: Config) -> list[str]: ): cmdline += [f"systemd.hostname={config.machine}"] - if config.qemu_cdrom: + if config.cdrom: # CD-ROMs are read-only so tell systemd to boot in volatile mode. cmdline += ["systemd.volatile=yes"] - if not config.qemu_gui: + if config.console != ConsoleMode.gui: cmdline += [ f"systemd.tty.term.console={term}", f"systemd.tty.columns.console={columns}", @@ -963,22 +964,22 @@ def run_qemu(args: Args, config: Config) -> None: if ( config.output_format in (OutputFormat.cpio, OutputFormat.uki, OutputFormat.esp) - and config.qemu_firmware not in (QemuFirmware.auto, QemuFirmware.linux) - and not config.qemu_firmware.is_uefi() + and config.firmware not in (Firmware.auto, Firmware.linux) + and not config.firmware.is_uefi() ): - die(f"{config.output_format} images cannot be booted with the '{config.qemu_firmware}' firmware") + die(f"{config.output_format} images cannot be booted with the '{config.firmware}' firmware") - if config.runtime_trees and config.qemu_firmware == QemuFirmware.bios: + if config.runtime_trees and config.firmware == Firmware.bios: die("RuntimeTrees= cannot be used when booting in BIOS firmware") - if config.qemu_kvm == ConfigFeature.enabled and not config.architecture.is_native(): + if config.kvm == ConfigFeature.enabled and not config.architecture.is_native(): die( f"KVM acceleration requested but {config.architecture} does not match " "the native host architecture" ) - if config.qemu_firmware_variables == Path("custom") and not config.secure_boot_certificate: - die("SecureBootCertificate= must be configured to use QemuFirmwareVariables=custom") + if config.firmware_variables == Path("custom") and not config.secure_boot_certificate: + die("SecureBootCertificate= must be configured to use FirmwareVariables=custom") # After we unshare the user namespace to sandbox qemu, we might not have access to /dev/kvm or related # device nodes anymore as access to these might be gated behind the kvm group and we won't be part of the @@ -1000,14 +1001,20 @@ def run_qemu(args: Args, config: Config) -> None: have_kvm = (qemu_version(config, qemu) < QEMU_KVM_DEVICE_VERSION and QemuDeviceNode.kvm.available()) or ( qemu_version(config, qemu) >= QEMU_KVM_DEVICE_VERSION and QemuDeviceNode.kvm in qemu_device_fds ) - if config.qemu_kvm == ConfigFeature.enabled and not have_kvm: + if config.kvm == ConfigFeature.enabled and not have_kvm: die("KVM acceleration requested but cannot access /dev/kvm") - if config.qemu_vsock == ConfigFeature.enabled and QemuDeviceNode.vhost_vsock not in qemu_device_fds: + if config.vsock == ConfigFeature.enabled and QemuDeviceNode.vhost_vsock not in qemu_device_fds: die("VSock requested but cannot access /dev/vhost-vsock") - if config.qemu_kernel: - kernel = config.qemu_kernel + if config.console not in (ConsoleMode.native, ConsoleMode.gui): + die( + f"Console mode {config.console} is not supported by the qemu vmm", + hint="Try the vmspawn vmm instead", + ) + + if config.linux: + kernel = config.linux elif "-kernel" in args.cmdline: kernel = Path(args.cmdline[args.cmdline.index("-kernel") + 1]) else: @@ -1015,7 +1022,7 @@ def run_qemu(args: Args, config: Config) -> None: if config.output_format in (OutputFormat.uki, OutputFormat.esp) and kernel: logging.warning( - f"Booting UKI output, kernel {kernel} configured with QemuKernel= or " + f"Booting UKI output, kernel {kernel} configured with Linux= or " "passed with -kernel will not be used" ) kernel = None @@ -1023,10 +1030,10 @@ def run_qemu(args: Args, config: Config) -> None: if kernel and not kernel.exists(): die(f"Kernel not found at {kernel}") - firmware = finalize_qemu_firmware(config, kernel) + firmware = finalize_firmware(config, kernel) if not kernel and ( - firmware == QemuFirmware.linux + firmware == Firmware.linux or config.output_format in (OutputFormat.cpio, OutputFormat.directory, OutputFormat.uki) ): if firmware.is_uefi(): @@ -1037,7 +1044,7 @@ def run_qemu(args: Args, config: Config) -> None: if not kernel.exists(): die( f"Kernel or UKI not found at {kernel}, please install a kernel in the image " - "or provide a -kernel argument to mkosi qemu" + "or provide a -kernel argument to mkosi vm" ) ovmf = find_ovmf_firmware(config, firmware) @@ -1050,19 +1057,19 @@ def run_qemu(args: Args, config: Config) -> None: or config.runtime_home or config.output_format == OutputFormat.directory ): - shm = ["-object", f"memory-backend-memfd,id=mem,size={config.qemu_mem // 1024**2}M,share=on"] + shm = ["-object", f"memory-backend-memfd,id=mem,size={config.ram // 1024**2}M,share=on"] machine = f"type={config.architecture.default_qemu_machine()}" if firmware.is_uefi() and config.architecture.supports_smm(): - machine += f",smm={'on' if firmware == QemuFirmware.uefi_secure_boot else 'off'}" + machine += f",smm={'on' if firmware == Firmware.uefi_secure_boot else 'off'}" if shm: machine += ",memory-backend=mem" cmdline: list[PathString] = [ qemu, "-machine", machine, - "-smp", str(config.qemu_smp or os.cpu_count()), - "-m", f"{config.qemu_mem // 1024**2}M", + "-smp", str(config.cpus or os.cpu_count()), + "-m", f"{config.ram // 1024**2}M", "-object", "rng-random,filename=/dev/urandom,id=rng0", "-device", "virtio-rng-pci,rng=rng0,id=rng-device0", "-device", "virtio-balloon,free-page-reporting=on", @@ -1080,7 +1087,7 @@ def run_qemu(args: Args, config: Config) -> None: elif config.runtime_network == Network.none: cmdline += ["-nic", "none"] - if config.qemu_kvm != ConfigFeature.disabled and have_kvm and config.architecture.can_kvm(): + if config.kvm != ConfigFeature.disabled and have_kvm and config.architecture.can_kvm(): accel = "kvm" if qemu_version(config, qemu) >= QEMU_KVM_DEVICE_VERSION: index = list(qemu_device_fds.keys()).index(QemuDeviceNode.kvm) @@ -1095,24 +1102,24 @@ def run_qemu(args: Args, config: Config) -> None: cid: Optional[int] = None if QemuDeviceNode.vhost_vsock in qemu_device_fds: - if config.qemu_vsock_cid == QemuVsockCID.auto: + if config.vsock_cid == VsockCID.auto: cid = find_unused_vsock_cid(config, qemu_device_fds[QemuDeviceNode.vhost_vsock]) - elif config.qemu_vsock_cid == QemuVsockCID.hash: + elif config.vsock_cid == VsockCID.hash: cid = hash_to_vsock_cid(hash_output(config)) else: - cid = config.qemu_vsock_cid + cid = config.vsock_cid if vsock_cid_in_use(qemu_device_fds[QemuDeviceNode.vhost_vsock], cid): die( f"VSock connection ID {cid} is already in use by another virtual machine", - hint="Use QemuVsockConnectionId=auto to have mkosi automatically " + hint="Use VsockConnectionId=auto to have mkosi automatically " "find a free vsock connection ID", ) index = list(qemu_device_fds.keys()).index(QemuDeviceNode.vhost_vsock) cmdline += ["-device", f"vhost-vsock-pci,guest-cid={cid},vhostfd={SD_LISTEN_FDS_START + index}"] - if config.qemu_gui: + if config.console == ConsoleMode.gui: if config.architecture.is_arm_variant(): cmdline += ["-device", "virtio-gpu-pci"] else: @@ -1147,13 +1154,13 @@ def run_qemu(args: Args, config: Config) -> None: ovmf_vars, ovmf_vars_format = finalize_firmware_variables(config, qemu, ovmf, stack) cmdline += ["-drive", f"file={ovmf_vars},if=pflash,format={ovmf_vars_format}"] - if firmware == QemuFirmware.uefi_secure_boot: + if firmware == Firmware.uefi_secure_boot: cmdline += [ "-global", "ICH9-LPC.disable_s3=1", "-global", "driver=cfi.pflash01,property=secure,value=on", ] # fmt: skip - if config.qemu_cdrom and config.output_format in (OutputFormat.disk, OutputFormat.esp): + if config.cdrom and config.output_format in (OutputFormat.disk, OutputFormat.esp): # CD-ROM devices have sector size 2048 so we transform disk images into ones with sector size # 2048. src = (config.output_dir_or_cwd() / config.output_with_compression).resolve() @@ -1292,9 +1299,9 @@ def add_virtiofs_mount( cache = f"cache.writeback=on,cache.direct={yes_no(direct)},cache.no-flush={yes_no(ephemeral)},aio=io_uring" # noqa: E501 device_type = "virtio-blk-pci" - if config.qemu_cdrom: + if config.cdrom: device_type = "scsi-cd" - elif config.qemu_removable: + elif config.removable: device_type = "scsi-hd,removable=on" cmdline += [ @@ -1302,8 +1309,8 @@ def add_virtiofs_mount( "-device", f"{device_type},drive=mkosi,bootindex=1", ] # fmt: skip - if config.qemu_swtpm == ConfigFeature.enabled or ( - config.qemu_swtpm == ConfigFeature.auto + if config.tpm == ConfigFeature.enabled or ( + config.tpm == ConfigFeature.auto and firmware.is_uefi() and config.find_binary("swtpm") is not None ): @@ -1355,7 +1362,7 @@ def add_virtiofs_mount( f"type=11,value=io.systemd.boot.kernel-cmdline-extra={' '.join(kcl).replace(',', ',,')}", ] - for _, drives in groupby(config.qemu_drives, key=lambda d: d.file_id): + for _, drives in groupby(config.drives, key=lambda d: d.file_id): file = stack.enter_context(finalize_drive(config, drives[0])) for drive in drives: @@ -1428,7 +1435,7 @@ def run_ssh(args: Args, config: Config) -> None: if not (p := INVOKING_USER.runtime_dir() / "machine" / f"{config.machine_or_name()}.json").exists(): die( f"{p} not found, cannot SSH into virtual machine {config.machine_or_name()}", - hint="Is the machine running and was it built with Ssh=yes and QemuVsock=yes?", + hint="Is the machine running and was it built with Ssh=yes and Vsock=yes?", ) state = json.loads(p.read_text()) diff --git a/mkosi/resources/man/mkosi.1.md b/mkosi/resources/man/mkosi.1.md index 9bc22f83e..e37a8889f 100644 --- a/mkosi/resources/man/mkosi.1.md +++ b/mkosi/resources/man/mkosi.1.md @@ -18,7 +18,7 @@ mkosi — Build Bespoke OS Images `mkosi [options…] boot [nspawn settings…]` -`mkosi [options…] qemu [qemu parameters…]` +`mkosi [options…] vm [vmm parameters…]` `mkosi [options…] ssh [command line…]` @@ -89,7 +89,7 @@ The following command line verbs are known: the `boot` verb, which can contain extra nspawn options as well as arguments which are passed as the *kernel command line* to the init system in the image. -`qemu` +`vm` : Similar to `boot`, but uses the configured virtual machine monitor (by default `qemu`) to boot up the image, i.e. instead of container virtualization, virtual machine virtualization is used. How extra @@ -99,8 +99,8 @@ The following command line verbs are known: `ssh` : When the image is built with the `Ssh=yes` option, this command - connects to a booted virtual machine (`qemu`) via SSH. Make sure to - run `mkosi ssh` with the same config as `mkosi build` so that it has + connects to a booted virtual machine via SSH. Make sure to run `mkosi ssh` + with the same config as `mkosi build` so that it has the necessary information available to connect to the running virtual machine via SSH. Specifically, the SSH private key from the `SshKey=` setting is used to connect to the virtual machine. Use `mkosi genkey` @@ -111,7 +111,7 @@ The following command line verbs are known: The `Machine=` option can be used to give the machine a custom hostname when booting it which can later be used to ssh into the image - (e.g. `mkosi --machine=mymachine qemu` followed by + (e.g. `mkosi --machine=mymachine vm` followed by `mkosi --machine=mymachine ssh`). `journalctl` @@ -133,7 +133,7 @@ The following command line verbs are known: `sandbox` : Run arbitrary commands inside of the same sandbox used to execute - other verbs such as `boot`, `shell`, `qemu` and more. This means + other verbs such as `boot`, `shell`, `vm` and more. This means `/usr` will be replaced by `/usr` from the tools tree if one is used while everything else will remain in place. If no command is provided, `$SHELL` will be executed or `bash` if `$SHELL` is not set. @@ -564,7 +564,7 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, 8, which default to `xz`, and OCI images, which default to `gzip`. Note that when applied to block device image types, compression means the image cannot be started directly but needs to be - decompressed first. This also means that the `shell`, `boot`, `qemu` verbs + decompressed first. This also means that the `shell`, `boot`, `vm` verbs are not available when this option is used. Implied for `tar`, `cpio`, `uki`, `esp`, and `oci`. @@ -1076,7 +1076,7 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, `Ssh=`, `--ssh` : If specified, an sshd socket unit and matching service are installed in the final image that expose SSH over VSock. When building with this - option and running the image using `mkosi qemu`, the `mkosi ssh` + option and running the image using `mkosi vm`, the `mkosi ssh` command can be used to connect to the container/VM via SSH. Note that you still have to make sure openssh is installed in the image to make this option behave correctly. Run `mkosi genkey` to automatically @@ -1461,10 +1461,10 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, build without specifying `--force`. To give an example of why this is useful, if you run - `mkosi -O my-custom-output-dir -f` followed by `mkosi qemu`, `mkosi` + `mkosi -O my-custom-output-dir -f` followed by `mkosi vm`, `mkosi` will fail saying the image hasn't been built yet. If you run `mkosi -O my-custom-output-dir --history=yes -f` followed by - `mkosi qemu`, it will boot the image built in the previous step as + `mkosi vm`, it will boot the image built in the previous step as expected. `BuildSources=`, `--build-sources=` @@ -1574,69 +1574,67 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, invocation and are interpreted as extra vmspawn options and extra kernel command line arguments. -`QemuGui=`, `--qemu-gui=` -: If enabled, qemu is executed with its graphical interface instead of - with a serial console. +`Console=`, `--console=` +: Configures how to set up the console of the VM. Takes one of `interactive`, `read-only`, `native`, or + `gui`. Defaults to `interactive`. `interactive` provides an interactive terminal interface to the VM. + `read-only` is similar, but is strictly read-only, i.e. does not accept any input from the user. + `native` also provides a TTY-based interface, but uses qemu's native implementation (which means the qemu + monitor is available). `gui` shows the qemu graphical UI. -`QemuSmp=`, `--qemu-smp=` -: When used with the `qemu` verb, this options sets `qemu`'s `-smp` - argument which controls the number of guest's CPUs. Defaults to `2`. +`CPUs=`, `--cpus=` +: Configures the number of CPU cores to assign to the guest when booting a virtual machine. + Defaults to `2`. When set to `0`, the number of CPUs available to the mkosi process will be used. -`QemuMem=`, `--qemu-mem=` -: When used with the `qemu` verb, this options sets `qemu`'s `-m` - argument which controls the amount of guest's RAM. Defaults to `2G`. +`RAM=`, `--ram=` +: Configures the amount of RAM assigned to the guest when booting a virtual machine. Defaults to `2G`. -`QemuKvm=`, `--qemu-kvm=` -: When used with the `qemu` verb, this option specifies whether QEMU should use KVM acceleration. Takes a +`KVM=`, `--kvm=` +: Configures whether KVM acceleration should be used when booting a virtual machine. Takes a boolean value or `auto`. Defaults to `auto`. -`QemuVsock=`, `--qemu-vsock=` -: When used with the `qemu` verb, this option specifies whether QEMU should be configured with a vsock. Takes +`Vsock=`, `--vsock=` +: Configures whether to provision a vsock when booting a virtual machine. Takes a boolean value or `auto`. Defaults to `auto`. -`QemuVsockConnectionId=`, `--qemu-vsock-cid=` -: When used with the `qemu` verb, this option specifies the vsock - connection ID to use. Takes a number in the interval `[3, 0xFFFFFFFF)` - or `hash` or `auto`. Defaults to `auto`. When set to `hash`, the - connection ID will be derived from the full path to the image. When - set to `auto`, `mkosi` will try to find a free connection ID - automatically. Otherwise, the provided number will be used as is. - -`QemuSwtpm=`, `--qemu-swtpm=` -: When used with the `qemu` verb, this option specifies whether to start an instance of swtpm to be used as a - TPM with qemu. This requires swtpm to be installed on the host. Takes a boolean value or `auto`. Defaults - to `auto`. - -`QemuCdrom=`, `--qemu-cdrom=` -: When used with the `qemu` verb, this option specifies whether to - attach the image to the virtual machine as a CD-ROM device. Takes a - boolean. Defaults to `no`. - -`QemuRemovable=`, `--qemu-removable=` -: When used with the `qemu` verb, this option specifies whether to attach the image to the virtual machine - as a removable device. Takes a boolean. Defaults to `no`. - -`QemuFirmware=`, `--qemu-firmware=` -: When used with the `qemu` verb, this option specifies which firmware - to use. Takes one of `uefi`, `uefi-secure-boot`, `bios`, `linux`, or - `auto`. Defaults to `auto`. When set to `uefi`, the OVMF firmware - without secure boot support is used. When set to `uefi-secure-boot`, - the OVMF firmware with secure boot support is used. When set to - `bios`, the default SeaBIOS firmware is used. When set to `linux`, - direct kernel boot is used. See the `QemuKernel=` option for more - details on which kernel image is used with direct kernel boot. When - set to `auto`, `uefi-secure-boot` is used if possible and `linux` - otherwise. - -`QemuFirmwareVariables=`, `--qemu-firmware-variables=` -: When used with the `qemu` verb, this option specifies the path to the - the firmware variables file to use. Currently, this option is only - taken into account when the `uefi` or `uefi-secure-boot` firmware is - used. If not specified, mkosi will search for the default variables - file and use that instead. +`VsockConnectionId=`, `vsock-cid=` +: Configures the vsock connection ID to use when booting a virtual machine. + Takes a number in the interval `[3, 0xFFFFFFFF)` or `hash` or `auto`. + Defaults to `auto`. When set to `hash`, the connection ID will be derived + from the full path to the image. When set to `auto`, `mkosi` will try to + find a free connection ID automatically. Otherwise, the provided number will + be used as is. + +`TPM=`, `--tpm=` +: Configure whether to use a virtual TPM when booting a virtual machine. + Takes a boolean value or `auto`. Defaults to `auto`. + +`Cdrom=`, `--cdrom=` +: Configures whether to attach the image as a CD-ROM device when booting a + virtual machine. Takes a boolean. Defaults to `no`. + +`Removable=`, `--removable=` +: Configures whether to attach the image as a removable device when booting + a virtual machine. Takes a boolean. Defaults to `no`. + +`Firmware=`, `--firmware=` +: Configures the virtual machine firmware to use. Takes one of `uefi`, + `uefi-secure-boot`, `bios`, `linux`, or `auto`. Defaults to `auto`. + When set to `uefi`, the OVMF firmware without secure boot support + is used. When set to `uefi-secure-boot`, the OVMF firmware with + secure boot support is used. When set to `bios`, the default SeaBIOS + firmware is used. When set to `linux`, direct kernel boot is used. + See the `Linux=` option for more details on which kernel image is + used with direct kernel boot. When set to `auto`, `uefi-secure-boot` + is used if possible and `linux` otherwise. + +`FirmwareVariables=`, `--firmware-variables=` +: Configures the path to the the virtual machine firmware variables file + to use. Currently, this option is only taken into account when the `uefi` + or `uefi-secure-boot` firmware is used. If not specified, mkosi will search + for the default variables file and use that instead. When set to `microsoft`, a firmware variables file with the Microsoft secure boot certificates already enrolled will be used. @@ -1649,7 +1647,7 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, [virt-firmware](https://gitlab.com/kraxel/virt-firmware) project can be used to customize OVMF variable files. -`QemuKernel=`, `--qemu-kernel=` +`Linux=`, `--linux=` : Set the kernel image to use for qemu direct kernel boot. If not specified, mkosi will use the kernel provided via the command line (`-kernel` option) or latest the kernel that was installed into @@ -1660,10 +1658,10 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, configured firmware, qemu might boot the kernel itself or using the configured firmware. -`QemuDrives=`, `--qemu-drive=` -: Add a qemu drive. Takes a colon-delimited string of format +`Drives=`, `--drive=` +: Add a drive. Takes a colon-delimited string of format `:[:[:[:]]]`. `id` specifies - the qemu ID assigned to the drive. This can be used as the `drive=` + the ID assigned to the drive. This can be used as the `drive=` property in various qemu devices. `size` specifies the size of the drive. This takes a size in bytes. Additionally, the suffixes `K`, `M` and `G` can be used to specify a size in kilobytes, megabytes and @@ -1679,8 +1677,8 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, ```ini [Runtime] - QemuDrives=btrfs:10G - ext4:20G + Drives=btrfs:10G + ext4:20G QemuArgs=-device nvme,serial=btrfs,drive=btrfs -device nvme,serial=ext4,drive=ext4 ``` @@ -1690,14 +1688,14 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, qemu. `Ephemeral=`, `--ephemeral` -: When used with the `shell`, `boot`, or `qemu` verbs, this option runs the specified verb on a temporary +: When used with the `shell`, `boot`, or `vm` verbs, this option runs the specified verb on a temporary snapshot of the output image that is removed immediately when the container terminates. Taking the temporary snapshot is more efficient on file systems that support reflinks natively (btrfs or xfs) than on more traditional file systems that do not (ext4). `Credentials=`, `--credential=` -: Set credentials to be passed to systemd-nspawn or qemu respectively - when `mkosi shell/boot` or `mkosi qemu` are used. This option takes a +: Set credentials to be passed to systemd-nspawn or the virtual machine respectively + when `mkosi shell/boot` or `mkosi vm` are used. This option takes a space separated list of values which can be either key=value pairs or paths. If a path is provided, if it is a file, the credential name will be the name of the file. If the file is executable, the @@ -1731,12 +1729,12 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, machine in these directories will be owned by the user running mkosi on the host. - Note that when using `mkosi qemu` with this feature systemd v254 or + Note that when using `mkosi vm` with this feature systemd v254 or newer has to be installed in the image. `RuntimeSize=`, `--runtime-size=` : If specified, disk images are grown to the specified size when - they're booted with `mkosi boot` or `mkosi qemu`. Takes a size in + they're booted with `mkosi boot` or `mkosi vm`. Takes a size in bytes. Additionally, the suffixes `K`, `M` and `G` can be used to specify a size in kilobytes, megabytes and gigabytes respectively. @@ -1744,9 +1742,9 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, : Takes a boolean value or `auto`. Specifies whether to mount extra scratch space to `/var/tmp`. If enabled, practically unlimited scratch space is made available under `/var/tmp` when booting the image with - `mkosi qemu`, `mkosi boot` or `mkosi shell`. + `mkosi vm`, `mkosi boot` or `mkosi shell`. - Note that using this feature with `mkosi qemu` requires systemd v254 + Note that using this feature with `mkosi vm` requires systemd v254 or newer in the guest. `RuntimeNetwork=`, `--runtime-network=` @@ -1755,7 +1753,7 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, up usermode networking. `interface` sets up a virtual network connection between the host and the image. This translates to a veth interface for `mkosi shell` and `mkosi boot` and a tap interface for - `mkosi qemu` and `mkosi vmspawn`. + `mkosi vm` and `mkosi vmspawn`. Note that when using `interface`, mkosi does not automatically configure the host interface. It is expected that a recent version of @@ -1766,21 +1764,21 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, : Mount the build sources configured with `BuildSources=` and the build directory (if one is configured) to the same locations in `/work` that they were mounted to when running the build script when using `mkosi - boot` or `mkosi qemu`. + boot` or `mkosi vm`. `RuntimeHome=`, `--runtime-home=` : Mount the current home directory from which mkosi is running to - `/root` when using `mkosi boot` or `mkosi qemu`. + `/root` when using `mkosi boot` or `mkosi vm`. `UnitProperties=`, `--unit-property=` : Configure systemd unit properties to add to the systemd scopes - allocated when using `mkosi boot` or `mkosi qemu`. These are passed + allocated when using `mkosi boot` or `mkosi vm`. These are passed directly to the `--property` options of `systemd-nspawn` and `systemd-run` respectively. `SshKey=`, `--ssh-key=` : Path to the X509 private key in PEM format to use to connect to a - virtual machine started with `mkosi qemu` and built with the `Ssh=` + virtual machine started with `mkosi vm` and built with the `Ssh=` option enabled via the `mkosi ssh` command. If not configured and `mkosi.key` exists in the working directory, it will automatically be used for this purpose. Run `mkosi genkey` to automatically generate @@ -1788,7 +1786,7 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, `SshCertificate=`, `--ssh-certificate=` : Path to the X509 certificate in PEM format to provision as the SSH - public key in virtual machines started with `mkosi qemu`. If not + public key in virtual machines started with `mkosi vm`. If not configured and `mkosi.crt` exists in the working directory, it will automatically be used for this purpose. Run `mkosi genkey` to automatically generate a certificate in `mkosi.crt`. @@ -2190,7 +2188,7 @@ current working directory. The following scripts are supported: modify the configuration. It receives the configuration serialized as JSON on stdin and should output the modified configuration serialized as JSON on stdout. Note that this script only runs when building or - booting the image (`build`, `qemu`, `boot` and `shell` verbs). If a + booting the image (`build`, `vm`, `boot` and `shell` verbs). If a default tools tree is configured, it will be built before running the configure scripts and the configure scripts will run with the tools tree available. This also means that the modifications made by @@ -2765,7 +2763,7 @@ Create and run a bootable *GPT* image, as `foobar.raw`: ```console $ mkosi -d fedora -p kernel-core -p systemd -p systemd-boot -p udev -o foobar.raw # mkosi --output foobar.raw boot -$ mkosi --output foobar.raw qemu +$ mkosi --output foobar.raw vm ``` Create and run a *Fedora Linux* image in a plain directory: @@ -2815,7 +2813,7 @@ $ chmod +x mkosi.build # systemd-nspawn -bi image.raw ``` -## Different ways to boot with `qemu` +## Different ways to boot with `vm` The easiest way to boot a virtual machine is to build an image with the required components and let `mkosi` call `qemu` with all the right options: @@ -2824,7 +2822,7 @@ $ mkosi -d fedora \ --autologin \ -p systemd-udev,systemd-boot,kernel-core \ build -$ mkosi -d fedora qemu +$ mkosi -d fedora vm ... fedora login: root (automatic login) [root@fedora ~]# @@ -2839,13 +2837,13 @@ The qemu monitor may for example be used to inject special keys or shut down the machine quickly. Alternatively the machine can be shut down using `Ctrl-a x`. -To boot with a graphical window, add `--qemu-qui`: +To boot with a graphical window, add `--console=gui`: ```console -$ mkosi -d fedora --qemu-gui qemu +$ mkosi -d fedora --console=gui qemu ``` A kernel may be booted directly with -`mkosi qemu -kernel ... -initrd ... -append '...'`. +`mkosi vm -kernel ... -initrd ... -append '...'`. This is a bit faster because no boot loader is used, and it is also easier to experiment with different kernels and kernel commandlines. Note that despite the name, qemu's `-append` option replaces @@ -2854,7 +2852,7 @@ and any previous `-append` specifications. The UKI is also copied into the output directory and may be booted directly: ```console -$ mkosi qemu -kernel mkosi.output/fedora~38/image.efi +$ mkosi vm -kernel mkosi.output/fedora~38/image.efi ``` When booting using an external kernel, we don't need the kernel *in* the image, @@ -2863,7 +2861,7 @@ but we would still want the kernel modules to be installed. It is also possible to do a *direct kernel boot* into a boot loader, taking advantage of the fact that `systemd-boot(7)` is a valid UEFI binary: ```console -$ mkosi qemu -kernel /usr/lib/systemd/boot/efi/systemd-bootx64.efi +$ mkosi vm -kernel /usr/lib/systemd/boot/efi/systemd-bootx64.efi ``` In this scenario, the kernel is loaded from the ESP in the image by `systemd-boot`. @@ -2916,7 +2914,7 @@ include # Frequently Asked Questions (FAQ) -- Why does `mkosi qemu` with KVM not work on Debian/Kali/Ubuntu? +- Why does `mkosi vm` with KVM not work on Debian/Kali/Ubuntu? While other distributions are OK with allowing access to `/dev/kvm`, on Debian/Kali/Ubuntu this is only allowed for users in the `kvm` group. Because diff --git a/mkosi/vmspawn.py b/mkosi/vmspawn.py index 1c3b73f52..d163a277f 100644 --- a/mkosi/vmspawn.py +++ b/mkosi/vmspawn.py @@ -8,9 +8,9 @@ from mkosi.config import ( Args, Config, + Firmware, Network, OutputFormat, - QemuFirmware, yes_no, ) from mkosi.log import die @@ -18,8 +18,8 @@ apply_runtime_size, copy_ephemeral, finalize_credentials, + finalize_firmware, finalize_kernel_command_line_extra, - finalize_qemu_firmware, ) from mkosi.run import run from mkosi.types import PathString @@ -30,36 +30,37 @@ def run_vmspawn(args: Args, config: Config) -> None: if config.output_format not in (OutputFormat.disk, OutputFormat.esp, OutputFormat.directory): die(f"{config.output_format} images cannot be booted in systemd-vmspawn") - if config.qemu_firmware == QemuFirmware.bios: + if config.firmware == Firmware.bios: die("systemd-vmspawn cannot boot BIOS firmware images") - if config.qemu_cdrom: + if config.cdrom: die("systemd-vmspawn does not support CD-ROM images") - if config.qemu_firmware_variables and config.qemu_firmware_variables != Path("microsoft"): - die("mkosi vmspawn does not support QemuFirmwareVariables=") + if config.firmware_variables and config.firmware_variables != Path("microsoft"): + die("mkosi vmspawn does not support FirmwareVariables=") - kernel = config.qemu_kernel - firmware = finalize_qemu_firmware(config, kernel) + kernel = config.linux + firmware = finalize_firmware(config, kernel) - if not kernel and firmware == QemuFirmware.linux: + if not kernel and firmware == Firmware.linux: kernel = config.output_dir_or_cwd() / config.output_split_kernel if not kernel.exists(): die( f"Kernel or UKI not found at {kernel}", - hint="Please install a kernel in the image or provide a --qemu-kernel" + hint="Please install a kernel in the image or provide a --linux" " argument to mkosi vmspawn", ) cmdline: list[PathString] = [ "systemd-vmspawn", - "--cpus", str(config.qemu_smp or os.cpu_count()), - "--ram", str(config.qemu_mem), - "--kvm", config.qemu_kvm.to_tristate(), - "--vsock", config.qemu_vsock.to_tristate(), - "--tpm", config.qemu_swtpm.to_tristate(), + "--cpus", str(config.cpus or os.cpu_count()), + "--ram", str(config.ram), + "--kvm", config.kvm.to_tristate(), + "--vsock", config.vsock.to_tristate(), + "--tpm", config.tpm.to_tristate(), "--secure-boot", yes_no(config.secure_boot), "--register", yes_no(config.register), + "--console", str(config.console), ] # fmt: skip if config.runtime_network == Network.user: @@ -67,9 +68,6 @@ def run_vmspawn(args: Args, config: Config) -> None: elif config.runtime_network == Network.interface: cmdline += ["--network-tap"] - if config.qemu_gui: - cmdline += ["--console=gui"] - cmdline += [f"--set-credential={k}:{v}" for k, v in finalize_credentials(config).items()] with contextlib.ExitStack() as stack: diff --git a/tests/__init__.py b/tests/__init__.py index 9e5780e94..1a6341d02 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -138,15 +138,15 @@ def boot(self, options: Sequence[str] = (), args: Sequence[str] = ()) -> Complet return result - def vm(self, verb: str, options: Sequence[str] = (), args: Sequence[str] = ()) -> CompletedProcess: + def vm(self, options: Sequence[str] = (), args: Sequence[str] = ()) -> CompletedProcess: result = self.mkosi( - verb, + "vm", [ "--runtime-build-sources=no", - "--qemu-vsock=yes", + "--vsock=yes", # TODO: Drop once both Hyper-V bugs are fixed in Github Actions. "--qemu-args=-cpu max,pcid=off", - "--qemu-mem=2G", + "--ram=2G", "--ephemeral", *options, ], @@ -164,12 +164,6 @@ def vm(self, verb: str, options: Sequence[str] = (), args: Sequence[str] = ()) - return result - def qemu(self, options: Sequence[str] = (), args: Sequence[str] = ()) -> CompletedProcess: - return self.vm("qemu", options, args) - - def vmspawn(self, options: Sequence[str] = (), args: Sequence[str] = ()) -> CompletedProcess: - return self.vm("vmspawn", options, args) - def genkey(self) -> CompletedProcess: return self.mkosi("genkey", ["--force"], user=self.uid, group=self.gid) diff --git a/tests/test_boot.py b/tests/test_boot.py index e92159b06..3de163b6c 100644 --- a/tests/test_boot.py +++ b/tests/test_boot.py @@ -5,7 +5,7 @@ import pytest -from mkosi.config import Bootloader, OutputFormat, QemuFirmware +from mkosi.config import Bootloader, Firmware, OutputFormat from mkosi.distributions import Distribution from mkosi.qemu import find_virtiofsd from mkosi.run import find_binary, run @@ -54,15 +54,15 @@ def test_format(config: ImageConfig, format: OutputFormat) -> None: if format == OutputFormat.directory and not find_virtiofsd(): return - image.qemu() + image.vm() if have_vmspawn() and format in (OutputFormat.disk, OutputFormat.directory): - image.vmspawn() + image.vm(options=["--vmm=vmspawn"]) if format != OutputFormat.disk: return - image.qemu(["--qemu-firmware=bios"]) + image.vm(["--firmware=bios"]) @pytest.mark.parametrize("bootloader", Bootloader) @@ -70,9 +70,9 @@ def test_bootloader(config: ImageConfig, bootloader: Bootloader) -> None: if config.distribution == Distribution.rhel_ubi: return - firmware = QemuFirmware.linux if bootloader == Bootloader.none else QemuFirmware.auto + firmware = Firmware.linux if bootloader == Bootloader.none else Firmware.auto with Image(config) as image: image.genkey() image.build(["--format=disk", "--bootloader", str(bootloader)]) - image.qemu(["--qemu-firmware", str(firmware)]) + image.vm(["--firmware", str(firmware)]) diff --git a/tests/test_config.py b/tests/test_config.py index a7717ff0d..aca3e189f 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -357,7 +357,7 @@ def test_profiles(tmp_path: Path) -> None: Distribution=fedora [Runtime] - QemuKvm=yes + KVM=yes """ ) @@ -382,7 +382,7 @@ def test_profiles(tmp_path: Path) -> None: assert config.profiles == ["profile"] # The profile should override mkosi.conf.d/ assert config.distribution == Distribution.fedora - assert config.qemu_kvm == ConfigFeature.enabled + assert config.kvm == ConfigFeature.enabled (d / "mkosi.conf").unlink() @@ -392,7 +392,7 @@ def test_profiles(tmp_path: Path) -> None: assert config.profiles == ["profile"] # The profile should override mkosi.conf.d/ assert config.distribution == Distribution.fedora - assert config.qemu_kvm == ConfigFeature.enabled + assert config.kvm == ConfigFeature.enabled (d / "mkosi.conf").write_text( """\ @@ -489,6 +489,7 @@ def test_parse_load_verb(tmp_path: Path) -> None: assert parse_config(["shell"])[0].verb == Verb.shell assert parse_config(["boot"])[0].verb == Verb.boot assert parse_config(["qemu"])[0].verb == Verb.qemu + assert parse_config(["vm"])[0].verb == Verb.vm assert parse_config(["journalctl"])[0].verb == Verb.journalctl assert parse_config(["coredumpctl"])[0].verb == Verb.coredumpctl with pytest.raises(SystemExit): diff --git a/tests/test_initrd.py b/tests/test_initrd.py index 4ad8120d3..f7aa0ba25 100644 --- a/tests/test_initrd.py +++ b/tests/test_initrd.py @@ -53,7 +53,7 @@ def passphrase() -> Iterator[Path]: def test_initrd(config: ImageConfig) -> None: with Image(config) as image: image.build(options=["--format=disk"]) - image.qemu() + image.vm() @pytest.mark.skipif(os.getuid() != 0, reason="mkosi-initrd LVM test can only be executed as root") @@ -94,9 +94,9 @@ def test_initrd_lvm(config: ImageConfig) -> None: lvm.rename(Path(image.output_dir) / "image.raw") - image.qemu( + image.vm( [ - "--qemu-firmware=linux", + "--firmware=linux", # LVM confuses systemd-repart so we mask it for this test. "--kernel-command-line-extra=systemd.mask=systemd-repart.service", "--kernel-command-line-extra=root=LABEL=root", @@ -151,7 +151,7 @@ def test_initrd_luks(config: ImageConfig, passphrase: Path) -> None: with Image(config) as image: image.build(["--repart-directory", repartd, "--passphrase", passphrase, "--format=disk"]) - image.qemu(["--credential=cryptsetup.passphrase=mkosi"]) + image.vm(["--credential=cryptsetup.passphrase=mkosi"]) @pytest.mark.skipif(os.getuid() != 0, reason="mkosi-initrd LUKS+LVM test can only be executed as root") @@ -206,11 +206,11 @@ def test_initrd_luks_lvm(config: ImageConfig, passphrase: Path) -> None: lvm.rename(Path(image.output_dir) / "image.raw") - image.qemu( + image.vm( [ "--format=disk", "--credential=cryptsetup.passphrase=mkosi", - "--qemu-firmware=linux", + "--firmware=linux", "--kernel-command-line-extra=root=LABEL=root", f"--kernel-command-line-extra=rd.luks.uuid={luks_uuid}", ] diff --git a/tests/test_json.py b/tests/test_json.py index 3cd3a5de2..160fb523a 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -21,21 +21,22 @@ Config, ConfigFeature, ConfigTree, + ConsoleMode, DocFormat, + Drive, + Firmware, Incremental, KeySource, KeySourceType, ManifestFormat, Network, OutputFormat, - QemuDrive, - QemuFirmware, - QemuVsockCID, SecureBootSignTool, ShimBootloader, UKIProfile, Verb, Vmm, + VsockCID, ) from mkosi.distributions import Distribution from mkosi.versioncomp import GenericVersion @@ -117,8 +118,10 @@ def test_config() -> None: } ], "BuildSourcesEphemeral": true, + "CPUs": 2, "CacheDirectory": "/is/this/the/cachedir", "CacheOnly": "always", + "Cdrom": false, "Checksum": false, "CleanPackageMetadata": "auto", "CleanScripts": [ @@ -129,6 +132,7 @@ def test_config() -> None: "ConfigureScripts": [ "/configure" ], + "Console": "gui", "Credentials": { "credkey": "credval" }, @@ -136,6 +140,22 @@ def test_config() -> None: "dep1" ], "Distribution": "fedora", + "Drives": [ + { + "Directory": "/foo/bar", + "FileId": "red", + "Id": "abc", + "Options": "abc,qed", + "Size": 200 + }, + { + "Directory": null, + "FileId": "wcd", + "Id": "abc", + "Options": "", + "Size": 200 + } + ], "Environment": { "BAR": "BAR", "Qux": "Qux", @@ -147,6 +167,8 @@ def test_config() -> None: "ExtraTrees": [], "Files": [], "FinalizeScripts": [], + "Firmware": "linux", + "FirmwareVariables": "/foo/bar", "Format": "uki", "ForwardJournal": "/mkosi.journal", "History": true, @@ -165,6 +187,7 @@ def test_config() -> None: "/efi/initrd1", "/efi/initrd2" ], + "KVM": "auto", "KernelCommandLine": [], "KernelCommandLineExtra": [ "look", @@ -188,6 +211,7 @@ def test_config() -> None: "KernelModulesInitrdIncludeHost": true, "Key": null, "Keymap": "wow, so much keymap", + "Linux": null, "LocalMirror": null, "Locale": "en_C.UTF-8", "LocaleMessages": "", @@ -234,36 +258,10 @@ def test_config() -> None: "ProxyPeerCertificate": "/my/peer/cert", "ProxyUrl": "https://my/proxy", "QemuArgs": [], - "QemuCdrom": false, - "QemuDrives": [ - { - "Directory": "/foo/bar", - "FileId": "red", - "Id": "abc", - "Options": "abc,qed", - "Size": 200 - }, - { - "Directory": null, - "FileId": "wcd", - "Id": "abc", - "Options": "", - "Size": 200 - } - ], - "QemuFirmware": "linux", - "QemuFirmwareVariables": "/foo/bar", - "QemuGui": true, - "QemuKernel": null, - "QemuKvm": "auto", - "QemuMem": 123, - "QemuRemovable": false, - "QemuSmp": 2, - "QemuSwtpm": "auto", - "QemuVsock": "enabled", - "QemuVsockConnectionId": -2, + "RAM": 123, "Register": true, "Release": "53", + "Removable": false, "RemoveFiles": [], "RemovePackages": [ "all" @@ -350,6 +348,7 @@ def test_config() -> None: "/sync" ], "SysupdateDirectory": "/sysupdate", + "TPM": "auto", "Timezone": null, "ToolsTree": null, "ToolsTreeCertificates": true, @@ -403,6 +402,8 @@ def test_config() -> None: "VolatilePackages": [ "abc" ], + "Vsock": "enabled", + "VsockConnectionId": -2, "WithDocs": true, "WithNetwork": false, "WithRecommends": true, @@ -422,68 +423,74 @@ def test_config() -> None: build_dir=None, build_packages=["pkg1", "pkg2"], build_scripts=[Path("/path/to/buildscript")], - build_sources=[ConfigTree(Path("/qux"), Path("/frob"))], build_sources_ephemeral=True, + build_sources=[ConfigTree(Path("/qux"), Path("/frob"))], cache_dir=Path("/is/this/the/cachedir"), cacheonly=Cacheonly.always, + cdrom=False, checksum=False, clean_package_metadata=ConfigFeature.auto, clean_scripts=[Path("/clean")], compress_level=3, compress_output=Compression.bz2, configure_scripts=[Path("/configure")], + console=ConsoleMode.gui, + cpus=2, credentials={"credkey": "credval"}, dependencies=["dep1"], distribution=Distribution.fedora, - environment={"foo": "foo", "BAR": "BAR", "Qux": "Qux"}, + drives=[Drive("abc", 200, Path("/foo/bar"), "abc,qed", "red"), Drive("abc", 200, None, "", "wcd")], environment_files=[], + environment={"foo": "foo", "BAR": "BAR", "Qux": "Qux"}, ephemeral=True, extra_search_paths=[], extra_trees=[], files=[], finalize_scripts=[], + firmware_variables=Path("/foo/bar"), + firmware=Firmware.linux, forward_journal=Path("/mkosi.journal"), history=True, hostname=None, - vmm=Vmm.qemu, - image="default", image_id="myimage", image_version="5", + image="default", incremental=Incremental.no, initrd_packages=["clevis"], initrd_volatile_packages=["abc"], initrds=[Path("/efi/initrd1"), Path("/efi/initrd2")], - microcode_host=True, - kernel_command_line=[], kernel_command_line_extra=["look", "im", "on", "the", "kernel", "command", "line"], + kernel_command_line=[], kernel_modules_exclude=["nvidia"], - kernel_modules_include=["loop"], kernel_modules_include_host=True, - kernel_modules_initrd=True, + kernel_modules_include=["loop"], kernel_modules_initrd_exclude=[], - kernel_modules_initrd_include=[], kernel_modules_initrd_include_host=True, + kernel_modules_initrd_include=[], + kernel_modules_initrd=True, key=None, keymap="wow, so much keymap", + kvm=ConfigFeature.auto, + linux=None, local_mirror=None, - locale="en_C.UTF-8", locale_messages="", - machine="machine", + locale="en_C.UTF-8", machine_id=uuid.UUID("b58253b0cc924a348782bcd99b20d07f"), + machine="machine", make_initrd=False, manifest_format=[ManifestFormat.json, ManifestFormat.changelog], + microcode_host=True, minimum_version=GenericVersion("123"), mirror=None, nspawn_settings=None, openpgp_tool="gpg", - output="outfile", output_dir=Path("/your/output/here"), output_format=OutputFormat.uki, output_mode=0o123, + output="outfile", overlay=True, package_cache_dir=Path("/a/b/c"), package_directories=[], - sandbox_trees=[ConfigTree(Path("/foo/bar"), None)], packages=[], pass_environment=["abc"], passphrase=None, @@ -497,24 +504,10 @@ def test_config() -> None: proxy_peer_certificate=Path("/my/peer/cert"), proxy_url="https://my/proxy", qemu_args=[], - qemu_cdrom=False, - qemu_removable=False, - qemu_drives=[ - QemuDrive("abc", 200, Path("/foo/bar"), "abc,qed", "red"), - QemuDrive("abc", 200, None, "", "wcd"), - ], - qemu_firmware=QemuFirmware.linux, - qemu_firmware_variables=Path("/foo/bar"), - qemu_gui=True, - qemu_kernel=None, - qemu_kvm=ConfigFeature.auto, - qemu_mem=123, - qemu_smp=2, - qemu_swtpm=ConfigFeature.auto, - qemu_vsock=ConfigFeature.enabled, - qemu_vsock_cid=QemuVsockCID.hash, + ram=123, register=True, release="53", + removable=False, remove_files=[], remove_packages=["all"], repart_dirs=[], @@ -533,53 +526,58 @@ def test_config() -> None: ConfigTree(Path("/foo/bar"), Path("/baz")), ConfigTree(Path("/bar/baz"), Path("/qux")), ], + sandbox_trees=[ConfigTree(Path("/foo/bar"), None)], sector_size=None, - secure_boot=True, secure_boot_auto_enroll=True, - secure_boot_certificate=None, secure_boot_certificate_source=CertificateSource(type=CertificateSourceType.file), - secure_boot_key=Path("/path/to/keyfile"), + secure_boot_certificate=None, secure_boot_key_source=KeySource(type=KeySourceType.file), + secure_boot_key=Path("/path/to/keyfile"), secure_boot_sign_tool=SecureBootSignTool.systemd_sbsign, + secure_boot=True, seed=uuid.UUID("7496d7d8-7f08-4a2b-96c6-ec8c43791b60"), selinux_relabel=ConfigFeature.disabled, shim_bootloader=ShimBootloader.none, - sign=False, - sign_expected_pcr=ConfigFeature.disabled, - sign_expected_pcr_key=Path("/my/key"), - sign_expected_pcr_key_source=KeySource(type=KeySourceType.file), - sign_expected_pcr_certificate=Path("/my/cert"), sign_expected_pcr_certificate_source=CertificateSource(type=CertificateSourceType.file), + sign_expected_pcr_certificate=Path("/my/cert"), + sign_expected_pcr_key_source=KeySource(type=KeySourceType.file), + sign_expected_pcr_key=Path("/my/key"), + sign_expected_pcr=ConfigFeature.disabled, + sign=False, skeleton_trees=[ConfigTree(Path("/foo/bar"), Path("/")), ConfigTree(Path("/bar/baz"), Path("/qux"))], source_date_epoch=12345, split_artifacts=[ArtifactOutput.uki, ArtifactOutput.kernel], - ssh=False, ssh_certificate=Path("/path/to/cert"), ssh_key=None, + ssh=False, sync_scripts=[Path("/sync")], sysupdate_dir=Path("/sysupdate"), timezone=None, - tools_tree=None, tools_tree_certificates=True, tools_tree_distribution=Distribution.fedora, tools_tree_mirror=None, - tools_tree_sandbox_trees=[ConfigTree(Path("/a/b/c"), Path("/"))], - tools_tree_packages=[], tools_tree_package_directories=[Path("/abc")], + tools_tree_packages=[], tools_tree_release=None, tools_tree_repositories=["abc"], + tools_tree_sandbox_trees=[ConfigTree(Path("/a/b/c"), Path("/"))], + tools_tree=None, + tpm=ConfigFeature.auto, unified_kernel_image_format="myuki", unified_kernel_image_profiles=[UKIProfile(profile={"key": "value"}, cmdline=["key=value"])], unified_kernel_images=ConfigFeature.auto, unit_properties=["PROPERTY=VALUE"], use_subvolumes=ConfigFeature.auto, - verity=ConfigFeature.enabled, + verity_certificate_source=CertificateSource(type=CertificateSourceType.file), verity_certificate=Path("/path/to/cert"), - verity_key=None, verity_key_source=KeySource(type=KeySourceType.file), - verity_certificate_source=CertificateSource(type=CertificateSourceType.file), + verity_key=None, + verity=ConfigFeature.enabled, + vmm=Vmm.qemu, volatile_package_directories=[Path("def")], volatile_packages=["abc"], + vsock_cid=VsockCID.hash, + vsock=ConfigFeature.enabled, with_docs=True, with_network=False, with_recommends=True,