{ testers, inputs, sources ? import ../npins, ... }: testers.runNixOSTest ( { lib, config, hostPkgs, ... }: let pathToRoot = ../../..; pathFromRoot = "deployment/check/basic"; ## TODO: sanity check the existence of (pathToRoot + "/flake.nix") ## TODO: sanity check that (pathToRoot + "/${pathFromRoot}" == ./.) ## The whole repository, with the flake at its root. src = lib.fileset.toSource { fileset = pathToRoot; root = pathToRoot; }; targetNetworkJSON = hostPkgs.writeText "target-network.json" ( builtins.toJSON config.nodes.target.system.build.networkConfig ); in { name = "deployment-basic"; # imports = [ # ]; nodes = { deployer = { pkgs, nodes, ... }: { # environment.systemPackages = [ # ]; virtualisation = { ## Memory use is expected to be dominated by the NixOS evaluation, ## which happens on the deployer. memorySize = 4096; diskSize = 10 * 1024; cores = 2; }; nix.settings = { substituters = lib.mkForce [ ]; hashed-mirrors = null; connect-timeout = 1; }; system.extraDependencies = [ sources.nixpkgs pkgs.stdenv pkgs.stdenvNoCC pkgs.cowsay pkgs.cowsay.inputDerivation # NOTE: Crucial!!! ## Some derivations will be different compared to target's initial ## state, so we'll need to be able to build something similar. ## Generally the derivation inputs aren't that different, so we ## use the initial state of the target as a base. nodes.target.system.build.toplevel.inputDerivation nodes.target.system.build.etc.inputDerivation nodes.target.system.path.inputDerivation nodes.target.system.build.bootStage1.inputDerivation nodes.target.system.build.bootStage2.inputDerivation ] ++ lib.concatLists ( lib.mapAttrsToList ( _k: v: if v ? source.inputDerivation then [ v.source.inputDerivation ] else [ ] ) nodes.target.environment.etc ); }; target.imports = [ ./minimalTarget.nix ]; }; testScript = '' start_all() target.wait_for_unit("multi-user.target") deployer.wait_for_unit("multi-user.target") with subtest("Unpacking"): deployer.succeed("cp -r --no-preserve=mode ${src} work") with subtest("Configure the network"): deployer.copy_from_host("${targetNetworkJSON}", "/root/target-network.json") deployer.succeed("mv /root/target-network.json work/${pathFromRoot}/target-network.json") with subtest("Configure the deployer key"): deployer.succeed("""mkdir -p ~/.ssh && ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa""") deployer_key = deployer.succeed("cat ~/.ssh/id_rsa.pub").strip() deployer.succeed(f"echo '{deployer_key}' > work/${pathFromRoot}/deployer.pub") target.succeed(f"mkdir -p /root/.ssh && echo '{deployer_key}' >> /root/.ssh/authorized_keys") with subtest("Configure the target host key"): target_host_key = target.succeed("ssh-keyscan target | grep -v '^#' | cut -f 2- -d ' ' | head -n 1") deployer.succeed(f"echo '{target_host_key}' > work/${pathFromRoot}/target_host_key.pub") ## NOTE: This is super slow. It could probably be optimised in Nix, for ## instance by allowing to grab things directly from the host's store. with subtest("Override the lock"): deployer.succeed(""" cd work nix flake lock --extra-experimental-features 'flakes nix-command' \ --offline -v \ --override-input nixpkgs ${inputs.nixpkgs} \ ; """) with subtest("Check the status before deployment"): target.fail("cowsay hi 1>&2") with subtest("Run the deployment"): deployer.succeed("cd work && tofu apply --show-trace --no-interactive") with subtest("Check the deployment"): target.succeed("cowsay hi 1>&2") ''; } )