From: Daan De Meyer Date: Sun, 8 Sep 2024 14:38:55 +0000 (+0200) Subject: Add sysupdate verb X-Git-Tag: v25~307 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f23106f2f3dd6972c89ffd1fe52a8730bacf0fbe;p=thirdparty%2Fmkosi.git Add sysupdate verb --- diff --git a/mkosi/__init__.py b/mkosi/__init__.py index 956347530..e4301705c 100644 --- a/mkosi/__init__.py +++ b/mkosi/__init__.py @@ -111,6 +111,7 @@ from mkosi.sandbox import ( unshare, userns_has_single_user, ) +from mkosi.sysupdate import run_sysupdate from mkosi.tree import copy_tree, make_tree, move_tree, rmtree from mkosi.types import PathString from mkosi.user import INVOKING_USER @@ -2233,6 +2234,15 @@ def check_tools(config: Config, verb: Verb) -> None: if verb == Verb.qemu and config.vmm == Vmm.vmspawn: check_systemd_tool(config, "systemd-vmspawn", version="256", reason="boot images with vmspawn") + if verb == Verb.sysupdate: + check_systemd_tool( + config, + "systemd-sysupdate", + "/usr/lib/systemd/systemd-sysupdate", + version="257~devel", + reason="Update the host system with systemd-sysupdate", + ) + def configure_ssh(context: Context) -> None: if not context.config.ssh: @@ -4128,4 +4138,5 @@ def run_verb(args: Args, images: Sequence[Config], *, resources: Path) -> None: Verb.qemu: run_vm, Verb.serve: run_serve, Verb.burn: run_burn, + Verb.sysupdate: run_sysupdate, }[args.verb](args, last) diff --git a/mkosi/config.py b/mkosi/config.py index a8218bacf..a1f57b0aa 100644 --- a/mkosi/config.py +++ b/mkosi/config.py @@ -75,6 +75,7 @@ class Verb(StrEnum): burn = enum.auto() dependencies = enum.auto() completion = enum.auto() + sysupdate = enum.auto() def supports_cmdline(self) -> bool: return self in ( @@ -88,6 +89,7 @@ class Verb(StrEnum): Verb.burn, Verb.completion, Verb.documentation, + Verb.sysupdate, ) def needs_build(self) -> bool: @@ -98,6 +100,7 @@ class Verb(StrEnum): Verb.qemu, Verb.serve, Verb.burn, + Verb.sysupdate, ) def needs_root(self) -> bool: @@ -1445,6 +1448,7 @@ class Config: image_version: Optional[str] split_artifacts: bool repart_dirs: list[Path] + sysupdate_dir: Optional[Path] sector_size: Optional[int] overlay: bool seed: uuid.UUID @@ -3061,6 +3065,16 @@ SETTINGS = ( parse=config_make_path_parser(required=False), help="Set the path used to store forwarded machine journals", ), + ConfigSetting( + dest="sysupdate_dir", + long="--sysupdate-dir", + metavar="PATH", + name="SysupdateDirectory", + section="Host", + parse=config_make_path_parser(), + paths=("mkosi.sysupdate",), + help="Directory containing systemd-sysupdate transfer definitions", + ), ConfigSetting( dest="qemu_gui", metavar="BOOL", diff --git a/mkosi/resources/man/mkosi.md b/mkosi/resources/man/mkosi.md index 3320a8077..4f6ffafc7 100644 --- a/mkosi/resources/man/mkosi.md +++ b/mkosi/resources/man/mkosi.md @@ -26,6 +26,8 @@ mkosi — Build Bespoke OS Images `mkosi [options…] coredumpctl [command line…]` +`mkosi [options…] sysupdate [command line…]` + `mkosi [options…] clean` `mkosi [options…] serve` @@ -124,6 +126,13 @@ The following command line verbs are known: forwarded journal instead of the image. Note that this requires configuring systemd-coredump to store coredumps in the journal. +`sysupdate` +: Invokes `systemd-sysupdate` with the `--transfer-source=` option set + to the output directory and the `--definitions=` option set to the + directory configured with `SysupdateDirectory=`. Any arguments + specified after the `sysupdate` verb are passed directly to + `systemd-sysupdate` invocation. + `clean` : Remove build artifacts generated on a previous build. If combined with `-f`, also removes incremental build cache images. If `-f` is @@ -1699,6 +1708,21 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, of file if your workload produces more than `4G` worth of journal data. +`SysupdateDirectory=`, `--sysupdate-dir=` +: Path to a directory containing systemd-sysupdate transfer definition + files that are used by `mkosi sysupdate`. If `mkosi.sysupdate/` + exists in the local directory, it will be used for this purpose as + well. + + Note that `mkosi sysupdate` invokes `systemd-sysupdate` with + `--transfer-source=` set to the mkosi output directory. To make use + of this in a transfer definition file, set `PathRelativeTo=explicit` + to have the `Path=` setting for the transfer source be interpreted + relative to the mkosi output directory. Generally, configuring + `PathRelativeTo=explicit` and `Path=/` for the transfer source is + sufficient for the match pattern to be interpreted relative to the + mkosi output directory. + ### [Match] Section. `Profile=` diff --git a/mkosi/sysupdate.py b/mkosi/sysupdate.py new file mode 100644 index 000000000..efb3cf7ef --- /dev/null +++ b/mkosi/sysupdate.py @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +import os +import sys +from pathlib import Path + +from mkosi.config import Args, Config +from mkosi.log import die +from mkosi.run import run +from mkosi.types import PathString + + +def run_sysupdate(args: Args, config: Config) -> None: + if not config.split_artifacts: + die("SplitArtifacts= must be enabled to be able to use mkosi sysupdate") + + if not config.sysupdate_dir: + die("No sysupdate definitions directory specified", + hint="Specify a directory containing systemd-sysupdate transfer definitions with SysupdateDirectory=") + + if not (sysupdate := config.find_binary("systemd-sysupdate", "/usr/lib/systemd/systemd-sysupdate")): + die("Could not find systemd-sysupdate") + + cmd: list[PathString] = [ + sysupdate, + "--definitions", config.sysupdate_dir, + "--transfer-source", config.output_dir_or_cwd(), + *args.cmdline, + ] + + run( + cmd, + stdin=sys.stdin, + stdout=sys.stdout, + env=os.environ | config.environment, + log=False, + sandbox=config.sandbox( + binary=sysupdate, + devices=True, + network=True, + relaxed=True, + options=[ + *(["--bind", "/boot", "/boot"] if Path("/boot").exists() else []), + *(["--bind", "/efi", "/efi"] if Path("/efi").exists() else []), + ] + ), + ) diff --git a/tests/test_json.py b/tests/test_json.py index c2a044c6a..f887d3f80 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -318,6 +318,7 @@ def test_config() -> None: "SyncScripts": [ "/sync" ], + "SysupdateDirectory": "/sysupdate", "Timezone": null, "ToolsTree": null, "ToolsTreeCertificates": true, @@ -494,6 +495,7 @@ def test_config() -> None: ssh_certificate=Path("/path/to/cert"), ssh_key=None, sync_scripts=[Path("/sync")], + sysupdate_dir=Path("/sysupdate"), timezone=None, tools_tree=None, tools_tree_certificates=True,