Add vmTest for Nixinate

This initializes ./test/default.nix which is referred to by the
flake.nix under the `checks` attribute. This default.nix should point to
all future tests, where they can be looked up and ran like:

nix build .#checks.x86_64-linux.vmTest

The test included is a simple NixOS VM Test. It uses Nixinate to deploy
a machine with `services.nginx.enable = true` set, and tests whether
nginx.service is started and reachable after deployment.
This commit is contained in:
matthewcroughan 2022-03-31 20:36:59 +01:00
parent fcae9a11d0
commit 971bfe5d1f
6 changed files with 162 additions and 125 deletions

124
examples/flake.lock generated
View file

@ -1,124 +0,0 @@
{
"nodes": {
"examples": {
"inputs": {
"nixinate": "nixinate_2",
"nixpkgs": "nixpkgs_2"
},
"locked": {
"narHash": "sha256-1iruH96Aame+4NAAwSwVZAbHzfnKxhMLjgoVvJar6ls=",
"path": "./examples",
"type": "path"
},
"original": {
"path": "./examples",
"type": "path"
}
},
"nixinate": {
"inputs": {
"examples": "examples",
"nixpkgs": "nixpkgs_3"
},
"locked": {
"lastModified": 1646587087,
"narHash": "sha256-SwOHL/tte1H8VvftnxtWCr5FIlZaGvNy57P9sMSrZ5Q=",
"owner": "matthewcroughan",
"repo": "nixinate",
"rev": "886c6a2b3bef14cacf6c3021df0a75bb57f9fbc7",
"type": "github"
},
"original": {
"owner": "matthewcroughan",
"repo": "nixinate",
"type": "github"
}
},
"nixinate_2": {
"inputs": {
"nixpkgs": "nixpkgs"
},
"locked": {
"narHash": "sha256-lk8eIWYxtHqDT4ZmSFuXMlG067RdPqLCQocnN+hNE7U=",
"path": "/etc/nixos/nixinate",
"type": "path"
},
"original": {
"path": "/etc/nixos/nixinate",
"type": "path"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1640887906,
"narHash": "sha256-Eupk1UlNicCD2UNZuEKt6yhE6kFWAxXM/HyziOjG9CA=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "8a053bc2255659c5ca52706b9e12e76a8f50dbdd",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-21.11",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1641147223,
"narHash": "sha256-eJnmISYGR7LeqEev4bsI/qcU0SgeFKHs3jnL4vMGL+k=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "08370e1e271f6fe00d302bebbe510fe0e2c611ca",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-21.11",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1647893727,
"narHash": "sha256-pOi7VdCb+s5Cwh5CS7YEZVRgH9uCmE87J5W7iXv29Ck=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "1ec61dd4167f04be8d05c45780818826132eea0d",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_4": {
"locked": {
"lastModified": 1641147223,
"narHash": "sha256-eJnmISYGR7LeqEev4bsI/qcU0SgeFKHs3jnL4vMGL+k=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "08370e1e271f6fe00d302bebbe510fe0e2c611ca",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-21.11",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixinate": "nixinate",
"nixpkgs": "nixpkgs_4"
}
}
},
"root": "root",
"version": 7
}

View file

@ -3,7 +3,7 @@
inputs = { inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
}; };
outputs = { self, nixpkgs, ... }: outputs = { self, nixpkgs, ... }@inputs:
let let
version = builtins.substring 0 8 self.lastModifiedDate; version = builtins.substring 0 8 self.lastModifiedDate;
supportedSystems = [ "x86_64-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin" ]; supportedSystems = [ "x86_64-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin" ];
@ -73,5 +73,18 @@
}; };
}; };
nixinate = forAllSystems (system: pkgs: nixpkgsFor.${system}.generateApps); nixinate = forAllSystems (system: pkgs: nixpkgsFor.${system}.generateApps);
checks = forAllSystems (system: pkgs:
let
vmTests = import ./tests {
makeTest = (import (nixpkgs + "/nixos/lib/testing-python.nix") { inherit system; }).makeTest;
inherit pkgs inputs;
};
in
pkgs.lib.optionalAttrs pkgs.stdenv.isLinux vmTests # vmTests can only be ran on Linux, so append them only if on Linux.
//
{
# Other checks here...
}
);
}; };
} }

4
tests/default.nix Normal file
View file

