diff --git a/flake.nix b/flake.nix index 0ad326a..933855e 100644 --- a/flake.nix +++ b/flake.nix @@ -6,7 +6,10 @@ flake-utils.url = "github:numtide/flake-utils"; - linger.url = "github:mindsbackyard/linger-flake"; + linger = { + url = "github:mindsbackyard/linger-flake"; + inputs.flake-utils.follows = "flake-utils"; + }; }; outputs = { self, nixpkgs, flake-utils, linger }: with flake-utils.lib; eachSystem (with system; [ x86_64-linux aarch64-linux ]) (curSystem: diff --git a/lib/options.nix b/lib/options.nix new file mode 100644 index 0000000..f52be68 --- /dev/null +++ b/lib/options.nix @@ -0,0 +1,40 @@ +nixpkgsLib: with nixpkgsLib; { + mkContainerEnvOption = { envVar, ... }@optionAttrs: + (mkOption (removeAttrs optionAttrs [ "envVar" ])) + // { inherit envVar; }; + + mkHostPortsOption = { service, publicDefaultPort }: { + hostInternalPort = mkOption { + type = types.port; + description = '' + The internal port on the host on which the ${service} port of the pihole container should be exposed. + Only needs to be specified if he container port should be exposed + or if the port-forwarding for this service is enabled. + + As the pihole container is running rootless this cannot be a privileged port (<1024). + ''; + }; + + hostPublicPort = mkOption { + type = types.port; + description = '' + The public port on the host on which the ${service} port of the pihole container should be forwared to. + + This option can be used to together with the according `forwardPublicToInternal` to expose a pihole subservice on a privileged port, + e.g., if you want to expose the DNS service on port 53. + ''; + default = publicDefaultPort; + }; + + forwardPublicToInternal = mkOption { + type = types.bool; + description = '' + Enable port-forwarding between the public & the internal port of the host. + This effectively makes pihole's ${service} port available on the network to which the host is connected to. + + Use this option together with the according `hostPublicPort` to expose a pihole subservice on a privileged port. + ''; + default = false; + }; + }; +} diff --git a/lib/util.nix b/lib/util.nix index 2b29586..532f8e2 100644 --- a/lib/util.nix +++ b/lib/util.nix @@ -1,5 +1,5 @@ -{ - collectAttrFragments = predicate: attrs: with builtins; let +with builtins; let + collectAttrFragments = predicate: attrs: let _collectAttrFragments = attrs: concatMap (key: _collectAttrFragmentsBelowKey key attrs.${key}) (attrNames attrs) ; @@ -12,7 +12,7 @@ in _collectAttrFragments attrs ; - accessValueOfFragment = attrs: fragment: with builtins; let + accessValueOfFragment = attrs: fragment: let _accessValueOfFragment = value: fragment: if fragment == [] then value else _accessValueOfFragment (value.${head fragment}) (tail fragment) @@ -20,8 +20,26 @@ in _accessValueOfFragment attrs fragment ; - toEnvValue = value: with builtins; - if isBool value then (if value then "true" else "false") - else if isList value then "[${concatStringSep ";" value}]" - else value; + toEnvValue = value: + if isBool value then (if value then "true" else "false") + else if isList value then "[${concatStringSep ";" value}]" + else value + ; + +in { + extractContainerEnvVars = piholeOptionDeclarations: piholeOptionDefinitions: let + _opt = piholeOptionDeclarations; + _cfg = piholeOptionDefinitions; + + _envVarFragments = collectAttrFragments (value: isAttrs value && value ? "envVar") _opt.piholeConfig; + in filter + (envVar: envVar.value != null) + (map + (fragment: { + name = getAttr "envVar" (accessValueOfFragment _opt.piholeConfig fragment); + value = toEnvValue (accessValueOfFragment _cfg.piholeConfig fragment); + }) + _envVarFragments + ) + ; } diff --git a/modules/pihole-container.factory.nix b/modules/pihole-container.factory.nix index 41ffcf7..7802701 100644 --- a/modules/pihole-container.factory.nix +++ b/modules/pihole-container.factory.nix @@ -1,50 +1,12 @@ { piholeFlake, lingerFlake }: { config, pkgs, lib, ... }: with lib; with builtins; let - inherit (import ../lib/util.nix) collectAttrFragments accessValueOfFragment toEnvValue; + inherit (import ../lib/util.nix) extractContainerEnvVars; + inherit (import ../lib/options.nix lib) mkContainerEnvOption mkHostPortsOption; cfg = config.services.pihole; hostUserCfg = config.users.users.${cfg.hostConfig.user}; systemTimeZone = config.time.timeZone; defaultPiholeVolumesDir = "${config.users.users.${cfg.hostConfig.user}.home}/pihole-volumes"; - mkContainerEnvOption = { envVar, ... }@optionAttrs: - (mkOption (removeAttrs optionAttrs [ "envVar" ])) - // { inherit envVar; }; - - mkHostPortsOption = { service, publicDefaultPort }: { - hostInternalPort = mkOption { - type = types.port; - description = '' - The internal port on the host on which the ${service} port of the pihole container should be exposed. - Only needs to be specified if he container port should be exposed - or if the port-forwarding for this service is enabled. - - As the pihole container is running rootless this cannot be a privileged port (<1024). - ''; - }; - - hostPublicPort = mkOption { - type = types.port; - description = '' - The public port on the host on which the ${service} port of the pihole container should be forwared to. - - This option can be used to together with the according `forwardPublicToInternal` to expose a pihole subservice on a privileged port, - e.g., if you want to expose the DNS service on port 53. - ''; - default = publicDefaultPort; - }; - - forwardPublicToInternal = mkOption { - type = types.bool; - description = '' - Enable port-forwarding between the public & the internal port of the host. - This effectively makes pihole's ${service} port available on the network to which the host is connected to. - - Use this option together with the according `hostPublicPort` to expose a pihole subservice on a privileged port. - ''; - default = false; - }; - }; - in rec { options = { services.pihole = { @@ -113,7 +75,7 @@ in rec { }; - piholeConfiguration = { + piholeConfig = { tz = mkContainerEnvOption { type = types.str; description = "Set your timezone to make sure logs rotate at local midnight instead of at UTC midnight."; @@ -334,20 +296,7 @@ in rec { path = [ "/run/wrappers" ]; serviceConfig = let - opt = options.services.pihole; - - containerEnvVars = let - envVarFragments = collectAttrFragments (value: isAttrs value && value ? "envVar") opt.piholeConfiguration; - in filter - (envVar: envVar.value != null) - (map - (fragment: { - name = getAttr "envVar" (accessValueOfFragment opt.piholeConfiguration fragment); - value = toEnvValue (accessValueOfFragment cfg.piholeConfiguration fragment); - }) - envVarFragments - ) - ; + containerEnvVars = extractContainerEnvVars options.services.pihole cfg; in { ExecStartPre = mkIf cfg.hostConfig.persistVolumes [ "${pkgs.coreutils}/bin/mkdir -p ${cfg.hostConfig.volumesPath}/etc-pihole"