services...

This commit is contained in:
plasmagoat 2025-07-30 00:22:33 +02:00
parent 73d2f44d74
commit 8552656731
15 changed files with 918 additions and 490 deletions

View file

@ -6,9 +6,18 @@ serviceName: {
with lib; let
cfg = config.homelab.services.${serviceName};
homelabCfg = config.homelab;
shouldEnableLogging =
cfg.logging.files
!= []
|| cfg.logging.extraSources != [];
in {
options.homelab.services.${serviceName}.logging = {
enable = mkEnableOption "logging for ${serviceName}";
enable = mkOption {
type = types.bool;
description = "Enable logging for ${serviceName}";
default = shouldEnableLogging;
};
files = mkOption {
type = types.listOf types.str;
@ -51,37 +60,33 @@ in {
};
};
config = mkIf (cfg.enable && cfg.logging.enable) {
homelab.logging.sources =
[
{
name = "${serviceName}-logs";
type = "file";
files = {
paths = cfg.logging.files;
multiline = cfg.logging.multiline;
config = mkIf cfg.enable {
homelab.logging.sources = mkIf cfg.logging.enable (
# Only create file source if files are specified
(optional (cfg.logging.files != []) {
name = "${serviceName}-logs";
type = "file";
files = {
paths = cfg.logging.files;
multiline = cfg.logging.multiline;
};
labels =
cfg.logging.extraLabels
// {
service = serviceName;
node = homelabCfg.hostname;
environment = homelabCfg.environment;
};
labels =
cfg.logging.extraLabels
// {
service = serviceName;
node = homelabCfg.hostname;
environment = homelabCfg.environment;
};
pipelineStages =
mkIf (cfg.logging.parsing.regex != null) [
{
regex.expression = cfg.logging.parsing.regex;
}
]
++ [
{
labels = listToAttrs (map (field: nameValuePair field null) cfg.logging.parsing.extractFields);
}
];
enabled = true;
}
]
++ cfg.logging.extraSources;
pipelineStages =
(optional (cfg.logging.parsing.regex != null) {
regex.expression = cfg.logging.parsing.regex;
})
++ (optional (cfg.logging.parsing.extractFields != []) {
labels = listToAttrs (map (field: nameValuePair field null) cfg.logging.parsing.extractFields);
});
enabled = true;
})
++ cfg.logging.extraSources
);
};
}

View file

@ -6,47 +6,69 @@ serviceName: {
with lib; let
cfg = config.homelab.services.${serviceName};
homelabCfg = config.homelab;
hasMetricsConfig =
cfg.monitoring.metrics.path
!= null
|| cfg.monitoring.metrics.extraEndpoints != [];
hasHealthCheckConfig =
cfg.monitoring.healthCheck.path
!= null
|| cfg.monitoring.healthCheck.conditions != []
|| cfg.monitoring.healthCheck.extraChecks != [];
in {
# Define the service-specific monitoring options
options.homelab.services.${serviceName}.monitoring = {
enable = mkEnableOption "monitoring for ${serviceName}";
enable = mkOption {
type = types.bool;
description = "Enable monitoring for ${serviceName}";
default = hasMetricsConfig || hasHealthCheckConfig;
};
metrics = {
enable = mkOption {
type = types.bool;
default = true;
default = hasMetricsConfig;
};
path = mkOption {
type = types.str;
default = "/metrics";
type = types.nullOr types.str;
default = null;
description = "Metrics endpoint path. Setting this enables metrics collection.";
};
extraEndpoints = mkOption {
type = types.listOf types.attrs;
default = [];
description = "Additional metrics endpoints. Adding endpoints enables metrics collection.";
};
};
healthCheck = {
enable = mkOption {
type = types.bool;
default = true;
default = hasHealthCheckConfig;
};
path = mkOption {
type = types.str;
default = "/health";
type = types.nullOr types.str;
default = null;
description = "Health check endpoint path. Setting this enables health checks.";
example = "/health";
};
conditions = mkOption {
type = types.listOf types.str;
default = ["[STATUS] == 200"];
description = "Health check conditions. Setting conditions enables health checks.";
example = ["[STATUS] == 200"];
};
extraChecks = mkOption {
type = types.listOf types.attrs;
default = [];
description = "Additional health checks. Adding checks enables health monitoring.";
};
};
@ -57,52 +79,50 @@ in {
};
# Generate the homelab config automatically when service is enabled
config = mkIf (cfg.enable && cfg.monitoring.enable) {
homelab.monitoring = {
metrics =
[
{
name = "${serviceName}-main";
host = homelabCfg.hostname;
port = cfg.port;
path = cfg.monitoring.metrics.path;
jobName = serviceName;
scrapeInterval = "30s";
labels =
cfg.monitoring.extraLabels
// {
service = serviceName;
node = homelabCfg.hostname;
environment = homelabCfg.environment;
};
}
]
++ cfg.monitoring.metrics.extraEndpoints;
config = mkIf cfg.enable {
homelab.monitoring = mkIf cfg.monitoring.enable {
metrics = mkIf hasMetricsConfig (
(optional (cfg.monitoring.metrics.path != null) {
name = "${serviceName}-main";
host = homelabCfg.hostname;
port = cfg.port;
path = cfg.monitoring.metrics.path;
jobName = serviceName;
scrapeInterval = "30s";
labels =
cfg.monitoring.extraLabels
// {
service = serviceName;
node = homelabCfg.hostname;
environment = homelabCfg.environment;
};
})
++ cfg.monitoring.metrics.extraEndpoints
);
healthChecks =
[
{
name = "${serviceName}-health";
host = homelabCfg.hostname;
port = cfg.port;
path = cfg.monitoring.healthCheck.path;
protocol = "http";
method = "GET";
interval = "30s";
timeout = "10s";
conditions = cfg.monitoring.healthCheck.conditions;
group = "services";
labels =
cfg.monitoring.extraLabels
// {
service = serviceName;
node = homelabCfg.hostname;
environment = homelabCfg.environment;
};
enabled = true;
}
]
++ cfg.monitoring.healthCheck.extraChecks;
healthChecks = mkIf hasHealthCheckConfig (
(optional (cfg.monitoring.healthCheck.path != null) {
name = "${serviceName}-health";
host = homelabCfg.hostname;
port = cfg.port;
path = cfg.monitoring.healthCheck.path;
protocol = "http";
method = "GET";
interval = "30s";
timeout = "10s";
conditions = cfg.monitoring.healthCheck.conditions;
group = "services";
labels =
cfg.monitoring.extraLabels
// {
service = serviceName;
node = homelabCfg.hostname;
environment = homelabCfg.environment;
};
enabled = true;
})
++ cfg.monitoring.healthCheck.extraChecks
);
};
};
}

View file

@ -8,7 +8,11 @@ with lib; let
homelabCfg = config.homelab;
in {
options.homelab.services.${serviceName}.proxy = {
enable = mkEnableOption "reverse proxy for ${serviceName}";
enable = mkOption {
type = types.bool;
description = "Enable reverse proxy for ${serviceName}";
default = true;
};
subdomain = mkOption {
type = types.str;
@ -39,8 +43,8 @@ in {
};
};
config = mkIf (cfg.enable && cfg.proxy.enable) {
homelab.reverseProxy.entries =
config = mkIf cfg.enable {
homelab.reverseProxy.entries = mkIf cfg.proxy.enable (
[
{
subdomain = cfg.proxy.subdomain;
@ -59,6 +63,7 @@ in {
enableAuth = sub.enableAuth;
enableSSL = true;
})
cfg.proxy.additionalSubdomains;
cfg.proxy.additionalSubdomains
);
};
}

View file

@ -219,8 +219,7 @@ in {
homelab.services.${serviceName}.monitoring.enable = mkDefault true;
}
# Smart defaults for Gatus
(mkIf cfg.monitoring.enable {
{
homelab.services.${serviceName}.monitoring = mkDefault {
metrics = {
path = "/metrics";
@ -240,9 +239,9 @@ in {
tier = "monitoring";
};
};
})
}
(mkIf cfg.logging.enable {
{
homelab.services.${serviceName}.logging = mkDefault {
files = ["/var/log/gatus/gatus.log"];
parsing = {
@ -255,13 +254,13 @@ in {
application = "gatus";
};
};
})
}
(mkIf cfg.proxy.enable {
{
homelab.services.${serviceName}.proxy = mkDefault {
subdomain = "status";
enableAuth = false; # Status page should be public
};
})
}
]);
}

View file

@ -45,7 +45,7 @@ in {
}
# Smart defaults for Grafana
(mkIf cfg.logging.enable {
{
# Grafana-specific log setup
homelab.services.${serviceName}.logging = mkDefault {
files = ["/var/log/grafana/grafana.log"];
@ -59,9 +59,8 @@ in {
component = "dashboard";
};
};
})
(mkIf cfg.monitoring.enable {
}
{
homelab.services.${serviceName}.monitoring = mkDefault {
metrics.path = "/metrics";
healthCheck = {
@ -73,14 +72,13 @@ in {
tier = "monitoring";
};
};
})
(mkIf cfg.proxy.enable {
}
{
# Grafana needs auth by default (admin interface)
homelab.services.${serviceName}.proxy = mkDefault {
subdomain = "grafana";
# enableAuth = true;
};
})
}
]);
}

View file

@ -168,7 +168,6 @@ in {
# Service configuration with smart defaults
config = mkIf cfg.enable (mkMerge [
# Core Prometheus service
{
services.prometheus = {
enable = true;
@ -203,39 +202,21 @@ in {
};
networking.firewall.allowedTCPPorts = [cfg.port];
homelab.services.${serviceName}.monitoring.enable = mkDefault true;
}
{
homelab.services.${serviceName}.monitoring = {
metrics.path = "/metrics";
healthCheck.path = "/-/healthy"; # ✅ Enables health checks
healthCheck.conditions = ["[STATUS] == 200" "[RESPONSE_TIME] < 1000"];
# Smart defaults for Prometheus
(mkIf cfg.monitoring.enable {
homelab.services.${serviceName}.monitoring = mkDefault {
metrics = {
path = "/metrics";
extraEndpoints = [];
};
healthCheck = {
path = "/-/healthy";
conditions = ["[STATUS] == 200" "[RESPONSE_TIME] < 1000"];
extraChecks = [
{
name = "prometheus-ready";
port = cfg.port;
path = "/-/ready";
conditions = ["[STATUS] == 200"];
group = "monitoring";
}
];
};
extraLabels = {
component = "monitoring-server";
tier = "monitoring";
};
};
})
(mkIf cfg.logging.enable {
homelab.services.${serviceName}.logging = mkDefault {
}
{
homelab.services.${serviceName}.logging = {
files = ["/var/log/prometheus/prometheus.log"];
parsing = {
# Prometheus log format: ts=2024-01-01T12:00:00.000Z caller=main.go:123 level=info msg="message"
@ -247,13 +228,11 @@ in {
application = "prometheus";
};
};
})
(mkIf cfg.proxy.enable {
homelab.services.${serviceName}.proxy = mkDefault {
subdomain = "prometheus";
enableAuth = true; # Admin interface needs protection
}
{
homelab.services.${serviceName}.proxy = {
enableAuth = true;
};
})
}
]);
}