]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
Add sandbox verb
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Sat, 2 Nov 2024 17:57:31 +0000 (18:57 +0100)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Sun, 3 Nov 2024 09:41:27 +0000 (10:41 +0100)
In systemd, to run the integration tests, we need to run meson on
the host which will itself invoke mkosi to run the integration tests.
This means all the dependencies to run meson need to be installed on
the host. This doesn't just mean meson needs to be installed, but also
a compiler and various required build dependencies of systemd to allow
building tools invoked by mkosi to build the image.

To avoid having to install these dependencies on the host system, let's
introduce a sandbox verb which runs a command in the mkosi sandbox that's
also used by other verbs such as boot, qemu and shell. This then allows
extra required tools to be installed in the tools tree via ToolsTreePackages=
to allow running these commands without having to install them on the host
system.

mkosi/__init__.py
mkosi/config.py
mkosi/resources/man/mkosi.1.md
mkosi/resources/mkosi-tools/mkosi.conf
mkosi/resources/mkosi-tools/mkosi.conf.d/10-arch.conf
mkosi/resources/mkosi-tools/mkosi.conf.d/10-centos/mkosi.conf.d/20-epel-packages.conf
mkosi/resources/mkosi-tools/mkosi.conf.d/10-debian-kali-ubuntu/mkosi.conf
mkosi/resources/mkosi-tools/mkosi.conf.d/10-fedora/mkosi.conf
mkosi/resources/mkosi-tools/mkosi.conf.d/10-opensuse.conf

index abda7e3d0864d9242fed4d342971272ddb9e17c3..6970926d59ba666bfe86ffd4c1c2bb8398951269 100644 (file)
@@ -3750,6 +3750,31 @@ def build_image(context: Context) -> None:
     print_output_size(context.config.output_dir_or_cwd() / context.config.output_with_compression)
 
 
+def run_sandbox(args: Args, config: Config) -> None:
+    cmdline = args.cmdline or [os.getenv("SHELL", "bash")]
+    options: list[PathString] = ["--same-dir"]
+
+    # If we're not using tools tree certificates we don't have to do anything since the relaxed sandbox will
+    # already have /etc and /var from the host so we don't need to do anything extra.
+    if config.tools_tree_certificates:
+        options += finalize_crypto_mounts(config)
+
+    run(
+        cmdline,
+        stdin=sys.stdin,
+        stdout=sys.stdout,
+        env=os.environ | {"MKOSI_IN_SANDBOX": "1"},
+        log=False,
+        sandbox=config.sandbox(
+            binary=cmdline[0],
+            devices=True,
+            network=True,
+            relaxed=True,
+            options=options,
+        ),
+    )
+
+
 def run_shell(args: Args, config: Config) -> None:
     opname = "acquire shell in" if args.verb == Verb.shell else "boot"
     if config.output_format in (OutputFormat.tar, OutputFormat.cpio):
@@ -4597,7 +4622,7 @@ def run_verb(args: Args, images: Sequence[Config], *, resources: Path) -> None:
         logging.info(f"Output path {output} exists already. (Use --force to rebuild.)")
         return
 
