nixos/systemd: add units for capsule support

+53
+4
nixos/modules/system/boot/systemd.nix
··· 208 208 ++ [ 209 209 "systemd-exit.service" 210 210 "systemd-update-done.service" 211 + 212 + # Capsule support 213 + "capsule@.service" 214 + "capsule.slice" 211 215 ] 212 216 ++ cfg.additionalUpstreamSystemUnits; 213 217
+1
nixos/modules/system/boot/systemd/user.nix
··· 30 30 "background.slice" 31 31 "basic.target" 32 32 "bluetooth.target" 33 + "capsule@.target" 33 34 "default.target" 34 35 "exit.target" 35 36 "graphical-session-pre.target"
+1
nixos/tests/all-tests.nix
··· 1411 1411 systemd-binfmt = handleTestOn [ "x86_64-linux" ] ./systemd-binfmt.nix { }; 1412 1412 systemd-boot = handleTest ./systemd-boot.nix { }; 1413 1413 systemd-bpf = runTest ./systemd-bpf.nix; 1414 + systemd-capsules = runTest ./systemd-capsules.nix; 1414 1415 systemd-confinement = handleTest ./systemd-confinement { }; 1415 1416 systemd-coredump = runTest ./systemd-coredump.nix; 1416 1417 systemd-credentials-tpm2 = runTest ./systemd-credentials-tpm2.nix;
+47
nixos/tests/systemd-capsules.nix
··· 1 + { lib, ... }: 2 + { 3 + name = "systemd-capsules"; 4 + 5 + meta.maintainers = with lib.maintainers; [ fpletz ]; 6 + 7 + nodes.machine = 8 + { pkgs, ... }: 9 + { 10 + environment.systemPackages = [ pkgs.hello ]; 11 + systemd.user.services.alice-sleep = { 12 + wantedBy = [ "capsule@alice.target" ]; 13 + serviceConfig = { 14 + ExecStart = "${pkgs.coreutils}/bin/sleep 999"; 15 + }; 16 + }; 17 + }; 18 + 19 + testScript = # python 20 + '' 21 + machine.wait_for_unit("multi-user.target") 22 + 23 + with subtest("capsule setup"): 24 + machine.succeed("systemctl start capsule@alice.service") 25 + 26 + with subtest("imperative user service in capsule"): 27 + machine.succeed("systemd-run --capsule=alice --unit=sleeptest.service /run/current-system/sw/bin/sleep 999") 28 + machine.succeed("systemctl --capsule=alice status sleeptest.service") 29 + 30 + with subtest("declarative user service in capsule"): 31 + machine.succeed("systemctl --capsule=alice status alice-sleep.service") 32 + machine.succeed("systemctl --capsule=alice stop alice-sleep.service") 33 + machine.fail("systemctl --capsule=alice status alice-sleep.service") 34 + machine.succeed("systemctl --capsule=alice start alice-sleep.service") 35 + machine.succeed("systemctl --capsule=alice status alice-sleep.service") 36 + 37 + with subtest("interactive shell with terminal in capsule"): 38 + hello_output = machine.succeed("systemd-run -t --capsule=alice /run/current-system/sw/bin/bash -i -c 'hello | tee ~/hello'") 39 + assert hello_output == "Hello, world!\r\n" 40 + machine.copy_from_vm("/var/lib/capsules/alice/hello") 41 + 42 + with subtest("capsule cleanup"): 43 + machine.succeed("systemctl --capsule=alice stop sleeptest.service") 44 + machine.succeed("systemctl stop capsule@alice.service") 45 + machine.succeed("systemctl clean --all capsule@alice.service") 46 + ''; 47 + }