From: Daan De Meyer Date: Mon, 10 Feb 2025 18:18:46 +0000 (+0100) Subject: serve: Add StorageTargetMode= feature X-Git-Tag: v26~398^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b851139620ae065f875b829235e6cd5b30f0da5b;p=thirdparty%2Fmkosi.git serve: Add StorageTargetMode= feature Let's make it configurable whether we run systemd-storagetm as part of serve. --- diff --git a/mkosi/__init__.py b/mkosi/__init__.py index d710d29c8..9d8698c1c 100644 --- a/mkosi/__init__.py +++ b/mkosi/__init__.py @@ -101,6 +101,7 @@ from mkosi.qemu import ( start_journal_remote, ) from mkosi.run import ( + Popen, apivfs_options, chroot_cmd, chroot_options, @@ -4310,14 +4311,42 @@ def run_coredumpctl(args: Args, config: Config) -> None: run_systemd_tool("coredumpctl", args, config) +def start_storage_target_mode(config: Config) -> AbstractContextManager[Optional[Popen]]: + if config.storage_target_mode == ConfigFeature.disabled: + return contextlib.nullcontext() + + if config.storage_target_mode == ConfigFeature.auto and os.getuid() != 0: + return contextlib.nullcontext() + + if config.output_format != OutputFormat.disk: + if config.storage_target_mode == ConfigFeature.enabled: + die("Storage target mode is only supported for the 'disk' output format") + + return contextlib.nullcontext() + + if not config.find_binary("/usr/lib/systemd/systemd-storagetm"): + if config.storage_target_mode == ConfigFeature.enabled: + die("Storage target mode enabled but systemd-storagetm is not installed") + + return contextlib.nullcontext() + + return spawn( + ["/usr/lib/systemd/systemd-storagetm", config.output_with_format], + stdin=sys.stdin, + stdout=sys.stdout, + sandbox=config.sandbox( + network=True, + relaxed=True, + options=["--chdir", config.output_dir_or_cwd()], + setup=become_root_cmd(), + ), + ) + + def run_serve(args: Args, config: Config) -> None: """Serve the output directory via a tiny HTTP server""" with contextlib.ExitStack() as stack: - want_storagetm = config.output_format == OutputFormat.disk and config.find_binary( - "/usr/lib/systemd/systemd-storagetm" - ) - http = stack.enter_context( spawn( [python_binary(config), "-m", "http.server", "8081"], @@ -4331,26 +4360,15 @@ def run_serve(args: Args, config: Config) -> None: ) ) - if want_storagetm: - storagetm = stack.enter_context( - spawn( - ["/usr/lib/systemd/systemd-storagetm", config.output_with_format], - stdin=sys.stdin, - stdout=sys.stdout, - sandbox=config.sandbox( - network=True, - relaxed=True, - options=["--chdir", config.output_dir_or_cwd()], - setup=become_root_cmd(), - ), - ) - ) + storagetm = stack.enter_context(start_storage_target_mode(config)) + # If we run systemd-storagetm with run0, it replaces the foreground process group with its own which + # means the http process doesn't get SIGINT from the terminal, so let's send it ourselves in that + # case. + if storagetm and os.getuid() != 0: storagetm.wait() http.send_signal(signal.SIGINT) - http.wait() - def generate_key_cert_pair(args: Args) -> None: """Generate a private key and accompanying X509 certificate using openssl""" diff --git a/mkosi/config.py b/mkosi/config.py index ed24c7d15..c18f95c8c 100644 --- a/mkosi/config.py +++ b/mkosi/config.py @@ -1943,6 +1943,7 @@ class Config: credentials: dict[str, str] kernel_command_line_extra: list[str] register: ConfigFeature + storage_target_mode: ConfigFeature runtime_trees: list[ConfigTree] runtime_size: Optional[int] runtime_scratch: ConfigFeature @@ -3825,6 +3826,14 @@ SETTINGS: list[ConfigSetting[Any]] = [ default=ConfigFeature.auto, help="Register booted vm/container with systemd-machined", ), + ConfigSetting( + dest="storage_target_mode", + metavar="FEATURE", + section="Runtime", + parse=config_parse_feature, + default=ConfigFeature.auto, + help="Run systemd-storagetm as part of the serve verb", + ), ] SETTINGS_LOOKUP_BY_NAME = {name: s for s in SETTINGS for name in [s.name, *s.compat_names]} SETTINGS_LOOKUP_BY_DEST = {s.dest: s for s in SETTINGS} @@ -5061,6 +5070,7 @@ def summary(config: Config) -> str: Machine: {config.machine_or_name()} Forward Journal: {none_to_none(config.forward_journal)} Register guest with machined: {config.register} + Storage Target Mode: {config.storage_target_mode} Virtual Machine Monitor: {config.vmm} Console: {config.console} diff --git a/mkosi/resources/man/mkosi.1.md b/mkosi/resources/man/mkosi.1.md index a8d6cb9c4..e402e38dd 100644 --- a/mkosi/resources/man/mkosi.1.md +++ b/mkosi/resources/man/mkosi.1.md @@ -1850,6 +1850,16 @@ 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. +`StorageTargetMode=`, `--storage-target-mode=` +: Specifies whether the `serve` verb should start + **systemd-storagetm** to serve disk images over NVME-TCP. Takes a + boolean value or `auto`. If enabled, systemd-storagetm is always + started and mkosi will fail if it cannot start systemd-storagetm. If + disabled, systemd-storagetm is never started. If `auto`, + systemd-storagetm will be started if a disk image is being built, + the systemd-storagetm binary is found and `mkosi serve` is being + invoked as the root user. + `SysupdateDirectory=`, `--sysupdate-directory=` : Path to a directory containing systemd-sysupdate transfer definition files that are used by `mkosi sysupdate`. If `mkosi.sysupdate/` diff --git a/tests/test_json.py b/tests/test_json.py index 31265dfc1..a5be927bc 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -353,6 +353,7 @@ def test_config() -> None: "Ssh": false, "SshCertificate": "/path/to/cert", "SshKey": null, + "StorageTargetMode": "enabled", "SyncScripts": [ "/sync" ], @@ -566,6 +567,7 @@ def test_config() -> None: ssh_certificate=Path("/path/to/cert"), ssh_key=None, ssh=False, + storage_target_mode=ConfigFeature.enabled, sync_scripts=[Path("/sync")], sysupdate_dir=Path("/sysupdate"), timezone=None,