summaryrefslogtreecommitdiffstats
path: root/nixos/modules/config/lix-remote-build.nix
blob: 76f785617978b237d8deb78e36d4b152d4cbb90a (plain)
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
/*
  Manages the remote build configuration toml as designed by lix, /etc/nix/machines.toml

  See also
   - ./nix.nix
   - nixos/modules/services/system/nix-daemon.nix
*/
{
  config,
  lib,
  pkgs,
  ...
}:

let
  inherit (lib)
    any
    concatMapStrings
    concatStringsSep
    filter
    getVersion
    mkIf
    mkOption
    optional
    optionalString
    types
    versionAtLeast
    ;

  cfg = config.lix;

  format = pkgs.formats.toml { };
  configFile = format.generate "machines.toml" (
    lib.filterAttrsRecursive (_: v: v != null) cfg.buildMachines
  );

in
{
  meta.maintainers = with lib.maintainers; [ rootile ];
  options = {
    lix.buildMachines = lib.mkOption {
      default = { };
      description = ''
        Lix TOML configuration for remote builders
      '';
      type = types.submodule {
        options = {
          version = mkOption {
            type = types.int;
            default = 1;
            example = 2;
            description = ''
              version of the TOML format.
            '';
            internal = true;
          };
          machines = mkOption {
            type = types.attrsOf (
              types.submodule {
                freeformType = format.type;
                options = {
                  uri = mkOption {
                    type = types.str;
                    example = "ssh-ng://andesite@andesite.lix.systems";
                    description = ''
                      The URI of the remote store in the format
                      `ssh[-ng]://[username@]hostname[?port=<port>]`, e.g. `ssh://nix@mac` or `ssh://mac`.
                      If the ssh server is not listening on port 22 (e.g. port 1337 in this case)
                      the URI would be `ssh[-ng]://nix@mac?port=1337`. The hostname
                      may be an alias defined in your `~/.ssh/config`.
                    '';
                  };
                  system-types = mkOption {
                    type = types.nullOr (types.listOf types.str);
                    default = null;
                    example = [
                      "x86_64-linux"
                      "aarch64-linux"
                    ];
                    description = ''
                      A list of Nix platform type identifiers, such as
                      `x86_64-darwin`. It is possible for a machine to support multiple
                      platform types, e.g., `i686-linux` and `x86_64-linux`.

                    '';
                  };
                  ssh-key = mkOption {
                    type = types.nullOr types.path;
                    default = null;
                    example = "/root/.ssh/id_buildhost_builduser";
                    description = ''
                      The path to the SSH private key with which to authenticate on
                      the build machine. The private key must not have a passphrase.
                      If null, the building user (root on NixOS machines) must have an
                      appropriate ssh configuration to log in non-interactively.
                    '';
                  };
                  jobs = mkOption {
                    type = types.ints.u32;
                    default = 1;
                    description = ''
                      The maximum number of builds that Lix will execute in parallel on
                      the machine. Typically, this should be equal to the number of CPU
                      cores divided by the cores within the target machines configuration, i.e. `jobs * cores ~= cpu cores`
                    '';
                  };
                  speed-factor = mkOption {
                    type = types.numbers.positive;
                    default = 1;
                    description = ''
                      The “speed factor”, indicating the relative speed of the machine. If
                      there are multiple machines of the right type, Lix will prefer the
                      fastest, taking load into account.
                    '';
                  };
                  mandatory-features = mkOption {
                    type = types.nullOr (types.listOf types.str);
                    default = null;
                    example = [ "big-parallel" ];
                    description = ''
                      A list of *mandatory features*. A machine will only
                      be used to build a derivation if all the machine’s mandatory
                      features appear in the derivation’s `requiredSystemFeatures`
                      attribute.
                    '';
                  };
                  supported-features = mkOption {
                    type = types.nullOr (types.listOf types.str);
                    default = null;
                    example = [
                      "kvm"
                      "big-parallel"
                    ];
                    description = ''
                      A list of *supported features*. If a derivation has
                      the `requiredSystemFeatures` attribute, then Lix will only schedule
                      the derivation on a machine that has the specified features. For
                      example, the attribute

                      ```nix
                      requiredSystemFeatures = [ "kvm" ];
                      ```

                      will cause the build to be performed on a machine that has the `kvm`
                      feature.
                    '';
                  };
                  ssh-public-host-key = mkOption {
                    type = types.nullOr types.str;
                    default = null;
                    description = ''
                      The public host key of this builder.
                      If null, SSH will use its regular known-hosts file when connecting.
                    '';
                  };
                  enable = mkOption {
                    type = types.bool;
                    default = true;
                    description = ''
                      Whether to enable this machine statically.
                    '';
                  };
                };
              }
            );
            default = { };
            description = ''
              This option lists the machines to be used if distributed builds are
              enabled (see {option}`nix.distributedBuilds`).
              Nix will perform derivations on those machines via SSH by copying the
              inputs to the Nix store on the remote machine, starting the build,
              then copying the output back to the local Nix store.
            '';
          };
        };
        freeformType = format.type;
      };
    };
  };

  config = mkIf (config.nix.enable && cfg.buildMachines.machines != { }) {
    assertions =
      let
        badMachine = m: m.system-types == null || m.system-types == [ ];
      in
      [
        {
          assertion = !(any badMachine (builtins.attrValues cfg.buildMachines.machines));
          message = ''
            At least one system type (via `system-types`) must be set for every build machine.
              Invalid machine specifications:
          ''
          + "      "
          + (concatStringsSep "\n      " (
            builtins.attrNames (lib.filterAttrs (_: badMachine) cfg.buildMachines.machines)
          ));
        }
        {
          assertion = config.nix.package.pname == "lix";
          message = ''
            TOML configuration of remote builders is only supported in lix.
          '';
        }
        {
          assertion = lib.versionAtLeast config.nix.package.version "2.95";
          message = ''
            TOML configuration was introduced in lix 2.95.0. Current version is ${config.nix.package.version}
          '';
        }
        {
          assertion = config.nix.buildMachines == [ ];
          message = ''
            mix-matching between lix and nix build machines is not supported.
          '';
        }
      ];

    nix.settings.builders = "@${configFile}";
  };
}