ooknet/modules/nixos/server/services/ookflix/lib.nix

147 lines
4.5 KiB
Nix

{
lib,
config,
self,
...
}: let
inherit (lib) getExe nameValuePair mkOption mkEnableOption elem assertMsg;
inherit (builtins) attrValues;
inherit (lib.types) int path port str;
inherit (config.ooknet) server;
inherit (config.virtualisation) podman;
cfg = server.ookflix;
ookflixEnabled = elem "ookflix" server.services;
mkSubdomainOption = name: description: example:
mkOption {
type = str;
default = "${name}.${server.domain}";
inherit description example;
};
# check config.ids for static uid/gid based on service name, if available use that, if not, use fallback.
# check fallback doesnt conflict with existing static id
getId = idType: name: fallback: let
allNixosIds = attrValues config.ids.${idType};
fallbackConflict = elem fallback allNixosIds;
in
mkOption {
type = int;
default =
config.ids.${idType}.${name}
or (
assert assertMsg (!fallbackConflict)
"Fallback ${idType} ${toString fallback} for ${name} conflicts with NixOS static allocation"; fallback
);
description = "${idType} of ${name} container";
example = 224;
};
mkUserOption = name: fallback: {
name = mkOption {
type = str;
default = name;
description = "Name of ${name} container user";
example = "${name}";
};
id = getId "uids" name fallback;
};
mkGroupOption = name: fallback: {
name = mkOption {
type = str;
default = name;
};
id = getId "gids" name fallback;
};
mkPortOption = value: description: example:
mkOption {
type = port;
default = value;
inherit description example;
};
mkVolumeOption = rootPath: pathValue:
mkOption {
type = path;
default =
if rootPath == "state"
then "${cfg.volumes.state.root}/${pathValue}"
else if rootPath == "data"
then "${cfg.volumes.data.root}/${pathValue}"
else if rootPath == "media"
then "${cfg.volumes.media.root}/${pathValue}"
else if rootPath == "torrents"
then "${cfg.volumes.torrents.root}/${pathValue}"
else if rootPath == "usenet"
then "${cfg.volumes.usenet.root}/${pathValue}"
else if rootPath == "usenet/complete"
then "${cfg.volumes.usenet.complete.root}/${pathValue}"
else if rootPath == "root"
then pathValue
else throw "Invalid VolumeOption rootPath: ${rootPath}. Must be one of 'state' 'data' 'media' 'torrents' 'usenet' 'usenet/complete' 'root'";
};
mkServiceOptions = name: {
port,
gid,
uid,
...
} @ args: {
enable = mkEnableOption "Enable ${name} container" // {default = ookflixEnabled;};
port = mkPortOption args.port "Port for ${name} container." 80;
domain = mkSubdomainOption name "Domain for ${name} container." "${name}.mydomain.com";
stateDir = mkVolumeOption "state" name;
user = mkUserOption name args.uid;
group = mkGroupOption name args.gid;
};
mkBasicServiceOptions = name: {
gid,
uid,
...
} @ args: {
enable = mkEnableOption "Enable ${name} container" // {default = ookflixEnabled;};
user = mkUserOption name args.uid;
group = mkGroupOption name args.gid;
};
mkServiceUser = service: {
users.${service} = {
isSystemUser = true;
uid = cfg.services.${service}.user.id;
name = service;
group = service;
};
groups.${service} = {
gid = cfg.services.${service}.group.id;
name = service;
};
};
mkServiceStateDir = service: {
"${cfg.services.${service}.stateDir}"."d" = {
mode = "0700";
user = cfg.services.${service}.user.name;
group = cfg.services.${service}.group.name;
};
};
mkServiceStateFile = service: file: {
"${cfg.services.${service}.stateDir}/${file}"."f" = {
mode = "0600";
user = cfg.services.${service}.user.name;
group = cfg.services.${service}.group.name;
};
};
mkNetworkService = name: _network:
nameValuePair "podman-network-${name}" {
description = "Podman network ${name} for ookflix";
serviceConfig = {
Type = "oneshot";
RemainsAfterExit = true;
ExecStart = "${getExe podman.package} network create -d bridge ${name}";
ExecStop = "${getExe podman.package} network rm -f ${name}";
};
};
in {
inherit mkServiceStateFile mkBasicServiceOptions mkServiceOptions mkServiceStateDir mkServiceUser mkUserOption mkPortOption mkGroupOption mkVolumeOption mkSubdomainOption mkNetworkService;
}