-    if args.verb != Verb.build and not args.force and not output.exists():
+    if args.verb not in (Verb.build, Verb.sandbox) and not args.force and not output.exists():
         die(
             f"Image '{last.name()}' has not been built yet",
             hint="Make sure to build the image first with 'mkosi build' or use '--force'",
@@ -4605,7 +4630,7 @@ def run_verb(args: Args, images: Sequence[Config], *, resources: Path) -> None:
 
     check_workspace_directory(last)
 
-    if last.incremental == Incremental.strict:
+    if args.verb != Verb.sandbox and last.incremental == Incremental.strict:
         if args.force > 1:
             die(
                 "Cannot remove incremental caches when building with Incremental=strict",
@@ -4636,7 +4661,7 @@ def run_verb(args: Args, images: Sequence[Config], *, resources: Path) -> None:
 
     # First, process all directory removals because otherwise if different images share directories
     # a later image build could end up deleting the output generated by an earlier image build.
-    if needs_build(args, last) or args.wipe_build_dir:
+    if args.verb != Verb.sandbox and (needs_build(args, last) or args.wipe_build_dir):
         for config in images:
             run_clean(args, config, resources=resources)
 
@@ -4652,6 +4677,9 @@ def run_verb(args: Args, images: Sequence[Config], *, resources: Path) -> None:
                 sync_repository_metadata(args, [tools], resources=resources, dst=Path(metadata_dir))
                 fork_and_wait(run_build, args, tools, resources=resources, metadata_dir=Path(metadata_dir))
 
+    if args.verb == Verb.sandbox:
+        return run_sandbox(args, last)
+
     for i, config in enumerate(images):
         with prepend_to_environ_path(config):
             check_tools(config, args.verb)
index 7788b309e948f338b5b874380b7ee6c1c4cdf732..644244c6e39df8160d980c5981db0e4963305300 100644 (file)
@@ -77,6 +77,7 @@ class Verb(StrEnum):
     dependencies = enum.auto()
     completion = enum.auto()
     sysupdate = enum.auto()
+    sandbox = enum.auto()
 
     def supports_cmdline(self) -> bool:
         return self in (
@@ -91,6 +92,7 @@ class Verb(StrEnum):
             Verb.completion,
             Verb.documentation,
             Verb.sysupdate,
+            Verb.sandbox,
         )
 
     def needs_build(self) -> bool:
@@ -102,6 +104,7 @@ class Verb(StrEnum):
             Verb.serve,
             Verb.burn,
             Verb.sysupdate,
+            Verb.sandbox,
         )
 
     def needs_config(self) -> bool:
@@ -3013,7 +3016,13 @@ SETTINGS = (
         dest="tools_tree",
         metavar="PATH",
         section="Build",
-        parse=config_make_path_parser(constants=("default",)),
+        parse=(
+            # If we're running inside of mkosi sandbox, the tools tree is already in place so don't pick it
+            # up again.
+            config_make_path_parser(constants=("default",))
+            if not os.getenv("MKOSI_IN_SANDBOX")
+            else lambda value, old: None
+        ),
         paths=("mkosi.tools",),
         help="Look up programs to execute inside the given tree",
         nargs="?",
@@ -3615,6 +3624,7 @@ def create_argument_parser(chdir: bool = True) -> argparse.ArgumentParser:
                 mkosi [options…] {b}journalctl{e}    [command line…]
                 mkosi [options…] {b}coredumpctl{e}   [command line…]
                 mkosi [options…] {b}sysupdate{e}     [command line…]
+                mkosi [options…] {b}sandbox{e}       [command line…]
                 mkosi [options…] {b}clean{e}
                 mkosi [options…] {b}serve{e}
                 mkosi [options…] {b}burn{e}          [device]
index 069787a5a114a9ae1aa21f6e8121e28ee60ca95c..d89c6af31f2fbac292987d643943fd6bb6e40660 100644 (file)
@@ -28,6 +28,8 @@ mkosi — Build Bespoke OS Images
 
 `mkosi [options…] sysupdate [command line…]`
 
+`mkosi [options…] sandbox [command line …]`
+
 `mkosi [options…] clean`
 
 `mkosi [options…] serve`
@@ -135,6 +137,13 @@ The following command line verbs are known:
     specified after the `sysupdate` verb are passed directly to
     `systemd-sysupdate` invocation.
 
+`sandbox`
+:   Run arbitrary commands inside of the same sandbox used to execute
+    other verbs such as `boot`, `shell`, `qemu` 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.
+
 `clean`
 :   Remove build artifacts generated on a previous build. If combined
     with `-f`, also removes incremental build cache images. If `-f` is
index 4a744c59eee60c9ee8ea0ea280a6492754fe194b..3dda76643a754a59c675c15a2b8e36827430b3f9 100644 (file)
@@ -10,6 +10,7 @@ BuildSources=
 
 [Content]
 Bootable=no
+SELinuxRelabel=no
 Packages=
         acl
         attr
@@ -38,5 +39,5 @@ Packages=
         tar
         util-linux
         xfsprogs
+        zsh
         zstd
-SELinuxRelabel=no
index f44c33a230d7dd9b28343111b5f59e17bc883669..c7937c533c0685ca2f9fb7a60dc7f23180f93961 100644 (file)
@@ -14,6 +14,7 @@ Packages=
         dpkg
         edk2-ovmf
         erofs-utils
+        fish
         git
         grub
         openssh
index a13ecea7dacd3de9703918d15eb08bd4293e8aa9..a3624437115d3c3cad612b7f5f3fc85c11e96ef3 100644 (file)
@@ -9,6 +9,7 @@ Packages=
         archlinux-keyring
         debian-keyring
         distribution-gpg-keys
+        fish
         pacman
         sbsigntools
         ubu-keyring
index bde44e73bec87ebfe5265bc581b27b4504239fb6..6874d84e7e9ce3f1bdd12839e8e047b7020b86be 100644 (file)
@@ -20,6 +20,7 @@ Packages=
         createrepo-c
         debian-archive-keyring
         erofs-utils
+        fish
         git-core
         grub-common
         libarchive-tools
index 25f37e66f3b2ffd302317c780a0ce10c152cb471..13137fae90bc80a5b8b1cbd836edd3ecbf3d3b9f 100644 (file)
@@ -13,6 +13,7 @@ Packages=
         dnf5
         dnf5-plugins
         erofs-utils
+        fish
         pacman
         qemu-system-aarch64-core
         qemu-system-ppc-core
index 585f84a6f5fc612768b8b693f39a23d3d85679bb..7e6c54c7130e02f7a5dee34a96cb62eeeb1be119 100644 (file)
@@ -13,6 +13,7 @@ Packages=
         dnf5
         dnf5-plugins
         erofs-utils
+        fish
         git-core
         glibc-gconv-modules-extra
         grep