about summary refs log tree commit diff
path: root/nixos/lib/testing/network.nix
blob: 04ea9a2bc9f7ac7b38832f63c9abd51448b15e7d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
{ lib, nodes, ... }:

let
  inherit (lib)
    attrNames concatMap concatMapStrings flip forEach head
    listToAttrs mkDefault mkOption nameValuePair optionalString
    range types zipListsWith zipLists
    mdDoc
    ;

  nodeNumbers =
    listToAttrs
      (zipListsWith
        nameValuePair
        (attrNames nodes)
        (range 1 254)
      );

  networkModule = { config, nodes, pkgs, ... }:
    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 config.virtualisation.test.nodeNumber}";
              prefixLength = 24;
            }];
        });

      networkConfig =
        {
          networking.hostName = mkDefault config.virtualisation.test.nodeName;

          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 (attrNames nodes)
            (m':
              let config = nodes.${m'}; in
              optionalString (config.networking.primaryIPAddress != "")
                ("${config.networking.primaryIPAddress} " +
                  optionalString (config.networking.domain != null)
                    "${config.networking.hostName}.${config.networking.domain} " +
                  "${config.networking.hostName}\n"));

          virtualisation.qemu.options =
            let qemu-common = import ../qemu-common.nix { inherit lib pkgs; };
            in
            flip concatMap interfacesNumbered
              ({ fst, snd }: qemu-common.qemuNICFlags snd fst config.virtualisation.test.nodeNumber);
        };

    in
    {
      key = "ip-address";
      config = networkConfig // {
        # Expose the networkConfig items for tests like nixops
        # that need to recreate the network config.
        system.build.networkConfig = networkConfig;
      };
    };

  nodeNumberModule = (regular@{ config, name, ... }: {
    options = {
      virtualisation.test.nodeName = mkOption {
        internal = true;
        default = name;
        # We need to force this in specilisations, otherwise it'd be
        # readOnly = true;
        description = mdDoc ''
          The `name` in `nodes.<name>`; stable across `specialisations`.
        '';
      };
      virtualisation.test.nodeNumber = mkOption {
        internal = true;
        type = types.int;
        readOnly = true;
        default = nodeNumbers.${config.virtualisation.test.nodeName};
        description = mdDoc ''
          A unique number assigned for each node in `nodes`.
        '';
      };

      # specialisations override the `name` module argument,
      # so we push the real `virtualisation.test.nodeName`.
      specialisation = mkOption {
        type = types.attrsOf (types.submodule {
          options.configuration = mkOption {
            type = types.submoduleWith {
              modules = [
                {
                  config.virtualisation.test.nodeName =
                    # assert regular.config.virtualisation.test.nodeName != "configuration";
                    regular.config.virtualisation.test.nodeName;
                }
              ];
            };
          };
        });
      };
    };
  });

in
{
  config = {
    extraBaseModules = { imports = [ networkModule nodeNumberModule ]; };
  };
}