at 23.11-pre 3.9 kB view raw
1{ lib, nodes, ... }: 2 3let 4 inherit (lib) 5 attrNames concatMap concatMapStrings flip forEach head 6 listToAttrs mkDefault mkOption nameValuePair optionalString 7 range types zipListsWith zipLists 8 mdDoc 9 ; 10 11 nodeNumbers = 12 listToAttrs 13 (zipListsWith 14 nameValuePair 15 (attrNames nodes) 16 (range 1 254) 17 ); 18 19 networkModule = { config, nodes, pkgs, ... }: 20 let 21 interfacesNumbered = zipLists config.virtualisation.vlans (range 1 255); 22 interfaces = forEach interfacesNumbered ({ fst, snd }: 23 nameValuePair "eth${toString snd}" { 24 ipv4.addresses = 25 [{ 26 address = "192.168.${toString fst}.${toString config.virtualisation.test.nodeNumber}"; 27 prefixLength = 24; 28 }]; 29 }); 30 31 networkConfig = 32 { 33 networking.hostName = mkDefault config.virtualisation.test.nodeName; 34 35 networking.interfaces = listToAttrs interfaces; 36 37 networking.primaryIPAddress = 38 optionalString (interfaces != [ ]) (head (head interfaces).value.ipv4.addresses).address; 39 40 # Put the IP addresses of all VMs in this machine's 41 # /etc/hosts file. If a machine has multiple 42 # interfaces, use the IP address corresponding to 43 # the first interface (i.e. the first network in its 44 # virtualisation.vlans option). 45 networking.extraHosts = flip concatMapStrings (attrNames nodes) 46 (m': 47 let config = nodes.${m'}; in 48 optionalString (config.networking.primaryIPAddress != "") 49 ("${config.networking.primaryIPAddress} " + 50 optionalString (config.networking.domain != null) 51 "${config.networking.hostName}.${config.networking.domain} " + 52 "${config.networking.hostName}\n")); 53 54 virtualisation.qemu.options = 55 let qemu-common = import ../qemu-common.nix { inherit lib pkgs; }; 56 in 57 flip concatMap interfacesNumbered 58 ({ fst, snd }: qemu-common.qemuNICFlags snd fst config.virtualisation.test.nodeNumber); 59 }; 60 61 in 62 { 63 key = "ip-address"; 64 config = networkConfig // { 65 # Expose the networkConfig items for tests like nixops 66 # that need to recreate the network config. 67 system.build.networkConfig = networkConfig; 68 }; 69 }; 70 71 nodeNumberModule = (regular@{ config, name, ... }: { 72 options = { 73 virtualisation.test.nodeName = mkOption { 74 internal = true; 75 default = name; 76 # We need to force this in specilisations, otherwise it'd be 77 # readOnly = true; 78 description = mdDoc '' 79 The `name` in `nodes.<name>`; stable across `specialisations`. 80 ''; 81 }; 82 virtualisation.test.nodeNumber = mkOption { 83 internal = true; 84 type = types.int; 85 readOnly = true; 86 default = nodeNumbers.${config.virtualisation.test.nodeName}; 87 description = mdDoc '' 88 A unique number assigned for each node in `nodes`. 89 ''; 90 }; 91 92 # specialisations override the `name` module argument, 93 # so we push the real `virtualisation.test.nodeName`. 94 specialisation = mkOption { 95 type = types.attrsOf (types.submodule { 96 options.configuration = mkOption { 97 type = types.submoduleWith { 98 modules = [ 99 { 100 config.virtualisation.test.nodeName = 101 # assert regular.config.virtualisation.test.nodeName != "configuration"; 102 regular.config.virtualisation.test.nodeName; 103 } 104 ]; 105 }; 106 }; 107 }); 108 }; 109 }; 110 }); 111 112in 113{ 114 config = { 115 extraBaseModules = { imports = [ networkModule nodeNumberModule ]; }; 116 }; 117}