2024-06-25 12:39:04 +02:00
|
|
|
pkgs: test:
|
|
|
|
let
|
2024-11-11 17:25:42 +01:00
|
|
|
inherit (pkgs.lib)
|
|
|
|
mapAttrsToList
|
|
|
|
concatStringsSep
|
|
|
|
genAttrs
|
|
|
|
mkIf
|
|
|
|
;
|
2024-06-25 12:39:04 +02:00
|
|
|
inherit (builtins) attrNames;
|
|
|
|
|
2024-11-11 17:25:42 +01:00
|
|
|
interactiveConfig = (
|
|
|
|
{ config, ... }:
|
|
|
|
{
|
|
|
|
# so we can run `nix shell nixpkgs#foo` on the machines
|
|
|
|
nix.extraOptions = ''
|
|
|
|
extra-experimental-features = nix-command flakes
|
|
|
|
'';
|
2024-06-25 12:39:04 +02:00
|
|
|
|
2024-11-11 17:25:42 +01:00
|
|
|
# so we can ssh in and rebuild them
|
|
|
|
services.openssh = {
|
|
|
|
enable = true;
|
|
|
|
settings = {
|
|
|
|
PermitRootLogin = "yes";
|
|
|
|
PermitEmptyPasswords = "yes";
|
|
|
|
UsePAM = false;
|
|
|
|
};
|
2024-06-25 12:39:04 +02:00
|
|
|
};
|
|
|
|
|
2024-11-11 17:25:42 +01:00
|
|
|
virtualisation = mkIf (config.networking.hostName == "jumphost") {
|
|
|
|
forwardPorts = [
|
|
|
|
{
|
|
|
|
from = "host";
|
|
|
|
host.port = 2222;
|
|
|
|
guest.port = 22;
|
|
|
|
}
|
|
|
|
];
|
|
|
|
};
|
|
|
|
}
|
|
|
|
);
|
2024-06-25 12:39:04 +02:00
|
|
|
|
|
|
|
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=(${
|
2024-11-11 17:25:42 +01:00
|
|
|
concatStringsSep " " (
|
|
|
|
mapAttrsToList (
|
|
|
|
n: v: ''["${n}"]="${v.system.build.toplevel}"''
|
|
|
|
) rebuildableTest.driverInteractive.nodes
|
|
|
|
)
|
2024-06-25 12:39:04 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
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
|
2024-11-11 17:25:42 +01:00
|
|
|
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 { });
|
|
|
|
}
|
|
|
|
);
|
2024-06-25 12:39:04 +02:00
|
|
|
in
|
2024-11-11 17:25:42 +01:00
|
|
|
preOverride
|
|
|
|
// {
|
2024-06-25 12:39:04 +02:00
|
|
|
driverInteractive = preOverride.driverInteractive.overrideAttrs (old: {
|
|
|
|
# this comes from runCommand, not mkDerivation, so this is the only
|
|
|
|
# hook we have to override
|
2024-11-11 17:25:42 +01:00
|
|
|
buildCommand =
|
|
|
|
old.buildCommand
|
|
|
|
+ ''
|
|
|
|
ln -s ${sshConfig} $out/ssh-config
|
|
|
|
ln -s ${rebuildScript}/bin/rebuild $out/bin/rebuild
|
|
|
|
'';
|
2024-06-25 12:39:04 +02:00
|
|
|
});
|
|
|
|
};
|
|
|
|
in
|
|
|
|
rebuildableTest
|