feat: implement more stuff with new servarr module
Some checks failed
Test action / kaas (push) Failing after 0s

This commit is contained in:
Chris Kruining 2025-12-08 16:29:02 +01:00
parent 894774be4f
commit 4826cb6a72
No known key found for this signature in database
GPG key ID: EB894A3560CCCAD2
3 changed files with 152 additions and 320 deletions

View file

@ -3,16 +3,12 @@
lib, lib,
namespace, namespace,
config, config,
inputs,
system,
... ...
}: let }: let
inherit (lib) mkIf mkEnableOption mkOption; inherit (lib) mkIf mkEnableOption mkOption;
inherit (lib.types) str; inherit (lib.types) str;
cfg = config.${namespace}.services.media; cfg = config.${namespace}.services.media;
arr = ["radarr"];
in { in {
options.${namespace}.services.media = { options.${namespace}.services.media = {
enable = mkEnableOption "Enable media services"; enable = mkEnableOption "Enable media services";
@ -60,64 +56,19 @@ in {
}; };
systemd.tmpfiles.rules = [ systemd.tmpfiles.rules = [
"d '${cfg.path}/series' 0700 ${cfg.user} ${cfg.group} - -" # "d '${cfg.path}/series' 0770 ${cfg.user} ${cfg.group} - -"
"d '${cfg.path}/movies' 0700 ${cfg.user} ${cfg.group} - -" # "d '${cfg.path}/movies' 0770 ${cfg.user} ${cfg.group} - -"
"d '${cfg.path}/music' 0700 ${cfg.user} ${cfg.group} - -" # "d '${cfg.path}/music' 0770 ${cfg.user} ${cfg.group} - -"
"d '${cfg.path}/qbittorrent' 0700 ${cfg.user} ${cfg.group} - -" "d '${cfg.path}/qbittorrent' 0770 ${cfg.user} ${cfg.group} - -"
"d '${cfg.path}/sabnzbd' 0700 ${cfg.user} ${cfg.group} - -" "d '${cfg.path}/sabnzbd' 0770 ${cfg.user} ${cfg.group} - -"
"d '${cfg.path}/reiverr/config' 0700 ${cfg.user} ${cfg.group} - -" "d '${cfg.path}/downloads/incomplete' 0770 ${cfg.user} ${cfg.group} - -"
"d '${cfg.path}/downloads/incomplete' 0700 ${cfg.user} ${cfg.group} - -" "d '${cfg.path}/downloads/done' 0770 ${cfg.user} ${cfg.group} - -"
"d '${cfg.path}/downloads/done' 0700 ${cfg.user} ${cfg.group} - -"
"d /var/lib/radarrApplyTerraform 0755 ${cfg.user} ${cfg.group} -"
]; ];
#========================================================================= #=========================================================================
# Services # Services
#========================================================================= #=========================================================================
services = let services = {
arr-services =
arr
|> lib.imap (i: service: {
name = service;
value =
{
enable = true;
openFirewall = true;
environmentFiles = [
config.sops.templates."${service}/config.env".path
];
settings = {
auth.authenticationMethod = "External";
server = {
bindaddress = "0.0.0.0";
port = 2000 + i;
};
postgres = {
host = "localhost";
port = "5432";
user = service;
maindb = service;
logdb = service;
};
};
}
// (
if service != "prowlarr"
then {
user = cfg.user;
group = cfg.group;
}
else {}
);
})
|> lib.listToAttrs;
in
arr-services
// {
bazarr = { bazarr = {
enable = true; enable = true;
openFirewall = true; openFirewall = true;
@ -126,6 +77,12 @@ in {
listenPort = 2005; listenPort = 2005;
}; };
flaresolverr = {
enable = true;
openFirewall = true;
port = 2007;
};
# port is harcoded in nixpkgs module # port is harcoded in nixpkgs module
jellyfin = { jellyfin = {
enable = true; enable = true;
@ -134,50 +91,8 @@ in {
group = cfg.group; group = cfg.group;
}; };
flaresolverr = { postgresql = {
enable = true; enable = true;
openFirewall = true;
port = 2007;
};
qbittorrent = {
enable = true;
openFirewall = true;
webuiPort = 2008;
serverConfig = {
LegalNotice.Accepted = true;
Prefecences.WebUI = {
Username = "admin";
};
};
user = cfg.user;
group = cfg.group;
};
# port is harcoded in nixpkgs module
sabnzbd = {
enable = true;
openFirewall = true;
configFile = "${cfg.path}/sabnzbd/config.ini";
user = cfg.user;
group = cfg.group;
};
postgresql = let
databases = arr |> lib.concatMap (s: [s "${s}-log"]);
in {
enable = true;
ensureDatabases = arr;
ensureUsers =
arr
|> lib.map (service: {
name = service;
ensureDBOwnership = true;
});
}; };
caddy = { caddy = {
@ -190,142 +105,15 @@ in {
}; };
}; };
systemd.services.radarrApplyTerraform = let
# this is a nix package, the generated json file to be exact
terraformConfiguration = inputs.terranix.lib.terranixConfiguration {
inherit system;
modules = [
({
config,
lib,
...
}: {
config = {
variable = {
api_key = {
type = "string";
description = "Radarr api key";
};
};
terraform.required_providers.radarr = {
source = "devopsarr/radarr";
version = "2.2.0";
};
provider.radarr = {
url = "http://127.0.0.1:2001";
api_key = lib.tfRef "var.api_key";
};
resource = {
radarr_root_folder.local = {
path = "/var/media/movies";
};
};
};
})
];
};
in {
description = "Radarr terraform apply";
wantedBy = ["multi-user.target"];
wants = ["radarr.service"];
script = ''
#!/usr/bin/env bash
if [ "$(systemctl is-active radarr)" != "active" ]; then
echo "Radarr is not running"
exit 1
fi
# Sleep for a bit to give radarr the chance to start up
sleep 5s
# Print the path to the source for easier debugging
echo "config location: ${terraformConfiguration}"
# Copy infra code into workspace
cp -f ${terraformConfiguration} config.tf.json
# Initialize OpenTofu
${lib.getExe pkgs.opentofu} init
# Run the infrastructure code
# ${lib.getExe pkgs.opentofu} plan -var-file='${config.sops.templates."radarr/config.tfvars".path}'
${lib.getExe pkgs.opentofu} apply -auto-approve -var-file='${config.sops.templates."radarr/config.tfvars".path}'
'';
serviceConfig = {
Type = "oneshot";
User = cfg.user;
Group = cfg.group;
WorkingDirectory = "/var/lib/radarrApplyTerraform";
EnvironmentFile = [
config.sops.templates."radarr/config.env".path
];
};
};
systemd.services.jellyfin.serviceConfig.killSignal = lib.mkForce "SIGKILL"; systemd.services.jellyfin.serviceConfig.killSignal = lib.mkForce "SIGKILL";
sops = { sops = {
secrets = let secrets = {
arrSecrets =
arr
|> lib.map (service: {
name = "${service}/apikey";
value = {
owner = cfg.user;
group = cfg.group;
restartUnits = ["${service}.service"];
};
})
|> lib.listToAttrs;
in
arrSecrets
// {
# "qbittorrent/password" = {}; # "qbittorrent/password" = {};
"qbittorrent/password_hash" = {}; "qbittorrent/password_hash" = {};
}; };
templates = let templates = {
apikeys =
arr
|> lib.map (service: {
name = "${service}/config.env";
value = {
owner = cfg.user;
group = cfg.group;
restartUnits = ["${service}.service"];
content = ''
${lib.toUpper service}__AUTH__APIKEY="${config.sops.placeholder."${service}/apikey"}"
'';
};
})
|> lib.listToAttrs;
tfvars =
arr
|> lib.map (service: {
name = "${service}/config.tfvars";
value = {
owner = cfg.user;
group = cfg.group;
restartUnits = ["${service}ApplyTerraform.service"];
content = ''
api_key = "${config.sops.placeholder."${service}/apikey"}"
'';
};
})
|> lib.listToAttrs;
qbittorrent = {
"qbittorrent/password.conf" = { "qbittorrent/password.conf" = {
owner = cfg.user; owner = cfg.user;
group = cfg.group; group = cfg.group;
@ -337,8 +125,6 @@ in {
''; '';
}; };
}; };
in
apikeys // tfvars // qbittorrent;
}; };
}; };
} }

