WiP! build tests with nixos-module system
This commit is contained in:
parent
5db9421732
commit
c765ba3b02
13
flake.nix
13
flake.nix
|
@ -139,15 +139,12 @@
|
||||||
|
|
||||||
checks =
|
checks =
|
||||||
# Checks for continous testing
|
# Checks for continous testing
|
||||||
|
let tests = import ./tests;
|
||||||
|
in
|
||||||
with (forAllCrossSystems ({ system, localSystem, crossSystem }:
|
with (forAllCrossSystems ({ system, localSystem, crossSystem }:
|
||||||
import ./tests {
|
tests {
|
||||||
inherit self;
|
flake = self;
|
||||||
apps = self.apps.${system};
|
inherit system localSystem crossSystem;
|
||||||
localPackages = nixpkgsFor.${localSystem};
|
|
||||||
genodepkgs = self.packages.${system};
|
|
||||||
lib = self.lib.${system};
|
|
||||||
nixpkgs = nixpkgsFor.${system};
|
|
||||||
legacyPackages = self.legacyPackages.${system};
|
|
||||||
} // {
|
} // {
|
||||||
ports = nixpkgsFor.${localSystem}.symlinkJoin {
|
ports = nixpkgsFor.${localSystem}.symlinkJoin {
|
||||||
name = "ports";
|
name = "ports";
|
||||||
|
|
93
nixos-modules/genode-init.nix
Normal file
93
nixos-modules/genode-init.nix
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
# genodeInit.children is an attrset of nixos configurations, like containers
|
||||||
|
|
||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [ ];
|
||||||
|
|
||||||
|
options.genode.init = {
|
||||||
|
|
||||||
|
config = mkOption {
|
||||||
|
description = "Dhall configuration of this init instance";
|
||||||
|
type = types.either types.str types.path;
|
||||||
|
};
|
||||||
|
|
||||||
|
inputs = mkOption {
|
||||||
|
description = "List of packages to build a ROM store with.";
|
||||||
|
type = types.listOf types.package;
|
||||||
|
};
|
||||||
|
|
||||||
|
subinits = mkOption {
|
||||||
|
type = types.attrsOf (types.submodule ({ config, options, name, ... }: {
|
||||||
|
options = {
|
||||||
|
|
||||||
|
config = mkOption {
|
||||||
|
description = ''
|
||||||
|
A specification of the desired configuration of this sub-init, as a NixOS module.
|
||||||
|
'';
|
||||||
|
type =
|
||||||
|
let confPkgs = if config.pkgs == null then pkgs else config.pkgs;
|
||||||
|
in lib.mkOptionType {
|
||||||
|
name = "Toplevel NixOS config";
|
||||||
|
merge = loc: defs:
|
||||||
|
(import (confPkgs.path + "/nixos/lib/eval-config.nix") {
|
||||||
|
inherit system;
|
||||||
|
pkgs = confPkgs;
|
||||||
|
baseModules =
|
||||||
|
import (confPkgs.path + "/nixos/modules/module-list.nix");
|
||||||
|
inherit (confPkgs) lib;
|
||||||
|
modules = let
|
||||||
|
extraConfig = {
|
||||||
|
_file = "module at ${__curPos.file}:${
|
||||||
|
toString __curPos.line
|
||||||
|
}";
|
||||||
|
config = { };
|
||||||
|
};
|
||||||
|
in [ extraConfig ] ++ (map (x: x.value) defs);
|
||||||
|
prefix = [ "containers" name ];
|
||||||
|
}).config;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
pkgs = mkOption {
|
||||||
|
type = types.nullOr types.attrs;
|
||||||
|
default = null;
|
||||||
|
example = literalExample "pkgs";
|
||||||
|
description = ''
|
||||||
|
Customise which nixpkgs to use for this container.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkMerge [
|
||||||
|
(mkIf options.config.isDefined {
|
||||||
|
path = config.config.system.build.toplevel;
|
||||||
|
})
|
||||||
|
];
|
||||||
|
}));
|
||||||
|
|
||||||
|
default = { };
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
|
||||||
|
system.build.initXml = pkgs.buildPackages.runCommand "init.xml" {
|
||||||
|
nativeBuildInputs = with pkgs.buildPackages; [ dhall xorg.lndir ];
|
||||||
|
DHALL_GENODE = "${pkgs.genodePackages.dhallGenode}/binary.dhall";
|
||||||
|
INIT_CONFIG = config.genode.init.config;
|
||||||
|
} ''
|
||||||
|
export XDG_CACHE_HOME=$NIX_BUILD_TOP
|
||||||
|
lndir -silent \
|
||||||
|
${pkgs.genodePackages.dhallGenode}/.cache \
|
||||||
|
$XDG_CACHE_HOME
|
||||||
|
dhall text <<< "(env:DHALL_GENODE).Init.render (env:INIT_CONFIG)" > $out
|
||||||
|
'';
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,21 +1,31 @@
|
||||||
{ self, apps, localPackages, genodepkgs, lib, nixpkgs, legacyPackages }:
|
{ flake, system, localSystem, crossSystem }:
|
||||||
|
|
||||||
|
let
|
||||||
|
apps = flake.apps.${system};
|
||||||
|
localPackages = flake.legacyPackages.${localSystem};
|
||||||
|
genodepkgs = flake.packages.${system};
|
||||||
|
lib = flake.lib.${system};
|
||||||
|
nixpkgs = flake.legacyPackages.${system};
|
||||||
|
legacyPackages = flake.legacyPackages.${system};
|
||||||
|
|
||||||
|
in with import ./lib/build-vms.nix {
|
||||||
|
inherit flake system localSystem crossSystem;
|
||||||
|
pkgs = flake.legacyPackages.${system};
|
||||||
|
localPackages = flake.inputs.nixpkgs.legacyPackages.${localSystem};
|
||||||
|
modulesPath = "${flake.inputs.nixpkgs}/nixos/modules";
|
||||||
|
};
|
||||||
|
with flake.legacyPackages.${system};
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
callTest = path:
|
testSpecs = map (p: import p) [
|
||||||
import path {
|
|
||||||
pkgs = testPkgs;
|
|
||||||
inherit nixpkgs localPackages legacyPackages;
|
|
||||||
};
|
|
||||||
|
|
||||||
testFiles = map callTest [
|
|
||||||
./log.nix
|
./log.nix
|
||||||
./posix.nix
|
# ./posix.nix
|
||||||
./tox-bootstrapd.nix
|
# ./tox-bootstrapd.nix
|
||||||
./vmm_arm.nix
|
# ./vmm_arm.nix
|
||||||
./vmm_x86.nix
|
# ./vmm_x86.nix
|
||||||
./x86.nix
|
# ./x86.nix
|
||||||
] ++ (callTest ./solo5);
|
]; # TODO ++ (callTest ./solo5);
|
||||||
|
|
||||||
testPkgs = genodepkgs;
|
testPkgs = genodepkgs;
|
||||||
|
|
||||||
|
@ -27,6 +37,7 @@ let
|
||||||
x86_64-genode = "${qemuPkg}/bin/qemu-system-x86_64";
|
x86_64-genode = "${qemuPkg}/bin/qemu-system-x86_64";
|
||||||
}.${genodepkgs.stdenv.hostPlatform.system};
|
}.${genodepkgs.stdenv.hostPlatform.system};
|
||||||
|
|
||||||
|
# TODO: move the cores into nixos modules
|
||||||
cores = [
|
cores = [
|
||||||
{
|
{
|
||||||
prefix = "hw-pc-";
|
prefix = "hw-pc-";
|
||||||
|
@ -141,6 +152,7 @@ let
|
||||||
let
|
let
|
||||||
testDriverName = "genode-test-driver-${name}";
|
testDriverName = "genode-test-driver-${name}";
|
||||||
|
|
||||||
|
# TODO: move buildVM into a nixos module
|
||||||
buildVM = vmName:
|
buildVM = vmName:
|
||||||
{ config, inputs, env ? { }, extraPaths ? [ ] }:
|
{ config, inputs, env ? { }, extraPaths ? [ ] }:
|
||||||
let
|
let
|
||||||
|
@ -178,7 +190,6 @@ let
|
||||||
./test-wrapper.dhall
|
./test-wrapper.dhall
|
||||||
} (${config}) $(stat --format '%s' ${storeTarball}/store.tar) ${storeManifest} ${manifest}";
|
} (${config}) $(stat --format '%s' ${storeTarball}/store.tar) ${storeManifest} ${manifest}";
|
||||||
env' = {
|
env' = {
|
||||||
DHALL_GENODE = "${testPkgs.dhallGenode}/source.dhall";
|
|
||||||
DHALL_GENODE_TEST = "${./test.dhall}";
|
DHALL_GENODE_TEST = "${./test.dhall}";
|
||||||
} // env;
|
} // env;
|
||||||
|
|
||||||
|
@ -197,7 +208,10 @@ let
|
||||||
''${apps.render-init.program} <<< "(${config'}).config" > $out'';
|
''${apps.render-init.program} <<< "(${config'}).config" > $out'';
|
||||||
};
|
};
|
||||||
|
|
||||||
nodes = lib.mapAttrs buildVM
|
# nodes = lib.mapAttrs buildVM
|
||||||
|
# (t.nodes or (if t ? machine then { machine = t.machine; } else { }));
|
||||||
|
|
||||||
|
nodes = buildVirtualNetwork
|
||||||
(t.nodes or (if t ? machine then { machine = t.machine; } else { }));
|
(t.nodes or (if t ? machine then { machine = t.machine; } else { }));
|
||||||
|
|
||||||
testScript' =
|
testScript' =
|
||||||
|
@ -207,7 +221,9 @@ let
|
||||||
else
|
else
|
||||||
testScript;
|
testScript;
|
||||||
|
|
||||||
vms = map (node: node.script) (lib.attrValues nodes);
|
vlans = map (m: m.config.virtualisation.vlans) (lib.attrValues nodes);
|
||||||
|
|
||||||
|
vms = map (m: m.config.system.build.vm) (lib.attrValues nodes);
|
||||||
|
|
||||||
# Generate onvenience wrappers for running the test driver
|
# Generate onvenience wrappers for running the test driver
|
||||||
# interactively with the specified network, and for starting the
|
# interactively with the specified network, and for starting the
|
||||||
|
@ -285,7 +301,7 @@ let
|
||||||
} else
|
} else
|
||||||
null;
|
null;
|
||||||
|
|
||||||
in lib.lists.crossLists f [ cores' testFiles ];
|
in lib.lists.crossLists f [ cores' testSpecs ];
|
||||||
|
|
||||||
in builtins.listToAttrs (builtins.filter (_: _ != null) testList)
|
in builtins.listToAttrs (builtins.filter (_: _ != null) testList)
|
||||||
|
|
||||||
|
|
109
tests/lib/build-vms.nix
Normal file
109
tests/lib/build-vms.nix
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
{ flake, system, localSystem, crossSystem
|
||||||
|
# Nixpkgs, for qemu, lib and more
|
||||||
|
, localPackages, pkgs, modulesPath }:
|
||||||
|
|
||||||
|
with pkgs.lib;
|
||||||
|
with import ./qemu-flags.nix { inherit pkgs; };
|
||||||
|
|
||||||
|
rec {
|
||||||
|
|
||||||
|
inherit pkgs;
|
||||||
|
|
||||||
|
qemu = pkgs.qemu_test;
|
||||||
|
|
||||||
|
# Build a virtual network from an attribute set `{ machine1 =
|
||||||
|
# config1; ... machineN = configN; }', where `machineX' is the
|
||||||
|
# hostname and `configX' is a NixOS system configuration. Each
|
||||||
|
# machine is given an arbitrary IP address in the virtual network.
|
||||||
|
buildVirtualNetwork = nodes:
|
||||||
|
let nodesOut = mapAttrs (n: buildVM nodesOut) (assignIPAddresses nodes);
|
||||||
|
in nodesOut;
|
||||||
|
|
||||||
|
buildVM = nodes: configurations:
|
||||||
|
|
||||||
|
import "${modulesPath}/../lib/eval-config.nix" {
|
||||||
|
inherit system;
|
||||||
|
modules = configurations;
|
||||||
|
baseModules = (import "${modulesPath}/module-list.nix") ++ [
|
||||||
|
"${modulesPath}/virtualisation/qemu-vm.nix"
|
||||||
|
"${modulesPath}/testing/test-instrumentation.nix" # !!! should only get added for automated test runs
|
||||||
|
{
|
||||||
|
key = "no-manual";
|
||||||
|
documentation.nixos.enable = false;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
key = "qemu";
|
||||||
|
system.build.qemu = qemu;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
key = "nodes";
|
||||||
|
_module.args.nodes = nodes;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
nixpkgs = {
|
||||||
|
inherit system crossSystem localSystem;
|
||||||
|
pkgs = flake.legacyPackages.${system};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Given an attribute set { machine1 = config1; ... machineN =
|
||||||
|
# configN; }, sequentially assign IP addresses in the 192.168.1.0/24
|
||||||
|
# range to each machine, and set the hostname to the attribute name.
|
||||||
|
assignIPAddresses = nodes:
|
||||||
|
|
||||||
|
let
|
||||||
|
|
||||||
|
machines = attrNames nodes;
|
||||||
|
|
||||||
|
machinesNumbered = zipLists machines (range 1 254);
|
||||||
|
|
||||||
|
nodes_ = forEach machinesNumbered (m:
|
||||||
|
nameValuePair m.fst [
|
||||||
|
({ config, nodes, ... }:
|
||||||
|
let
|
||||||
|
interfacesNumbered =
|
||||||
|
zipLists config.virtualisation.vlans (range 1 255);
|
||||||
|
interfaces = forEach interfacesNumbered ({ fst, snd }:
|
||||||
|
nameValuePair "eth${toString snd}" {
|
||||||
|
ipv4.addresses = [{
|
||||||
|
address = "192.168.${toString fst}.${toString m.snd}";
|
||||||
|
prefixLength = 24;
|
||||||
|
}];
|
||||||
|
});
|
||||||
|
in {
|
||||||
|
key = "ip-address";
|
||||||
|
config = {
|
||||||
|
networking.hostName = mkDefault m.fst;
|
||||||
|
|
||||||
|
networking.interfaces = listToAttrs interfaces;
|
||||||
|
|
||||||
|
networking.primaryIPAddress = optionalString (interfaces != [ ])
|
||||||
|
(head (head interfaces).value.ipv4.addresses).address;
|
||||||
|
|
||||||
|
# Put the IP addresses of all VMs in this machine's
|
||||||
|
# /etc/hosts file. If a machine has multiple
|
||||||
|
# interfaces, use the IP address corresponding to
|
||||||
|
# the first interface (i.e. the first network in its
|
||||||
|
# virtualisation.vlans option).
|
||||||
|
networking.extraHosts = flip concatMapStrings machines (m':
|
||||||
|
let config = (getAttr m' nodes).config;
|
||||||
|
in optionalString (config.networking.primaryIPAddress != "")
|
||||||
|
("${config.networking.primaryIPAddress} "
|
||||||
|
+ optionalString (config.networking.domain != null)
|
||||||
|
"${config.networking.hostName}.${config.networking.domain} "
|
||||||
|
+ ''
|
||||||
|
${config.networking.hostName}
|
||||||
|
''));
|
||||||
|
|
||||||
|
virtualisation.qemu.options = forEach interfacesNumbered
|
||||||
|
({ fst, snd }: qemuNICFlags snd fst m.snd);
|
||||||
|
};
|
||||||
|
})
|
||||||
|
(getAttr m.fst nodes)
|
||||||
|
]);
|
||||||
|
|
||||||
|
in listToAttrs nodes_;
|
||||||
|
|
||||||
|
}
|
32
tests/lib/qemu-flags.nix
Normal file
32
tests/lib/qemu-flags.nix
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
# QEMU flags shared between various Nix expressions.
|
||||||
|
{ pkgs }:
|
||||||
|
|
||||||
|
let
|
||||||
|
zeroPad = n:
|
||||||
|
pkgs.lib.optionalString (n < 16) "0" +
|
||||||
|
(if n > 255
|
||||||
|
then throw "Can't have more than 255 nets or nodes!"
|
||||||
|
else pkgs.lib.toHexString n);
|
||||||
|
in
|
||||||
|
|
||||||
|
rec {
|
||||||
|
qemuNicMac = net: machine: "52:54:00:12:${zeroPad net}:${zeroPad machine}";
|
||||||
|
|
||||||
|
qemuNICFlags = nic: net: machine:
|
||||||
|
[ "-device virtio-net-pci,netdev=vlan${toString nic},mac=${qemuNicMac net machine}"
|
||||||
|
"-netdev vde,id=vlan${toString nic},sock=$QEMU_VDE_SOCKET_${toString net}"
|
||||||
|
];
|
||||||
|
|
||||||
|
qemuSerialDevice = if pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64 then "ttyS0"
|
||||||
|
else if pkgs.stdenv.isAarch32 || pkgs.stdenv.isAarch64 then "ttyAMA0"
|
||||||
|
else throw "Unknown QEMU serial device for system '${pkgs.stdenv.hostPlatform.system}'";
|
||||||
|
|
||||||
|
qemuBinary = qemuPkg: {
|
||||||
|
x86_64-linux = "${qemuPkg}/bin/qemu-kvm -cpu max";
|
||||||
|
armv7l-linux = "${qemuPkg}/bin/qemu-system-arm -enable-kvm -machine virt -cpu host";
|
||||||
|
aarch64-linux = "${qemuPkg}/bin/qemu-system-aarch64 -enable-kvm -machine virt,gic-version=host -cpu host";
|
||||||
|
x86_64-darwin = "${qemuPkg}/bin/qemu-kvm -cpu max";
|
||||||
|
aarch64-genode = "${qemuPkg}/bin/qemu-system-aarch64 -M virt,virtualization=true,gic_version=3 -cpu cortex-a53";
|
||||||
|
x86_64-genode = "${qemuPkg}/bin/qemu-system-x86_64 -machine q35";
|
||||||
|
}.${pkgs.stdenv.hostPlatform.system} or "${qemuPkg}/bin/qemu-kvm";
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
let Test = ./test.dhall ? env:DHALL_GENODE_TEST
|
let Genode =
|
||||||
|
env:DHALL_GENODE
|
||||||
let Genode = Test.Genode
|
? https://git.sr.ht/~ehmry/dhall-genode/blob/master/package.dhall
|
||||||
|
|
||||||
let Child = Genode.Init.Child
|
let Child = Genode.Init.Child
|
||||||
|
|
||||||
in Test::{
|
in Genode.Init::{
|
||||||
, children = toMap
|
, children = toMap
|
||||||
{ test-log =
|
{ test-log =
|
||||||
Child.flat
|
Child.flat
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
{ pkgs, ... }:
|
|
||||||
with pkgs;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
name = "log";
|
name = "log";
|
||||||
machine = {
|
machine = { config, pkgs, ... }: {
|
||||||
|
imports = [
|
||||||
|
../nixos-modules/genode-init.nix
|
||||||
|
];
|
||||||
|
genode.init = {
|
||||||
config = ./log.dhall;
|
config = ./log.dhall;
|
||||||
inputs = [ (pkgs.genodeSources.depot "test-log") ];
|
inputs = [ (pkgs.genodeSources.depot "test-log") ];
|
||||||
};
|
};
|
||||||
|
};
|
||||||
testScript = ''
|
testScript = ''
|
||||||
start_all()
|
start_all()
|
||||||
machine.wait_until_serial_output("Test done.")
|
machine.wait_until_serial_output("Test done.")
|
||||||
|
|
Loading…
Reference in New Issue
Block a user