126 lines
3.6 KiB
Nix
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;
|
|
}
|