206 lines
7.2 KiB
Nix
206 lines
7.2 KiB
Nix
{ lib, config, pkgs }:
|
|
|
|
with lib;
|
|
|
|
{
|
|
mkPodmanService = {
|
|
name,
|
|
description,
|
|
defaultPort ? "0",
|
|
defaultSubdomain ? name,
|
|
pod ? name,
|
|
reverseProxied ? true,
|
|
composeText,
|
|
scheme ? "http",
|
|
middlewares ? null,
|
|
dependencies ? [ "traefik.service" "${config.numbus.services.dns}.service" ],
|
|
extraOptions ? {},
|
|
extraConfig ? {},
|
|
configDirEnabled ? true,
|
|
dataDirEnabled ? true,
|
|
startDelay ? 180,
|
|
dirPermissions ? [],
|
|
generatedSecrets ? {},
|
|
importedSecrets ? {},
|
|
envFile ? null,
|
|
...
|
|
}:
|
|
|
|
let
|
|
cfg = config.numbus.services.${name};
|
|
hasSecrets = (generatedSecrets != {}) || (importedSecrets != {});
|
|
envFilePath = if envFile == null then "/var/lib/numbus-server/${name}/.env" else envFile;
|
|
envFileArg = if hasSecrets || envFile != null then "--env-file ${envFilePath}" else "";
|
|
in
|
|
|
|
{
|
|
options.numbus.services.${name} = recursiveUpdate ({
|
|
enable = mkEnableOption description;
|
|
|
|
subdomain = mkOption {
|
|
type = types.str;
|
|
default = defaultSubdomain;
|
|
example = defaultSubdomain;
|
|
description = "The subdomain that ${name} will use";
|
|
};
|
|
|
|
port = mkOption {
|
|
type = types.str;
|
|
default = defaultPort;
|
|
example = defaultPort;
|
|
description = "The port that ${name} will use.";
|
|
};
|
|
|
|
reverseProxied = mkOption {
|
|
type = types.bool;
|
|
default = reverseProxied;
|
|
example = reverseProxied;
|
|
description = "Whether to create a Traefik reverse proxy configuration for this service.";
|
|
};
|
|
} // (optionalAttrs configDirEnabled {
|
|
configDir = mkOption {
|
|
type = types.str;
|
|
default = "/mnt/config/${name}";
|
|
example = "/mnt/config/${name}";
|
|
description = "The directory where ${name}'s configuration files will be stored";
|
|
};
|
|
}) // (optionalAttrs dataDirEnabled {
|
|
dataDir = mkOption {
|
|
type = types.str;
|
|
default = "/mnt/data/${name}";
|
|
example = "/mnt/data/${name}";
|
|
description = "The directory where ${name}'s data will be stored";
|
|
};
|
|
})) extraOptions;
|
|
|
|
config = mkIf cfg.enable (mkMerge [
|
|
{
|
|
environment.etc."podman/${name}/compose.yaml".text = composeText;
|
|
|
|
environment.etc."traefik/rules/${name}.yaml" = mkIf cfg.reverseProxied {
|
|
text = ''
|
|
http:
|
|
routers:
|
|
${name}:
|
|
rule: "Host(`${cfg.subdomain}.${config.numbus.services.domain}`)"
|
|
entrypoints:
|
|
- "websecure"
|
|
service: ${name}
|
|
middlewares:
|
|
${concatStringsSep "\n" (map (m: " - ${m}") middlewares)}
|
|
tls:
|
|
certresolver: "cloudflare"
|
|
options: "secureTLS"
|
|
services:
|
|
${name}:
|
|
loadBalancer:
|
|
servers:
|
|
- url: "${scheme}://host.containers.internal:${cfg.port}"
|
|
'';
|
|
};
|
|
|
|
systemd.services."${name}" = {
|
|
description = "Podman container : ${name}";
|
|
after = dependencies;
|
|
wantedBy = [ "multi-user.target" ];
|
|
onFailure = [ "service-failure-notify@%n.service" ];
|
|
startLimitBurst = 5;
|
|
startLimitIntervalSec = 600;
|
|
path = [ pkgs.podman pkgs.podman-compose pkgs.slirp4netns pkgs.su pkgs.sudo pkgs.coreutils ];
|
|
serviceConfig = {
|
|
Type = "exec";
|
|
TimeoutStartSec = "1000";
|
|
ExecStartPre = [
|
|
"${pkgs.bash}/bin/bash -c 'sleep $((RANDOM % ${toString startDelay}))'"
|
|
"${pkgs.bash}/bin/bash -c 'export PATH=/run/wrappers/bin:$PATH; exec ${pkgs.sudo}/bin/sudo -u numbus-admin podman-compose -f /etc/podman/${name}/compose.yaml pull'"
|
|
];
|
|
ExecStart = "${pkgs.bash}/bin/bash -c 'export PATH=/run/wrappers/bin:$PATH; exec ${pkgs.sudo}/bin/sudo -u numbus-admin podman-compose ${envFileArg} --in-pod ${toString pod} -f /etc/podman/${name}/compose.yaml up --remove-orphans'";
|
|
ExecStop = "${pkgs.bash}/bin/bash -c 'export PATH=/run/wrappers/bin:$PATH; exec ${pkgs.sudo}/bin/sudo -u numbus-admin podman-compose ${envFileArg} --in-pod ${toString pod} -f /etc/podman/${name}/compose.yaml down'";
|
|
Restart = "on-failure";
|
|
RestartSec = "3m";
|
|
};
|
|
};
|
|
|
|
systemd.services."${name}-permissions" = mkIf (dirPermissions != []) {
|
|
description = "Podman container : ${name} : check and fix permissions";
|
|
before = [ "${name}.service" ];
|
|
wantedBy = [ "multi-user.target" "${name}.service" ];
|
|
onFailure = [ "service-failure-notify@%n.service" ];
|
|
startLimitBurst = 5;
|
|
startLimitIntervalSec = 600;
|
|
path = [ pkgs.coreutils ];
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
RemainAfterExit = true;
|
|
Restart = "on-failure";
|
|
RestartSec = "5m";
|
|
};
|
|
script = ''
|
|
${concatStringsSep "\n" (map (perm: ''
|
|
set -- ${perm}
|
|
WANTED_PERMISSIONS=$1
|
|
FOLDER_PATH=$2
|
|
|
|
if [[ ! -e "$FOLDER_PATH" ]]; then
|
|
mkdir -p "$FOLDER_PATH"
|
|
elif [[ ! -d "$FOLDER_PATH" ]]; then
|
|
rm "$FOLDER_PATH"
|
|
mkdir -p "$FOLDER_PATH"
|
|
fi
|
|
|
|
ACTUAL_PERMISSIONS=$(stat -c '%u:%g' "$FOLDER_PATH")
|
|
if [[ "$ACTUAL_PERMISSIONS" != "$WANTED_PERMISSIONS" ]]; then
|
|
chown -R "$WANTED_PERMISSIONS" "$FOLDER_PATH"
|
|
fi
|
|
'') dirPermissions)}
|
|
exit 0
|
|
'';
|
|
};
|
|
|
|
systemd.services."${name}-secrets" = mkIf hasSecrets {
|
|
description = "Podman container create secrets : ${name}";
|
|
before = [ "${name}.service" ];
|
|
wantedBy = [ "multi-user.target" "${name}.service" ];
|
|
onFailure = [ "service-failure-notify@%n.service" ];
|
|
startLimitBurst = 5;
|
|
startLimitIntervalSec = 600;
|
|
path = [ pkgs.coreutils pkgs.xkcdpass pkgs.gnugrep ];
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
RemainAfterExit = true;
|
|
Restart = "on-failure";
|
|
RestartSec = "5m";
|
|
};
|
|
script = ''
|
|
mkdir -p /var/lib/numbus-server/${name}
|
|
SECRETS_FILE="${envFilePath}"
|
|
|
|
if [[ ! -f "$SECRETS_FILE" ]]; then
|
|
touch "$SECRETS_FILE"
|
|
fi
|
|
|
|
# Generated Secrets (only if missing)
|
|
${concatStringsSep "\n" (mapAttrsToList (k: v: ''
|
|
if ! grep -q "^${k}=" "$SECRETS_FILE"; then
|
|
echo "${k}=\"$(${v})\"" >> "$SECRETS_FILE"
|
|
fi
|
|
'') generatedSecrets)}
|
|
|
|
# Imported Secrets (update or append)
|
|
${concatStringsSep "\n" (mapAttrsToList (k: v: ''
|
|
if grep -q "^${k}=" "$SECRETS_FILE"; then
|
|
grep -v "^${k}=" "$SECRETS_FILE" > "$SECRETS_FILE.tmp"
|
|
mv "$SECRETS_FILE.tmp" "$SECRETS_FILE"
|
|
fi
|
|
echo "${k}=\"${lib.escapeShellArg v}\"" >> "$SECRETS_FILE"
|
|
'') importedSecrets)}
|
|
|
|
chown numbus-admin:users "$SECRETS_FILE"
|
|
chmod 600 "$SECRETS_FILE"
|
|
'';
|
|
};
|
|
}
|
|
extraConfig
|
|
]);
|
|
};
|
|
} |