From 4797026924cc5bdee6baaa581dd53457d22ce330 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Sun, 7 Apr 2024 19:23:02 +0200 Subject: [PATCH] Add RuntimeBuildSources= setting This setting mounts the build sources and build directory into a booted container/virtual machine in the same location that they were mounted to do the build. This helps both with making gdb more useful in the container as the sources will be available for use by gdb without having to do any source directory mapping. It also helps with doing incremental builds inside the container. --- mkosi/__init__.py | 9 +++++++++ mkosi/config.py | 9 +++++++++ mkosi/qemu.py | 40 ++++++++++++++++++++++++++++++++-------- mkosi/resources/mkosi.md | 7 +++++++ mkosi/vmspawn.py | 9 +++++++++ tests/test_json.py | 2 ++ 6 files changed, 68 insertions(+), 8 deletions(-) diff --git a/mkosi/__init__.py b/mkosi/__init__.py index 0365b8f04..1044b08a0 100644 --- a/mkosi/__init__.py +++ b/mkosi/__init__.py @@ -3851,6 +3851,15 @@ def run_shell(args: Args, config: Config) -> None: else: cmdline += ["--image", fname] + if config.runtime_build_sources: + with finalize_source_mounts(config, ephemeral=False) as mounts: + for mount in mounts: + uidmap = "rootidmap" if Path(mount.src).stat().st_uid == INVOKING_USER.uid else "noidmap" + cmdline += ["--bind", f"{mount.src}:{mount.dst}:norbind,{uidmap}"] + + if config.build_dir: + cmdline += ["--bind", f"{config.build_dir}:/work/build:norbind,noidmap"] + for tree in config.runtime_trees: target = Path("/root/src") / (tree.target or "") # We add norbind because very often RuntimeTrees= will be used to mount the source directory into the diff --git a/mkosi/config.py b/mkosi/config.py index 4042c4a7e..4a8c92d1a 100644 --- a/mkosi/config.py +++ b/mkosi/config.py @@ -1475,6 +1475,7 @@ class Config: runtime_size: Optional[int] runtime_scratch: ConfigFeature runtime_network: Network + runtime_build_sources: bool ssh_key: Optional[Path] ssh_certificate: Optional[Path] machine: Optional[str] @@ -2794,6 +2795,13 @@ SETTINGS = ( help="Set networking backend to use when booting the image", default=Network.user, ), + ConfigSetting( + dest="runtime_build_sources", + metavar="BOOL", + section="Host", + parse=config_parse_boolean, + help="Mount build sources and build directory in /work when booting the image", + ), ConfigSetting( dest="ssh_key", metavar="PATH", @@ -3948,6 +3956,7 @@ def summary(config: Config) -> str: Runtime Size: {format_bytes_or_none(config.runtime_size)} Runtime Scratch: {config.runtime_scratch} Runtime Network: {config.runtime_network} + Runtime Build Sources: {config.runtime_build_sources} SSH Signing Key: {none_to_none(config.ssh_key)} SSH Certificate: {none_to_none(config.ssh_certificate)} Machine: {config.machine_or_name()} diff --git a/mkosi/qemu.py b/mkosi/qemu.py index 75cb4df76..07e4e46f3 100644 --- a/mkosi/qemu.py +++ b/mkosi/qemu.py @@ -36,6 +36,7 @@ from mkosi.config import ( want_selinux_relabel, ) from mkosi.log import ARG_DEBUG, die +from mkosi.mounts import finalize_source_mounts from mkosi.partition import finalize_root, find_partitions from mkosi.run import SD_LISTEN_FDS_START, AsyncioThread, find_binary, fork_and_wait, run, spawn from mkosi.sandbox import Mount @@ -298,8 +299,8 @@ def find_virtiofsd(*, tools: Path = Path("/")) -> Optional[Path]: @contextlib.contextmanager -def start_virtiofsd(config: Config, directory: Path, *, name: str, selinux: bool = False) -> Iterator[Path]: - uidmap = directory.stat().st_uid == INVOKING_USER.uid +def start_virtiofsd(config: Config, directory: PathString, *, name: str, selinux: bool = False) -> Iterator[Path]: + uidmap = Path(directory).stat().st_uid == INVOKING_USER.uid virtiofsd = find_virtiofsd(tools=config.tools()) if virtiofsd is None: @@ -795,7 +796,7 @@ def run_qemu(args: Args, config: Config) -> None: # A shared memory backend might increase ram usage so only add one if actually necessary for virtiofsd. shm = [] - if config.runtime_trees or config.output_format == OutputFormat.directory: + if config.runtime_trees or config.runtime_build_sources or config.output_format == OutputFormat.directory: shm = ["-object", f"memory-backend-memfd,id=mem,size={config.qemu_mem // 1024**2}M,share=on"] machine = f"type={config.architecture.default_qemu_machine()}" @@ -953,15 +954,38 @@ def run_qemu(args: Args, config: Config) -> None: ] kcl += ["root=root", "rootfstype=virtiofs", "rw"] - for tree in config.runtime_trees: - sock = stack.enter_context(start_virtiofsd(config, tree.source, name=os.fspath(tree.source))) - tag = tree.target.name if tree.target else tree.source.name + def add_virtiofs_mount( + sock: Path, + dst: PathString, + cmdline: list[PathString], + kcl: list[str], + *, tag: str + ) -> None: cmdline += [ "-chardev", f"socket,id={sock.name},path={sock}", "-device", f"vhost-user-fs-pci,queue-size=1024,chardev={sock.name},tag={tag}", ] - target = Path("/root/src") / (tree.target or "") - kcl += [f"systemd.mount-extra={tag}:{target}:virtiofs"] + kcl += [f"systemd.mount-extra={tag}:{dst}:virtiofs"] + + if config.runtime_build_sources: + with finalize_source_mounts(config, ephemeral=False) as mounts: + for mount in mounts: + sock = stack.enter_context(start_virtiofsd(config, mount.src, name=os.fspath(mount.src))) + add_virtiofs_mount(sock, mount.dst, cmdline, kcl, tag=Path(mount.src).name) + + if config.build_dir: + sock = stack.enter_context(start_virtiofsd(config, config.build_dir, name=os.fspath(config.build_dir))) + add_virtiofs_mount(sock, "/work/build", cmdline, kcl, tag="build") + + for tree in config.runtime_trees: + sock = stack.enter_context(start_virtiofsd(config, tree.source, name=os.fspath(tree.source))) + add_virtiofs_mount( + sock, + Path("/root/src") / (tree.target or ""), + cmdline, + kcl, + tag=tree.target.name if tree.target else tree.source.name, + ) if want_scratch(config) or config.output_format in (OutputFormat.disk, OutputFormat.esp): cmdline += ["-device", "virtio-scsi-pci,id=scsi"] diff --git a/mkosi/resources/mkosi.md b/mkosi/resources/mkosi.md index 4b08c2474..04953b64a 100644 --- a/mkosi/resources/mkosi.md +++ b/mkosi/resources/mkosi.md @@ -1821,6 +1821,13 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, `systemd-networkd` is running on the host which will automatically configure the host interface of the link. +`RuntimeBuildSources=`, `--runtime-build-sources=` + +: 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`. + `SshKey=`, `--ssh-key=` : Path to the X509 private key in PEM format to use to connect to a diff --git a/mkosi/vmspawn.py b/mkosi/vmspawn.py index 44ea057d7..c1b910f99 100644 --- a/mkosi/vmspawn.py +++ b/mkosi/vmspawn.py @@ -14,6 +14,7 @@ from mkosi.config import ( yes_no, ) from mkosi.log import die +from mkosi.mounts import finalize_source_mounts from mkosi.qemu import ( apply_runtime_size, copy_ephemeral, @@ -77,6 +78,14 @@ def run_vmspawn(args: Args, config: Config) -> None: apply_runtime_size(config, fname) + if config.runtime_build_sources: + with finalize_source_mounts(config, ephemeral=False) as mounts: + for mount in mounts: + cmdline += ["--bind", f"{mount.src}:{mount.dst}"] + + if config.build_dir: + cmdline += ["--bind", f"{config.build_dir}:/work/build"] + for tree in config.runtime_trees: target = Path("/root/src") / (tree.target or "") cmdline += ["--bind", f"{tree.source}:{target}"] diff --git a/tests/test_json.py b/tests/test_json.py index e36c41aed..a4c961c1a 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -259,6 +259,7 @@ def test_config() -> None: false ], "RootShell": "/bin/tcsh", + "RuntimeBuildSources": true, "RuntimeNetwork": "interface", "RuntimeScratch": "enabled", "RuntimeSize": 8589934592, @@ -439,6 +440,7 @@ def test_config() -> None: repository_key_check = False, root_password = ("test1234", False), root_shell = "/bin/tcsh", + runtime_build_sources = True, runtime_network = Network.interface, runtime_scratch = ConfigFeature.enabled, runtime_size = 8589934592, -- 2.47.2