feat(exports): service access

This commit is contained in:
arcnmx 2024-02-19 17:34:39 -08:00
parent 91918b8061
commit 871b1c5b2d
69 changed files with 1317 additions and 509 deletions

View file

@ -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;
};
};
}

View 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";
};
};
};
}

View 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;
};
}

View 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";
};
};
};
}

View 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";
};
};
};
}

View 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
};
};
}

View 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";
};
};
}

View 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";
};
};
};
}

View 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";
};
};
};
}

View 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";
};
};
};
}

View 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;
};
};
};
}

View 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";
};
};
};
}

View 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";
};
};
};
}

View 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";
};
};
};
}

View 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";
};
};
}

View 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";
};
};
}

View 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";
};
};
};
}

View 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
];
};
}

View file

@ -0,0 +1,7 @@
{...}: {
config.exports.services.tailscale = {
id = "tail";
nixos.serviceAttr = "tailscale";
ports = {};
};
}

View 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";
};
};
};
}

View 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";
};
};
}

View 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";
};
};
}

View file

@ -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;