{ config, lib, pkgs, ... }: with lib; let mapOptional = f: val: if (val != null) then (f val) else null; host = import ../types/host.nix { inherit lib; }; in { options.fudo.hosts = with types; mkOption { type = attrsOf (submodule host.hostOpts); description = "Host configurations for all hosts known to the system."; default = { }; }; config = let hostname = config.instance.hostname; host-cfg = config.fudo.hosts.${hostname}; site-name = host-cfg.site; site = config.fudo.sites.${site-name}; domain-name = host-cfg.domain; domain = config.fudo.domains.${domain-name}; has-build-servers = (length (attrNames site.build-servers)) > 0; has-build-keys = (length host-cfg.build-pubkeys) > 0; in { networking = { hostName = config.instance.hostname; domain = domain-name; nameservers = site.nameservers; # This will cause a loop on the gateway itself #defaultGateway = site.gateway-v4; #defaultGateway6 = site.gateway-v6; firewall = { enable = (length host-cfg.external-interfaces) > 0; allowedTCPPorts = [ 22 ]; }; hostId = mkIf (host-cfg.machine-id != null) (substring 0 8 host-cfg.machine-id); }; # NixOS generates a stupid hosts file, just force it environment.etc = { hosts = let host-entries = mapAttrsToList (ip: hostnames: "${ip} ${concatStringsSep " " hostnames}") config.fudo.system.hostfile-entries; in mkForce { text = '' 127.0.0.1 ${hostname}.${domain-name} ${hostname} localhost 127.0.0.2 ${hostname} localhost ::1 ${hostname}.${domain-name} ${hostname} localhost ${concatStringsSep "\n" host-entries} ''; user = "root"; group = "root"; mode = "0444"; }; machine-id = mkIf (host-cfg.machine-id != null) { text = host-cfg.machine-id; user = "root"; group = "root"; mode = "0444"; }; current-system-packages.text = with builtins; let packages = map (p: "${p.name}") config.environment.systemPackages; sorted-unique = sort lessThan (unique packages); in concatStringsSep "\n" sorted-unique; }; # fudo.hosts.${hostname}.build-pubkeys = # map builtins.readFile # (map (build-key-path: "${build-key-path}/${hostname}.key.pub") # (optional (site.build-key-path != null) site.build-key-path)); # nix = mkIf # (has-build-servers && has-build-keys && site.enable-distributed-builds) { # buildMachines = mapAttrsToList (hostname: buildOpts: { # hostName = "${hostname}.${domain-name}"; # maxJobs = buildOpts.max-jobs; # speedFactor = buildOpts.speed-factor; # supportedFeatures = buildOpts.supported-features; # sshKey = config.fudo.secrets.host-secrets.${hostname}.build-private-key.target-file; # }) site.build-servers; # distributedBuilds = true; # }; time.timeZone = site.timezone; krb5.libdefaults.default_realm = domain.gssapi-realm; services.cron.mailto = domain.admin-email; environment.systemPackages = with pkgs; mkIf (host-cfg.docker-server) [ docker nix-prefetch-docker ]; virtualisation.docker = mkIf (host-cfg.docker-server) { enable = true; enableOnBoot = true; autoPrune.enable = true; }; fudo = let try-attr = attr: set: if (hasAttr attr set) then set.${attr} else null; files = config.fudo.secrets.files; keytab-file = try-attr hostname files.host-keytabs; build-private-key-file = mapOptional (keypair: keypair.private-key) (try-attr hostname files.build-keypairs); backplane-passwd-source = try-attr hostname files.backplane-passwords; backplane-passwd-target = "/var/run/backplane/passwd"; in { secrets.host-secrets.${hostname} = { host-keytab = mkIf (keytab-file != null) { source-file = keytab-file; target-file = "/etc/krb5.keytab"; user = "root"; }; build-private-key = mkIf (build-private-key-file != null) { source-file = build-private-key-file; target-file = "/var/run/nix-build/host.key"; user = "root"; }; backplane-passwd = mkIf (backplane-passwd-source != null) { source-file = backplane-passwd-source; target-file = backplane-passwd-target; user = config.fudo.client.dns.user; }; }; client.dns.password-file = mkIf (backplane-passwd-source != null) backplane-passwd-target; }; programs.adb.enable = host-cfg.android-dev; users.groups.adbusers = mkIf host-cfg.android-dev { members = config.instance.local-admins; }; boot.tmpOnTmpfs = host-cfg.tmp-on-tmpfs; # programs.ssh.knownHosts = let # keyed-hosts = # filterAttrs (host: opts: opts.ssh-pubkeys != []) config.fudo.hosts; # crossProduct = f: list0: list1: # concatMap (el0: map (el1: f el0 el1) list1) list0; # getHostnames = hostOpts: # [ hostOpts.hostname ] # ++ (crossProduct (host: domain: "${host}.${domain}") # ([ hostOpts.hostname ] ++ hostOpts.aliases) # ([ hostOpts.domain ] ++ hostOpts.extra-domains)); # getHostEntryPairs = host: # map (hostname: nameValuePair hostname { publicKey = host.ssh-pubkey; }) # (getHostnames host); # hostAttrsToList = hostAttrs: # mapAttrsToList (hostname: opts: { hostname = hostname; } // opts) # hostAttrs; # getKnownHosts = hosts: # concatMap getHostEntryPairs (hostAttrsToList hosts); # in listToAttrs (getKnownHosts keyed-hosts); }; }