150 lines
4.5 KiB
Nix
150 lines
4.5 KiB
Nix
|
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 = "no";
|
||
|
};
|
||
|
};
|
||
|
|
||
|
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
|
||
|
|