forked from Fediversity/Fediversity
This PR adds a basic deployment test to the repository. This test will, in a NixOS test, run a deployer VM and a target VM, and check that we manage to run `nixops4 apply` on the deployer VM to change things on the target VM. The ideas are all @roberth's and this test has been extremely heavily inspired by https://github.com/nixops4/nixops4-nixos/blob/main/test/default/nixosTest.nix. Reviewed-on: Fediversity/Fediversity#323 Reviewed-by: Valentin Gagarin <valentin.gagarin@tweag.io> Co-authored-by: Nicolas “Niols” Jeannerod <nicolas.jeannerod@moduscreate.com> Co-committed-by: Nicolas “Niols” Jeannerod <nicolas.jeannerod@moduscreate.com>
161 lines
5.6 KiB
Nix
161 lines
5.6 KiB
Nix
{
|
|
testers,
|
|
inputs,
|
|
runCommandNoCC,
|
|
nixops4-flake-in-a-bottle,
|
|
...
|
|
}:
|
|
|
|
testers.runNixOSTest (
|
|
{
|
|
lib,
|
|
config,
|
|
hostPkgs,
|
|
...
|
|
}:
|
|
let
|
|
vmSystem = config.node.pkgs.hostPlatform.system;
|
|
|
|
pathToRoot = ../../..;
|
|
pathFromRoot = "deployment/check/basic";
|
|
deploymentName = "check-deployment-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;
|
|
};
|
|
|
|
## We will need to override some inputs by the empty flake, so we make one.
|
|
emptyFlake = runCommandNoCC "empty-flake" { } ''
|
|
mkdir $out
|
|
echo "{ outputs = { self }: {}; }" > $out/flake.nix
|
|
'';
|
|
|
|
targetNetworkJSON = hostPkgs.writeText "target-network.json" (
|
|
builtins.toJSON config.nodes.target.system.build.networkConfig
|
|
);
|
|
|
|
in
|
|
{
|
|
name = "deployment-basic";
|
|
imports = [
|
|
inputs.nixops4-nixos.modules.nixosTest.static
|
|
];
|
|
|
|
nodes = {
|
|
deployer =
|
|
{ pkgs, nodes, ... }:
|
|
{
|
|
environment.systemPackages = [
|
|
inputs.nixops4.packages.${vmSystem}.default
|
|
];
|
|
|
|
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 =
|
|
[
|
|
"${inputs.flake-parts}"
|
|
"${inputs.flake-parts.inputs.nixpkgs-lib}"
|
|
"${inputs.nixops4}"
|
|
"${inputs.nixops4-nixos}"
|
|
"${inputs.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 flake-parts ${inputs.flake-parts} \
|
|
--override-input nixops4 ${nixops4-flake-in-a-bottle} \
|
|
\
|
|
--override-input nixops4-nixos ${inputs.nixops4-nixos} \
|
|
--override-input nixops4-nixos/flake-parts ${inputs.nixops4-nixos.inputs.flake-parts} \
|
|
--override-input nixops4-nixos/flake-parts/nixpkgs-lib ${inputs.nixops4-nixos.inputs.flake-parts.inputs.nixpkgs-lib} \
|
|
--override-input nixops4-nixos/nixops4-nixos ${emptyFlake} \
|
|
--override-input nixops4-nixos/nixpkgs ${inputs.nixops4-nixos.inputs.nixpkgs} \
|
|
--override-input nixops4-nixos/nixops4 ${nixops4-flake-in-a-bottle} \
|
|
--override-input nixops4-nixos/git-hooks-nix ${emptyFlake} \
|
|
\
|
|
--override-input nixpkgs ${inputs.nixpkgs} \
|
|
--override-input git-hooks ${inputs.git-hooks} \
|
|
;
|
|
""")
|
|
|
|
with subtest("Check the status before deployment"):
|
|
target.fail("cowsay hi 1>&2")
|
|
|
|
with subtest("Run the deployment"):
|
|
deployer.succeed("cd work && nixops4 apply ${deploymentName} --show-trace --no-interactive")
|
|
|
|
with subtest("Check the deployment"):
|
|
target.succeed("cowsay hi 1>&2")
|
|
'';
|
|
}
|
|
)
|