at 25.11-pre 8.2 kB view raw
1import ./make-test-python.nix ( 2 { pkgs, ... }: 3 let 4 5 container = 6 { config, ... }: 7 { 8 # We re-use the NixOS container option ... 9 boot.isContainer = true; 10 # ... and revert unwanted defaults 11 networking.useHostResolvConf = false; 12 13 # use networkd to obtain systemd network setup 14 networking.useNetworkd = true; 15 networking.useDHCP = false; 16 17 # systemd-nspawn expects /sbin/init 18 boot.loader.initScript.enable = true; 19 20 imports = [ ../modules/profiles/minimal.nix ]; 21 22 system.stateVersion = config.system.nixos.release; 23 24 nixpkgs.pkgs = pkgs; 25 }; 26 27 containerSystem = 28 (import ../lib/eval-config.nix { 29 system = null; 30 modules = [ container ]; 31 }).config.system.build.toplevel; 32 33 containerName = "container"; 34 containerRoot = "/var/lib/machines/${containerName}"; 35 36 containerTarball = pkgs.callPackage ../lib/make-system-tarball.nix { 37 storeContents = [ 38 { 39 object = containerSystem; 40 symlink = "/nix/var/nix/profiles/system"; 41 } 42 ]; 43 44 contents = [ 45 { 46 source = containerSystem + "/etc/os-release"; 47 target = "/etc/os-release"; 48 } 49 { 50 source = containerSystem + "/init"; 51 target = "/sbin/init"; 52 } 53 ]; 54 }; 55 in 56 { 57 name = "systemd-machinectl"; 58 59 nodes.machine = 60 { lib, ... }: 61 { 62 # use networkd to obtain systemd network setup 63 networking.useNetworkd = true; 64 networking.useDHCP = false; 65 66 # do not try to access cache.nixos.org 67 nix.settings.substituters = lib.mkForce [ ]; 68 69 # auto-start container 70 systemd.targets.machines.wants = [ "systemd-nspawn@${containerName}.service" ]; 71 72 virtualisation.additionalPaths = [ 73 containerSystem 74 containerTarball 75 ]; 76 77 systemd.tmpfiles.rules = [ 78 "d /var/lib/machines/shared-decl 0755 root root - -" 79 ]; 80 systemd.nspawn.shared-decl = { 81 execConfig = { 82 Boot = false; 83 Parameters = "${containerSystem}/init"; 84 }; 85 filesConfig = { 86 BindReadOnly = "/nix/store"; 87 }; 88 }; 89 90 systemd.nspawn.${containerName} = { 91 filesConfig = { 92 # workaround to fix kernel namespaces; needed for Nix sandbox 93 # https://github.com/systemd/systemd/issues/27994#issuecomment-1704005670 94 Bind = "/proc:/run/proc"; 95 }; 96 }; 97 98 systemd.services."systemd-nspawn@${containerName}" = { 99 serviceConfig.Environment = [ 100 # Disable tmpfs for /tmp 101 "SYSTEMD_NSPAWN_TMPFS_TMP=0" 102 103 # force unified cgroup delegation, which would be the default 104 # if systemd could check the capabilities of the installed systemd. 105 # see also: https://github.com/NixOS/nixpkgs/pull/198526 106 "SYSTEMD_NSPAWN_UNIFIED_HIERARCHY=1" 107 ]; 108 overrideStrategy = "asDropin"; 109 }; 110 111 # open DHCP for container 112 networking.firewall.extraCommands = '' 113 ${pkgs.iptables}/bin/iptables -A nixos-fw -i ve-+ -p udp -m udp --dport 67 -j nixos-fw-accept 114 ''; 115 }; 116 117 testScript = '' 118 start_all() 119 machine.wait_for_unit("default.target"); 120 121 # Test machinectl start stop of shared-decl 122 machine.succeed("machinectl start shared-decl"); 123 machine.wait_until_succeeds("systemctl -M shared-decl is-active default.target"); 124 machine.succeed("machinectl stop shared-decl"); 125 126 # create containers root 127 machine.succeed("mkdir -p ${containerRoot}"); 128 129 # start container with shared nix store by using same arguments as for systemd-nspawn@.service 130 machine.succeed("systemd-run systemd-nspawn --machine=${containerName} --network-veth -U --bind-ro=/nix/store ${containerSystem}/init") 131 machine.wait_until_succeeds("systemctl -M ${containerName} is-active default.target"); 132 133 # Test machinectl stop 134 machine.succeed("machinectl stop ${containerName}"); 135 136 # Install container 137 # Workaround for nixos-install 138 machine.succeed("chmod o+rx /var/lib/machines"); 139 machine.succeed("nixos-install --root ${containerRoot} --system ${containerSystem} --no-channel-copy --no-root-passwd"); 140 141 # Allow systemd-nspawn to apply user namespace on immutable files 142 machine.succeed("chattr -i ${containerRoot}/var/empty"); 143 144 # Test machinectl start 145 machine.succeed("machinectl start ${containerName}"); 146 machine.wait_until_succeeds("systemctl -M ${containerName} is-active default.target"); 147 148 # Test systemd-nspawn configured unified cgroup delegation 149 # see also: 150 # https://github.com/systemd/systemd/blob/main/docs/CGROUP_DELEGATION.md#three-different-tree-setups- 151 machine.succeed('systemd-run --pty --wait -M ${containerName} /run/current-system/sw/bin/stat --format="%T" --file-system /sys/fs/cgroup > fstype') 152 machine.succeed('test $(tr -d "\\r" < fstype) = cgroup2fs') 153 154 # Test if systemd-nspawn provides a working environment for nix to build derivations 155 # https://nixos.org/guides/nix-pills/07-working-derivation 156 machine.succeed('systemd-run --pty --wait -M ${containerName} /run/current-system/sw/bin/nix-instantiate --expr \'derivation { name = "myname"; builder = "/bin/sh"; args = [ "-c" "echo foo > $out" ]; system = "${pkgs.system}"; }\' --add-root /tmp/drv') 157 machine.succeed('systemd-run --pty --wait -M ${containerName} /run/current-system/sw/bin/nix-store --option substitute false --realize /tmp/drv') 158 159 # Test nss_mymachines without nscd 160 machine.succeed('LD_LIBRARY_PATH="/run/current-system/sw/lib" getent -s hosts:mymachines hosts ${containerName}'); 161 162 # Test nss_mymachines via nscd 163 machine.succeed("getent hosts ${containerName}"); 164 165 # Test systemd-nspawn network configuration to container 166 machine.succeed("networkctl --json=short status ve-${containerName} | ${pkgs.jq}/bin/jq -e '.OperationalState == \"routable\"'"); 167 168 # Test systemd-nspawn network configuration to host 169 machine.succeed("machinectl shell ${containerName} /run/current-system/sw/bin/networkctl --json=short status host0 | ${pkgs.jq}/bin/jq -r '.OperationalState == \"routable\"'"); 170 171 # Test systemd-nspawn network configuration 172 machine.succeed("ping -n -c 1 ${containerName}"); 173 174 # Test systemd-nspawn uses a user namespace 175 machine.succeed("test $(machinectl status ${containerName} | grep 'UID Shift: ' | wc -l) = 1") 176 177 # Test systemd-nspawn reboot 178 machine.succeed("machinectl shell ${containerName} /run/current-system/sw/bin/reboot"); 179 machine.wait_until_succeeds("systemctl -M ${containerName} is-active default.target"); 180 181 # Test machinectl reboot 182 machine.succeed("machinectl reboot ${containerName}"); 183 machine.wait_until_succeeds("systemctl -M ${containerName} is-active default.target"); 184 185 # Restart machine 186 machine.shutdown() 187 machine.start() 188 machine.wait_for_unit("default.target"); 189 190 # Test auto-start 191 machine.succeed("machinectl show ${containerName}") 192 193 # Test machinectl stop 194 machine.succeed("machinectl stop ${containerName}"); 195 machine.wait_until_succeeds("test $(systemctl is-active systemd-nspawn@${containerName}) = inactive"); 196 197 # Test tmpfs for /tmp 198 machine.fail("mountpoint /tmp"); 199 200 # Show to to delete the container 201 machine.succeed("chattr -i ${containerRoot}/var/empty"); 202 machine.succeed("rm -rf ${containerRoot}"); 203 204 # Test import tarball, start, stop and remove 205 machine.succeed("machinectl import-tar ${containerTarball}/tarball/*.tar* ${containerName}"); 206 machine.succeed("machinectl start ${containerName}"); 207 machine.wait_until_succeeds("systemctl -M ${containerName} is-active default.target"); 208 machine.succeed("machinectl stop ${containerName}"); 209 machine.wait_until_succeeds("test $(systemctl is-active systemd-nspawn@${containerName}) = inactive"); 210 machine.succeed("machinectl remove ${containerName}"); 211 ''; 212 } 213)