From: Daan De Meyer Date: Thu, 9 Feb 2023 11:53:32 +0000 (+0100) Subject: Simplify kernel image and initrd handling X-Git-Tag: v15~330 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=af87828065c8eb65e4c089f6d07a6e231a3dafc0;p=thirdparty%2Fmkosi.git Simplify kernel image and initrd handling - Let's stop writing files in /etc in favor of passing the information via other ways - Let's stop defaulting to "bls" layout which is intended for type 1 images, we only use UKIs so we don't need the "bls" layout - kernel-install now defaults to the "other" layout, which means it won't create the entry directory in /boot anymore. We update the initrd find logic to take this into account - Remove --machine-id as it was only really there for testing the config parsing which we now deal with by not storing the machine ID at all --- diff --git a/NEWS.md b/NEWS.md index 2b3679a83..af3724cc8 100644 --- a/NEWS.md +++ b/NEWS.md @@ -45,6 +45,7 @@ `--source-file-transfer-final` might be reimplemented in the future using virtiofsd. - Dropped `--include-dir` option. Usage can be replaced by using `--incremental` and reading includes from the cached build image tree. +- Removed `--machine-id` in favor of shipping images without a machine ID at all. ## v14 diff --git a/mkosi.md b/mkosi.md index fc64bd40f..b6004a93e 100644 --- a/mkosi.md +++ b/mkosi.md @@ -543,12 +543,6 @@ a boolean argument: either "1", "yes", or "true" to enable, or "0", in building or further container import stages. This option strips SELinux context attributes from the resulting tar archive. -`MachineID=`, `--machine-id` - -: Set the machine's ID to the specified value. If unused, a random ID will -be used while building the image and the final image will be shipped without -a machine ID. - ### [Content] Section `BasePackages=`, `--base-packages` diff --git a/mkosi/__init__.py b/mkosi/__init__.py index 017203616..dc90e9fd7 100644 --- a/mkosi/__init__.py +++ b/mkosi/__init__.py @@ -249,27 +249,6 @@ def prepare_tree_root(state: MkosiState) -> None: btrfs_subvol_create(state.root) -def prepare_tree(state: MkosiState, cached: bool) -> None: - if cached: - # Reuse machine-id from cached image. - state.machine_id = uuid.UUID(state.root.joinpath("etc/machine-id").read_text().strip()).hex - # Always update kernel command line. - if not state.do_run_build_script and state.config.bootable: - state.root.joinpath("etc/kernel/cmdline").write_text(" ".join(state.config.kernel_command_line) + "\n") - return - - with complete_step("Setting up basic OS tree…"): - state.root.mkdir(mode=0o755, exist_ok=True) - # We need an initialized machine ID for the build & boot logic to work - state.root.joinpath("etc").mkdir(mode=0o755, exist_ok=True) - state.root.joinpath("etc/machine-id").write_text(f"{state.machine_id}\n") - - state.root.joinpath("etc/kernel").mkdir(mode=0o755, exist_ok=True) - state.root.joinpath("etc/kernel/cmdline").write_text(" ".join(state.config.kernel_command_line) + "\n") - state.root.joinpath("etc/kernel/entry-token").write_text(f"{state.machine_id}\n") - state.root.joinpath("etc/kernel/install.conf").write_text("layout=bls\n") - - def clean_paths( root: Path, globs: Sequence[str], @@ -429,18 +408,9 @@ def reset_machine_id(state: MkosiState) -> None: return with complete_step("Resetting machine ID"): - if not state.config.machine_id: - machine_id = state.root / "etc/machine-id" - machine_id.unlink(missing_ok=True) - machine_id.write_text("uninitialized\n") - - dbus_machine_id = state.root / "var/lib/dbus/machine-id" - try: - dbus_machine_id.unlink() - except FileNotFoundError: - pass - else: - dbus_machine_id.symlink_to("../../../etc/machine-id") + machine_id = state.root / "etc/machine-id" + machine_id.unlink(missing_ok=True) + machine_id.write_text("uninitialized\n") def reset_random_seed(root: Path) -> None: @@ -610,7 +580,7 @@ def install_boot_loader(state: MkosiState) -> None: return with complete_step("Installing boot loader…"): - run(["bootctl", "install", "--root", state.root], env={"SYSTEMD_ESP_PATH": "/boot", **os.environ}) + run(["bootctl", "install", "--root", state.root], env={"SYSTEMD_ESP_PATH": "/boot"}) def install_extra_trees(state: MkosiState) -> None: @@ -750,15 +720,6 @@ def gen_kernel_images(state: MkosiState) -> Iterator[tuple[str, Path]]: yield kver.name, kimg -def initrd_path(state: MkosiState, kver: str) -> Path: - # initrd file is versioned in Debian Bookworm - initrd = state.root / boot_directory(state, kver) / f"initrd.img-{kver}" - if not initrd.exists(): - initrd = state.root / boot_directory(state, kver) / "initrd" - - return initrd - - def install_unified_kernel(state: MkosiState, roothash: Optional[str]) -> None: # Iterates through all kernel versions included in the image and generates a combined # kernel+initrd+cmdline+osrelease EFI file from it and places it in the /EFI/Linux directory of the ESP. @@ -815,6 +776,9 @@ def install_unified_kernel(state: MkosiState, roothash: Optional[str]) -> None: else: boot_options = "" + if state.config.kernel_command_line: + boot_options = f"{boot_options} {' '.join(state.config.kernel_command_line)}" + if roothash: boot_options = f"{boot_options} {roothash}" @@ -842,7 +806,11 @@ def install_unified_kernel(state: MkosiState, roothash: Optional[str]) -> None: "--pcr-banks", "sha1,sha256" ] - cmd += [state.root / kimg, initrd_path(state, kver)] + initrd = state.root.joinpath(state.installer.initrd_path(kver)) + if not initrd.exists(): + die(f"Initrd not found at {initrd}") + + cmd += [state.root / kimg, initrd] run(cmd) @@ -1341,7 +1309,6 @@ class ArgumentParserMkosi(argparse.ArgumentParser): "BuildPackages": "--build-package", "PostInstallationScript": "--postinst-script", "TarStripSELinuxContext": "--tar-strip-selinux-context", - "MachineID": "--machine-id", "SignExpectedPCR": "--sign-expected-pcr", "RepositoryDirectories": "--repository-directory", "Credentials": "--credential", @@ -1742,10 +1709,6 @@ def create_parser() -> ArgumentParserMkosi: default=True, help=argparse.SUPPRESS, ) - group.add_argument( - "--machine-id", - help="Defines a fixed machine ID for all our build-time runs.", - ) group.add_argument("--password", help="Set the root password") group.add_argument( @@ -2711,12 +2674,6 @@ def load_args(args: argparse.Namespace) -> MkosiConfig: if args.netdev and is_centos_variant(args.distribution) and "epel" not in args.repositories: die("--netdev is only supported on EPEL centOS variants") - if args.machine_id is not None: - try: - uuid.UUID(hex=args.machine_id) - except ValueError: - die(f"Sorry, {args.machine_id} is not a valid machine ID.") - # If we are building a sysext we don't want to add base packages to the # extension image, as they will already be in the base image. if args.base_image is not None: @@ -2927,8 +2884,6 @@ def print_summary(config: MkosiConfig) -> None: if config.secure_boot_certificate: print(" SecureBoot Cert.:", config.secure_boot_certificate) - print(" Machine ID:", none_to_no(config.machine_id)) - print("\nCONTENT:") print(" Packages:", line_join_list(config.packages)) @@ -3108,10 +3063,6 @@ def configure_netdev(state: MkosiState, cached: bool) -> None: run(["systemctl", "--root", state.root, "enable", "systemd-networkd"]) -def boot_directory(state: MkosiState, kver: str) -> Path: - return Path("boot") / state.machine_id / kver - - def run_kernel_install(state: MkosiState, cached: bool) -> None: if not state.config.bootable or state.do_run_build_script: return @@ -3243,7 +3194,6 @@ def build_image(state: MkosiState, *, manifest: Optional[Manifest] = None) -> No return with mount_image(state, cached): - prepare_tree(state, cached) install_skeleton_trees(state, cached) install_distribution(state, cached) configure_locale(state.root, cached) @@ -3375,7 +3325,7 @@ def remove_artifacts(state: MkosiState, for_cache: bool = False) -> None: with complete_step(f"Removing artifacts from {what}…"): unlink_try_hard(state.root) - unlink_try_hard(state.var_tmp()) + unlink_try_hard(state.var_tmp) def build_stuff(uid: int, gid: int, config: MkosiConfig) -> None: @@ -3390,7 +3340,6 @@ def build_stuff(uid: int, gid: int, config: MkosiConfig) -> None: workspace=workspace_dir, cache=cache, do_run_build_script=False, - machine_id=config.machine_id or uuid.uuid4().hex, for_cache=False, ) diff --git a/mkosi/backend.py b/mkosi/backend.py index 50f0a4a4c..46bb2d571 100644 --- a/mkosi/backend.py +++ b/mkosi/backend.py @@ -321,7 +321,6 @@ class MkosiConfig: debug: list[str] auto_bump: bool workspace_dir: Optional[Path] - machine_id: Optional[str] # QEMU-specific options qemu_headless: bool @@ -396,7 +395,6 @@ class MkosiState: workspace: Path cache: Path do_run_build_script: bool - machine_id: str for_cache: bool environment: dict[str, str] = dataclasses.field(init=False) installer: DistributionInstaller = dataclasses.field(init=False) @@ -418,20 +416,21 @@ class MkosiState: die("No installer for this distribution.") self.installer = instance + self.root.mkdir(exist_ok=True, mode=0o755) + self.var_tmp.mkdir(exist_ok=True) + self.staging.mkdir(exist_ok=True) + @property def root(self) -> Path: return self.workspace / "root" + @property def var_tmp(self) -> Path: - p = self.workspace / "var-tmp" - p.mkdir(exist_ok=True) - return p + return self.workspace / "var-tmp" @property def staging(self) -> Path: - p = self.workspace / "staging" - p.mkdir(exist_ok=True) - return p + return self.workspace / "staging" def should_compress_output(config: Union[argparse.Namespace, MkosiConfig]) -> Union[bool, str]: @@ -449,10 +448,6 @@ def should_compress_output(config: Union[argparse.Namespace, MkosiConfig]) -> Un return False if c is None else c -def workspace(root: Path) -> Path: - return root.parent - - def format_rlimit(rlimit: int) -> str: limits = resource.getrlimit(rlimit) soft = "infinity" if limits[0] == resource.RLIM_INFINITY else str(limits[0]) diff --git a/mkosi/distributions/__init__.py b/mkosi/distributions/__init__.py index 3d2e5db36..af42b4e0d 100644 --- a/mkosi/distributions/__init__.py +++ b/mkosi/distributions/__init__.py @@ -15,8 +15,12 @@ class DistributionInstaller: raise NotImplementedError @staticmethod - def kernel_image(name: str, architecture: str) -> Path: - return Path("lib/modules") / name / "vmlinuz" + def kernel_image(kver: str, architecture: str) -> Path: + return Path("lib/modules") / kver / "vmlinuz" + + @staticmethod + def initrd_path(kver: str) -> Path: + return Path("boot") / f"initramfs-{kver}.img" @classmethod def cache_path(cls) -> list[str]: diff --git a/mkosi/distributions/debian.py b/mkosi/distributions/debian.py index dba18f870..60cc8b98d 100644 --- a/mkosi/distributions/debian.py +++ b/mkosi/distributions/debian.py @@ -45,6 +45,10 @@ class DebianInstaller(DistributionInstaller): def kernel_image(name: str, architecture: str) -> Path: return Path(f"boot/vmlinuz-{name}") + @staticmethod + def initrd_path(kver: str) -> Path: + return Path("boot") / f"initrd.img-{kver}" + @classmethod def install(cls, state: "MkosiState") -> None: # Either the image builds or it fails and we restart, we don't need safety fsyncs when bootstrapping diff --git a/mkosi/distributions/opensuse.py b/mkosi/distributions/opensuse.py index f4540376d..dc341eaa6 100644 --- a/mkosi/distributions/opensuse.py +++ b/mkosi/distributions/opensuse.py @@ -1,6 +1,7 @@ # SPDX-License-Identifier: LGPL-2.1+ import shutil +from pathlib import Path from mkosi.backend import MkosiState, add_packages, patch_file, sort_packages from mkosi.distributions import DistributionInstaller @@ -22,6 +23,10 @@ class OpensuseInstaller(DistributionInstaller): def install(cls, state: "MkosiState") -> None: return install_opensuse(state) + @staticmethod + def initrd_path(kver: str) -> Path: + return Path("boot") / f"initrd-{kver}" + @complete_step("Installing openSUSE…") def install_opensuse(state: MkosiState) -> None: diff --git a/mkosi/run.py b/mkosi/run.py index 61475c500..d36821910 100644 --- a/mkosi/run.py +++ b/mkosi/run.py @@ -260,7 +260,7 @@ def run_with_apivfs( "--proc", state.root / "proc", "--dev", state.root / "dev", "--ro-bind", "/sys", state.root / "sys", - "--bind", state.var_tmp(), state.root / "var/tmp", + "--bind", state.var_tmp, state.root / "var/tmp", *bwrap_params, "sh", "-c", ] @@ -297,7 +297,7 @@ def run_workspace_command( "--dev", "/dev", "--proc", "/proc", "--ro-bind", "/sys", "/sys", - "--bind", state.var_tmp(), "/var/tmp", + "--bind", state.var_tmp, "/var/tmp", *bwrap_params, ] diff --git a/tests/test_backend.py b/tests/test_backend.py index afbcc46e7..9a8034b08 100644 --- a/tests/test_backend.py +++ b/tests/test_backend.py @@ -13,7 +13,6 @@ from mkosi.backend import ( safe_tar_extract, set_umask, strip_suffixes, - workspace, ) from mkosi.log import MkosiException @@ -37,13 +36,6 @@ def test_set_umask() -> None: assert tmp3 == 0o777 -def test_workspace() -> None: - assert workspace(Path("/home/folder/mkosi/mkosi")) == Path("/home/folder/mkosi") - assert workspace(Path("/home/../home/folder/mkosi/mkosi")) == Path("/home/../home/folder/mkosi") - assert workspace(Path("/")) == Path("/") - assert workspace(Path()) == Path() - - def test_safe_tar_extract(tmp_path: Path) -> None: name = secrets.token_hex() testfile = tmp_path / name diff --git a/tests/test_parse_load_args.py b/tests/test_parse_load_args.py index a28f9915f..220762b9d 100644 --- a/tests/test_parse_load_args.py +++ b/tests/test_parse_load_args.py @@ -2,7 +2,6 @@ import argparse import tempfile -import uuid from contextlib import contextmanager from os import chdir, getcwd from pathlib import Path @@ -60,28 +59,6 @@ def test_os_distribution() -> None: config.write_text(f"[Distribution]\nDistribution={dist}") assert parse([]).distribution == dist -def test_machine_id() -> None: - id = uuid.uuid4().hex - load_args = parse(["--machine-id", id]) - - assert load_args.machine_id == id - - with pytest.raises(MkosiException): - parse(["--machine-id", "notValidKey"]) - with pytest.raises(tuple((argparse.ArgumentError, SystemExit))): - parse(["--machine-id"]) - - with cd_temp_dir(): - config = Path("mkosi.conf") - config.write_text(f"[Output]\nMachineID={id}") - load_args = parse([]) - assert load_args.machine_id == id - - with cd_temp_dir(): - config = Path("mkosi.conf") - config.write_text("[Output]\nMachineID=") - with pytest.raises(MkosiException): - parse([]) def test_hostname() -> None: assert parse(["--hostname", "name"]).hostname == "name"