Skip to content

Commit

Permalink
Merge NixOS#1526
Browse files Browse the repository at this point in the history
1526: Integration test r=roberth a=roberth

TODO
 
 - [x] NixOS#1484
 - [x] provide a Hercules CI agent for running this VM test (requires KVM)

Scoped out:
 - reduce build dependency outputs closure? (currently adds all deps all the way up to bootstrap deps) # NixOS/nixpkgs#180529


Co-authored-by: Robert Hensing <[email protected]>
  • Loading branch information
bors[bot] and roberth authored Jul 9, 2022
2 parents bd6b955 + fc863f9 commit dcafae5
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 12 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
name: CI
on:
push:
branches: [ "master" ]
branches:
- "master"
- "staging"
- "trying"
pull_request:
branches: [ "**" ]
jobs:
Expand Down
19 changes: 19 additions & 0 deletions bors.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
status = [
# Checks
# listed as CI / x / (pull_request)
"parsing",
"build",
"black",
"mypy",
"flake8",
# Allowed to fail. Highlights possible increases in tech debt.
# "mypy-ratchet",
"coverage",
"docs",
"poetry-up-to-date",

# Run the VM tests after approval
"ci/hercules/onPush/default",
"ci/hercules/evaluation",
]
delete_merged_branches = true
33 changes: 22 additions & 11 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -122,17 +122,28 @@
'';
};

checks.doc = pkgs.stdenv.mkDerivation {
name = "check-lint-docs";
# we use cleanPythonSources because the default gitignore
# implementation doesn't support the restricted evaluation
src = pkgs.poetry2nix.cleanPythonSources {
src = ./.;
checks = {
doc = pkgs.stdenv.mkDerivation {
name = "check-lint-docs";
# we use cleanPythonSources because the default gitignore
# implementation doesn't support the restricted evaluation
src = pkgs.poetry2nix.cleanPythonSources {
src = ./.;
};
dontBuild = true;
installPhase = ''
${linters.doc}/bin/lint-docs | tee $out
'';
};
dontBuild = true;
installPhase = ''
${linters.doc}/bin/lint-docs | tee $out
'';
} // utils.lib.flattenTree (
import ./integration-tests {
inherit pkgs;
nixops = self.defaultPackage.${system};
}
);
}) // {
herculesCI = {
ciSystems = ["x86_64-linux"];
};
});
};
}
104 changes: 104 additions & 0 deletions integration-tests/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
{ pkgs, nixops }:
let
inherit (pkgs) lib;
inherit (lib) optionalAttrs;

tests = {
legacy = testLegacyNetwork;
};

testLegacyNetwork = pkgs.nixosTest ({
name = "nixops-legacy-network";
nodes = {
deployer = { config, lib, nodes, pkgs, modulesPath, ... }: {
imports = [ (modulesPath + "/installer/cd-dvd/channel.nix") ];
environment.systemPackages = [ nixops ];
nix.settings.substituters = lib.mkForce [ ];
users.users.person.isNormalUser = true;
virtualisation.writableStore = true;
virtualisation.additionalPaths = [
pkgs.hello
pkgs.figlet

# This includes build dependencies all the way down. Not efficient,
# but we do need build deps to an *arbitrary* depth, which is hard to
# determine.
(allDrvOutputs nodes.server.config.system.build.toplevel)
];
};
server = { lib, ... }: {
imports = [ ./legacy/base-configuration.nix ];
};
};

testScript = { nodes }:
let
deployerSetup = pkgs.writeScript "deployerSetup" ''
#!${pkgs.runtimeShell}
set -eux -o pipefail
cp --no-preserve=mode -r ${./legacy} unicorn
cp --no-preserve=mode ${./ssh-keys.nix} unicorn/ssh-keys.nix
mkdir -p ~/.ssh
cp ${snakeOilPrivateKey} ~/.ssh/id_ed25519
chmod 0400 ~/.ssh/id_ed25519
'';
serverNetworkJSON = pkgs.writeText "server-network.json"
(builtins.toJSON nodes.server.config.system.build.networkConfig);
in
''
import shlex
def deployer_do(cmd):
cmd = shlex.quote(cmd)
return deployer.succeed(f"su person -l -c {cmd} &>/dev/console")
start_all()
deployer_do("cat /etc/hosts")
deployer_do("${deployerSetup}")
deployer_do("cp ${serverNetworkJSON} unicorn/server-network.json")
# Establish that ssh works, regardless of nixops
# Easy way to accept the server host key too.
server.wait_for_open_port(22)
deployer.wait_for_unit("network.target")
# Put newlines on console, to flush the console reader's line buffer
# in case nixops' last output did not end in a newline, as is the case
# with a status line (if implemented?)
deployer.succeed("while sleep 60s; do echo [60s passed]; done >&2 &")
deployer_do("cd ~/unicorn; ssh -oStrictHostKeyChecking=accept-new root@server echo hi")
# Create and deploy
deployer_do("cd ~/unicorn; nixops create")
deployer_do("cd ~/unicorn; nixops deploy --confirm")
deployer_do("cd ~/unicorn; nixops ssh server 'hello | figlet'")
'';
});

