{ lib, entities, ... }: with lib; let getHostSite = hostname: let site-name = entities.hosts."${hostname}".site; in entities.sites."${site-name}"; getHostDomain = hostname: let domain-name = entities.hosts."${hostname}".domain; in entities.domains."${domain-name}"; getHostRealm = hostname: (getHostDomain hostname).gssapi-realm; getHostFqdn = hostname: let hostDomain = entities.hosts."${hostname}".domain; in "${hostname}.${hostDomain}"; getHostNetworkSettings = hostname: let hostDomain = entities.hosts."${hostname}".domain; hostNetwork = entities.zones."${hostDomain}"; in hostNetwork.hosts."${hostname}"; getIfAttr = as: a: if hasAttr as a then getAttr as a else null; getHostIpv4 = hostname: getIfAttr "ipv4-address" (getHostNetworkSettings hostname); getHostIpv6 = hostname: getIfAttr "ipv6-address" (getHostNetworkSettings hostname); getHostIps = hostname: filter (o: o != null) [ (getHostIpv4 hostname) (getHostIpv6 hostname) ]; getDomainPostgresqlServer = domain: getHostFqdn entities.domains."${domain}".postgresql-server; getSiteHosts = site: attrNames (filterAttrs (_: hostOpts: hostOpts.site == site) entities.hosts); getDomainHosts = domain: attrNames (filterAttrs (_: hostOpts: hostOpts.domain == domain) entities.hosts); getSiteGatewayV4 = siteName: let site = entities.sites."${siteName}"; in if hasAttr "local-gateway" site then getHostIpv4 site.local-gateway else site.gateway-v4; getHostGatewayV4 = hostname: getSiteGatewayV4 entities.hosts."${hostname}".site; getSiteGatewayV6 = siteName: let site = entities.sites."${siteName}"; in if hasAttr "local-gateway" site then getHostIpv6 site.local-gateway else site.gateway-v6; getHostGatewayV6 = hostname: getSiteGatewayV6 entities.hosts."${hostname}".site; getSiteNetwork = siteName: entities.sites."${siteName}".network; getSiteV4PrefixLength = siteName: toInt (elemAt (splitString "/" (getSiteNetwork siteName))); getSiteV6PrefixLength = siteName: abort "not implemented: getSiteV6PrefixLength"; in { inherit getHostSite getHostDomain getHostRealm getHostFqdn getHostIpv4 getHostIpv6 getHostIps getDomainPostgresqlServer getSiteHosts getDomainHosts getSiteGatewayV4 getHostGatewayV4 getSiteGatewayV6 getHostGatewayV6 getSiteV4PrefixLength getSiteV6PrefixLength; fudo-types = with lib.types; { networkHost.options = { hostname = mkOption { type = str; description = "Hostname"; }; ipv4-address = mkOption { type = nullOr str; description = "The V4 IP of a given host, if any."; default = null; }; ipv6-address = mkOption { type = nullOr str; description = "The V6 IP of a given host, if any."; default = null; }; mac-address = mkOption { type = nullOr str; description = "The MAC address of a given host, if desired for IP reservation."; default = null; }; description = mkOption { type = nullOr str; description = "Description of the host."; default = null; }; sshfp-records = mkOption { type = listOf str; description = "List of SSHFP records for this host."; default = [ ]; }; }; networkHosts = let # This is necessary because of the default 'name'...sigh. networkHostOpt = { name, ... }: { options = { hostname = mkOption { type = str; description = "Hostname"; default = name; }; ipv4-address = mkOption { type = nullOr str; description = "The V4 IP of a given host, if any."; default = null; }; ipv6-address = mkOption { type = nullOr str; description = "The V6 IP of a given host, if any."; default = null; }; mac-address = mkOption { type = nullOr str; description = "The MAC address of a given host, if desired for IP reservation."; default = null; }; description = mkOption { type = nullOr str; description = "Description of the host."; default = null; }; sshfp-records = mkOption { type = listOf str; description = "List of SSHFP records for this host."; default = [ ]; }; }; }; in attrsOf (submodule networkHostOpt); }; }