nixos/modules/state.nix
2024-11-17 18:09:11 +01:00

117 lines
3.6 KiB
Nix

{
lib,
config,
...
}: let
state = builtins.import ../state.nix;
ty = {
ipv4 = lib.types.strMatching "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}";
ipv6 = lib.types.strMatching "(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))";
};
in {
options.state = with lib; {
vpn.ipv4 = mkOption {
type = ty.ipv4;
description = "VPN IPv4";
readOnly = true;
};
vpn.ipv6 = mkOption {
type = types.str;
description = "VPN IPv6";
readOnly = true;
};
vpn.machine = mkOption {
type = with types;
attrsOf (submodule {
options = {
ipv4 = mkOption {
type = ty.ipv4;
description = "VPN IPv4";
};
ipv6 = mkOption {
type = ty.ipv6;
description = "VPN IPv6";
};
};
});
description = "VPN IP definitions for all available machines";
readOnly = true;
};
vpn.dns = mkOption {
type = ty.ipv4;
description = "VPN internal DNS server address";
readOnly = true;
};
vpn.cnames = mkOption {
type = types.attrsOf types.str;
description = "CNAMES for our internal DNS server";
readOnly = true;
};
services = mkOption {
type = with types;
attrsOf (submodule {
options = {
host = mkOption {
type = str;
description = "Host where the service runs";
};
port = mkOption {
type = number;
description = "Port over which the service can be accessed";
};
external = mkOption {
type = nullOr bool;
description = "Whether this service should be exposed (outside of VPN)";
};
};
});
description = "Service settings";
readOnly = true;
};
};
config.state = let
host = config.networking.hostName;
in {
vpn.ipv4 =
if state ? vpn.${host}.v4
then state.vpn.${host}.v4
else builtins.throw "VPN IPv4 not defined for ${host}";
vpn.ipv6 =
if state ? vpn.${host}.v6
then state.vpn.${host}.v6
else builtins.throw "VPN IPv6 not defined for ${host}";
vpn.machine =
if state ? vpn
then
builtins.mapAttrs (_: conf: {
ipv4 = conf.v4;
ipv6 = conf.v6;
})
state.vpn
else builtins.throw "No VPN definitions";
vpn.dns =
if state ? services && state.services ? dns
then
(
if state ? vpn && state.vpn ? "${state.services.dns.host}"
then state.vpn.${state.services.dns.host}.v4
else builtins.throw "No VPN entry for DNS host"
)
else builtins.throw "No DNS service defined!";
vpn.cnames =
(
if state ? cnames
then state.cnames
else {}
)
// (
builtins.mapAttrs (_name: value: value.host) config.state.services
);
services =
if state ? services
then state.services
else {};
};
}