# modules/lib/helpers.nix {lib, ...}: with lib; rec { # Helper to merge global configurations from multiple sources mergeGlobalConfigs = configs: let mergeEndpoints = foldl' (acc: cfg: acc ++ cfg.monitoring.endpoints) []; mergeBackups = foldl' (acc: cfg: acc ++ cfg.backups.jobs) []; mergeProxyEntries = foldl' (acc: cfg: acc ++ cfg.reverseProxy.entries) []; in { monitoring.endpoints = mergeEndpoints configs; backups.jobs = mergeBackups configs; reverseProxy.entries = mergeProxyEntries configs; }; # Helper to create a service module template createServiceModule = { name, port, hasMetrics ? true, hasWebUI ? true, dataDir ? "/var/lib/${name}", }: { config, lib, pkgs, ... }: with lib; let cfg = config.services.${name}; in { options.services.${name} = { enable = mkEnableOption "${name} service"; port = mkOption { type = types.port; default = port; description = "Port for ${name}"; }; dataDir = mkOption { type = types.str; default = dataDir; description = "Data directory for ${name}"; }; enableMetrics = mkOption { type = types.bool; default = hasMetrics; description = "Enable metrics endpoint"; }; exposeWeb = mkOption { type = types.bool; default = hasWebUI; description = "Expose web interface"; }; }; config = mkIf cfg.enable { homelab.global = { backups.jobs = [ { name = "${name}-data"; backend = "restic"; paths = [cfg.dataDir]; schedule = "daily"; } ]; reverseProxy.entries = mkIf cfg.exposeWeb [ { subdomain = name; port = cfg.port; } ]; monitoring.endpoints = mkIf cfg.enableMetrics [ { name = name; port = cfg.port; path = "/metrics"; jobName = name; } ]; }; }; }; # Helper to generate nginx configuration from proxy entries generateNginxConfig = proxyEntries: domain: let createVHost = entry: { "${entry.subdomain}.${domain}" = { enableACME = entry.enableSSL; forceSSL = entry.enableSSL; locations."${entry.path}" = { proxyPass = "http://${entry.targetHost}:${toString entry.port}"; proxyWebsockets = entry.websockets; extraConfig = '' proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; ${concatStringsSep "\n" (mapAttrsToList ( name: value: "proxy_set_header ${name} ${value};" ) entry.customHeaders)} ''; }; }; }; in foldl' (acc: entry: acc // (createVHost entry)) {} proxyEntries; # Helper to generate Prometheus scrape configs generatePrometheusConfig = endpoints: let endpointsByJob = groupBy (e: e.jobName) endpoints; createJobConfig = jobName: jobEndpoints: { job_name = jobName; scrape_interval = (head jobEndpoints).scrapeInterval; metrics_path = (head jobEndpoints).path; static_configs = [ { targets = map (e: "${e.targetHost}:${toString e.port}") jobEndpoints; labels = foldl' (acc: e: acc // e.labels) {} jobEndpoints; } ]; }; in mapAttrsToList createJobConfig endpointsByJob; }