@ -0,0 +1,4 @@
{ pkgs, makeTest, inputs }:
{
vmTest = import ./vmTest { inherit pkgs makeTest inputs; };
}

104
tests/vmTest/default.nix Normal file
View file

@ -0,0 +1,104 @@
{ pkgs, makeTest, inputs }:
let
# 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
'';
# Imports a flake with inputs passed in by hand, rather than
# builtins.getFlake, which cannot be used in this way.
callLocklessFlake = path: inputs: let
r = {outPath = path;} //
((import (path + "/flake.nix")).outputs (inputs // {self = r;}));
in
r;
exampleFlake = pkgs.writeTextFile {
name = "nixinate-example-flake";
destination = "/flake.nix";
text = ''
{
outputs = { self, nixpkgs }:
let
makeTest = (import (nixpkgs + "/nixos/lib/testing-python.nix") { system = "${pkgs.hostPlatform.system}"; }).makeTest;
baseConfig = ((makeTest { nodes.baseConfig = { ... }: {}; testScript = "";}).nodes {}).baseConfig.extendModules {
modules = [
${builtins.readFile ./nixinateeBase.nix}
${builtins.readFile ./nixinateeAdditional.nix}
{
_module.args.nixinate = {
host = "nixinatee";
sshUser = "nixinator";
buildOn = "local"; # valid args are "local" or "remote"
};
}
];
};
in
{
nixosConfigurations = {
nixinatee = baseConfig;
};
};
}
'';
};
deployScript = inputs.self.nixinate.${pkgs.hostPlatform.system} (callLocklessFlake "${exampleFlake}" { nixpkgs = inputs.nixpkgs; });
exampleSystem = (callLocklessFlake "${exampleFlake}" { nixpkgs = inputs.nixpkgs; }).nixosConfigurations.nixinatee.config.system.build.toplevel;
in
makeTest {
nodes = {
nixinatee = { ... }: {
imports = [
./nixinateeBase.nix
];
virtualisation = {
writableStore = true;
};
};
nixinator = { ... }: {
virtualisation = {
additionalPaths = [
(allDrvOutputs exampleSystem)
];
};
nix = {
extraOptions =
let empty_registry = builtins.toFile "empty-flake-registry.json" ''{"flakes":[],"version":2}''; in
''
experimental-features = nix-command flakes
flake-registry = ${empty_registry}
'';
registry.nixpkgs.flake = inputs.nixpkgs;
};
};
};
testScript =
''
start_all()
nixinatee.wait_for_unit("sshd.service")
nixinator.wait_for_unit("multi-user.target")
nixinator.succeed("mkdir ~/.ssh/")
nixinator.succeed("ssh-keyscan -H nixinatee >> ~/.ssh/known_hosts")
nixinator.succeed("exec ${deployScript.nixinate.nixinatee.program} >&2")
nixinatee.wait_for_unit("nginx.service")
nixinatee.wait_for_open_port("80")
with subtest("Check that Nginx webserver can be reached by deployer after deployment"):
assert "<title>Welcome to nginx!</title>" in nixinator.succeed(
"curl -sSf http:/nixinatee/ | grep title"
)
with subtest("Check that Nginx webserver can be reached by deployee after deployment"):
assert "<title>Welcome to nginx!</title>" in nixinatee.succeed(
"curl -sSf http:/127.0.0.1/ | grep title"
)
'';
}

View file

@ -0,0 +1,8 @@
# Configuration that will be added to the nixinatee node. Nixinate will deploy
# the combination of nixinateBase.nix + nixinateAdditional.nix
{
config = {
services.nginx.enable = true;
networking.firewall.allowedTCPPorts = [ 80 ];
};
}

View file

@ -0,0 +1,32 @@
# Common configuration of nixinatee node in the vmTest. This is the base
# configuration which is required to perform the test.
{
config = {
nix.trustedUsers = [ "nixinator" ];
security.sudo.extraRules = [{
users = [ "nixinator" ];
commands = [{
command = "ALL";
options = [ "NOPASSWD" ];
}];
}];
users = {
mutableUsers = false;
users = {
nixinator = {
extraGroups = [
"wheel"
];
password = "";
isNormalUser = true;
};
};
};
services.openssh = {
enable = true;
extraConfig = "PermitEmptyPasswords yes";
};
documentation.enable = false;
boot.loader.grub.enable = false;
};
}