View file

@ -41,7 +41,8 @@ in {
port, port,
... ...
}: (mkIf enable { }: (mkIf enable {
"${service}" = { "${service}" =
{
enable = true; enable = true;
openFirewall = true; openFirewall = true;
@ -65,12 +66,43 @@ in {
logdb = service; logdb = service;
}; };
}; };
}; }
// (lib.optionalAttrs (service != "prowlarr") {
user = service;
group = "media";
});
})) }))
|> lib.mergeAttrsList |> lib.mkMerge
|> (set: |> (set:
set set
// { // {
qbittorrent = {
enable = true;
openFirewall = true;
webuiPort = 2008;
serverConfig = {
LegalNotice.Accepted = true;
Prefecences.WebUI = {
Username = "admin";
};
};
user = "qbittorrent";
group = "media";
};
# port is harcoded in nixpkgs module
sabnzbd = {
enable = true;
openFirewall = true;
configFile = "${cfg.path}/sabnzbd/config.ini";
user = "sabnzbd";
group = "media";
};
postgresql = { postgresql = {
ensureDatabases = cfg |> lib.attrNames; ensureDatabases = cfg |> lib.attrNames;
ensureUsers = ensureUsers =
@ -83,7 +115,7 @@ in {
}; };
}); });
systemd = systemd.services =
cfg cfg
|> lib.mapAttrsToList (service: { |> lib.mapAttrsToList (service: {
enable, enable,
@ -92,11 +124,7 @@ in {
rootFolders, rootFolders,
... ...
}: (mkIf enable { }: (mkIf enable {
tmpfiles.rules = [ "${service}ApplyTerraform" = let
"d /var/lib/${service}ApplyTerraform 0755 ${service} ${service} -"
];
services."${service}ApplyTerraform" = let
terraformConfiguration = inputs.terranix.lib.terranixConfiguration { terraformConfiguration = inputs.terranix.lib.terranixConfiguration {
inherit system; inherit system;
@ -116,7 +144,17 @@ in {
terraform.required_providers.${service} = { terraform.required_providers.${service} = {
source = "devopsarr/${service}"; source = "devopsarr/${service}";
version = "2.2.0"; version =
{
radarr = "2.3.3";
sonarr = "3.4.0";
prowlarr = "3.1.0";
lidarr = "1.13.0";
readarr = "2.1.0";
whisparr = "1.2.0";
}.${
service
};
}; };
provider.${service} = { provider.${service} = {
@ -125,10 +163,11 @@ in {
}; };
resource = { resource = {
"${service}_root_folder" = "${service}_root_folder" = mkIf (lib.elem service ["radarr" "sonarr" "whisparr"]) (
rootFolders rootFolders
|> lib.imap (i: f: lib.nameValuePair "local${toString i}" {path = f;}) |> lib.imap (i: f: lib.nameValuePair "local${toString i}" {path = f;})
|> lib.listToAttrs; |> lib.listToAttrs
);
}; };
}; };
}) })
@ -140,9 +179,16 @@ in {
wantedBy = ["multi-user.target"]; wantedBy = ["multi-user.target"];
wants = ["${service}.service"]; wants = ["${service}.service"];
script = '' preStart = ''
#!/usr/bin/env bash install -d -m 0770 -o ${service} -g media /var/lib/${service}ApplyTerraform
${
rootFolders
|> lib.map (folder: "install -d -m 0770 -o media -g media ${folder}")
|> lib.join "\n"
}
'';
script = ''
# Sleep for a bit to give the service a chance to start up # Sleep for a bit to give the service a chance to start up
sleep 5s sleep 5s
@ -158,7 +204,7 @@ in {
cp -f ${terraformConfiguration} config.tf.json cp -f ${terraformConfiguration} config.tf.json
# Initialize OpenTofu # Initialize OpenTofu
${lib.getExe pkgs.opentofu} init ${lib.getExe pkgs.opentofu} init -upgrade
# Run the infrastructure code # Run the infrastructure code
${lib.getExe pkgs.opentofu} \ ${lib.getExe pkgs.opentofu} \
@ -173,7 +219,7 @@ in {
serviceConfig = { serviceConfig = {
Type = "oneshot"; Type = "oneshot";
User = service; User = service;
Group = service; Group = "media";
WorkingDirectory = "/var/lib/${service}ApplyTerraform"; WorkingDirectory = "/var/lib/${service}ApplyTerraform";
@ -183,28 +229,33 @@ in {
}; };
}; };
})) }))
|> lib.mergeAttrsList; |> lib.mkMerge;
users.users = users =
cfg cfg
|> lib.mapAttrsToList (service: {enable, ...}: (mkIf enable { |> lib.mapAttrsToList (service: {enable, ...}: (mkIf enable {
"${service}".extraGroups = ["media"]; users.${service} = {
isSystemUser = true;
group = lib.mkDefault service;
extraGroups = ["media"];
};
groups.${service} = {};
})) }))
|> lib.mergeAttrsList; |> lib.mkMerge;
sops = sops =
cfg cfg
|> lib.mapAttrsToList (service: {enable, ...}: (mkIf enable { |> lib.mapAttrsToList (service: {enable, ...}: (mkIf enable {
secrets."${service}/apikey" = { secrets."${service}/apikey" = {
owner = service; owner = service;
group = service; group = "media";
restartUnits = ["${service}.service"]; restartUnits = ["${service}.service"];
}; };
templates = { templates = {
"${service}/config.env" = { "${service}/config.env" = {
owner = service; owner = service;
group = service; group = "media";
restartUnits = ["${service}.service"]; restartUnits = ["${service}.service"];
content = '' content = ''
${lib.toUpper service}__AUTH__APIKEY="${config.sops.placeholder."${service}/apikey"}" ${lib.toUpper service}__AUTH__APIKEY="${config.sops.placeholder."${service}/apikey"}"
@ -213,7 +264,7 @@ in {
"${service}/config.tfvars" = { "${service}/config.tfvars" = {
owner = service; owner = service;
group = service; group = "media";
restartUnits = ["${service}.service"]; restartUnits = ["${service}.service"];
content = '' content = ''
api_key = "${config.sops.placeholder."${service}/apikey"}" api_key = "${config.sops.placeholder."${service}/apikey"}"
@ -221,15 +272,6 @@ in {
}; };
}; };
})) }))
|> lib.mergeAttrsList; |> lib.mkMerge;
}; };
# cfg
# |> lib.mapAttrsToList (service: { enable, debug, port, rootFolders, ... }: (mkIf enable {
# # sops = {
# # };
# }))
# |> lib.mergeAttrsList
# ;
} }

View file

@ -165,9 +165,13 @@
media.mydia.enable = true; media.mydia.enable = true;
media.nfs.enable = true; media.nfs.enable = true;
media.servarr = { media.servarr = {
# radarr = { radarr = {
# port = 2001; enable = true;
# }; port = 2001;
rootFolders = [
"/var/media/movies"
];
};
sonarr = { sonarr = {
enable = true; enable = true;