at 24.11-pre 6.2 kB view raw
1import ./make-test-python.nix ({ pkgs, ... }: 2let 3 4 container = { config, ... }: { 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 system.stateVersion = config.system.nixos.version; 20 }; 21 22 containerSystem = (import ../lib/eval-config.nix { 23 inherit (pkgs) system; 24 modules = [ container ]; 25 }).config.system.build.toplevel; 26 27 containerName = "container"; 28 containerRoot = "/var/lib/machines/${containerName}"; 29 30 containerTarball = pkgs.callPackage ../lib/make-system-tarball.nix { 31 storeContents = [ 32 { 33 object = containerSystem; 34 symlink = "/nix/var/nix/profiles/system"; 35 } 36 ]; 37 38 contents = [ 39 { 40 source = containerSystem + "/etc/os-release"; 41 target = "/etc/os-release"; 42 } 43 { 44 source = containerSystem + "/init"; 45 target = "/sbin/init"; 46 } 47 ]; 48 }; 49in 50{ 51 name = "systemd-machinectl"; 52 53 nodes.machine = { lib, ... }: { 54 # use networkd to obtain systemd network setup 55 networking.useNetworkd = true; 56 networking.useDHCP = false; 57 58 # do not try to access cache.nixos.org 59 nix.settings.substituters = lib.mkForce [ ]; 60 61 # auto-start container 62 systemd.targets.machines.wants = [ "systemd-nspawn@${containerName}.service" ]; 63 64 virtualisation.additionalPaths = [ containerSystem containerTarball ]; 65 66 systemd.tmpfiles.rules = [ 67 "d /var/lib/machines/shared-decl 0755 root root - -" 68 ]; 69 systemd.nspawn.shared-decl = { 70 execConfig = { 71 Boot = false; 72 Parameters = "${containerSystem}/init"; 73 }; 74 filesConfig = { 75 BindReadOnly = "/nix/store"; 76 }; 77 }; 78 79 systemd.services."systemd-nspawn@${containerName}" = { 80 serviceConfig.Environment = [ 81 # Disable tmpfs for /tmp 82 "SYSTEMD_NSPAWN_TMPFS_TMP=0" 83 ]; 84 overrideStrategy = "asDropin"; 85 }; 86 87 # open DHCP for container 88 networking.firewall.extraCommands = '' 89 ${pkgs.iptables}/bin/iptables -A nixos-fw -i ve-+ -p udp -m udp --dport 67 -j nixos-fw-accept 90 ''; 91 }; 92 93 testScript = '' 94 start_all() 95 machine.wait_for_unit("default.target"); 96 97 # Test machinectl start stop of shared-decl 98 machine.succeed("machinectl start shared-decl"); 99 machine.wait_until_succeeds("systemctl -M shared-decl is-active default.target"); 100 machine.succeed("machinectl stop shared-decl"); 101 102 # create containers root 103 machine.succeed("mkdir -p ${containerRoot}"); 104 105 # start container with shared nix store by using same arguments as for systemd-nspawn@.service 106 machine.succeed("systemd-run systemd-nspawn --machine=${containerName} --network-veth -U --bind-ro=/nix/store ${containerSystem}/init") 107 machine.wait_until_succeeds("systemctl -M ${containerName} is-active default.target"); 108 109 # Test machinectl stop 110 machine.succeed("machinectl stop ${containerName}"); 111 112 # Install container 113 # Workaround for nixos-install 114 machine.succeed("chmod o+rx /var/lib/machines"); 115 machine.succeed("nixos-install --root ${containerRoot} --system ${containerSystem} --no-channel-copy --no-root-passwd"); 116 117 # Allow systemd-nspawn to apply user namespace on immutable files 118 machine.succeed("chattr -i ${containerRoot}/var/empty"); 119 120 # Test machinectl start 121 machine.succeed("machinectl start ${containerName}"); 122 machine.wait_until_succeeds("systemctl -M ${containerName} is-active default.target"); 123 124 # Test nss_mymachines without nscd 125 machine.succeed('LD_LIBRARY_PATH="/run/current-system/sw/lib" getent -s hosts:mymachines hosts ${containerName}'); 126 127 # Test nss_mymachines via nscd 128 machine.succeed("getent hosts ${containerName}"); 129 130 # Test systemd-nspawn network configuration to container 131 machine.succeed("networkctl --json=short status ve-${containerName} | ${pkgs.jq}/bin/jq -e '.OperationalState == \"routable\"'"); 132 133 # Test systemd-nspawn network configuration to host 134 machine.succeed("machinectl shell ${containerName} /run/current-system/sw/bin/networkctl --json=short status host0 | ${pkgs.jq}/bin/jq -r '.OperationalState == \"routable\"'"); 135 136 # Test systemd-nspawn network configuration 137 machine.succeed("ping -n -c 1 ${containerName}"); 138 139 # Test systemd-nspawn uses a user namespace 140 machine.succeed("test $(machinectl status ${containerName} | grep 'UID Shift: ' | wc -l) = 1") 141 142 # Test systemd-nspawn reboot 143 machine.succeed("machinectl shell ${containerName} /run/current-system/sw/bin/reboot"); 144 machine.wait_until_succeeds("systemctl -M ${containerName} is-active default.target"); 145 146 # Test machinectl reboot 147 machine.succeed("machinectl reboot ${containerName}"); 148 machine.wait_until_succeeds("systemctl -M ${containerName} is-active default.target"); 149 150 # Restart machine 151 machine.shutdown() 152 machine.start() 153 machine.wait_for_unit("default.target"); 154 155 # Test auto-start 156 machine.succeed("machinectl show ${containerName}") 157 158 # Test machinectl stop 159 machine.succeed("machinectl stop ${containerName}"); 160 machine.wait_until_succeeds("test $(systemctl is-active systemd-nspawn@${containerName}) = inactive"); 161 162 # Test tmpfs for /tmp 163 machine.fail("mountpoint /tmp"); 164 165 # Show to to delete the container 166 machine.succeed("chattr -i ${containerRoot}/var/empty"); 167 machine.succeed("rm -rf ${containerRoot}"); 168 169 # Test import tarball, start, stop and remove 170 machine.succeed("machinectl import-tar ${containerTarball}/tarball/*.tar* ${containerName}"); 171 machine.succeed("machinectl start ${containerName}"); 172 machine.wait_until_succeeds("systemctl -M ${containerName} is-active default.target"); 173 machine.succeed("machinectl stop ${containerName}"); 174 machine.wait_until_succeeds("test $(systemctl is-active systemd-nspawn@${containerName}) = inactive"); 175 machine.succeed("machinectl remove ${containerName}"); 176 ''; 177})