mirror of
https://github.com/gensokyo-zone/infrastructure.git
synced 2026-02-09 12:29:19 -08:00
feat(exports): service access
This commit is contained in:
parent
91918b8061
commit
871b1c5b2d
69 changed files with 1317 additions and 509 deletions
20
modules/nixos/keycloak.nix
Normal file
20
modules/nixos/keycloak.nix
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{config, lib, ...}: let
|
||||
inherit (lib.options) mkOption;
|
||||
inherit (lib.modules) mkOptionDefault;
|
||||
cfg = config.services.keycloak;
|
||||
in {
|
||||
options.services.keycloak = with lib.types; {
|
||||
protocol = mkOption {
|
||||
type = enum [ "http" "https" ];
|
||||
readOnly = true;
|
||||
};
|
||||
port = mkOption {
|
||||
type = port;
|
||||
readOnly = true;
|
||||
};
|
||||
};
|
||||
config.services.keycloak = {
|
||||
protocol = mkOptionDefault (if cfg.sslCertificate != null then "https" else "http");
|
||||
port = mkOptionDefault cfg.settings."${cfg.protocol}-port";
|
||||
};
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
{config, lib, ...}: let
|
||||
inherit (lib.options) mkOption mkEnableOption;
|
||||
inherit (lib.modules) mkIf mkDefault mkOptionDefault;
|
||||
inherit (lib.modules) mkIf mkOptionDefault;
|
||||
inherit (lib.lists) filter optional;
|
||||
inherit (lib.strings) hasInfix concatStrings;
|
||||
inherit (config.services) resolved;
|
||||
|
|
|
|||
|
|
@ -4,12 +4,11 @@
|
|||
inputs,
|
||||
...
|
||||
}: let
|
||||
inherit (inputs.self.lib.lib) mkAlmostOptionDefault;
|
||||
inherit (inputs.self.lib.lib) mkAlmostOptionDefault mkAddress6;
|
||||
inherit (lib.options) mkOption mkEnableOption;
|
||||
inherit (lib.modules) mkIf mkMerge mkBefore mkOptionDefault mkForce;
|
||||
inherit (lib.attrsets) attrValues mapAttrs;
|
||||
inherit (lib.lists) optional filter concatMap;
|
||||
inherit (lib.strings) hasPrefix hasInfix;
|
||||
inherit (config.services) nginx;
|
||||
listenModule = { config, virtualHost, listenKind, ... }: {
|
||||
options = with lib.types; {
|
||||
|
|
@ -76,9 +75,8 @@
|
|||
listenConfigs = let
|
||||
# TODO: handle quic listener..?
|
||||
mkListenHost = { addr, port }: let
|
||||
addr' = if hasInfix ":" addr && !hasPrefix "[" addr then "[${addr}]" else addr;
|
||||
host =
|
||||
if addr != null then "${addr'}:${toString port}"
|
||||
if addr != null then "${mkAddress6 addr}:${toString port}"
|
||||
else toString port;
|
||||
in assert port != null; host;
|
||||
mkDirective = addr: let
|
||||
|
|
|
|||
|
|
@ -73,14 +73,14 @@
|
|||
cert = let
|
||||
mkCopyCert = copyCert: {
|
||||
name = mkDefault copyCert.name;
|
||||
keyPath = mkAlmostOptionDefault copyCert.keyPath;
|
||||
path = mkAlmostOptionDefault copyCert.path;
|
||||
keyPath = mkDefault copyCert.keyPath;
|
||||
path = mkDefault copyCert.path;
|
||||
};
|
||||
copyCertVhost = mkCopyCert nginx.virtualHosts.${cfg.cert.copyFromVhost}.ssl.cert;
|
||||
copyCertStreamServer = mkCopyCert nginx.stream.servers.${cfg.cert.copyFromStreamServer}.ssl.cert;
|
||||
in mkMerge [
|
||||
(mkIf (cfg.cert.copyFromVhost != null) copyCertVhost)
|
||||
(mkIf (cfg.cert.copyFromStreamServer != null) copyCertStreamServer)
|
||||
(mkIf (cfg.cert.copyFromVhost != null) copyCertVhost)
|
||||
];
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
gensokyo-zone,
|
||||
...
|
||||
}: let
|
||||
inherit (gensokyo-zone.lib) mkAddress6;
|
||||
inherit (lib.options) mkOption mkEnableOption;
|
||||
inherit (lib.modules) mkIf mkMerge mkBefore mkOptionDefault;
|
||||
inherit (lib.attrsets) mapAttrsToList;
|
||||
inherit (lib.lists) optional;
|
||||
inherit (lib.strings) hasPrefix hasInfix;
|
||||
cfg = config.services.nginx.stream;
|
||||
upstreamServerModule = {config, name, ...}: {
|
||||
options = with lib.types; {
|
||||
|
|
@ -45,9 +46,7 @@
|
|||
config = let
|
||||
settings = mapAttrsToList (key: value: "${key}=${toString value}") config.settings;
|
||||
in {
|
||||
server = let
|
||||
addr = if hasInfix ":" config.addr && ! hasPrefix "[" config.addr then "[${config.addr}]" else config.addr;
|
||||
in mkOptionDefault "${addr}:${toString config.port}";
|
||||
server = mkOptionDefault "${mkAddress6 config.addr}:${toString config.port}";
|
||||
serverConfig = mkMerge (
|
||||
[ (mkBefore config.server) ]
|
||||
++ settings
|
||||
|
|
@ -76,6 +75,9 @@
|
|||
servers = mkOption {
|
||||
type = attrsOf upstreamServer;
|
||||
};
|
||||
ssl = {
|
||||
enable = mkEnableOption "ssl upstream";
|
||||
};
|
||||
extraConfig = mkOption {
|
||||
type = lines;
|
||||
default = "";
|
||||
|
|
@ -119,11 +121,35 @@
|
|||
type = lines;
|
||||
internal = true;
|
||||
};
|
||||
proxy = {
|
||||
upstream = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
};
|
||||
url = mkOption {
|
||||
type = nullOr str;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
streamConfig = mkMerge [
|
||||
proxy = {
|
||||
url = mkOptionDefault (
|
||||
if config.proxy.upstream != null then cfg.upstreams.${config.proxy.upstream}.name
|
||||
else null
|
||||
);
|
||||
};
|
||||
streamConfig = let
|
||||
proxyUpstream = cfg.upstreams.${config.proxy.upstream};
|
||||
in mkMerge [
|
||||
config.extraConfig
|
||||
(mkIf (config.proxy.upstream != null && proxyUpstream.ssl.enable) ''
|
||||
proxy_ssl on;
|
||||
proxy_ssl_verify off;
|
||||
'')
|
||||
(mkIf (config.proxy.url != null) ''
|
||||
proxy_pass ${config.proxy.url};
|
||||
'')
|
||||
];
|
||||
serverBlock = mkOptionDefault ''
|
||||
server {
|
||||
|
|
|
|||
|
|
@ -8,10 +8,12 @@
|
|||
}: let
|
||||
inherit (inputs.self) nixosConfigurations;
|
||||
inherit (inputs.self.lib) systems;
|
||||
inherit (inputs.self.lib.lib) domain;
|
||||
inherit (inputs.self.lib.lib) domain mkAddress6;
|
||||
inherit (lib.options) mkOption mkEnableOption;
|
||||
inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault;
|
||||
inherit (lib.attrsets) mapAttrs;
|
||||
inherit (lib.attrsets) mapAttrs attrValues;
|
||||
inherit (lib.lists) findSingle;
|
||||
inherit (lib.trivial) mapNullable;
|
||||
cfg = config.access;
|
||||
systemConfig = config;
|
||||
systemAccess = access;
|
||||
|
|
@ -42,20 +44,29 @@
|
|||
config = {
|
||||
networking.access = {
|
||||
moduleArgAttrs = let
|
||||
mkGetAddressFor = addressForAttr: hostName: network: let
|
||||
mkGetAddressFor = nameAllowed: addressForAttr: hostName: network: let
|
||||
forSystem = access.systemFor hostName;
|
||||
err = throw "no lan interface found between ${config.networking.hostName} and ${hostName}";
|
||||
err = throw "no interface found between ${config.networking.hostName} -> ${hostName}@${network}";
|
||||
fallback = if nameAllowed
|
||||
then lib.warn "getAddressFor hostname fallback for ${config.networking.hostName} -> ${hostName}@${network}" (access.getHostnameFor hostName network)
|
||||
else err;
|
||||
local = forSystem.access.${addressForAttr}.local or forSystem.access.address4ForNetwork.local or fallback;
|
||||
int = forSystem.access.${addressForAttr}.int or forSystem.access.address4ForNetwork.int or fallback;
|
||||
tail = forSystem.access.${addressForAttr}.tail or fallback;
|
||||
in {
|
||||
lan =
|
||||
if has'Int then forSystem.access.${addressForAttr}.int or forSystem.access.${addressForAttr}.local or err
|
||||
else if has'Local then forSystem.access.${addressForAttr}.local or err
|
||||
else err;
|
||||
${if has'Local then "local" else null} = forSystem.access.${addressForAttr}.local or err;
|
||||
${if has'Int then "int" else null} = forSystem.access.${addressForAttr}.int or err;
|
||||
${if has'Tail then "tail" else null} = forSystem.access.${addressForAttr}.tail or err;
|
||||
}.${network} or err;
|
||||
if hostName == system.name then forSystem.access.${addressForAttr}.localhost
|
||||
else if has'Int then int
|
||||
else if has'Local then local
|
||||
else fallback;
|
||||
${if has'Local then "local" else null} = local;
|
||||
${if has'Int then "int" else null} = int;
|
||||
${if has'Tail then "tail" else null} = tail;
|
||||
}.${network} or fallback;
|
||||
in {
|
||||
inherit (systemAccess) hostnameForNetwork address4ForNetwork address6ForNetwork;
|
||||
inherit (systemAccess)
|
||||
hostnameForNetwork address4ForNetwork address6ForNetwork
|
||||
systemForService systemForServiceId;
|
||||
addressForNetwork = systemAccess.${addressForAttr};
|
||||
systemFor = hostName:
|
||||
if hostName == config.networking.hostName
|
||||
|
|
@ -73,21 +84,39 @@
|
|||
if hostName == config.networking.hostName
|
||||
then config
|
||||
else systemAccess.nixosForOrNull hostName;
|
||||
getAddressFor = mkGetAddressFor addressForAttr;
|
||||
getAddress4For = mkGetAddressFor "address4ForNetwork";
|
||||
getAddress6For = mkGetAddressFor "address6ForNetwork";
|
||||
getAddressFor = mkGetAddressFor true addressForAttr;
|
||||
getAddress4For = mkGetAddressFor false "address4ForNetwork";
|
||||
getAddress6For = mkGetAddressFor false "address6ForNetwork";
|
||||
getHostnameFor = hostName: network: let
|
||||
forSystem = access.systemFor hostName;
|
||||
err = throw "no ${network} interface found between ${config.networking.hostName} and ${hostName}";
|
||||
in {
|
||||
lan =
|
||||
if has'Int then forSystem.access.hostnameForNetwork.int or forSystem.access.hostnameForNetwork.local or err
|
||||
if hostName == system.name then forSystem.access.hostnameForNetwork.localhost
|
||||
else if has'Int then forSystem.access.hostnameForNetwork.int or forSystem.access.hostnameForNetwork.local or err
|
||||
else if has'Local then forSystem.access.hostnameForNetwork.local or err
|
||||
else err;
|
||||
${if has'Local then "local" else null} = forSystem.access.hostnameForNetwork.local or err;
|
||||
${if has'Int then "int" else null} = forSystem.access.hostnameForNetwork.int or err;
|
||||
${if has'Tail then "tail" else null} = forSystem.access.hostnameForNetwork.tail or err;
|
||||
}.${network} or err;
|
||||
proxyUrlFor = {
|
||||
system ? if serviceId != null then access.systemForServiceId serviceId else access.systemForService serviceName,
|
||||
serviceName ? mapNullable (serviceId: (findSingle (s: s.id == serviceId) null null (attrValues system.exports.services)).name) serviceId,
|
||||
serviceId ? null,
|
||||
service ? system.exports.services.${serviceName},
|
||||
portName ? "default",
|
||||
network ? "lan",
|
||||
scheme ? null,
|
||||
}: let
|
||||
port = service.ports.${portName};
|
||||
scheme' = if scheme == null then port.protocol else scheme;
|
||||
port' = if !port.enable
|
||||
then throw "${system.name}.exports.services.${service.name}.ports.${portName} isn't enabled"
|
||||
else ":${toString port.port}";
|
||||
host = access.getAddressFor system.name network;
|
||||
url = "${scheme'}://${mkAddress6 host}${port'}";
|
||||
in assert service.enable; url;
|
||||
};
|
||||
};
|
||||
networking.tempAddresses = mkIf cfg.global.enable (
|
||||
|
|
@ -110,7 +139,6 @@ in {
|
|||
type = str;
|
||||
default = domain;
|
||||
};
|
||||
tailscale.enable = mkEnableOption "tailscale access";
|
||||
global.enable = mkEnableOption "globally routeable";
|
||||
hostnameForNetwork = mkOption {
|
||||
type = attrsOf str;
|
||||
|
|
@ -143,6 +171,7 @@ in {
|
|||
hostnameForNetwork = mkMerge [
|
||||
(mapAttrs (_: mapNetworkFqdn) config.network.networks)
|
||||
{
|
||||
localhost = mkOptionDefault "localhost";
|
||||
lan = mkMerge [
|
||||
(mapNetwork' mkDefault "fqdn" int)
|
||||
(mapNetworkFqdn local)
|
||||
|
|
@ -153,6 +182,7 @@ in {
|
|||
address4ForNetwork = mkMerge [
|
||||
(mapAttrs (_: mapNetwork4) config.network.networks)
|
||||
{
|
||||
localhost = mkOptionDefault "127.0.0.1";
|
||||
lan = mkMerge [
|
||||
(mapNetwork' mkDefault "address4" int)
|
||||
(mapNetwork4 local)
|
||||
|
|
@ -162,6 +192,7 @@ in {
|
|||
address6ForNetwork = mkMerge [
|
||||
(mapAttrs (_: mapNetwork6) config.network.networks)
|
||||
{
|
||||
localhost = mkOptionDefault "::1";
|
||||
lan = mkMerge [
|
||||
(mapNetwork' mkDefault "address6" int)
|
||||
(mapNetwork6 local)
|
||||
|
|
@ -176,6 +207,16 @@ in {
|
|||
systemForOrNull = hostName: systems.${hostName}.config or null;
|
||||
nixosFor = hostName: nixosConfigurations.${hostName}.config or (access.systemFor hostName).built.config;
|
||||
nixosForOrNull = hostName: nixosConfigurations.${hostName}.config or (access.systemForOrNull hostName).built.config or null;
|
||||
systemForService = service: let
|
||||
hasService = system: system.config.exports.services.${service}.enable;
|
||||
notFound = throw "no system found serving ${service}";
|
||||
multiple = throw "multiple systems found serving ${service}";
|
||||
in (findSingle hasService notFound multiple (attrValues systems)).config;
|
||||
systemForServiceId = serviceId: let
|
||||
hasService = system: findSingle (service: service.id == serviceId && service.enable) null multiple (attrValues system.config.exports.services) != null;
|
||||
notFound = throw "no system found serving ${serviceId}";
|
||||
multiple = throw "multiple systems found serving ${serviceId}";
|
||||
in (findSingle hasService notFound multiple (attrValues systems)).config;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
22
modules/system/exports/dnsmasq.nix
Normal file
22
modules/system/exports/dnsmasq.nix
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{lib, gensokyo-zone, ...}: let
|
||||
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
|
||||
inherit (lib.attrsets) mapAttrs;
|
||||
in {
|
||||
config.exports.services.dnsmasq = { config, ... }: {
|
||||
id = mkAlmostOptionDefault "dns";
|
||||
nixos = {
|
||||
serviceAttr = "dnsmasq";
|
||||
};
|
||||
defaults.port.listen = mkAlmostOptionDefault "lan";
|
||||
ports = mapAttrs (_: mapAlmostOptionDefaults) {
|
||||
default = {
|
||||
port = 53;
|
||||
transport = "udp";
|
||||
};
|
||||
tcp = {
|
||||
port = config.ports.default.port;
|
||||
transport = "tcp";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
48
modules/system/exports/exports.nix
Normal file
48
modules/system/exports/exports.nix
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
{
|
||||
config,
|
||||
name,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib.options) mkOption mkEnableOption;
|
||||
cfg = config.exports;
|
||||
systemConfig = config;
|
||||
exportModule = {
|
||||
config,
|
||||
name,
|
||||
...
|
||||
}: {
|
||||
options = with lib.types; {
|
||||
enable = mkEnableOption "exported service";
|
||||
name = mkOption {
|
||||
type = str;
|
||||
default = name;
|
||||
};
|
||||
serviceName = mkOption {
|
||||
type = str;
|
||||
default = name;
|
||||
};
|
||||
id = mkOption {
|
||||
type = str;
|
||||
default = cfg.services.${config.serviceName}.id/* or config.name*/;
|
||||
};
|
||||
};
|
||||
};
|
||||
in {
|
||||
options.exports = with lib.types; {
|
||||
exports = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [exportModule];
|
||||
specialArgs = {
|
||||
machine = name;
|
||||
inherit systemConfig;
|
||||
};
|
||||
});
|
||||
default = {};
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
_module.args.exports = cfg;
|
||||
};
|
||||
}
|
||||
18
modules/system/exports/freeipa.nix
Normal file
18
modules/system/exports/freeipa.nix
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
{lib, gensokyo-zone, ...}: let
|
||||
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
|
||||
inherit (lib.attrsets) mapAttrs;
|
||||
in {
|
||||
config.exports.services.freeipa = {
|
||||
id = mkAlmostOptionDefault "freeipa";
|
||||
ports = mapAttrs (_: mapAlmostOptionDefaults) {
|
||||
default = {
|
||||
port = 443;
|
||||
protocol = "https";
|
||||
};
|
||||
redirect = {
|
||||
port = 80;
|
||||
protocol = "http";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
34
modules/system/exports/freepbx.nix
Normal file
34
modules/system/exports/freepbx.nix
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
{lib, gensokyo-zone, ...}: let
|
||||
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
|
||||
inherit (lib.attrsets) mapAttrs;
|
||||
in {
|
||||
config.exports.services.freepbx = {
|
||||
id = mkAlmostOptionDefault "pbx";
|
||||
ports = mapAttrs (_: mapAlmostOptionDefaults) {
|
||||
http = {
|
||||
port = 80;
|
||||
protocol = "http";
|
||||
};
|
||||
https = {
|
||||
port = 443;
|
||||
protocol = "https";
|
||||
};
|
||||
ucp = {
|
||||
port = 8001;
|
||||
protocol = "http";
|
||||
};
|
||||
ucp-ssl = {
|
||||
port = 8003;
|
||||
protocol = "https";
|
||||
};
|
||||
asterisk = {
|
||||
port = 8088;
|
||||
protocol = "http";
|
||||
};
|
||||
asterisk-ssl = {
|
||||
port = 8089;
|
||||
protocol = "https";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
45
modules/system/exports/home-assistant.nix
Normal file
45
modules/system/exports/home-assistant.nix
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
{lib, gensokyo-zone, ...}: let
|
||||
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
|
||||
inherit (lib.modules) mkIf;
|
||||
inherit (lib.attrsets) mapAttrs;
|
||||
inherit (lib.lists) all imap0;
|
||||
inherit (lib.trivial) id;
|
||||
in {
|
||||
config.exports.services.home-assistant = { config, ... }: let
|
||||
mkAssertion = f: nixosConfig: let
|
||||
cfg = nixosConfig.services.home-assistant;
|
||||
in f nixosConfig cfg;
|
||||
assertPort = nixosConfig: cfg: {
|
||||
assertion = config.ports.default.port == cfg.config.http.server_port;
|
||||
message = "port mismatch";
|
||||
};
|
||||
assertHomekitPort = let
|
||||
portName = i: "homekit${toString i}";
|
||||
mkAssertPort = i: homekit: config.ports.${portName i}.port or null == homekit.port;
|
||||
in nixosConfig: cfg: {
|
||||
assertion = all id (imap0 mkAssertPort cfg.config.homekit);
|
||||
message = "homekit port mismatch";
|
||||
};
|
||||
in {
|
||||
id = mkAlmostOptionDefault "home";
|
||||
nixos = {
|
||||
serviceAttr = "home-assistant";
|
||||
assertions = mkIf config.enable [
|
||||
(mkAssertion assertPort)
|
||||
(mkAssertion assertHomekitPort)
|
||||
];
|
||||
};
|
||||
defaults.port.listen = mkAlmostOptionDefault "lan";
|
||||
ports = mapAttrs (_: mapAlmostOptionDefaults) {
|
||||
default = {
|
||||
port = 8123;
|
||||
protocol = "http";
|
||||
};
|
||||
homekit0 = {
|
||||
port = 21063;
|
||||
transport = "tcp";
|
||||
};
|
||||
# TODO: cast udp port range 32768 to 60999
|
||||
};
|
||||
};
|
||||
}
|
||||
21
modules/system/exports/invidious.nix
Normal file
21
modules/system/exports/invidious.nix
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{lib, gensokyo-zone, ...}: let
|
||||
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
|
||||
inherit (lib.modules) mkIf;
|
||||
in {
|
||||
config.exports.services.invidious = { config, ... }: {
|
||||
id = mkAlmostOptionDefault "yt";
|
||||
nixos = {
|
||||
serviceAttr = "invidious";
|
||||
assertions = mkIf config.enable [
|
||||
(nixosConfig: {
|
||||
assertion = config.ports.default.port == nixosConfig.services.invidious.port;
|
||||
message = "port mismatch";
|
||||
})
|
||||
];
|
||||
};
|
||||
ports.default = mapAlmostOptionDefaults {
|
||||
port = 3000;
|
||||
protocol = "http";
|
||||
};
|
||||
};
|
||||
}
|
||||
35
modules/system/exports/kerberos.nix
Normal file
35
modules/system/exports/kerberos.nix
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
{lib, gensokyo-zone, ...}: let
|
||||
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults;
|
||||
inherit (lib.attrsets) mapAttrs;
|
||||
in {
|
||||
config.exports.services.kerberos = { config, ... }: {
|
||||
id = "krb5";
|
||||
ports = mapAttrs (_: mapAlmostOptionDefaults) {
|
||||
default = {
|
||||
port = 88;
|
||||
transport = "tcp";
|
||||
};
|
||||
udp = {
|
||||
port = config.ports.default.port;
|
||||
transport = "udp";
|
||||
};
|
||||
kadmin = {
|
||||
port = 749;
|
||||
transport = "tcp";
|
||||
};
|
||||
kpasswd = {
|
||||
port = 464;
|
||||
transport = "tcp";
|
||||
};
|
||||
kpasswd-udp = {
|
||||
port = config.ports.kpasswd.port;
|
||||
transport = "udp";
|
||||
};
|
||||
ticket4 = {
|
||||
enable = false;
|
||||
port = 4444;
|
||||
transport = "udp";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
37
modules/system/exports/keycloak.nix
Normal file
37
modules/system/exports/keycloak.nix
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
{lib, gensokyo-zone, ...}: let
|
||||
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
|
||||
inherit (lib.modules) mkIf;
|
||||
inherit (lib.attrsets) mapAttrs;
|
||||
in {
|
||||
config.exports.services.keycloak = { config, ... }: {
|
||||
id = mkAlmostOptionDefault "sso";
|
||||
nixos = {
|
||||
serviceAttr = "keycloak";
|
||||
assertions = let
|
||||
mkAssertion = f: nixosConfig: let
|
||||
cfg = nixosConfig.services.keycloak;
|
||||
in f nixosConfig cfg;
|
||||
in mkIf config.enable [
|
||||
(mkAssertion (nixosConfig: cfg: {
|
||||
assertion = config.ports.${cfg.protocol}.port == cfg.port;
|
||||
message = "port mismatch";
|
||||
}))
|
||||
(mkAssertion (nixosConfig: cfg: {
|
||||
assertion = config.ports.${cfg.protocol}.enable;
|
||||
message = "port enable mismatch";
|
||||
}))
|
||||
];
|
||||
};
|
||||
ports = mapAttrs (_: mapAlmostOptionDefaults) {
|
||||
http = {
|
||||
enable = !config.ports.https.enable;
|
||||
port = 8080;
|
||||
protocol = "http";
|
||||
};
|
||||
https = {
|
||||
port = 8443;
|
||||
protocol = "https";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
19
modules/system/exports/ldap.nix
Normal file
19
modules/system/exports/ldap.nix
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{lib, gensokyo-zone, ...}: let
|
||||
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
|
||||
inherit (lib.attrsets) mapAttrs;
|
||||
in {
|
||||
config.exports.services.ldap = { config, ... }: {
|
||||
defaults.port.listen = mkAlmostOptionDefault "lan";
|
||||
ports = mapAttrs (_: mapAlmostOptionDefaults) {
|
||||
default = {
|
||||
port = 389;
|
||||
transport = "tcp";
|
||||
};
|
||||
ssl = {
|
||||
port = 636;
|
||||
ssl = true;
|
||||
listen = "wan";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
38
modules/system/exports/mosquitto.nix
Normal file
38
modules/system/exports/mosquitto.nix
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
{lib, gensokyo-zone, ...}: let
|
||||
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
|
||||
inherit (lib.modules) mkIf;
|
||||
inherit (lib.attrsets) mapAttrs;
|
||||
inherit (lib.lists) all imap0;
|
||||
inherit (lib.trivial) id;
|
||||
in {
|
||||
config.exports.services.mosquitto = { config, ... }: {
|
||||
id = mkAlmostOptionDefault "mqtt";
|
||||
nixos = {
|
||||
serviceAttr = "mosquitto";
|
||||
assertions = mkIf config.enable [
|
||||
(nixosConfig: let
|
||||
cfg = nixosConfig.services.mosquitto;
|
||||
portName = i:
|
||||
if i == 0 then "default"
|
||||
else "listener${toString i}";
|
||||
mkAssertPort = i: listener: config.ports.${portName i}.port or null == listener.port;
|
||||
in {
|
||||
assertion = all id (imap0 mkAssertPort cfg.listeners);
|
||||
message = "port mismatch";
|
||||
})
|
||||
];
|
||||
};
|
||||
defaults.port.listen = mkAlmostOptionDefault "lan";
|
||||
ports = mapAttrs (_: mapAlmostOptionDefaults) {
|
||||
default = {
|
||||
port = 1883;
|
||||
transport = "tcp";
|
||||
};
|
||||
ssl = {
|
||||
enable = false;
|
||||
port = 8883;
|
||||
ssl = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
18
modules/system/exports/motion.nix
Normal file
18
modules/system/exports/motion.nix
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
{lib, gensokyo-zone, ...}: let
|
||||
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
|
||||
inherit (lib.attrsets) mapAttrs;
|
||||
in {
|
||||
config.exports.services.motion = { config, ... }: {
|
||||
defaults.port.listen = mkAlmostOptionDefault "lan";
|
||||
ports = mapAttrs (_: mapAlmostOptionDefaults) {
|
||||
default = {
|
||||
port = 8080;
|
||||
protocol = "http";
|
||||
};
|
||||
stream = {
|
||||
port = 8081;
|
||||
protocol = "http";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
77
modules/system/exports/nfs.nix
Normal file
77
modules/system/exports/nfs.nix
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
{lib, gensokyo-zone, ...}: let
|
||||
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
|
||||
inherit (lib.modules) mkIf;
|
||||
inherit (lib.attrsets) mapAttrs;
|
||||
in {
|
||||
config.exports.services.nfs = { config, ... }: let
|
||||
mkAssertion = f: nixosConfig: let
|
||||
cfg = nixosConfig.services.nfs;
|
||||
in f nixosConfig cfg;
|
||||
mkAssertionPort = portName: mkAssertion (nixosConfig: cfg: let
|
||||
portAttr = "${portName}Port";
|
||||
in {
|
||||
assertion = mkAssertPort config.ports.${portName} cfg.server.${portAttr};
|
||||
message = "${portAttr} mismatch";
|
||||
});
|
||||
mkAssertPort = port: cfgPort: let
|
||||
cmpPort = if port.enable then port.port else null;
|
||||
in cfgPort == cmpPort;
|
||||
in {
|
||||
nixos = {
|
||||
serviceAttrPath = [ "services" "nfs" "server" ];
|
||||
assertions = mkIf config.enable [
|
||||
(mkAssertionPort "statd")
|
||||
(mkAssertionPort "lockd")
|
||||
(mkAssertionPort "mountd")
|
||||
(mkAssertion (nixosConfig: cfg: {
|
||||
assertion = nixosConfig.services.rpcbind.enable == config.ports.rpcbind.enable;
|
||||
message = "rpcbind enable mismatch";
|
||||
}))
|
||||
];
|
||||
};
|
||||
# TODO: expose over wan
|
||||
defaults.port.listen = mkAlmostOptionDefault "lan";
|
||||
ports = mapAttrs (_: mapAlmostOptionDefaults) {
|
||||
default = {
|
||||
port = 2049;
|
||||
transport = "tcp";
|
||||
};
|
||||
udp = {
|
||||
port = config.ports.default.port;
|
||||
transport = "udp";
|
||||
};
|
||||
rpcbind = {
|
||||
port = 111;
|
||||
transport = "tcp";
|
||||
};
|
||||
rpcbind-udp = {
|
||||
port = config.ports.rpcbind.port;
|
||||
transport = "udp";
|
||||
};
|
||||
statd = {
|
||||
port = 4000;
|
||||
transport = "tcp";
|
||||
};
|
||||
statd-udp = {
|
||||
port = config.ports.statd.port;
|
||||
transport = "udp";
|
||||
};
|
||||
lockd = {
|
||||
port = 4001;
|
||||
transport = "tcp";
|
||||
};
|
||||
lockd-udp = {
|
||||
port = config.ports.lockd.port;
|
||||
transport = "udp";
|
||||
};
|
||||
mountd = {
|
||||
port = 4002;
|
||||
transport = "tcp";
|
||||
};
|
||||
mountd-udp = {
|
||||
port = config.ports.mountd.port;
|
||||
transport = "udp";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
43
modules/system/exports/plex.nix
Normal file
43
modules/system/exports/plex.nix
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
{lib, gensokyo-zone, ...}: let
|
||||
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
|
||||
inherit (lib.attrsets) mapAttrs;
|
||||
in {
|
||||
config.exports.services.plex = {
|
||||
nixos.serviceAttr = "plex";
|
||||
defaults.port.listen = mkAlmostOptionDefault "lan";
|
||||
ports = mapAttrs (_: mapAlmostOptionDefaults) {
|
||||
default = {
|
||||
port = 32400;
|
||||
protocol = "http";
|
||||
};
|
||||
roku = {
|
||||
port = 8324;
|
||||
transport = "tcp";
|
||||
};
|
||||
dlna-tcp = {
|
||||
port = 32469;
|
||||
transport = "tcp";
|
||||
};
|
||||
dlna-udp = {
|
||||
port = 1900;
|
||||
transport = "udp";
|
||||
};
|
||||
gdm0 = {
|
||||
port = 32410;
|
||||
transport = "udp";
|
||||
};
|
||||
gdm1 = {
|
||||
port = 32412;
|
||||
transport = "udp";
|
||||
};
|
||||
gdm2 = {
|
||||
port = 32413;
|
||||
transport = "udp";
|
||||
};
|
||||
gdm3 = {
|
||||
port = 32414;
|
||||
transport = "udp";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
27
modules/system/exports/postgresql.nix
Normal file
27
modules/system/exports/postgresql.nix
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{lib, gensokyo-zone, ...}: let
|
||||
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults;
|
||||
inherit (lib.modules) mkIf;
|
||||
in {
|
||||
config.exports.services.postgresql = { config, ... }: let
|
||||
mkAssertion = f: nixosConfig: let
|
||||
cfg = nixosConfig.services.postgresql;
|
||||
in f nixosConfig cfg;
|
||||
in {
|
||||
nixos = {
|
||||
assertions = mkIf config.enable [
|
||||
(mkAssertion (nixosConfig: cfg: {
|
||||
assertion = config.ports.default.port == cfg.settings.port;
|
||||
message = "port mismatch";
|
||||
}))
|
||||
(mkAssertion (nixosConfig: cfg: {
|
||||
assertion = config.ports.default.enable == cfg.enableTCPIP;
|
||||
message = "enableTCPIP mismatch";
|
||||
}))
|
||||
];
|
||||
};
|
||||
ports.default = mapAlmostOptionDefaults {
|
||||
port = 5432;
|
||||
transport = "tcp";
|
||||
};
|
||||
};
|
||||
}
|
||||
12
modules/system/exports/prox.nix
Normal file
12
modules/system/exports/prox.nix
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{lib, gensokyo-zone, ...}: let
|
||||
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
|
||||
in {
|
||||
config.exports.services.proxmox = { config, ... }: {
|
||||
id = mkAlmostOptionDefault "prox";
|
||||
defaults.port.listen = mkAlmostOptionDefault "lan";
|
||||
ports.default = mapAlmostOptionDefaults {
|
||||
port = 8006;
|
||||
protocol = "https";
|
||||
};
|
||||
};
|
||||
}
|
||||
29
modules/system/exports/samba.nix
Normal file
29
modules/system/exports/samba.nix
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
{lib, gensokyo-zone, ...}: let
|
||||
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
|
||||
inherit (lib.attrsets) mapAttrs;
|
||||
in {
|
||||
config.exports.services.samba = {
|
||||
id = mkAlmostOptionDefault "smb";
|
||||
nixos.serviceAttr = "samba";
|
||||
# TODO: expose over wan
|
||||
defaults.port.listen = mkAlmostOptionDefault "lan";
|
||||
ports = mapAttrs (_: mapAlmostOptionDefaults) {
|
||||
port0 = {
|
||||
port = 137;
|
||||
transport = "udp";
|
||||
};
|
||||
port1 = {
|
||||
port = 138;
|
||||
transport = "udp";
|
||||
};
|
||||
port2 = {
|
||||
port = 139;
|
||||
transport = "tcp";
|
||||
};
|
||||
default = {
|
||||
port = 445;
|
||||
transport = "tcp";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
155
modules/system/exports/services.nix
Normal file
155
modules/system/exports/services.nix
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
{
|
||||
config,
|
||||
name,
|
||||
lib,
|
||||
gensokyo-zone,
|
||||
...
|
||||
}: let
|
||||
inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
|
||||
inherit (lib.options) mkOption mkEnableOption;
|
||||
inherit (lib.modules) mkIf mkMerge mkOptionDefault;
|
||||
inherit (lib.attrsets) mapAttrsToList getAttrFromPath;
|
||||
inherit (lib.trivial) mapNullable;
|
||||
inherit (lib.strings) concatStringsSep;
|
||||
systemConfig = config;
|
||||
portModule = {config, service, ...}: {
|
||||
options = with lib.types; {
|
||||
enable =
|
||||
mkEnableOption "port"
|
||||
// {
|
||||
default = true;
|
||||
};
|
||||
listen = mkOption {
|
||||
type = enum ["wan" "lan" "int" "localhost"];
|
||||
};
|
||||
protocol = mkOption {
|
||||
type = nullOr (enum ["http" "https"]);
|
||||
default = null;
|
||||
};
|
||||
transport = mkOption {
|
||||
type = enum ["tcp" "udp" "unix"];
|
||||
};
|
||||
path = mkOption {
|
||||
type = nullOr path;
|
||||
default = null;
|
||||
description = "unix socket path";
|
||||
};
|
||||
ssl = mkOption {
|
||||
type = bool;
|
||||
default = false;
|
||||
};
|
||||
port = mkOption {
|
||||
type = nullOr int;
|
||||
};
|
||||
};
|
||||
config = {
|
||||
transport = mkMerge [
|
||||
(mkIf (config.protocol == "http" || config.protocol == "https") (mkOptionDefault "tcp"))
|
||||
(mkIf config.ssl (mkOptionDefault "tcp"))
|
||||
];
|
||||
ssl = mkIf (config.protocol == "https") (
|
||||
mkAlmostOptionDefault true
|
||||
);
|
||||
listen = mkOptionDefault service.defaults.port.listen;
|
||||
};
|
||||
};
|
||||
serviceModule = {
|
||||
config,
|
||||
name,
|
||||
...
|
||||
}: {
|
||||
options = with lib.types; {
|
||||
enable = mkEnableOption "hosted service";
|
||||
name = mkOption {
|
||||
type = str;
|
||||
default = name;
|
||||
};
|
||||
id = mkOption {
|
||||
type = str;
|
||||
default = config.name;
|
||||
};
|
||||
ports = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [portModule];
|
||||
specialArgs = {
|
||||
service = config;
|
||||
};
|
||||
});
|
||||
};
|
||||
nixos = {
|
||||
serviceAttr = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
};
|
||||
serviceAttrPath = mkOption {
|
||||
type = nullOr (listOf str);
|
||||
};
|
||||
assertions = mkOption {
|
||||
type = listOf (functionTo attrs);
|
||||
default = [ ];
|
||||
};
|
||||
};
|
||||
defaults = {
|
||||
port = {
|
||||
listen = mkOption {
|
||||
type = str;
|
||||
default = "int";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
config = {
|
||||
nixos = {
|
||||
serviceAttrPath = mkOptionDefault (
|
||||
mapNullable (serviceAttr: ["services" config.nixos.serviceAttr]) config.nixos.serviceAttr
|
||||
);
|
||||
assertions = let
|
||||
serviceConfig = getAttrFromPath config.nixos.serviceAttrPath;
|
||||
mkAssertion = f: nixosConfig: let
|
||||
cfg = serviceConfig nixosConfig;
|
||||
in f nixosConfig cfg;
|
||||
enableAssertion = nixosConfig: cfg: {
|
||||
assertion = (! cfg ? enable) || (config.enable == cfg.enable);
|
||||
message = "enable == nixosConfig.${concatStringsSep "." config.nixos.serviceAttrPath}.enable";
|
||||
};
|
||||
in [
|
||||
(mkIf (config.nixos.serviceAttrPath != null) (
|
||||
mkAssertion enableAssertion
|
||||
))
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
nixosModule = {config, system, ...}: let
|
||||
mapAssertion = service: a: let
|
||||
res = a config;
|
||||
in res // {
|
||||
message = "system.exports.${service.name}: " + res.message or "assertion failed";
|
||||
};
|
||||
assertions = mapAttrsToList (_: service: map (mapAssertion service) service.nixos.assertions) system.exports.services;
|
||||
in {
|
||||
config = {
|
||||
assertions = mkMerge assertions;
|
||||
# TODO: export ports via firewall according to enable/listen/etc
|
||||
};
|
||||
};
|
||||
in {
|
||||
options.exports = with lib.types; {
|
||||
services = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [serviceModule];
|
||||
specialArgs = {
|
||||
machine = name;
|
||||
inherit systemConfig;
|
||||
};
|
||||
});
|
||||
default = {};
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
modules = mkIf (config.type == "NixOS") [
|
||||
nixosModule
|
||||
];
|
||||
};
|
||||
}
|
||||
7
modules/system/exports/tailscale.nix
Normal file
7
modules/system/exports/tailscale.nix
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{...}: {
|
||||
config.exports.services.tailscale = {
|
||||
id = "tail";
|
||||
nixos.serviceAttr = "tailscale";
|
||||
ports = {};
|
||||
};
|
||||
}
|
||||
47
modules/system/exports/unifi.nix
Normal file
47
modules/system/exports/unifi.nix
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
{lib, gensokyo-zone, ...}: let
|
||||
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
|
||||
inherit (lib.attrsets) mapAttrs;
|
||||
in {
|
||||
config.exports.services.unifi = { config, ... }: {
|
||||
nixos.serviceAttr = "unifi";
|
||||
defaults.port.listen = mkAlmostOptionDefault "lan";
|
||||
ports = mapAttrs (_: mapAlmostOptionDefaults) {
|
||||
management = {
|
||||
# remote login
|
||||
port = 8443;
|
||||
protocol = "https";
|
||||
listen = "int";
|
||||
};
|
||||
uap = {
|
||||
# UAP to inform controller
|
||||
port = 8080;
|
||||
transport = "tcp";
|
||||
};
|
||||
portal = {
|
||||
# HTTP portal redirect, if guest portal is enabled
|
||||
port = 8880;
|
||||
protocol = "http";
|
||||
};
|
||||
portal-secure = {
|
||||
# HTTPS portal redirect
|
||||
port = 8843;
|
||||
protocol = "https";
|
||||
};
|
||||
speedtest = {
|
||||
# UniFi mobile speed test
|
||||
port = 6789;
|
||||
transport = "tcp";
|
||||
};
|
||||
stun = {
|
||||
port = 3478;
|
||||
transport = "udp";
|
||||
listen = "wan";
|
||||
};
|
||||
discovery = {
|
||||
# device discovery
|
||||
port = 10001;
|
||||
transport = "udp";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
22
modules/system/exports/vouch.nix
Normal file
22
modules/system/exports/vouch.nix
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{lib, gensokyo-zone, ...}: let
|
||||
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
|
||||
inherit (lib.modules) mkIf;
|
||||
in {
|
||||
config.exports.services.vouch-proxy = { config, ... }: {
|
||||
id = mkAlmostOptionDefault "login";
|
||||
defaults.port.listen = mkAlmostOptionDefault "localhost";
|
||||
nixos = {
|
||||
serviceAttr = "vouch-proxy";
|
||||
assertions = mkIf config.enable [
|
||||
(nixosConfig: {
|
||||
assertion = config.ports.default.port == nixosConfig.services.vouch-proxy.settings.vouch.port;
|
||||
message = "port mismatch";
|
||||
})
|
||||
];
|
||||
};
|
||||
ports.default = mapAlmostOptionDefaults {
|
||||
port = 30746;
|
||||
protocol = "http";
|
||||
};
|
||||
};
|
||||
}
|
||||
21
modules/system/exports/zigbee2mqtt.nix
Normal file
21
modules/system/exports/zigbee2mqtt.nix
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{lib, gensokyo-zone, ...}: let
|
||||
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
|
||||
inherit (lib.modules) mkIf;
|
||||
in {
|
||||
config.exports.services.zigbee2mqtt = { config, ... }: {
|
||||
id = mkAlmostOptionDefault "z2m";
|
||||
nixos = {
|
||||
serviceAttr = "zigbee2mqtt";
|
||||
assertions = mkIf config.enable [
|
||||
(nixosConfig: {
|
||||
assertion = config.ports.default.port == nixosConfig.services.zigbee2mqtt.settings.frontend.port;
|
||||
message = "port mismatch";
|
||||
})
|
||||
];
|
||||
};
|
||||
ports.default = mapAlmostOptionDefaults {
|
||||
port = 8072;
|
||||
protocol = "http";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -15,6 +15,11 @@ in {
|
|||
inherit (lib.types) str listOf attrs unspecified enum;
|
||||
inherit (lib.options) mkOption;
|
||||
in {
|
||||
name = mkOption {
|
||||
type = str;
|
||||
default = name;
|
||||
readOnly = true;
|
||||
};
|
||||
arch = mkOption {
|
||||
description = "Processor architecture of the host";
|
||||
type = str;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue