simple-nixos-fediverse/tests/rebuildableTest.nix

150 lines
4.5 KiB
Nix
Raw Permalink Normal View History

pkgs: test:
let
inherit (pkgs.lib) mapAttrsToList concatStringsSep genAttrs mkIf;
inherit (builtins) attrNames;
interactiveConfig = ({ config, ... }: {
# so we can run `nix shell nixpkgs#foo` on the machines
nix.extraOptions = ''
extra-experimental-features = nix-command flakes
'';
# so we can ssh in and rebuild them
services.openssh = {
enable = true;
settings = {
PermitRootLogin = "yes";
PermitEmptyPasswords = "yes";
UsePAM = false;
};
};
virtualisation = mkIf (config.networking.hostName == "jumphost") {
forwardPorts = [{
from = "host";
host.port = 2222;
guest.port = 22;
}];
};
});
sshConfig = pkgs.writeText "ssh-config" ''
Host *
User root
StrictHostKeyChecking no
BatchMode yes
ConnectTimeout 20
UserKnownHostsFile=/dev/null
LogLevel Error # no "added to known hosts"
Host jumphost
Port 2222
HostName localhost
Host * !jumphost
ProxyJump jumphost
'';
# one should first start up the interactive test driver, then start the
# machines, then update the config, and then redeploy with the `rebuildScript`
# associated with the new config.
rebuildScript = pkgs.writeShellScriptBin "rebuild" ''
# create an association array from machine names to the path to their
# configuration in the nix store
declare -A configPaths=(${
concatStringsSep " "
(mapAttrsToList
(n: v: ''["${n}"]="${v.system.build.toplevel}"'')
rebuildableTest.driverInteractive.nodes)
})
rebuild_one() {
machine="$1"
echo "pushing new config to $machine"
if [ -z ''${configPaths[$machine]+x} ]; then
echo 'No machine '"$machine"' in this test.'
exit 1
fi
if ! ssh -F ${sshConfig} $machine true; then
echo 'Couldn'"'"'t connect to '"$machine"'. Make sure you'"'"'ve started it with `'"$machine"'.start()` in the test interactive driver.'
exit 1
fi
# taken from nixos-rebuild (we only want to do the activate part)
cmd=(
"systemd-run"
"-E" "LOCALE_ARCHIVE"
"--collect"
"--no-ask-password"
"--pty"
"--quiet"
"--same-dir"
"--service-type=exec"
"--unit=nixos-rebuild-switch-to-configuration"
"--wait"
"''${configPaths[$machine]}/bin/switch-to-configuration"
"test"
)
if ! ssh -F ${sshConfig} $machine "''${cmd[@]}"; then
echo "warning: error(s) occurred while switching to the new configuration"
exit 1
fi
}
if ! ssh -F ${sshConfig} jumphost true; then
echo 'Couldn'"'"'t connect to jump host. Make sure you are running driverInteractive, and that you'"'"'ve run `jumphost.start()` and `jumphost.forward_port(2222,22)`'
exit 1
fi
if [ -n "$1" ]; then
rebuild_one "$1"
else
for machine in ${concatStringsSep " " (attrNames rebuildableTest.driverInteractive.nodes)}; do
rebuild_one $machine
done
fi
'';
# NOTE: This is awkward because NixOS does not expose the module interface
# that is used to build tests. When we upstream this, we can build it into the
# system more naturally (and expose more of the interface to end users while
# we're at it)
rebuildableTest =
let
preOverride = pkgs.nixosTest (test // {
interactive = (test.interactive or { }) // {
# no need to // with test.interactive.nodes here, since we are iterating
# over all of them, and adding back in the config via `imports`
nodes = genAttrs
(
attrNames test.nodes or { } ++
attrNames test.interactive.nodes or { } ++
[ "jumphost" ]
)
(n: {
imports = [
(test.interactive.${n} or { })
interactiveConfig
];
});
};
# override with test.passthru in case someone wants to overwrite us.
passthru = { inherit rebuildScript sshConfig; } // (test.passthru or { });
});
in
preOverride // {
driverInteractive = preOverride.driverInteractive.overrideAttrs (old: {
# this comes from runCommand, not mkDerivation, so this is the only
# hook we have to override
buildCommand = old.buildCommand + ''
ln -s ${sshConfig} $out/ssh-config
ln -s ${rebuildScript}/bin/rebuild $out/bin/rebuild
'';
});
};
in
rebuildableTest