1import ./make-test-python.nix ({ pkgs, ... }:
2 let
3
4 container = {
5 # We re-use the NixOS container option ...
6 boot.isContainer = true;
7 # ... and revert unwanted defaults
8 networking.useHostResolvConf = false;
9
10 # use networkd to obtain systemd network setup
11 networking.useNetworkd = true;
12 networking.useDHCP = false;
13
14 # systemd-nspawn expects /sbin/init
15 boot.loader.initScript.enable = true;
16
17 imports = [ ../modules/profiles/minimal.nix ];
18 };
19
20 containerSystem = (import ../lib/eval-config.nix {
21 inherit (pkgs) system;
22 modules = [ container ];
23 }).config.system.build.toplevel;
24
25 containerName = "container";
26 containerRoot = "/var/lib/machines/${containerName}";
27
28 in
29 {
30 name = "systemd-machinectl";
31
32 nodes.machine = { lib, ... }: {
33 # use networkd to obtain systemd network setup
34 networking.useNetworkd = true;
35 networking.useDHCP = false;
36
37 # do not try to access cache.nixos.org
38 nix.settings.substituters = lib.mkForce [ ];
39
40 # auto-start container
41 systemd.targets.machines.wants = [ "systemd-nspawn@${containerName}.service" ];
42
43 virtualisation.additionalPaths = [ containerSystem ];
44
45 # not needed, but we want to test the nspawn file generation
46 systemd.nspawn.${containerName} = { };
47
48 systemd.services."systemd-nspawn@${containerName}" = {
49 serviceConfig.Environment = [
50 # Disable tmpfs for /tmp
51 "SYSTEMD_NSPAWN_TMPFS_TMP=0"
52 ];
53 overrideStrategy = "asDropin";
54 };
55 };
56
57 testScript = ''
58 start_all()
59 machine.wait_for_unit("default.target");
60
61 # Install container
62 machine.succeed("mkdir -p ${containerRoot}");
63 # Workaround for nixos-install
64 machine.succeed("chmod o+rx /var/lib/machines");
65 machine.succeed("nixos-install --root ${containerRoot} --system ${containerSystem} --no-channel-copy --no-root-passwd");
66
67 # Allow systemd-nspawn to apply user namespace on immutable files
68 machine.succeed("chattr -i ${containerRoot}/var/empty");
69
70 # Test machinectl start
71 machine.succeed("machinectl start ${containerName}");
72 machine.wait_until_succeeds("systemctl -M ${containerName} is-active default.target");
73
74 # Test nss_mymachines without nscd
75 machine.succeed('LD_LIBRARY_PATH="/run/current-system/sw/lib" getent -s hosts:mymachines hosts ${containerName}');
76
77 # Test nss_mymachines via nscd
78 machine.succeed("getent hosts ${containerName}");
79
80 # Test systemd-nspawn network configuration
81 machine.succeed("ping -n -c 1 ${containerName}");
82
83 # Test systemd-nspawn uses a user namespace
84 machine.succeed("test $(machinectl status ${containerName} | grep 'UID Shift: ' | wc -l) = 1")
85
86 # Test systemd-nspawn reboot
87 machine.succeed("machinectl shell ${containerName} /run/current-system/sw/bin/reboot");
88 machine.wait_until_succeeds("systemctl -M ${containerName} is-active default.target");
89
90 # Test machinectl reboot
91 machine.succeed("machinectl reboot ${containerName}");
92 machine.wait_until_succeeds("systemctl -M ${containerName} is-active default.target");
93
94 # Restart machine
95 machine.shutdown()
96 machine.start()
97 machine.wait_for_unit("default.target");
98
99 # Test auto-start
100 machine.succeed("machinectl show ${containerName}")
101
102 # Test machinectl stop
103 machine.succeed("machinectl stop ${containerName}");
104 machine.wait_until_succeeds("test $(systemctl is-active systemd-nspawn@${containerName}) = inactive");
105
106 # Test tmpfs for /tmp
107 machine.fail("mountpoint /tmp");
108
109 # Show to to delete the container
110 machine.succeed("chattr -i ${containerRoot}/var/empty");
111 machine.succeed("rm -rf ${containerRoot}");
112 '';
113 }
114)