homelab/modules/lib/helpers.nix
plasmagoat bcbcc8b17b
Some checks failed
Test / tests (push) Has been cancelled
/ OpenTofu (push) Has been cancelled
homelab framework module init (everything is a mess)
2025-07-28 02:05:13 +02:00

126 lines
3.6 KiB
Nix

# 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;
}