267 lines
6.9 KiB
Nix
267 lines
6.9 KiB
Nix
{
|
|
config,
|
|
lib,
|
|
...
|
|
}:
|
|
with lib; let
|
|
serviceName = "gatus";
|
|
cfg = config.homelab.services.${serviceName};
|
|
homelabCfg = config.homelab;
|
|
|
|
# Convert homelab health checks to Gatus format
|
|
formatHealthCheck = check: let
|
|
# Build the URL based on the health check configuration
|
|
url = check._url or "http://${check.host}:${toString (check.port or 80)}${check.path}";
|
|
|
|
# Convert conditions to Gatus format (they should already be compatible)
|
|
conditions = check.conditions or ["[STATUS] == 200"];
|
|
|
|
# Convert alerts to Gatus format
|
|
alerts = map (alert: {
|
|
inherit (alert) type enabled;
|
|
failure-threshold = alert.failure-threshold or 3;
|
|
success-threshold = alert.success-threshold or 2;
|
|
description = "Health check alert for ${check.name}";
|
|
}) (check.alerts or []);
|
|
in {
|
|
name = check.name;
|
|
group = check.group or "default";
|
|
url = url;
|
|
interval = check.interval or "30s";
|
|
|
|
# Add method and headers for HTTP/HTTPS checks
|
|
method =
|
|
if (check.protocol == "http" || check.protocol == "https")
|
|
then check.method or "GET"
|
|
else null;
|
|
|
|
conditions = conditions;
|
|
|
|
# Add timeout
|
|
client = {
|
|
timeout = check.timeout or "10s";
|
|
};
|
|
|
|
# Add alerts if configured
|
|
alerts =
|
|
if alerts != []
|
|
then alerts
|
|
else [];
|
|
|
|
# Add labels for UI organization
|
|
ui = {
|
|
hide-hostname = false;
|
|
hide-url = false;
|
|
description = "Health check for ${check.name} on ${check.host or check._actualHost or "unknown"}";
|
|
};
|
|
};
|
|
|
|
# Generate Gatus configuration from aggregated health checks
|
|
gatusConfig =
|
|
recursiveUpdate {
|
|
# Global Gatus settings
|
|
alerting = mkIf (cfg.alerting != {}) cfg.alerting;
|
|
|
|
web = {
|
|
address = cfg.web.address;
|
|
port = cfg.port;
|
|
};
|
|
|
|
# Enable metrics
|
|
metrics = cfg.monitoring.enable;
|
|
|
|
ui = {
|
|
title = cfg.ui.title;
|
|
header = cfg.ui.header;
|
|
link = cfg.ui.link;
|
|
buttons = cfg.ui.buttons;
|
|
};
|
|
|
|
storage = cfg.storage;
|
|
|
|
# Convert all enabled health checks from the fleet to Gatus endpoints
|
|
endpoints = let
|
|
# Get all health checks - try global first, fallback to local
|
|
allHealthChecks = homelabCfg.monitoring.global.allHealthChecks
|
|
or homelabCfg.monitoring.allHealthChecks
|
|
or [];
|
|
|
|
# Filter only enabled health checks
|
|
enabledHealthChecks = filter (check: check.enabled or true) allHealthChecks;
|
|
|
|
# Convert to Gatus format
|
|
gatusEndpoints = map formatHealthCheck enabledHealthChecks;
|
|
in
|
|
gatusEndpoints;
|
|
}
|
|
cfg.extraConfig;
|
|
in {
|
|
imports = [
|
|
(import ../lib/features/monitoring.nix serviceName)
|
|
(import ../lib/features/logging.nix serviceName)
|
|
(import ../lib/features/proxy.nix serviceName)
|
|
];
|
|
|
|
# Core service options
|
|
options.homelab.services.${serviceName} = {
|
|
enable = mkEnableOption "Gatus Status Page";
|
|
|
|
port = mkOption {
|
|
type = types.port;
|
|
default = 8080;
|
|
};
|
|
|
|
description = mkOption {
|
|
type = types.str;
|
|
default = "Gatus Status Page";
|
|
};
|
|
|
|
# Gatus-specific options
|
|
ui = {
|
|
title = mkOption {
|
|
type = types.str;
|
|
default = "Homelab Status";
|
|
description = "Title for the Gatus web interface";
|
|
};
|
|
|
|
header = mkOption {
|
|
type = types.str;
|
|
default = "Homelab Services Status";
|
|
description = "Header text for the Gatus interface";
|
|
};
|
|
|
|
link = mkOption {
|
|
type = types.str;
|
|
default = "https://status.${homelabCfg.externalDomain}";
|
|
description = "Link in the Gatus header";
|
|
};
|
|
|
|
buttons = mkOption {
|
|
type = types.listOf (types.submodule {
|
|
options = {
|
|
name = mkOption {type = types.str;};
|
|
link = mkOption {type = types.str;};
|
|
};
|
|
});
|
|
default = [
|
|
{
|
|
name = "Grafana";
|
|
link = "https://grafana.${homelabCfg.externalDomain}";
|
|
}
|
|
{
|
|
name = "Prometheus";
|
|
link = "https://prometheus.${homelabCfg.externalDomain}";
|
|
}
|
|
];
|
|
description = "Navigation buttons in the Gatus interface";
|
|
};
|
|
};
|
|
|
|
alerting = mkOption {
|
|
type = types.attrs;
|
|
default = {};
|
|
description = "Gatus alerting configuration";
|
|
example = literalExpression ''
|
|
{
|
|
discord = {
|
|
webhook-url = "https://discord.com/api/webhooks/...";
|
|
default-alert = {
|
|
enabled = true;
|
|
description = "Health check failed";
|
|
failure-threshold = 3;
|
|
success-threshold = 2;
|
|
};
|
|
};
|
|
}
|
|
'';
|
|
};
|
|
|
|
storage = mkOption {
|
|
type = types.attrs;
|
|
default = {
|
|
type = "memory";
|
|
};
|
|
description = "Gatus storage configuration";
|
|
example = literalExpression ''
|
|
{
|
|
type = "postgres";
|
|
path = "postgres://user:password@localhost/gatus?sslmode=disable";
|
|
}
|
|
'';
|
|
};
|
|
|
|
web = {
|
|
address = mkOption {
|
|
type = types.str;
|
|
default = "0.0.0.0";
|
|
description = "Web interface bind address";
|
|
};
|
|
};
|
|
|
|
extraConfig = mkOption {
|
|
type = types.attrs;
|
|
default = {};
|
|
description = "Additional Gatus configuration options";
|
|
};
|
|
};
|
|
|
|
# Service configuration with smart defaults
|
|
config = mkIf cfg.enable (mkMerge [
|
|
# Core Gatus service
|
|
{
|
|
services.gatus = {
|
|
enable = true;
|
|
settings = gatusConfig;
|
|
};
|
|
|
|
networking.firewall.allowedTCPPorts = [cfg.port];
|
|
|
|
homelab.services.${serviceName}.monitoring.enable = mkDefault true;
|
|
}
|
|
|
|
# Smart defaults for Gatus
|
|
(mkIf cfg.monitoring.enable {
|
|
homelab.services.${serviceName}.monitoring = mkDefault {
|
|
metrics = {
|
|
path = "/metrics";
|
|
extraEndpoints = [];
|
|
};
|
|
healthCheck = {
|
|
path = "/health";
|
|
conditions = [
|
|
"[STATUS] == 200"
|
|
"[BODY].status == UP"
|
|
"[RESPONSE_TIME] < 1000"
|
|
];
|
|
extraChecks = [];
|
|
};
|
|
extraLabels = {
|
|
component = "status-monitoring";
|
|
tier = "monitoring";
|
|
};
|
|
};
|
|
})
|
|
|
|
(mkIf cfg.logging.enable {
|
|
homelab.services.${serviceName}.logging = mkDefault {
|
|
files = ["/var/log/gatus/gatus.log"];
|
|
parsing = {
|
|
# Gatus log format: 2024-01-01T12:00:00Z [INFO] message
|
|
regex = "^(?P<timestamp>\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z) \\[(?P<level>\\w+)\\] (?P<message>.*)";
|
|
extractFields = ["level"];
|
|
};
|
|
extraLabels = {
|
|
component = "status-monitoring";
|
|
application = "gatus";
|
|
};
|
|
};
|
|
})
|
|
|
|
(mkIf cfg.proxy.enable {
|
|
homelab.services.${serviceName}.proxy = mkDefault {
|
|
subdomain = "status";
|
|
enableAuth = false; # Status page should be public
|
|
};
|
|
})
|
|
]);
|
|
}
|