1{ system
2, # Use a minimal kernel?
3 minimal ? false
4, # Ignored
5 config ? null
6, # Nixpkgs, for qemu, lib and more
7 pkgs, lib
8, # !!! See comment about args in lib/modules.nix
9 specialArgs ? {}
10, # NixOS configuration to add to the VMs
11 extraConfigurations ? []
12}:
13
14with lib;
15
16rec {
17
18 inherit pkgs;
19
20 # Build a virtual network from an attribute set `{ machine1 =
21 # config1; ... machineN = configN; }', where `machineX' is the
22 # hostname and `configX' is a NixOS system configuration. Each
23 # machine is given an arbitrary IP address in the virtual network.
24 buildVirtualNetwork =
25 nodes: let nodesOut = mapAttrs (n: buildVM nodesOut) (assignIPAddresses nodes); in nodesOut;
26
27
28 buildVM =
29 nodes: configurations:
30
31 import ./eval-config.nix {
32 inherit system specialArgs;
33 modules = configurations ++ extraConfigurations;
34 baseModules = (import ../modules/module-list.nix) ++
35 [ ../modules/virtualisation/qemu-vm.nix
36 ../modules/testing/test-instrumentation.nix # !!! should only get added for automated test runs
37 { key = "no-manual"; documentation.nixos.enable = false; }
38 { key = "no-revision";
39 # Make the revision metadata constant, in order to avoid needless retesting.
40 # The human version (e.g. 21.05-pre) is left as is, because it is useful
41 # for external modules that test with e.g. nixosTest and rely on that
42 # version number.
43 config.system.nixos.revision = mkForce "constant-nixos-revision";
44 }
45 { key = "nodes"; _module.args.nodes = nodes; }
46 ] ++ optional minimal ../modules/testing/minimal-kernel.nix;
47 };
48
49
50 # Given an attribute set { machine1 = config1; ... machineN =
51 # configN; }, sequentially assign IP addresses in the 192.168.1.0/24
52 # range to each machine, and set the hostname to the attribute name.
53 assignIPAddresses = nodes:
54
55 let
56
57 machines = attrNames nodes;
58
59 machinesNumbered = zipLists machines (range 1 254);
60
61 nodes_ = forEach machinesNumbered (m: nameValuePair m.fst
62 [ ( { config, nodes, ... }:
63 let
64 interfacesNumbered = zipLists config.virtualisation.vlans (range 1 255);
65 interfaces = forEach interfacesNumbered ({ fst, snd }:
66 nameValuePair "eth${toString snd}" { ipv4.addresses =
67 [ { address = "192.168.${toString fst}.${toString m.snd}";
68 prefixLength = 24;
69 } ];
70 });
71
72 networkConfig =
73 { networking.hostName = mkDefault m.fst;
74
75 networking.interfaces = listToAttrs interfaces;
76
77 networking.primaryIPAddress =
78 optionalString (interfaces != []) (head (head interfaces).value.ipv4.addresses).address;
79
80 # Put the IP addresses of all VMs in this machine's
81 # /etc/hosts file. If a machine has multiple
82 # interfaces, use the IP address corresponding to
83 # the first interface (i.e. the first network in its
84 # virtualisation.vlans option).
85 networking.extraHosts = flip concatMapStrings machines
86 (m': let config = (getAttr m' nodes).config; in
87 optionalString (config.networking.primaryIPAddress != "")
88 ("${config.networking.primaryIPAddress} " +
89 optionalString (config.networking.domain != null)
90 "${config.networking.hostName}.${config.networking.domain} " +
91 "${config.networking.hostName}\n"));
92
93 virtualisation.qemu.options =
94 let qemu-common = import ../lib/qemu-common.nix { inherit lib pkgs; };
95 in flip concatMap interfacesNumbered
96 ({ fst, snd }: qemu-common.qemuNICFlags snd fst m.snd);
97 };
98
99 in
100 { key = "ip-address";
101 config = networkConfig // {
102 # Expose the networkConfig items for tests like nixops
103 # that need to recreate the network config.
104 system.build.networkConfig = networkConfig;
105 };
106 }
107 )
108 (getAttr m.fst nodes)
109 ] );
110
111 in listToAttrs nodes_;
112
113}