librepcb: 1.1.0 -> 1.2.0
[NixPkgs.git] / nixos / lib / testing / network.nix
blob8e6d383e6257f1baa9fd56355f9def9b02c0bd94
1 { lib, nodes, ... }:
3 let
4   inherit (lib)
5     attrNames concatMap concatMapStrings flip forEach head
6     listToAttrs mkDefault mkOption nameValuePair optionalString
7     range toLower types zipListsWith zipLists
8     ;
10   nodeNumbers =
11     listToAttrs
12       (zipListsWith
13         nameValuePair
14         (attrNames nodes)
15         (range 1 254)
16       );
18   networkModule = { config, nodes, pkgs, ... }:
19     let
20       qemu-common = import ../qemu-common.nix { inherit lib pkgs; };
22       # Convert legacy VLANs to named interfaces and merge with explicit interfaces.
23       vlansNumbered = forEach (zipLists config.virtualisation.vlans (range 1 255)) (v: {
24         name = "eth${toString v.snd}";
25         vlan = v.fst;
26         assignIP = true;
27       });
28       explicitInterfaces = lib.mapAttrsToList (n: v: v // { name = n; }) config.virtualisation.interfaces;
29       interfaces = vlansNumbered ++ explicitInterfaces;
30       interfacesNumbered = zipLists interfaces (range 1 255);
32       # Automatically assign IP addresses to requested interfaces.
33       assignIPs = lib.filter (i: i.assignIP) interfaces;
34       ipInterfaces = forEach assignIPs (i:
35         nameValuePair i.name {
36           ipv4.addresses = [
37             {
38               address = "192.168.${toString i.vlan}.${toString config.virtualisation.test.nodeNumber}";
39               prefixLength = 24;
40             }
41           ];
42           ipv6.addresses = [
43             {
44               address = "2001:db8:${toString i.vlan}::${toString config.virtualisation.test.nodeNumber}";
45               prefixLength = 64;
46             }
47           ];
48         });
50       qemuOptions = lib.flatten (forEach interfacesNumbered ({ fst, snd }:
51         qemu-common.qemuNICFlags snd fst.vlan config.virtualisation.test.nodeNumber));
52       udevRules = forEach interfacesNumbered ({ fst, snd }:
53         # MAC Addresses for QEMU network devices are lowercase, and udev string comparison is case-sensitive.
54         ''SUBSYSTEM=="net",ACTION=="add",ATTR{address}=="${toLower(qemu-common.qemuNicMac fst.vlan config.virtualisation.test.nodeNumber)}",NAME="${fst.name}"'');
56       networkConfig =
57         {
58           networking.hostName = mkDefault config.virtualisation.test.nodeName;
60           networking.interfaces = listToAttrs ipInterfaces;
62           networking.primaryIPAddress =
63             optionalString (ipInterfaces != [ ]) (head (head ipInterfaces).value.ipv4.addresses).address;
65           networking.primaryIPv6Address =
66             optionalString (ipInterfaces != [ ]) (head (head ipInterfaces).value.ipv6.addresses).address;
68           # Put the IP addresses of all VMs in this machine's
69           # /etc/hosts file.  If a machine has multiple
70           # interfaces, use the IP address corresponding to
71           # the first interface (i.e. the first network in its
72           # virtualisation.vlans option).
73           networking.extraHosts = flip concatMapStrings (attrNames nodes)
74             (m':
75               let
76                 config = nodes.${m'};
77                 hostnames =
78                   optionalString (config.networking.domain != null) "${config.networking.hostName}.${config.networking.domain} " +
79                   "${config.networking.hostName}\n";
80               in
81               optionalString (config.networking.primaryIPAddress != "")
82                 "${config.networking.primaryIPAddress} ${hostnames}" +
83               optionalString (config.networking.primaryIPv6Address != "")
84                 ("${config.networking.primaryIPv6Address} ${hostnames}"));
86           virtualisation.qemu.options = qemuOptions;
87           boot.initrd.services.udev.rules = concatMapStrings (x: x + "\n") udevRules;
88         };
90     in
91     {
92       key = "network-interfaces";
93       config = networkConfig // {
94         # Expose the networkConfig items for tests like nixops
95         # that need to recreate the network config.
96         system.build.networkConfig = networkConfig;
97       };
98     };
100   nodeNumberModule = (regular@{ config, name, ... }: {
101     options = {
102       virtualisation.test.nodeName = mkOption {
103         internal = true;
104         default = name;
105         # We need to force this in specilisations, otherwise it'd be
106         # readOnly = true;
107         description = ''
108           The `name` in `nodes.<name>`; stable across `specialisations`.
109         '';
110       };
111       virtualisation.test.nodeNumber = mkOption {
112         internal = true;
113         type = types.int;
114         readOnly = true;
115         default = nodeNumbers.${config.virtualisation.test.nodeName};
116         description = ''
117           A unique number assigned for each node in `nodes`.
118         '';
119       };
121       # specialisations override the `name` module argument,
122       # so we push the real `virtualisation.test.nodeName`.
123       specialisation = mkOption {
124         type = types.attrsOf (types.submodule {
125           options.configuration = mkOption {
126             type = types.submoduleWith {
127               modules = [
128                 {
129                   config.virtualisation.test.nodeName =
130                     # assert regular.config.virtualisation.test.nodeName != "configuration";
131                     regular.config.virtualisation.test.nodeName;
132                 }
133               ];
134             };
135           };
136         });
137       };
138     };
139   });
143   config = {
144     extraBaseModules = { imports = [ networkModule nodeNumberModule ]; };
145   };