inherit (import ./ssh-keys.nix pkgs) snakeOilPrivateKey snakeOilPublicKey;

/*
Return a store path with a closure containing everything including
derivations and all build dependency outputs, all the way down.
*/
allDrvOutputs = pkg:
let name = "allDrvOutputs-${pkg.pname or pkg.name or "unknown"}";
in
pkgs.runCommand name { refs = pkgs.writeReferencesToFile pkg.drvPath; } ''
touch $out
while read ref; do
case $ref in
*.drv)
cat $ref >>$out
;;
esac
done <$refs
'';

in
optionalAttrs pkgs.stdenv.isLinux tests
31 changes: 31 additions & 0 deletions integration-tests/legacy/base-configuration.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{ lib, modulesPath, pkgs, ... }:
let
ssh-keys =
if builtins.pathExists ../ssh-keys.nix
then # Outside sandbox
../ssh-keys.nix
else # In sandbox
./ssh-keys.nix;

inherit (import ssh-keys pkgs)
snakeOilPrivateKey snakeOilPublicKey;
in
{
imports = [
(modulesPath + "/virtualisation/qemu-vm.nix")
(modulesPath + "/testing/test-instrumentation.nix")
];
virtualisation.writableStore = true;
nix.settings.substituters = lib.mkForce [ ];
virtualisation.graphics = false;
documentation.enable = false;
services.qemuGuest.enable = true;
boot.loader.grub.enable = false;

services.openssh.enable = true;
users.users.root.openssh.authorizedKeys.keys = [
snakeOilPublicKey
];
security.pam.services.sshd.limits =
[{ domain = "*"; item = "memlock"; type = "-"; value = 1024; }];
}
15 changes: 15 additions & 0 deletions integration-tests/legacy/nixops.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
network = {
description = "Legacy Network using <nixpkgs> and legacy state.";
# NB this is not really what makes it a legacy network; lack of flakes is.
storage.legacy = { };
};
server = { lib, pkgs, ... }: {
deployment.targetEnv = "none";
imports = [
./base-configuration.nix
(lib.modules.importJSON ./server-network.json)
];
environment.systemPackages = [ pkgs.hello pkgs.figlet ];
};
}
15 changes: 15 additions & 0 deletions integration-tests/ssh-keys.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
pkgs:
{ snakeOilPrivateKey = pkgs.writeText "privkey.snakeoil" ''
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIHQf/khLvYrQ8IOika5yqtWvI0oquHlpRLTZiJy5dRJmoAoGCCqGSM49
AwEHoUQDQgAEKF0DYGbBwbj06tA3fd/+yP44cvmwmHBWXZCKbS+RQlAKvLXMWkpN
r1lwMyJZoSGgBHoUahoYjTh9/sJL7XLJtA==
-----END EC PRIVATE KEY-----
'';

snakeOilPublicKey = pkgs.lib.concatStrings [
"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHA"
"yNTYAAABBBChdA2BmwcG49OrQN33f/sj+OHL5sJhwVl2Qim0vkUJQCry1zFpKTa"
"9ZcDMiWaEhoAR6FGoaGI04ff7CS+1yybQ= snakeoil"
];
}

0 comments on commit dcafae5

Please sign in to comment.