nixos/adguardhome: update config to match new schema

Changed files
+111 -94
nixos
modules
services
networking
tests
+69 -51
nixos/modules/services/networking/adguardhome.nix
···
let
cfg = config.services.adguardhome;
args = concatStringsSep " " ([
"--no-check-update"
···
"--config /var/lib/AdGuardHome/AdGuardHome.yaml"
] ++ cfg.extraArgs);
-
configFile = pkgs.writeTextFile {
-
name = "AdGuardHome.yaml";
-
text = builtins.toJSON cfg.settings;
-
checkPhase = "${pkgs.adguardhome}/bin/adguardhome -c $out --check-config";
-
};
-
defaultBindPort = 3000;
-
-
in
-
{
-
-
imports =
-
let cfgPath = [ "services" "adguardhome" ];
-
in
-
[
-
(mkRenamedOptionModuleWith { sinceRelease = 2211; from = cfgPath ++ [ "host" ]; to = cfgPath ++ [ "settings" "bind_host" ]; })
-
(mkRenamedOptionModuleWith { sinceRelease = 2211; from = cfgPath ++ [ "port" ]; to = cfgPath ++ [ "settings" "bind_port" ]; })
-
];
options.services.adguardhome = with types; {
enable = mkEnableOption "AdGuard Home network-wide ad blocker";
openFirewall = mkOption {
default = false;
type = bool;
···
};
allowDHCP = mkOption {
-
default = cfg.settings.dhcp.enabled or false;
-
defaultText = literalExpression ''config.services.adguardhome.settings.dhcp.enabled or false'';
type = bool;
description = ''
Allows AdGuard Home to open raw sockets (`CAP_NET_RAW`), which is
···
'';
};
settings = mkOption {
default = null;
type = nullOr (submodule {
-
freeformType = (pkgs.formats.yaml { }).type;
options = {
schema_version = mkOption {
-
default = pkgs.adguardhome.schema_version;
-
defaultText = literalExpression "pkgs.adguardhome.schema_version";
type = int;
description = ''
Schema version for the configuration.
-
Defaults to the `schema_version` supplied by `pkgs.adguardhome`.
-
'';
-
};
-
bind_host = mkOption {
-
default = "0.0.0.0";
-
type = str;
-
description = ''
-
Host address to bind HTTP server to.
-
'';
-
};
-
bind_port = mkOption {
-
default = defaultBindPort;
-
type = port;
-
description = ''
-
Port to serve HTTP pages on.
'';
};
};
···
Set this to `null` (default) for a non-declarative configuration without any
Nix-supplied values.
-
Declarative configurations are supplied with a default `schema_version`, `bind_host`, and `bind_port`.
:::
'';
};
···
config = mkIf cfg.enable {
assertions = [
{
-
assertion = cfg.settings != null -> cfg.mutableSettings
-
|| (hasAttrByPath [ "dns" "bind_host" ] cfg.settings)
-
|| (hasAttrByPath [ "dns" "bind_hosts" ] cfg.settings);
-
message =
-
"AdGuard setting dns.bind_host or dns.bind_hosts needs to be configured for a minimal working configuration";
}
{
-
assertion = cfg.settings != null -> cfg.mutableSettings
-
|| hasAttrByPath [ "dns" "bootstrap_dns" ] cfg.settings;
-
message =
-
"AdGuard setting dns.bootstrap_dns needs to be configured for a minimal working configuration";
}
];
···
StartLimitBurst = 10;
};
-
preStart = optionalString (cfg.settings != null) ''
if [ -e "$STATE_DIRECTORY/AdGuardHome.yaml" ] \
&& [ "${toString cfg.mutableSettings}" = "1" ]; then
# Writing directly to AdGuardHome.yaml results in empty file
···
serviceConfig = {
DynamicUser = true;
-
ExecStart = "${pkgs.adguardhome}/bin/adguardhome ${args}";
-
AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ] ++ optionals cfg.allowDHCP [ "CAP_NET_RAW" ];
Restart = "always";
RestartSec = 10;
RuntimeDirectory = "AdGuardHome";
···
};
};
-
networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.settings.bind_port or defaultBindPort ];
};
}
···
let
cfg = config.services.adguardhome;
+
settingsFormat = pkgs.formats.yaml { };
args = concatStringsSep " " ([
"--no-check-update"
···
"--config /var/lib/AdGuardHome/AdGuardHome.yaml"
] ++ cfg.extraArgs);
+
settings = if (cfg.settings != null) then
+
cfg.settings // (if cfg.settings.schema_version < 23 then {
+
bind_host = cfg.host;
+
bind_port = cfg.port;
+
} else {
+
http.address = "${cfg.host}:${toString cfg.port}";
+
})
+
else
+
null;
+
configFile =
+
(settingsFormat.generate "AdGuardHome.yaml" settings).overrideAttrs (_: {
+
checkPhase = "${cfg.package}/bin/adguardhome -c $out --check-config";
+
});
+
in {
options.services.adguardhome = with types; {
enable = mkEnableOption "AdGuard Home network-wide ad blocker";
+
package = mkOption {
+
type = package;
+
default = pkgs.adguardhome;
+
defaultText = literalExpression "pkgs.adguardhome";
+
description = ''
+
The package that runs adguardhome.
+
'';
+
};
+
openFirewall = mkOption {
default = false;
type = bool;
···
};
allowDHCP = mkOption {
+
default = settings.dhcp.enabled or false;
+
defaultText = literalExpression "config.services.adguardhome.settings.dhcp.enabled or false";
type = bool;
description = ''
Allows AdGuard Home to open raw sockets (`CAP_NET_RAW`), which is
···
'';
};
+
host = mkOption {
+
default = "0.0.0.0";
+
type = str;
+
description = ''
+
Host address to bind HTTP server to.
+
'';
+
};
+
+
port = mkOption {
+
default = 3000;
+
type = port;
+
description = ''
+
Port to serve HTTP pages on.
+
'';
+
};
+
settings = mkOption {
default = null;
type = nullOr (submodule {
+
freeformType = settingsFormat.type;
options = {
schema_version = mkOption {
+
default = cfg.package.schema_version;
+
defaultText = literalExpression "cfg.package.schema_version";
type = int;
description = ''
Schema version for the configuration.
+
Defaults to the `schema_version` supplied by `cfg.package`.
'';
};
};
···
Set this to `null` (default) for a non-declarative configuration without any
Nix-supplied values.
+
Declarative configurations are supplied with a default `schema_version`, and `http.address`.
:::
'';
};
···
config = mkIf cfg.enable {
assertions = [
{
+
assertion = cfg.settings != null
+
-> !(hasAttrByPath [ "bind_host" ] cfg.settings);
+
message = "AdGuard option `settings.bind_host' has been superseded by `services.adguardhome.host'";
+
}
+
{
+
assertion = cfg.settings != null
+
-> !(hasAttrByPath [ "bind_port" ] cfg.settings);
+
message = "AdGuard option `settings.bind_host' has been superseded by `services.adguardhome.port'";
}
{
+
assertion = settings != null -> cfg.mutableSettings
+
|| hasAttrByPath [ "dns" "bootstrap_dns" ] settings;
+
message = "AdGuard setting dns.bootstrap_dns needs to be configured for a minimal working configuration";
+
}
+
{
+
assertion = settings != null -> cfg.mutableSettings
+
|| hasAttrByPath [ "dns" "bootstrap_dns" ] settings
+
&& isList settings.dns.bootstrap_dns;
+
message = "AdGuard setting dns.bootstrap_dns needs to be a list";
}
];
···
StartLimitBurst = 10;
};
+
preStart = optionalString (settings != null) ''
if [ -e "$STATE_DIRECTORY/AdGuardHome.yaml" ] \
&& [ "${toString cfg.mutableSettings}" = "1" ]; then
# Writing directly to AdGuardHome.yaml results in empty file
···
serviceConfig = {
DynamicUser = true;
+
ExecStart = "${cfg.package}/bin/adguardhome ${args}";
+
AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ]
+
++ optionals cfg.allowDHCP [ "CAP_NET_RAW" ];
Restart = "always";
RestartSec = 10;
RuntimeDirectory = "AdGuardHome";
···
};
};
+
networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ];
};
}
+42 -43
nixos/tests/adguardhome.nix
···
name = "adguardhome";
nodes = {
-
nullConf = { ... }: { services.adguardhome = { enable = true; }; };
-
emptyConf = { lib, ... }: {
services.adguardhome = {
enable = true;
};
};
-
declarativeConf = { ... }: {
services.adguardhome = {
enable = true;
mutableSettings = false;
-
settings = {
-
schema_version = 0;
-
dns = {
-
bind_host = "0.0.0.0";
-
bootstrap_dns = "127.0.0.1";
-
};
-
};
};
};
-
mixedConf = { ... }: {
services.adguardhome = {
enable = true;
mutableSettings = true;
-
settings = {
-
schema_version = 0;
-
dns = {
-
bind_host = "0.0.0.0";
-
bootstrap_dns = "127.0.0.1";
-
};
-
};
};
};
···
allowDHCP = true;
mutableSettings = false;
settings = {
-
schema_version = 0;
-
dns = {
-
bind_host = "0.0.0.0";
-
bootstrap_dns = "127.0.0.1";
-
};
dhcp = {
# This implicitly enables CAP_NET_RAW
enabled = true;
···
testScript = ''
with subtest("Minimal (settings = null) config test"):
-
nullConf.wait_for_unit("adguardhome.service")
with subtest("Default config test"):
-
emptyConf.wait_for_unit("adguardhome.service")
-
emptyConf.wait_for_open_port(3000)
with subtest("Declarative config test, DNS will be reachable"):
-
declarativeConf.wait_for_unit("adguardhome.service")
-
declarativeConf.wait_for_open_port(53)
-
declarativeConf.wait_for_open_port(3000)
with subtest("Mixed config test, check whether merging works"):
-
mixedConf.wait_for_unit("adguardhome.service")
-
mixedConf.wait_for_open_port(53)
-
mixedConf.wait_for_open_port(3000)
-
# Test whether merging works properly, even if nothing is changed
-
mixedConf.systemctl("restart adguardhome.service")
-
mixedConf.wait_for_unit("adguardhome.service")
-
mixedConf.wait_for_open_port(3000)
with subtest("Testing successful DHCP start"):
-
dhcpConf.wait_for_unit("adguardhome.service")
-
client.systemctl("start network-online.target")
-
client.wait_for_unit("network-online.target")
-
# Test IP assignment via DHCP
-
dhcpConf.wait_until_succeeds("ping -c 5 10.0.10.100")
-
# Test hostname resolution over DHCP-provided DNS
-
dhcpConf.wait_until_succeeds("ping -c 5 client.lan")
'';
}
···
name = "adguardhome";
nodes = {
+
nullConf = { services.adguardhome.enable = true; };
+
emptyConf = {
services.adguardhome = {
enable = true;
+
+
settings = { };
};
};
+
schemaVersionBefore23 = {
+
services.adguardhome = {
+
enable = true;
+
+
settings.schema_version = 20;
+
};
+
};
+
+
declarativeConf = {
services.adguardhome = {
enable = true;
mutableSettings = false;
+
settings.dns.bootstrap_dns = [ "127.0.0.1" ];
};
};
+
mixedConf = {
services.adguardhome = {
enable = true;
mutableSettings = true;
+
settings.dns.bootstrap_dns = [ "127.0.0.1" ];
};
};
···
allowDHCP = true;
mutableSettings = false;
settings = {
+
dns.bootstrap_dns = [ "127.0.0.1" ];
dhcp = {
# This implicitly enables CAP_NET_RAW
enabled = true;
···
testScript = ''
with subtest("Minimal (settings = null) config test"):
+
nullConf.wait_for_unit("adguardhome.service")
+
nullConf.wait_for_open_port(3000)
with subtest("Default config test"):
+
emptyConf.wait_for_unit("adguardhome.service")
+
emptyConf.wait_for_open_port(3000)
+
+
with subtest("Default schema_version 23 config test"):
+
schemaVersionBefore23.wait_for_unit("adguardhome.service")
+
schemaVersionBefore23.wait_for_open_port(3000)
with subtest("Declarative config test, DNS will be reachable"):
+
declarativeConf.wait_for_unit("adguardhome.service")
+
declarativeConf.wait_for_open_port(53)
+
declarativeConf.wait_for_open_port(3000)
with subtest("Mixed config test, check whether merging works"):
+
mixedConf.wait_for_unit("adguardhome.service")
+
mixedConf.wait_for_open_port(53)
+
mixedConf.wait_for_open_port(3000)
+
# Test whether merging works properly, even if nothing is changed
+
mixedConf.systemctl("restart adguardhome.service")
+
mixedConf.wait_for_unit("adguardhome.service")
+
mixedConf.wait_for_open_port(3000)
with subtest("Testing successful DHCP start"):
+
dhcpConf.wait_for_unit("adguardhome.service")
+
client.systemctl("start network-online.target")
+
client.wait_for_unit("network-online.target")
+
# Test IP assignment via DHCP
+
dhcpConf.wait_until_succeeds("ping -c 5 10.0.10.100")
+
# Test hostname resolution over DHCP-provided DNS
+
dhcpConf.wait_until_succeeds("ping -c 5 client.lan")
'';
}