diff options
author | Pol Dellaiera <pol.dellaiera@protonmail.com> | 2024-06-12 19:23:44 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-12 19:23:44 +0200 |
commit | 7d270d53b9ad06515d68122d6bcc47df615740bd (patch) | |
tree | 7381d49147482aaf61875d991ec5f83cdbb8a6d7 /nixos | |
parent | fbc538f6cd728268a6722549ee5955811fb855aa (diff) | |
parent | 1389666a117fd1698f388948ca506423c7df9870 (diff) |
Merge pull request #303429 from timhae/aria2-module
Aria2 module settings
Diffstat (limited to 'nixos')
-rw-r--r-- | nixos/modules/services/networking/aria2.nix | 170 | ||||
-rw-r--r-- | nixos/tests/all-tests.nix | 1 | ||||
-rw-r--r-- | nixos/tests/aria2.nix | 43 |
3 files changed, 150 insertions, 64 deletions
diff --git a/nixos/modules/services/networking/aria2.nix b/nixos/modules/services/networking/aria2.nix index f32f5682c9801..dd4823911f2b3 100644 --- a/nixos/modules/services/networking/aria2.nix +++ b/nixos/modules/services/networking/aria2.nix @@ -1,98 +1,137 @@ { config, lib, pkgs, ... }: -with lib; - let cfg = config.services.aria2; homeDir = "/var/lib/aria2"; - - settingsDir = "${homeDir}"; - sessionFile = "${homeDir}/aria2.session"; - downloadDir = "${homeDir}/Downloads"; - - rangesToStringList = map (x: builtins.toString x.from +"-"+ builtins.toString x.to); - - settingsFile = pkgs.writeText "aria2.conf" - '' - dir=${cfg.downloadDir} - listen-port=${concatStringsSep "," (rangesToStringList cfg.listenPortRange)} - rpc-listen-port=${toString cfg.rpcListenPort} - ''; - + defaultRpcListenPort = 6800; + defaultDir = "${homeDir}/Downloads"; + + rangesToStringList = map (x: + if x.from == x.to + then builtins.toString x.from + else builtins.toString x.from + "-" + builtins.toString x.to + ); + + portRangesToString = ranges: lib.concatStringsSep "," (map + (x: + if x.from == x.to + then builtins.toString x.from + else builtins.toString x.from + "-" + builtins.toString x.to + ) + ranges); + + customToKeyValue = lib.generators.toKeyValue { + mkKeyValue = lib.generators.mkKeyValueDefault + { + mkValueString = v: + if builtins.isList v then portRangesToString v + else lib.generators.mkValueStringDefault { } v; + } "="; + }; in { imports = [ - (mkRemovedOptionModule [ "services" "aria2" "rpcSecret" ] "Use services.aria2.rpcSecretFile instead") + (lib.mkRemovedOptionModule [ "services" "aria2" "rpcSecret" ] "Use services.aria2.rpcSecretFile instead") + (lib.mkRemovedOptionModule [ "services" "aria2" "extraArguments" ] "Use services.aria2.settings instead") + (lib.mkRenamedOptionModule [ "services" "aria2" "downloadDir" ] [ "services" "aria2" "settings" "dir" ]) + (lib.mkRenamedOptionModule [ "services" "aria2" "listenPortRange" ] [ "services" "aria2" "settings" "listen-port" ]) + (lib.mkRenamedOptionModule [ "services" "aria2" "rpcListenPort" ] [ "services" "aria2" "settings" "rpc-listen-port" ]) ]; options = { services.aria2 = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether or not to enable the headless Aria2 daemon service. - Aria2 daemon can be controlled via the RPC interface using - one of many WebUI (http://localhost:6800/ by default). + Aria2 daemon can be controlled via the RPC interface using one of many + WebUIs (http://localhost:${toString defaultRpcListenPort}/ by default). - Targets are downloaded to ${downloadDir} by default and are - accessible to users in the "aria2" group. + Targets are downloaded to `${defaultDir}` by default and are + accessible to users in the `aria2` group. ''; }; - openPorts = mkOption { - type = types.bool; + openPorts = lib.mkOption { + type = lib.types.bool; default = false; description = '' - Open listen and RPC ports found in listenPortRange and rpcListenPort - options in the firewall. - ''; - }; - downloadDir = mkOption { - type = types.path; - default = downloadDir; - description = '' - Directory to store downloaded files. - ''; - }; - listenPortRange = mkOption { - type = types.listOf types.attrs; - default = [ { from = 6881; to = 6999; } ]; - description = '' - Set UDP listening port range used by DHT(IPv4, IPv6) and UDP tracker. + Open listen and RPC ports found in `settings.listen-port` and + `settings.rpc-listen-port` options in the firewall. ''; }; - rpcListenPort = mkOption { - type = types.int; - default = 6800; - description = "Specify a port number for JSON-RPC/XML-RPC server to listen to. Possible Values: 1024-65535"; - }; - rpcSecretFile = mkOption { - type = types.path; + rpcSecretFile = lib.mkOption { + type = lib.types.path; example = "/run/secrets/aria2-rpc-token.txt"; description = '' A file containing the RPC secret authorization token. Read https://aria2.github.io/manual/en/html/aria2c.html#rpc-auth to know how this option value is used. ''; }; - extraArguments = mkOption { - type = types.separatedString " "; - example = "--rpc-listen-all --remote-time=true"; - default = ""; + settings = lib.mkOption { description = '' - Additional arguments to be passed to Aria2. + Generates the `aria2.conf` file. Refer to [the documentation][0] for + all possible settings. + + [0]: https://aria2.github.io/manual/en/html/aria2c.html#synopsis ''; + type = lib.types.submodule { + freeformType = with lib.types; attrsOf (oneOf [ bool int float singleLineStr ]); + options = { + save-session = lib.mkOption { + type = lib.types.singleLineStr; + default = "${homeDir}/aria2.session"; + description = "Save error/unfinished downloads to FILE on exit."; + }; + dir = lib.mkOption { + type = lib.types.singleLineStr; + default = defaultDir; + description = "Directory to store downloaded files."; + }; + conf-path = lib.mkOption { + type = lib.types.singleLineStr; + default = "${homeDir}/aria2.conf"; + description = "Configuration file path."; + }; + enable-rpc = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Enable JSON-RPC/XML-RPC server."; + }; + listen-port = lib.mkOption { + type = with lib.types; listOf (attrsOf port); + default = [{ from = 6881; to = 6999; }]; + description = "Set UDP listening port range used by DHT(IPv4, IPv6) and UDP tracker."; + }; + rpc-listen-port = lib.mkOption { + type = lib.types.port; + default = defaultRpcListenPort; + description = "Specify a port number for JSON-RPC/XML-RPC server to listen to. Possible Values: 1024-65535"; + }; + }; + }; }; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { + assertions = [ + { + assertion = cfg.settings.enable-rpc; + message = "RPC has to be enabled, the default module option takes care of that."; + } + { + assertion = !(cfg.settings ? rpc-secret); + message = "Set the RPC secret through services.aria2.rpcSecretFile so it will not end up in the world-readable nix store."; + } + ]; # Need to open ports for proper functioning - networking.firewall = mkIf cfg.openPorts { - allowedUDPPortRanges = config.services.aria2.listenPortRange; - allowedTCPPorts = [ config.services.aria2.rpcListenPort ]; + networking.firewall = lib.mkIf cfg.openPorts { + allowedUDPPortRanges = config.services.aria2.settings.listen-port; + allowedTCPPorts = [ config.services.aria2.settings.rpc-listen-port ]; }; users.users.aria2 = { @@ -107,7 +146,7 @@ in systemd.tmpfiles.rules = [ "d '${homeDir}' 0770 aria2 aria2 - -" - "d '${config.services.aria2.downloadDir}' 0770 aria2 aria2 - -" + "d '${config.services.aria2.settings.dir}' 0770 aria2 aria2 - -" ]; systemd.services.aria2 = { @@ -115,22 +154,25 @@ in after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; preStart = '' - if [[ ! -e "${sessionFile}" ]] + if [[ ! -e "${cfg.settings.save-session}" ]] then - touch "${sessionFile}" + touch "${cfg.settings.save-session}" fi - cp -f "${settingsFile}" "${settingsDir}/aria2.conf" - echo "rpc-secret=$(cat "$CREDENTIALS_DIRECTORY/rpcSecretFile")" >> "${settingsDir}/aria2.conf" + cp -f "${pkgs.writeText "aria2.conf" (customToKeyValue cfg.settings)}" "${cfg.settings.conf-path}" + chmod +w "${cfg.settings.conf-path}" + echo "rpc-secret=$(cat "$CREDENTIALS_DIRECTORY/rpcSecretFile")" >> "${cfg.settings.conf-path}" ''; serviceConfig = { Restart = "on-abort"; - ExecStart = "${pkgs.aria2}/bin/aria2c --enable-rpc --conf-path=${settingsDir}/aria2.conf ${config.services.aria2.extraArguments} --save-session=${sessionFile}"; + ExecStart = "${pkgs.aria2}/bin/aria2c --conf-path=${cfg.settings.conf-path}"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; User = "aria2"; Group = "aria2"; - LoadCredential="rpcSecretFile:${cfg.rpcSecretFile}"; + LoadCredential = "rpcSecretFile:${cfg.rpcSecretFile}"; }; }; }; + + meta.maintainers = [ lib.maintainers.timhae ]; } diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 3052c1ddfe0da..a9b6881aab0f8 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -130,6 +130,7 @@ in { appliance-repart-image = runTest ./appliance-repart-image.nix; apparmor = handleTest ./apparmor.nix {}; archi = handleTest ./archi.nix {}; + aria2 = handleTest ./aria2.nix {}; armagetronad = handleTest ./armagetronad.nix {}; artalk = handleTest ./artalk.nix {}; atd = handleTest ./atd.nix {}; diff --git a/nixos/tests/aria2.nix b/nixos/tests/aria2.nix new file mode 100644 index 0000000000000..48fe2094b5dcf --- /dev/null +++ b/nixos/tests/aria2.nix @@ -0,0 +1,43 @@ +import ./make-test-python.nix ({ pkgs, ... }: +let + rpcSecret = "supersecret"; + rpc-listen-port = 6800; + curlBody = { + jsonrpc = 2.0; + id = 1; + method = "aria2.getVersion"; + params = [ "token:${rpcSecret}" ]; + }; +in +rec { + name = "aria2"; + + nodes.machine = { + environment.etc."aria2Rpc".text = rpcSecret; + services.aria2 = { + enable = true; + rpcSecretFile = "/etc/aria2Rpc"; + settings = { + inherit rpc-listen-port; + allow-overwrite = false; + check-integrity = true; + console-log-level = "warn"; + listen-port = [{ from = 20000; to = 20010; } { from = 22222; to = 22222; }]; + max-concurrent-downloads = 50; + seed-ratio = 1.2; + summary-interval = 0; + }; + }; + }; + + testScript = '' + machine.start() + machine.wait_for_unit("aria2.service") + curl_cmd = 'curl --fail-with-body -X POST -H "Content-Type: application/json" \ + -d \'${builtins.toJSON curlBody}\' http://localhost:${toString rpc-listen-port}/jsonrpc' + print(machine.wait_until_succeeds(curl_cmd, timeout=10)) + machine.shutdown() + ''; + + meta.maintainers = [ pkgs.lib.maintainers.timhae ]; +}) |