{ lib, config, pkgs, self, ... }: let inherit (lib) filterAttrs mkEnableOption mkIf mapAttrsToList attrNames map concatLines mkOption types ; cfg = config.our.buildMachines; others = filterAttrs (n: _v: n != config.networking.hostName) self.nixosConfigurations; max = a: b: if a > b then a else b; mkBuilder = hostName: attrs: let config' = attrs.config; cfg' = config'.our.buildMachines; pkgs' = attrs.pkgs; in mkIf cfg'.enable { hostName = hostName; sshUser = "remotebuild"; # CPU architecture of the builder, and the operating system it runs. # If your builder supports multiple architectures # (e.g. search for "binfmt" for emulation), systems = [pkgs'.system] ++ config'.boot.binfmt.emulatedSystems; # Nix custom ssh-variant that avoids lots of "trusted-users" settings pain protocol = "ssh-ng"; # default is 1 but may keep the builder idle in between builds maxJobs = 3; speedFactor = max (cfg'.speedFactor - cfg.speedFactor + 1) 1; supportedFeatures = cfg'.supportedFeatures; mandatoryFeatures = []; }; buildMachines = mapAttrsToList mkBuilder others; remotebuildKeys = mapAttrsToList ( _name: attrs: attrs.config.clan.core.vars.generators.remotebuild.files."ssh.id_ed25519.pub".value ) others; mkMatch = host: '' Match User remotebuild Host ${host} IdentityFile ${config.clan.core.vars.generators.remotebuild.files."ssh.id_ed25519".path} ''; othersName = attrNames others; sshConfig = concatLines (map mkMatch othersName); in { options.our.buildMachines = { enable = mkEnableOption "Use this machine as a remoteBuilder for others and vice versa."; supportedFeatures = mkOption { type = types.listOf ( types.oneOf [ "nixos-test" "benchmark" "big-parallel" "kvm" ] ); default = []; description = '' kvm | Everything which builds inside a vm, like NixOS tests nixos-test | Machine can run NixOS tests big-parallel | kernel config, libreoffice, evolution, llvm and chromium benchmark | Machine can generate metrics (means the builds usually takes the same amount of time) ''; }; speedFactor = mkOption { type = types.int; default = 1; description = "How fast is the builder compared to your local machine"; }; }; config = mkIf cfg.enable { users.users.remotebuild = { isNormalUser = true; createHome = false; group = "remotebuild"; openssh.authorizedKeys.keys = remotebuildKeys; }; users.groups.remotebuild = {}; clan.core.vars.generators.remotebuild = { files."ssh.id_ed25519" = {}; files."ssh.id_ed25519.pub".secret = false; runtimeInputs = [ pkgs.coreutils pkgs.openssh ]; script = '' ssh-keygen -t ed25519 -N "" -f "$out"/ssh.id_ed25519 ''; }; programs.ssh.extraConfig = sshConfig; nix = { buildMachines = buildMachines; # required, otherwise remote buildMachines above aren't used distributedBuilds = true; # optional, useful when the builder has a faster internet connection than yours settings = { builders-use-substitutes = true; trusted-users = ["remotebuild"]; }; }; }; }