{ lib, config, pkgs }: with lib; { mkPodmanService = { description, name, secondName ? null, thirdName ? null, defaultSubdomain ? name, secondDefaultSubdomain ? secondName, thirdDefaultSubdomain ? thirdName, defaultPort ? "", secondDefaultPort ? "", thirdDefaultPort ? "", scheme ? "http", secondScheme ? "http", thirdScheme ? "http", reverseProxied ? true, secondReverseProxied ? false, thirdReverseProxied ? false, configDirEnabled ? true, secondConfigDirEnabled ? false, thirdConfigDirEnabled ? false, dataDirEnabled ? true, secondDataDirEnabled ? false, thirdDataDirEnabled ? false, pod ? "false", composeText, extraOptions ? {}, extraConfig ? {}, delaySec ? 180, useSopsSecrets ? false, # New argument to enable sops integration middlewares ? [ "secureHeaders" ], dependencies ? [ "traefik.service" "${config.numbus.services.dns}.service" ], }: let mkServiceOpts = svcName: svcDesc: svcPort: svcSubdomain: svcReverseProxied: svcConfigDir: svcDataDir: { numbus.services.${svcName} = { enable = mkEnableOption svcDesc; subdomain = mkOption { type = types.str; default = svcSubdomain; example = svcSubdomain; description = "The subdomain that ${svcName} will use"; }; port = mkOption { type = types.str; default = svcPort; example = svcPort; description = "The port that ${svcName} will use."; }; reverseProxied = mkOption { type = types.bool; default = svcReverseProxied; description = "Whether to create a Traefik reverse proxy configuration for this service."; }; } // (optionalAttrs svcConfigDir { configDir = mkOption { type = types.str; default = "/mnt/config/${svcName}"; example = "/mnt/config/${svcName}"; description = "The directory where ${svcName}'s configuration files will be stored"; }; }) // (optionalAttrs svcDataDir { dataDir = mkOption { type = types.str; default = "/mnt/data/${svcName}"; example = "/mnt/data/${svcName}"; description = "The directory where ${svcName}'s data will be stored"; }; }); }; cfg = config.numbus.services.${name}; cfg2 = if secondName != null then config.numbus.services.${secondName} else {}; cfg3 = if thirdName != null then config.numbus.services.${thirdName} else {}; mkTraefikConfig = svcName: svcCfg: svcScheme: mkIf (cfg.enable && svcCfg.reverseProxied) { text = '' http: routers: ${svcName}: rule: "Host(`${svcCfg.subdomain}.${config.numbus.services.domain}`)" entrypoints: - "websecure" service: ${svcName} middlewares: ${concatStringsSep "\n" (map (m: " - ${m}") middlewares)} tls: certresolver: "cloudflare" options: "secureTLS" services: ${svcName}: loadBalancer: servers: - url: "${svcScheme}://host.containers.internal:${svcCfg.port}" ''; }; in { options = mkMerge [ (mkServiceOpts name description defaultPort defaultSubdomain reverseProxied configDirEnabled dataDirEnabled) (optionalAttrs (secondName != null) (mkServiceOpts secondName "Secondary service for ${name}" secondDefaultPort secondDefaultSubdomain secondReverseProxied secondConfigDirEnabled secondDataDirEnabled)) (optionalAttrs (thirdName != null) (mkServiceOpts thirdName "Tertiary service for ${name}" thirdDefaultPort thirdDefaultSubdomain thirdReverseProxied thirdConfigDirEnabled thirdDataDirEnabled)) { numbus.services.${name} = extraOptions; } ]; config = mkIf cfg.enable (mkMerge [ { environment.etc."podman/${name}/compose.yaml".text = composeText; environment.etc = mkMerge [ { "${config.numbus.traefikDynamicConfigDir}/${name}.yaml" = mkTraefikConfig name cfg scheme; } (mkIf (secondName != null) { "${config.numbus.traefikDynamicConfigDir}/${secondName}.yaml" = mkTraefikConfig secondName cfg2 secondScheme; }) (mkIf (thirdName != null) { "${config.numbus.traefikDynamicConfigDir}/${thirdName}.yaml" = mkTraefikConfig thirdName cfg3 thirdScheme; }) ]; systemd.services."${name}" = { description = "Podman container : ${name}"; requires = dependencies; after = dependencies; wantedBy = [ "multi-user.target" ]; path = [ pkgs.podman pkgs.podman-compose pkgs.coreutils pkgs.sudo ]; serviceConfig = { Type = "exec"; ExecStartPre = [ "bash -c 'sleep $((RANDOM % ${toString delaySec}))'" "- sudo -u numbus-admin podman-compose -f /etc/podman/${name}/compose.yaml pull" ]; ExecStart = "sudo -u numbus-admin podman-compose --in-pod ${toString pod} -f /etc/podman/${name}/compose.yaml up --remove-orphans"; ExecStop = "sudo -u numbus-admin podman-compose --in-pod ${toString pod} -f /etc/podman/${name}/compose.yaml down"; Restart = "on-failure"; RestartSec = "1m"; StartLimitBurst = "5"; }; }; } extraConfig ]); }; }