diff options
Diffstat (limited to 'nixos/tests')
-rw-r--r-- | nixos/tests/all-tests.nix | 4 | ||||
-rw-r--r-- | nixos/tests/chromium.nix | 14 | ||||
-rw-r--r-- | nixos/tests/common/lxd/config.yaml | 24 | ||||
-rw-r--r-- | nixos/tests/dendrite.nix | 1 | ||||
-rw-r--r-- | nixos/tests/hydra/default.nix | 2 | ||||
-rw-r--r-- | nixos/tests/installed-tests/default.nix | 1 | ||||
-rw-r--r-- | nixos/tests/installed-tests/power-profiles-daemon.nix | 9 | ||||
-rw-r--r-- | nixos/tests/installer-systemd-stage-1.nix | 2 | ||||
-rw-r--r-- | nixos/tests/installer.nix | 79 | ||||
-rw-r--r-- | nixos/tests/kanidm.nix | 75 | ||||
-rw-r--r-- | nixos/tests/kernel-generic.nix | 1 | ||||
-rw-r--r-- | nixos/tests/lxd-image-server.nix | 63 | ||||
-rw-r--r-- | nixos/tests/lxd-image.nix | 89 | ||||
-rw-r--r-- | nixos/tests/lxd.nix | 134 | ||||
-rw-r--r-- | nixos/tests/matrix-appservice-irc.nix | 3 | ||||
-rw-r--r-- | nixos/tests/networking.nix | 20 | ||||
-rw-r--r-- | nixos/tests/openssh.nix | 18 | ||||
-rw-r--r-- | nixos/tests/pam/pam-oath-login.nix | 2 | ||||
-rw-r--r-- | nixos/tests/pgadmin4.nix | 85 | ||||
-rw-r--r-- | nixos/tests/pleroma.nix | 4 | ||||
-rw-r--r-- | nixos/tests/public-inbox.nix | 227 | ||||
-rw-r--r-- | nixos/tests/systemd-nspawn.nix | 13 | ||||
-rw-r--r-- | nixos/tests/uptermd.nix | 62 | ||||
-rw-r--r-- | nixos/tests/virtualbox.nix | 2 |
24 files changed, 626 insertions, 308 deletions
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 923464a0c9a3e..e86dda9cb3d28 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -253,6 +253,7 @@ in k3s-single-node = handleTest ./k3s-single-node.nix {}; k3s-single-node-docker = handleTest ./k3s-single-node-docker.nix {}; kafka = handleTest ./kafka.nix {}; + kanidm = handleTest ./kanidm.nix {}; kbd-setfont-decompress = handleTest ./kbd-setfont-decompress.nix {}; kbd-update-search-paths-patch = handleTest ./kbd-update-search-paths-patch.nix {}; kea = handleTest ./kea.nix {}; @@ -284,7 +285,6 @@ in loki = handleTest ./loki.nix {}; lvm2 = handleTest ./lvm2 {}; lxd = handleTest ./lxd.nix {}; - lxd-image = handleTest ./lxd-image.nix {}; lxd-nftables = handleTest ./lxd-nftables.nix {}; lxd-image-server = handleTest ./lxd-image-server.nix {}; #logstash = handleTest ./logstash.nix {}; @@ -456,6 +456,7 @@ in proxy = handleTest ./proxy.nix {}; prowlarr = handleTest ./prowlarr.nix {}; pt2-clone = handleTest ./pt2-clone.nix {}; + public-inbox = handleTest ./public-inbox.nix {}; pulseaudio = discoverTests (import ./pulseaudio.nix); qboot = handleTestOn ["x86_64-linux" "i686-linux"] ./qboot.nix {}; quorum = handleTest ./quorum.nix {}; @@ -574,6 +575,7 @@ in unifi = handleTest ./unifi.nix {}; unit-php = handleTest ./web-servers/unit-php.nix {}; upnp = handleTest ./upnp.nix {}; + uptermd = handleTest ./uptermd.nix {}; usbguard = handleTest ./usbguard.nix {}; user-activation-scripts = handleTest ./user-activation-scripts.nix {}; uwsgi = handleTest ./uwsgi.nix {}; diff --git a/nixos/tests/chromium.nix b/nixos/tests/chromium.nix index 3815dca762203..6b296fe8a61ae 100644 --- a/nixos/tests/chromium.nix +++ b/nixos/tests/chromium.nix @@ -45,12 +45,14 @@ mapAttrs (channel: chromiumPkg: makeTest { enableOCR = true; - machine.imports = [ ./common/user-account.nix ./common/x11.nix ]; - machine.virtualisation.memorySize = 2047; - machine.test-support.displayManager.auto.user = user; - machine.environment = { - systemPackages = [ chromiumPkg ]; - variables."XAUTHORITY" = "/home/alice/.Xauthority"; + nodes.machine = { ... }: { + imports = [ ./common/user-account.nix ./common/x11.nix ]; + virtualisation.memorySize = 2047; + test-support.displayManager.auto.user = user; + environment = { + systemPackages = [ chromiumPkg ]; + variables."XAUTHORITY" = "/home/alice/.Xauthority"; + }; }; testScript = let diff --git a/nixos/tests/common/lxd/config.yaml b/nixos/tests/common/lxd/config.yaml new file mode 100644 index 0000000000000..3bb667ed43f7c --- /dev/null +++ b/nixos/tests/common/lxd/config.yaml @@ -0,0 +1,24 @@ +storage_pools: + - name: default + driver: dir + config: + source: /var/lxd-pool + +networks: + - name: lxdbr0 + type: bridge + config: + ipv4.address: auto + ipv6.address: none + +profiles: + - name: default + devices: + eth0: + name: eth0 + network: lxdbr0 + type: nic + root: + path: / + pool: default + type: disk diff --git a/nixos/tests/dendrite.nix b/nixos/tests/dendrite.nix index a444c9b200189..d4a5bb1322638 100644 --- a/nixos/tests/dendrite.nix +++ b/nixos/tests/dendrite.nix @@ -17,6 +17,7 @@ import ./make-test-python.nix ( homeserver = { pkgs, ... }: { services.dendrite = { enable = true; + openRegistration = true; settings = { global.server_name = "test-dendrite-server.com"; global.private_key = private_key; diff --git a/nixos/tests/hydra/default.nix b/nixos/tests/hydra/default.nix index 9fc787842d854..baf18afbc5690 100644 --- a/nixos/tests/hydra/default.nix +++ b/nixos/tests/hydra/default.nix @@ -11,7 +11,7 @@ let inherit (import ./common.nix { inherit system; }) baseConfig; hydraPkgs = { - inherit (pkgs) hydra-unstable; + inherit (pkgs) hydra_unstable; }; makeHydraTest = with pkgs.lib; name: package: makeTest { diff --git a/nixos/tests/installed-tests/default.nix b/nixos/tests/installed-tests/default.nix index fd16b481168f4..c6fb37cfe5842 100644 --- a/nixos/tests/installed-tests/default.nix +++ b/nixos/tests/installed-tests/default.nix @@ -106,6 +106,5 @@ in malcontent = callInstalledTest ./malcontent.nix {}; ostree = callInstalledTest ./ostree.nix {}; pipewire = callInstalledTest ./pipewire.nix {}; - power-profiles-daemon = callInstalledTest ./power-profiles-daemon.nix {}; xdg-desktop-portal = callInstalledTest ./xdg-desktop-portal.nix {}; } diff --git a/nixos/tests/installed-tests/power-profiles-daemon.nix b/nixos/tests/installed-tests/power-profiles-daemon.nix deleted file mode 100644 index 43629a0155d24..0000000000000 --- a/nixos/tests/installed-tests/power-profiles-daemon.nix +++ /dev/null @@ -1,9 +0,0 @@ -{ pkgs, lib, makeInstalledTest, ... }: - -makeInstalledTest { - tested = pkgs.power-profiles-daemon; - - testConfig = { - services.power-profiles-daemon.enable = true; - }; -} diff --git a/nixos/tests/installer-systemd-stage-1.nix b/nixos/tests/installer-systemd-stage-1.nix index a8b418626e660..d02387ee80e09 100644 --- a/nixos/tests/installer-systemd-stage-1.nix +++ b/nixos/tests/installer-systemd-stage-1.nix @@ -27,7 +27,7 @@ simpleUefiGrubSpecialisation simpleUefiSystemdBoot # swraid - # zfsroot + zfsroot ; } diff --git a/nixos/tests/installer.nix b/nixos/tests/installer.nix index d8187d8e019d6..8bef4fad3dd2d 100644 --- a/nixos/tests/installer.nix +++ b/nixos/tests/installer.nix @@ -701,6 +701,85 @@ in { ''; }; + bcachefsSimple = makeInstallerTest "bcachefs-simple" { + extraInstallerConfig = { + boot.supportedFilesystems = [ "bcachefs" ]; + }; + + createPartitions = '' + machine.succeed( + "flock /dev/vda parted --script /dev/vda -- mklabel msdos" + + " mkpart primary ext2 1M 100MB" # /boot + + " mkpart primary linux-swap 100M 1024M" # swap + + " mkpart primary 1024M -1s", # / + "udevadm settle", + "mkswap /dev/vda2 -L swap", + "swapon -L swap", + "mkfs.bcachefs -L root /dev/vda3", + "mount -t bcachefs /dev/vda3 /mnt", + "mkfs.ext3 -L boot /dev/vda1", + "mkdir -p /mnt/boot", + "mount /dev/vda1 /mnt/boot", + ) + ''; + }; + + bcachefsEncrypted = makeInstallerTest "bcachefs-encrypted" { + extraInstallerConfig = { + boot.supportedFilesystems = [ "bcachefs" ]; + environment.systemPackages = with pkgs; [ keyutils ]; + }; + + # We don't want to use the normal way of unlocking bcachefs defined in tasks/filesystems/bcachefs.nix. + # So, override initrd.postDeviceCommands completely and simply unlock with the predefined password. + extraConfig = '' + boot.initrd.postDeviceCommands = lib.mkForce "echo password | bcachefs unlock /dev/vda3"; + ''; + + createPartitions = '' + machine.succeed( + "flock /dev/vda parted --script /dev/vda -- mklabel msdos" + + " mkpart primary ext2 1M 100MB" # /boot + + " mkpart primary linux-swap 100M 1024M" # swap + + " mkpart primary 1024M -1s", # / + "udevadm settle", + "mkswap /dev/vda2 -L swap", + "swapon -L swap", + "keyctl link @u @s", + "echo password | mkfs.bcachefs -L root --encrypted /dev/vda3", + "echo password | bcachefs unlock /dev/vda3", + "mount -t bcachefs /dev/vda3 /mnt", + "mkfs.ext3 -L boot /dev/vda1", + "mkdir -p /mnt/boot", + "mount /dev/vda1 /mnt/boot", + ) + ''; + }; + + bcachefsMulti = makeInstallerTest "bcachefs-multi" { + extraInstallerConfig = { + boot.supportedFilesystems = [ "bcachefs" ]; + }; + + createPartitions = '' + machine.succeed( + "flock /dev/vda parted --script /dev/vda -- mklabel msdos" + + " mkpart primary ext2 1M 100MB" # /boot + + " mkpart primary linux-swap 100M 1024M" # swap + + " mkpart primary 1024M 4096M" # / + + " mkpart primary 4096M -1s", # / + "udevadm settle", + "mkswap /dev/vda2 -L swap", + "swapon -L swap", + "mkfs.bcachefs -L root --metadata_replicas 2 --foreground_target ssd --promote_target ssd --background_target hdd --label ssd /dev/vda3 --label hdd /dev/vda4", + "mount -t bcachefs /dev/vda3:/dev/vda4 /mnt", + "mkfs.ext3 -L boot /dev/vda1", + "mkdir -p /mnt/boot", + "mount /dev/vda1 /mnt/boot", + ) + ''; + }; + # Test a basic install using GRUB 1. grub1 = makeInstallerTest "grub1" rec { createPartitions = '' diff --git a/nixos/tests/kanidm.nix b/nixos/tests/kanidm.nix new file mode 100644 index 0000000000000..d34f680f5224b --- /dev/null +++ b/nixos/tests/kanidm.nix @@ -0,0 +1,75 @@ +import ./make-test-python.nix ({ pkgs, ... }: + let + certs = import ./common/acme/server/snakeoil-certs.nix; + serverDomain = certs.domain; + in + { + name = "kanidm"; + meta.maintainers = with pkgs.lib.maintainers; [ erictapen Flakebi ]; + + nodes.server = { config, pkgs, lib, ... }: { + services.kanidm = { + enableServer = true; + serverSettings = { + origin = "https://${serverDomain}"; + domain = serverDomain; + bindaddress = "[::1]:8443"; + ldapbindaddress = "[::1]:636"; + }; + }; + + services.nginx = { + enable = true; + recommendedProxySettings = true; + virtualHosts."${serverDomain}" = { + forceSSL = true; + sslCertificate = certs."${serverDomain}".cert; + sslCertificateKey = certs."${serverDomain}".key; + locations."/".proxyPass = "http://[::1]:8443"; + }; + }; + + security.pki.certificateFiles = [ certs.ca.cert ]; + + networking.hosts."::1" = [ serverDomain ]; + networking.firewall.allowedTCPPorts = [ 80 443 ]; + + users.users.kanidm.shell = pkgs.bashInteractive; + + environment.systemPackages = with pkgs; [ kanidm openldap ripgrep ]; + }; + + nodes.client = { pkgs, nodes, ... }: { + services.kanidm = { + enableClient = true; + clientSettings = { + uri = "https://${serverDomain}"; + }; + }; + + networking.hosts."${nodes.server.config.networking.primaryIPAddress}" = [ serverDomain ]; + + security.pki.certificateFiles = [ certs.ca.cert ]; + }; + + testScript = { nodes, ... }: + let + ldapBaseDN = builtins.concatStringsSep "," (map (s: "dc=" + s) (pkgs.lib.splitString "." serverDomain)); + + # We need access to the config file in the test script. + filteredConfig = pkgs.lib.converge + (pkgs.lib.filterAttrsRecursive (_: v: v != null)) + nodes.server.config.services.kanidm.serverSettings; + serverConfigFile = (pkgs.formats.toml { }).generate "server.toml" filteredConfig; + + in + '' + start_all() + server.wait_for_unit("kanidm.service") + server.wait_until_succeeds("curl -sf https://${serverDomain} | grep Kanidm") + server.wait_until_succeeds("ldapsearch -H ldap://[::1]:636 -b '${ldapBaseDN}' -x '(name=test)'") + client.wait_until_succeeds("kanidm login -D anonymous && kanidm self whoami | grep anonymous@${serverDomain}") + (rv, result) = server.execute("kanidmd recover_account -d quiet -c ${serverConfigFile} -n admin 2>&1 | rg -o '[A-Za-z0-9]{48}'") + assert rv == 0 + ''; + }) diff --git a/nixos/tests/kernel-generic.nix b/nixos/tests/kernel-generic.nix index f34d5d6079404..1e60198abdd04 100644 --- a/nixos/tests/kernel-generic.nix +++ b/nixos/tests/kernel-generic.nix @@ -30,6 +30,7 @@ let linux_5_4_hardened linux_5_10_hardened linux_5_15_hardened + linux_5_17_hardened linux_testing; }; diff --git a/nixos/tests/lxd-image-server.nix b/nixos/tests/lxd-image-server.nix index fa40e33e74dd6..072f4570c2c9f 100644 --- a/nixos/tests/lxd-image-server.nix +++ b/nixos/tests/lxd-image-server.nix @@ -1,54 +1,21 @@ -import ./make-test-python.nix ({ pkgs, ...} : +import ./make-test-python.nix ({ pkgs, lib, ... } : let - # Since we don't have access to the internet during the tests, we have to - # pre-fetch lxd containers beforehand. - # - # I've chosen to import Alpine Linux, because its image is turbo-tiny and, - # generally, sufficient for our tests. - alpine-meta = pkgs.fetchurl { - url = "https://tarballs.nixos.org/alpine/3.12/lxd.tar.xz"; - hash = "sha256-1tcKaO9lOkvqfmG/7FMbfAEToAuFy2YMewS8ysBKuLA="; - }; - - alpine-rootfs = pkgs.fetchurl { - url = "https://tarballs.nixos.org/alpine/3.12/rootfs.tar.xz"; - hash = "sha256-Tba9sSoaiMtQLY45u7p5DMqXTSDgs/763L/SQp0bkCA="; + lxd-image = import ../release.nix { + configuration = { + # Building documentation makes the test unnecessarily take a longer time: + documentation.enable = lib.mkForce false; + }; }; - lxd-config = pkgs.writeText "config.yaml" '' - storage_pools: - - name: default - driver: dir - config: - source: /var/lxd-pool - - networks: - - name: lxdbr0 - type: bridge - config: - ipv4.address: auto - ipv6.address: none - - profiles: - - name: default - devices: - eth0: - name: eth0 - network: lxdbr0 - type: nic - root: - path: / - pool: default - type: disk - ''; - + lxd-image-metadata = lxd-image.lxdMeta.${pkgs.system}; + lxd-image-rootfs = lxd-image.lxdImage.${pkgs.system}; in { name = "lxd-image-server"; meta = with pkgs.lib.maintainers; { - maintainers = [ mkg20001 ]; + maintainers = [ mkg20001 patryk27 ]; }; nodes.machine = { lib, ... }: { @@ -100,20 +67,20 @@ in { # lxd expects the pool's directory to already exist machine.succeed("mkdir /var/lxd-pool") - machine.succeed( - "cat ${lxd-config} | lxd init --preseed" + "cat ${./common/lxd/config.yaml} | lxd init --preseed" ) machine.succeed( - "lxc image import ${alpine-meta} ${alpine-rootfs} --alias alpine" + "lxc image import ${lxd-image-metadata}/*/*.tar.xz ${lxd-image-rootfs}/*/*.tar.xz --alias nixos" ) - loc = "/var/www/simplestreams/images/iats/alpine/amd64/default/v1" + loc = "/var/www/simplestreams/images/iats/nixos/amd64/default/v1" with subtest("push image to server"): - machine.succeed("lxc launch alpine test") - machine.succeed("lxc stop test") + machine.succeed("lxc launch nixos test") + machine.sleep(5) + machine.succeed("lxc stop -f test") machine.succeed("lxc publish --public test --alias=testimg") machine.succeed("lxc image export testimg") machine.succeed("ls >&2") diff --git a/nixos/tests/lxd-image.nix b/nixos/tests/lxd-image.nix deleted file mode 100644 index 4930b55f19094..0000000000000 --- a/nixos/tests/lxd-image.nix +++ /dev/null @@ -1,89 +0,0 @@ -# This test ensures that the nixOS lxd images builds and functions properly -# It has been extracted from `lxd.nix` to seperate failures of just the image and the lxd software - -import ./make-test-python.nix ({ pkgs, ...} : let - release = import ../release.nix { - /* configuration = { - environment.systemPackages = with pkgs; [ stdenv ]; # inject stdenv so rebuild test works - }; */ - }; - - metadata = release.lxdMeta.${pkgs.system}; - image = release.lxdImage.${pkgs.system}; - - lxd-config = pkgs.writeText "config.yaml" '' - storage_pools: - - name: default - driver: dir - config: - source: /var/lxd-pool - - networks: - - name: lxdbr0 - type: bridge - config: - ipv4.address: auto - ipv6.address: none - - profiles: - - name: default - devices: - eth0: - name: eth0 - network: lxdbr0 - type: nic - root: - path: / - pool: default - type: disk - ''; -in { - name = "lxd-image"; - - meta = with pkgs.lib.maintainers; { - maintainers = [ mkg20001 ]; - }; - - nodes.machine = { lib, ... }: { - virtualisation = { - # disk full otherwise - diskSize = 2048; - - lxc.lxcfs.enable = true; - lxd.enable = true; - }; - }; - - testScript = '' - machine.wait_for_unit("sockets.target") - machine.wait_for_unit("lxd.service") - machine.wait_for_file("/var/lib/lxd/unix.socket") - - # It takes additional second for lxd to settle - machine.sleep(1) - - # lxd expects the pool's directory to already exist - machine.succeed("mkdir /var/lxd-pool") - - machine.succeed( - "cat ${lxd-config} | lxd init --preseed" - ) - - # TODO: test custom built container aswell - - with subtest("importing container works"): - machine.succeed("lxc image import ${metadata}/*/*.tar.xz ${image}/*/*.tar.xz --alias nixos") - - with subtest("launching container works"): - machine.succeed("lxc launch nixos machine -c security.nesting=true") - # make sure machine boots up properly - machine.sleep(5) - - with subtest("container shell works"): - machine.succeed("echo true | lxc exec machine /run/current-system/sw/bin/bash -") - machine.succeed("lxc exec machine /run/current-system/sw/bin/true") - - # with subtest("rebuilding works"): - # machine.succeed("lxc exec machine /run/current-system/sw/bin/nixos-rebuild switch") - ''; -}) diff --git a/nixos/tests/lxd.nix b/nixos/tests/lxd.nix index 162bbcc47e871..15d16564d641c 100644 --- a/nixos/tests/lxd.nix +++ b/nixos/tests/lxd.nix @@ -1,79 +1,18 @@ -import ./make-test-python.nix ({ pkgs, ...} : +import ./make-test-python.nix ({ pkgs, lib, ... } : let - # Since we don't have access to the internet during the tests, we have to - # pre-fetch lxd containers beforehand. - # - # I've chosen to import Alpine Linux, because its image is turbo-tiny and, - # generally, sufficient for our tests. - alpine-meta-x86 = pkgs.fetchurl { - url = "https://tarballs.nixos.org/alpine/3.12/lxd.tar.xz"; - hash = "sha256-1tcKaO9lOkvqfmG/7FMbfAEToAuFy2YMewS8ysBKuLA="; - }; - alpine-meta-for = arch: pkgs.stdenv.mkDerivation { - name = "alpine-meta-${arch}"; - version = "3.12"; - unpackPhase = "true"; - buildPhase = '' - runHook preBuild - - tar xvf ${alpine-meta-x86} - sed -i 's/architecture: .*/architecture: ${arch}/' metadata.yaml - - runHook postBuild - ''; - installPhase = '' - runHook preInstall - - tar czRf $out * - - runHook postInstall - ''; - }; + lxd-image = import ../release.nix { + configuration = { + # Building documentation makes the test unnecessarily take a longer time: + documentation.enable = lib.mkForce false; - alpine-meta = { - x86_64-linux = alpine-meta-x86; - aarch64-linux = alpine-meta-for "aarch64"; - }.${pkgs.system} or (throw "Unsupported system: ${pkgs.system}"); - - alpine-rootfs = { - x86_64-linux = pkgs.fetchurl { - url = "https://tarballs.nixos.org/alpine/3.12/rootfs.tar.xz"; - hash = "sha256-Tba9sSoaiMtQLY45u7p5DMqXTSDgs/763L/SQp0bkCA="; - }; - aarch64-linux = pkgs.fetchurl { - url = "https://dl-cdn.alpinelinux.org/alpine/v3.15/releases/aarch64/alpine-minirootfs-3.15.4-aarch64.tar.gz"; - hash = "sha256-9kBz8Jwmo8XepJhTMt5zilCaHHpflnUH7y9+0To39Us="; + # Our tests require `grep` & friends: + environment.systemPackages = with pkgs; [ busybox ]; }; - }.${pkgs.system} or (throw "Unsupported system: ${pkgs.system}"); - - lxd-config = pkgs.writeText "config.yaml" '' - storage_pools: - - name: default - driver: dir - config: - source: /var/lxd-pool - - networks: - - name: lxdbr0 - type: bridge - config: - ipv4.address: auto - ipv6.address: none - - profiles: - - name: default - devices: - eth0: - name: eth0 - network: lxdbr0 - type: nic - root: - path: / - pool: default - type: disk - ''; + }; + lxd-image-metadata = lxd-image.lxdMeta.${pkgs.system}; + lxd-image-rootfs = lxd-image.lxdImage.${pkgs.system}; in { name = "lxd"; @@ -84,6 +23,8 @@ in { nodes.machine = { lib, ... }: { virtualisation = { + diskSize = 2048; + # Since we're testing `limits.cpu`, we've gotta have a known number of # cores to lean on cores = 2; @@ -108,61 +49,66 @@ in { machine.succeed("mkdir /var/lxd-pool") machine.succeed( - "cat ${lxd-config} | lxd init --preseed" + "cat ${./common/lxd/config.yaml} | lxd init --preseed" ) machine.succeed( - "lxc image import ${alpine-meta} ${alpine-rootfs} --alias alpine" + "lxc image import ${lxd-image-metadata}/*/*.tar.xz ${lxd-image-rootfs}/*/*.tar.xz --alias nixos" ) - with subtest("Containers can be launched and destroyed"): - machine.succeed("lxc launch alpine test") - machine.succeed("lxc exec test true") - machine.succeed("lxc delete -f test") + with subtest("Container can be managed"): + machine.succeed("lxc launch nixos container") + machine.sleep(5) + machine.succeed("echo true | lxc exec container /run/current-system/sw/bin/bash -") + machine.succeed("lxc exec container true") + machine.succeed("lxc delete -f container") - with subtest("Containers are being mounted with lxcfs inside"): - machine.succeed("lxc launch alpine test") + with subtest("Container is mounted with lxcfs inside"): + machine.succeed("lxc launch nixos container") + machine.sleep(5) ## ---------- ## ## limits.cpu ## - machine.succeed("lxc config set test limits.cpu 1") - machine.succeed("lxc restart test") + machine.succeed("lxc config set container limits.cpu 1") + machine.succeed("lxc restart container") + machine.sleep(5) - # Since Alpine doesn't have `nproc` pre-installed, we've gotta resort - # to the primal methods assert ( "1" - == machine.succeed("lxc exec test grep -- -c ^processor /proc/cpuinfo").strip() + == machine.succeed("lxc exec container grep -- -c ^processor /proc/cpuinfo").strip() ) - machine.succeed("lxc config set test limits.cpu 2") - machine.succeed("lxc restart test") + machine.succeed("lxc config set container limits.cpu 2") + machine.succeed("lxc restart container") + machine.sleep(5) assert ( "2" - == machine.succeed("lxc exec test grep -- -c ^processor /proc/cpuinfo").strip() + == machine.succeed("lxc exec container grep -- -c ^processor /proc/cpuinfo").strip() ) ## ------------- ## ## limits.memory ## - machine.succeed("lxc config set test limits.memory 64MB") - machine.succeed("lxc restart test") + machine.succeed("lxc config set container limits.memory 64MB") + machine.succeed("lxc restart container") + machine.sleep(5) assert ( "MemTotal: 62500 kB" - == machine.succeed("lxc exec test grep -- MemTotal /proc/meminfo").strip() + == machine.succeed("lxc exec container grep -- MemTotal /proc/meminfo").strip() ) - machine.succeed("lxc config set test limits.memory 128MB") - machine.succeed("lxc restart test") + machine.succeed("lxc config set container limits.memory 128MB") + machine.succeed("lxc restart container") + machine.sleep(5) assert ( "MemTotal: 125000 kB" - == machine.succeed("lxc exec test grep -- MemTotal /proc/meminfo").strip() + == machine.succeed("lxc exec container grep -- MemTotal /proc/meminfo").strip() ) - machine.succeed("lxc delete -f test") + machine.succeed("lxc delete -f container") ''; }) diff --git a/nixos/tests/matrix-appservice-irc.nix b/nixos/tests/matrix-appservice-irc.nix index d1c561f95dbf2..70d4585239865 100644 --- a/nixos/tests/matrix-appservice-irc.nix +++ b/nixos/tests/matrix-appservice-irc.nix @@ -20,6 +20,9 @@ import ./make-test-python.nix ({ pkgs, ... }: enable_registration = true; + # don't use this in production, always use some form of verification + enable_registration_without_verification = true; + listeners = [ { # The default but tls=false bind_addresses = [ diff --git a/nixos/tests/networking.nix b/nixos/tests/networking.nix index a1150097a0917..2cc1e9b0942ca 100644 --- a/nixos/tests/networking.nix +++ b/nixos/tests/networking.nix @@ -139,6 +139,26 @@ let client.wait_until_succeeds("ping -c 1 192.168.3.1") ''; }; + dhcpDefault = { + name = "useDHCP-by-default"; + nodes.router = router; + nodes.client = { lib, ... }: { + # Disable test driver default config + networking.interfaces = lib.mkForce {}; + networking.useNetworkd = networkd; + virtualisation.vlans = [ 1 ]; + }; + testScript = '' + start_all() + client.wait_for_unit("multi-user.target") + client.wait_until_succeeds("ip addr show dev eth1 | grep '192.168.1'") + client.shell_interact() + client.succeed("ping -c 1 192.168.1.1") + router.succeed("ping -c 1 192.168.1.1") + router.succeed("ping -c 1 192.168.1.2") + client.succeed("ping -c 1 192.168.1.2") + ''; + }; dhcpSimple = { name = "SimpleDHCP"; nodes.router = router; diff --git a/nixos/tests/openssh.nix b/nixos/tests/openssh.nix index 003813379e697..4083f5906d79a 100644 --- a/nixos/tests/openssh.nix +++ b/nixos/tests/openssh.nix @@ -80,17 +80,21 @@ in { client.wait_for_unit("network.target") client.succeed( - "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server 'echo hello world' >&2" + "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server 'echo hello world' >&2", + timeout=30 ) client.succeed( - "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server 'ulimit -l' | grep 1024" + "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server 'ulimit -l' | grep 1024", + timeout=30 ) client.succeed( - "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server_lazy 'echo hello world' >&2" + "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server_lazy 'echo hello world' >&2", + timeout=30 ) client.succeed( - "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server_lazy 'ulimit -l' | grep 1024" + "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server_lazy 'ulimit -l' | grep 1024", + timeout=30 ) with subtest("configured-authkey"): @@ -99,10 +103,12 @@ in { ) client.succeed("chmod 600 privkey.snakeoil") client.succeed( - "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil server true" + "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil server true", + timeout=30 ) client.succeed( - "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil server_lazy true" + "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil server_lazy true", + timeout=30 ) with subtest("localhost-only"): diff --git a/nixos/tests/pam/pam-oath-login.nix b/nixos/tests/pam/pam-oath-login.nix index 8fb7553de9073..c532e81e674d7 100644 --- a/nixos/tests/pam/pam-oath-login.nix +++ b/nixos/tests/pam/pam-oath-login.nix @@ -7,7 +7,7 @@ let # how many passwords have been made. In this env, we'll always be on # the 0th counter, so the password is static. # - # Generated in nix-shell -p oathToolkit + # Generated in nix-shell -p oath-toolkit # via: oathtool -v -d6 -w10 cdd4083ef8ff1fa9178c6d46bfb1a3 # and picking a the first 4: oathSnakeOilPassword1 = "143349"; diff --git a/nixos/tests/pgadmin4.nix b/nixos/tests/pgadmin4.nix index 2f6dc3bd569ff..b30299d307eb9 100644 --- a/nixos/tests/pgadmin4.nix +++ b/nixos/tests/pgadmin4.nix @@ -1,53 +1,27 @@ -import ./make-test-python.nix ({ pkgs, lib, ... }: +import ./make-test-python.nix ({ pkgs, lib, buildDeps ? [ ], pythonEnv ? [ ], ... }: + + /* + This test suite replaces the typical pytestCheckHook function in python + packages. Pgadmin4 test suite needs a running and configured postgresql + server. This is why this test exists. + + To not repeat all the python dependencies needed, this test is called directly + from the pgadmin4 derivation, which also passes the currently + used propagatedBuildInputs and any python overrides. + + Unfortunately, there doesn't seem to be an easy way to otherwise include + the needed packages here. + + Due the the needed parameters a direct call to "nixosTests.pgadmin4" fails + and needs to be called as "pgadmin4.tests" + + */ let pgadmin4SrcDir = "/pgadmin"; pgadmin4Dir = "/var/lib/pgadmin"; pgadmin4LogDir = "/var/log/pgadmin"; - python-with-needed-packages = pkgs.python3.withPackages (ps: with ps; [ - selenium - testtools - testscenarios - flask - flask-babelex - flask-babel - flask-gravatar - flask_login - flask_mail - flask_migrate - flask_sqlalchemy - flask_wtf - flask-compress - passlib - pytz - simplejson - six - sqlparse - wtforms - flask-paranoid - psutil - psycopg2 - python-dateutil - sqlalchemy - itsdangerous - flask-security-too - bcrypt - cryptography - sshtunnel - ldap3 - gssapi - flask-socketio - eventlet - httpagentparser - user-agents - wheel - authlib - qrcode - pillow - pyotp - boto3 - ]); in { name = "pgadmin4"; @@ -55,12 +29,27 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: nodes.machine = { pkgs, ... }: { imports = [ ./common/x11.nix ]; + # needed because pgadmin 6.8 will fail, if those dependencies get updated + nixpkgs.overlays = [ + (self: super: { + pythonPackages = pythonEnv; + }) + ]; + environment.systemPackages = with pkgs; [ pgadmin4 postgresql - python-with-needed-packages chromedriver chromium + # include the same packages as in pgadmin minus speaklater3 + (python3.withPackages + (ps: buildDeps ++ + [ + # test suite package requirements + pythonPackages.testscenarios + pythonPackages.selenium + ]) + ) ]; services.postgresql = { enable = true; @@ -121,7 +110,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: with subtest("run browser test"): machine.succeed( 'cd ${pgadmin4SrcDir}/pgadmin4-${pkgs.pgadmin4.version}/web \ - && ${python-with-needed-packages.interpreter} regression/runtests.py --pkg browser --exclude \ + && python regression/runtests.py --pkg browser --exclude \ browser.tests.test_ldap_login.LDAPLoginTestCase,browser.tests.test_ldap_login' ) @@ -131,13 +120,13 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: machine.succeed( 'cd ${pgadmin4SrcDir}/pgadmin4-${pkgs.pgadmin4.version}/web \ && export FONTCONFIG_FILE=${pkgs.makeFontsConf { fontDirectories = [];}} \ - && ${python-with-needed-packages.interpreter} regression/runtests.py --pkg feature_tests' + && python regression/runtests.py --pkg feature_tests' ) with subtest("run resql test"): machine.succeed( 'cd ${pgadmin4SrcDir}/pgadmin4-${pkgs.pgadmin4.version}/web \ - && ${python-with-needed-packages.interpreter} regression/runtests.py --pkg resql' + && python regression/runtests.py --pkg resql' ) ''; }) diff --git a/nixos/tests/pleroma.nix b/nixos/tests/pleroma.nix index 90a9a25110447..8998716243a25 100644 --- a/nixos/tests/pleroma.nix +++ b/nixos/tests/pleroma.nix @@ -158,7 +158,9 @@ import ./make-test-python.nix ({ pkgs, ... }: # Waiting for pleroma to be up. timeout 5m bash -c 'while [[ "$(curl -s -o /dev/null -w '%{http_code}' https://pleroma.nixos.test/api/v1/instance)" != "200" ]]; do sleep 2; done' - pleroma_ctl user new jamy jamy@nixos.test --password 'jamy-password' --moderator --admin -y + # Toremove the RELEASE_COOKIE bit when https://github.com/NixOS/nixpkgs/issues/166229 gets fixed. + RELEASE_COOKIE="/var/lib/pleroma/.cookie" \ + pleroma_ctl user new jamy jamy@nixos.test --password 'jamy-password' --moderator --admin -y ''; tls-cert = pkgs.runCommand "selfSignedCerts" { buildInputs = [ pkgs.openssl ]; } '' diff --git a/nixos/tests/public-inbox.nix b/nixos/tests/public-inbox.nix new file mode 100644 index 0000000000000..7de40400fcbf5 --- /dev/null +++ b/nixos/tests/public-inbox.nix @@ -0,0 +1,227 @@ +import ./make-test-python.nix ({ pkgs, lib, ... }: +let + orga = "example"; + domain = "${orga}.localdomain"; + + tls-cert = pkgs.runCommand "selfSignedCert" { buildInputs = [ pkgs.openssl ]; } '' + openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -nodes -days 36500 \ + -subj '/CN=machine.${domain}' + install -D -t $out key.pem cert.pem + ''; +in +{ + name = "public-inbox"; + + meta.maintainers = with pkgs.lib.maintainers; [ julm ]; + + machine = { config, pkgs, nodes, ... }: let + inherit (config.services) gitolite public-inbox; + # Git repositories paths in Gitolite. + # Only their baseNameOf is used for configuring public-inbox. + repositories = [ + "user/repo1" + "user/repo2" + ]; + in + { + virtualisation.diskSize = 1 * 1024; + virtualisation.memorySize = 1 * 1024; + networking.domain = domain; + + security.pki.certificateFiles = [ "${tls-cert}/cert.pem" ]; + # If using security.acme: + #security.acme.certs."${domain}".postRun = '' + # systemctl try-restart public-inbox-nntpd public-inbox-imapd + #''; + + services.public-inbox = { + enable = true; + postfix.enable = true; + openFirewall = true; + settings.publicinbox = { + css = [ "href=https://machine.${domain}/style/light.css" ]; + nntpserver = [ "nntps://machine.${domain}" ]; + wwwlisting = "match=domain"; + }; + mda = { + enable = true; + args = [ "--no-precheck" ]; # Allow Bcc: + }; + http = { + enable = true; + port = "/run/public-inbox-http.sock"; + #port = 8080; + args = ["-W0"]; + mounts = [ + "https://machine.${domain}/inbox" + ]; + }; + nntp = { + enable = true; + #port = 563; + args = ["-W0"]; + cert = "${tls-cert}/cert.pem"; + key = "${tls-cert}/key.pem"; + }; + imap = { + enable = true; + #port = 993; + args = ["-W0"]; + cert = "${tls-cert}/cert.pem"; + key = "${tls-cert}/key.pem"; + }; + inboxes = lib.recursiveUpdate (lib.genAttrs (map baseNameOf repositories) (repo: { + address = [ + # Routed to the "public-inbox:" transport in services.postfix.transport + "${repo}@${domain}" + ]; + description = '' + ${repo}@${domain} : + discussions about ${repo}. + ''; + url = "https://machine.${domain}/inbox/${repo}"; + newsgroup = "inbox.comp.${orga}.${repo}"; + coderepo = [ repo ]; + })) + { + repo2 = { + hide = [ + "imap" # FIXME: doesn't work for IMAP as of public-inbox 1.6.1 + "manifest" + "www" + ]; + }; + }; + settings.coderepo = lib.listToAttrs (map (path: lib.nameValuePair (baseNameOf path) { + dir = "/var/lib/gitolite/repositories/${path}.git"; + cgitUrl = "https://git.${domain}/${path}.git"; + }) repositories); + }; + + # Use gitolite to store Git repositories listed in coderepo entries + services.gitolite = { + enable = true; + adminPubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJmoTOQnGqX+//us5oye8UuE+tQBx9QEM7PN13jrwgqY root@localhost"; + }; + systemd.services.public-inbox-httpd = { + serviceConfig.SupplementaryGroups = [ gitolite.group ]; + }; + + # Use nginx as a reverse proxy for public-inbox-httpd + services.nginx = { + enable = true; + recommendedGzipSettings = true; + recommendedOptimisation = true; + recommendedTlsSettings = true; + recommendedProxySettings = true; + virtualHosts."machine.${domain}" = { + forceSSL = true; + sslCertificate = "${tls-cert}/cert.pem"; + sslCertificateKey = "${tls-cert}/key.pem"; + locations."/".return = "302 /inbox"; + locations."= /inbox".return = "302 /inbox/"; + locations."/inbox".proxyPass = "http://unix:${public-inbox.http.port}:/inbox"; + # If using TCP instead of a Unix socket: + #locations."/inbox".proxyPass = "http://127.0.0.1:${toString public-inbox.http.port}/inbox"; + # Referred to by settings.publicinbox.css + # See http://public-inbox.org/meta/_/text/color/ + locations."= /style/light.css".alias = pkgs.writeText "light.css" '' + * { background:#fff; color:#000 } + + a { color:#00f; text-decoration:none } + a:visited { color:#808 } + + *.q { color:#008 } + + *.add { color:#060 } + *.del {color:#900 } + *.head { color:#000 } + *.hunk { color:#960 } + + .hl.num { color:#f30 } /* number */ + .hl.esc { color:#f0f } /* escape character */ + .hl.str { color:#f30 } /* string */ + .hl.ppc { color:#c3c } /* preprocessor */ + .hl.pps { color:#f30 } /* preprocessor string */ + .hl.slc { color:#099 } /* single-line comment */ + .hl.com { color:#099 } /* multi-line comment */ + /* .hl.opt { color:#ccc } */ /* operator */ + /* .hl.ipl { color:#ccc } */ /* interpolation */ + + /* keyword groups kw[a-z] */ + .hl.kwa { color:#f90 } + .hl.kwb { color:#060 } + .hl.kwc { color:#f90 } + /* .hl.kwd { color:#ccc } */ + ''; + }; + }; + + services.postfix = { + enable = true; + setSendmail = true; + #sslCert = "${tls-cert}/cert.pem"; + #sslKey = "${tls-cert}/key.pem"; + recipientDelimiter = "+"; + }; + + environment.systemPackages = [ + pkgs.mailutils + pkgs.openssl + ]; + + }; + + testScript = '' + start_all() + machine.wait_for_unit("multi-user.target") + machine.wait_for_unit("public-inbox-init.service") + + # Very basic check that Gitolite can work; + # Gitolite is not needed for the rest of this testScript + machine.wait_for_unit("gitolite-init.service") + + # List inboxes through public-inbox-httpd + machine.wait_for_unit("nginx.service") + machine.succeed("curl -L https://machine.${domain} | grep repo1@${domain}") + # The repo2 inbox is hidden + machine.fail("curl -L https://machine.${domain} | grep repo2@${domain}") + machine.wait_for_unit("public-inbox-httpd.service") + + # Send a mail and read it through public-inbox-httpd + # Must work too when using a recipientDelimiter. + machine.wait_for_unit("postfix.service") + machine.succeed("mail -t <${pkgs.writeText "mail" '' + Subject: Testing mail + From: root@localhost + To: repo1+extension@${domain} + Message-ID: <repo1@root-1> + Content-Type: text/plain; charset=utf-8 + Content-Disposition: inline + + This is a testing mail. + ''}") + machine.sleep(5) + machine.succeed("curl -L 'https://machine.${domain}/inbox/repo1/repo1@root-1/T/#u' | grep 'This is a testing mail.'") + + # Read a mail through public-inbox-imapd + machine.wait_for_open_port(993) + machine.wait_for_unit("public-inbox-imapd.service") + machine.succeed("openssl s_client -ign_eof -crlf -connect machine.${domain}:993 <${pkgs.writeText "imap-commands" '' + tag login anonymous@${domain} anonymous + tag SELECT INBOX.comp.${orga}.repo1.0 + tag FETCH 1 (BODY[HEADER]) + tag LOGOUT + ''} | grep '^Message-ID: <repo1@root-1>'") + + # TODO: Read a mail through public-inbox-nntpd + #machine.wait_for_open_port(563) + #machine.wait_for_unit("public-inbox-nntpd.service") + + # Delete a mail. + # Note that the use of an extension not listed in the addresses + # require to use --all + machine.succeed("curl -L https://machine.example.localdomain/inbox/repo1/repo1@root-1/raw | sudo -u public-inbox public-inbox-learn rm --all") + machine.fail("curl -L https://machine.example.localdomain/inbox/repo1/repo1@root-1/T/#u | grep 'This is a testing mail.'") + ''; +}) diff --git a/nixos/tests/systemd-nspawn.nix b/nixos/tests/systemd-nspawn.nix index 5bf55060d2e03..c2cb92d11301c 100644 --- a/nixos/tests/systemd-nspawn.nix +++ b/nixos/tests/systemd-nspawn.nix @@ -25,8 +25,15 @@ let nspawnImages = (pkgs.runCommand "localhost" { buildInputs = [ pkgs.coreutils pkgs.gnupg ]; } '' mkdir -p $out cd $out + + # produce a testimage.raw dd if=/dev/urandom of=$out/testimage.raw bs=$((1024*1024+7)) count=5 - sha256sum testimage.raw > SHA256SUMS + + # produce a testimage2.tar.xz, containing the hello store path + tar cvJpf testimage2.tar.xz ${pkgs.hello} + + # produce signature(s) + sha256sum testimage* > SHA256SUMS export GNUPGHOME="$(mktemp -d)" cp -R ${gpgKeyring}/* $GNUPGHOME gpg --batch --sign --detach-sign --output SHA256SUMS.gpg SHA256SUMS @@ -56,5 +63,9 @@ in { client.succeed( "cmp /var/lib/machines/testimage.raw ${nspawnImages}/testimage.raw" ) + client.succeed("machinectl pull-tar --verify=signature http://server/testimage2.tar.xz") + client.succeed( + "cmp /var/lib/machines/testimage2/${pkgs.hello}/bin/hello ${pkgs.hello}/bin/hello" + ) ''; }) diff --git a/nixos/tests/uptermd.nix b/nixos/tests/uptermd.nix new file mode 100644 index 0000000000000..b2ff9a1e0d9cf --- /dev/null +++ b/nixos/tests/uptermd.nix @@ -0,0 +1,62 @@ +import ./make-test-python.nix ({ pkgs, ...}: + +let + client = {pkgs, ...}:{ + environment.systemPackages = [ pkgs.upterm ]; + }; +in +{ + name = "uptermd"; + meta = with pkgs.lib.maintainers; { + maintainers = [ fleaz ]; + }; + + nodes = { + server = {config, ...}: { + services.uptermd = { + enable = true; + openFirewall = true; + port = 1337; + }; + }; + client1 = client; + client2 = client; + }; + + + testScript = '' + start_all() + + server.wait_for_unit("uptermd.service") + server.wait_for_unit("network-online.target") + + # Add SSH hostkeys from the server to both clients + # uptermd needs an '@cert-authority entry so we need to modify the known_hosts file + client1.execute("sleep 3; mkdir -p ~/.ssh && ssh -o StrictHostKeyChecking=no -p 1337 server ls") + client1.execute("echo @cert-authority $(cat ~/.ssh/known_hosts) > ~/.ssh/known_hosts") + client2.execute("sleep 3; mkdir -p ~/.ssh && ssh -o StrictHostKeyChecking=no -p 1337 server ls") + client2.execute("echo @cert-authority $(cat ~/.ssh/known_hosts) > ~/.ssh/known_hosts") + + client1.wait_for_unit("multi-user.target") + client1.wait_until_succeeds("pgrep -f 'agetty.*tty1'") + client1.wait_until_tty_matches(1, "login: ") + client1.send_chars("root\n") + client1.wait_until_succeeds("pgrep -u root bash") + + client1.execute("ssh-keygen -t ed25519 -N \"\" -f /root/.ssh/id_ed25519") + client1.send_chars("TERM=xterm upterm host --server ssh://server:1337 --force-command hostname -- bash > /tmp/session-details\n") + client1.wait_for_file("/tmp/session-details") + client1.send_key("q") + + # uptermd can't connect if we don't have a keypair + client2.execute("ssh-keygen -t ed25519 -N \"\" -f /root/.ssh/id_ed25519") + + # Grep the ssh connect command from the output of 'upterm host' + ssh_command = client1.succeed("grep 'SSH Session' /tmp/session-details | cut -d':' -f2-").strip() + + # Connect with client2. Because we used '--force-command hostname' we should get "client1" as the output + output = client2.succeed(ssh_command) + + assert output.strip() == "client1" + ''; +}) diff --git a/nixos/tests/virtualbox.nix b/nixos/tests/virtualbox.nix index 27093aab96ee5..4eb402a7d36ef 100644 --- a/nixos/tests/virtualbox.nix +++ b/nixos/tests/virtualbox.nix @@ -222,7 +222,7 @@ let machine.execute(ru("VBoxManage controlvm ${name} poweroff")) machine.succeed("rm -rf ${sharePath}") machine.succeed("mkdir -p ${sharePath}") - machine.succeed("chown alice.users ${sharePath}") + machine.succeed("chown alice:users ${sharePath}") def create_vm_${name}(): |