Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Aria2 module settings #303429

Merged
merged 3 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions maintainers/maintainer-list.nix
Original file line number Diff line number Diff line change
Expand Up @@ -20141,6 +20141,12 @@
githubId = 14172;
name = "Tim Cuthbertson";
};
timhae = {
email = "tim.haering@posteo.net";
githubId = 6264882;
github = "timhae";
name = "Tim Häring";
};
timma = {
email = "kunduru.it.iitb@gmail.com";
github = "ktrsoft";
Expand Down
170 changes: 106 additions & 64 deletions nixos/modules/services/networking/aria2.nix
Original file line number Diff line number Diff line change
@@ -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 = {
Expand All @@ -107,30 +146,33 @@ 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 = {
description = "aria2 Service";
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 ];
}
1 change: 1 addition & 0 deletions nixos/tests/all-tests.nix
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,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 {};
atd = handleTest ./atd.nix {};
atop = handleTest ./atop.nix {};
Expand Down
43 changes: 43 additions & 0 deletions nixos/tests/aria2.nix
Original file line number Diff line number Diff line change
@@ -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
ambroisie marked this conversation as resolved.
Show resolved Hide resolved
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 ];
})
8 changes: 6 additions & 2 deletions pkgs/tools/networking/aria2/default.nix
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{ lib, stdenv, fetchFromGitHub, fetchpatch, pkg-config, autoreconfHook
, gnutls, c-ares, libxml2, sqlite, zlib, libssh2
, cppunit, sphinx
, Security
, Security, nixosTests
}:

stdenv.mkDerivation rec {
Expand Down Expand Up @@ -38,12 +38,16 @@ stdenv.mkDerivation rec {

enableParallelBuilding = true;

passthru.tests = {
aria2 = nixosTests.aria2;
};

meta = with lib; {
homepage = "https://aria2.github.io";
description = "A lightweight, multi-protocol, multi-source, command-line download utility";
mainProgram = "aria2c";
license = licenses.gpl2Plus;
platforms = platforms.unix;
maintainers = with maintainers; [ Br1ght0ne koral ];
maintainers = with maintainers; [ Br1ght0ne koral timhae ];
};
}