1
1
Fork 1
mirror of https://github.com/oddlama/nix-config.git synced 2025-10-10 23:00:39 +02:00

feat(monitoring): remove location, add nginx upstream monitoring option

This commit is contained in:
oddlama 2024-07-15 17:36:04 +02:00
parent 2024c3bfd5
commit 18b2002c27
No known key found for this signature in database
GPG key ID: 14EFE510775FE39A
26 changed files with 352 additions and 218 deletions

View file

@ -13,6 +13,7 @@
./kanidm.nix
./meta.nix
./netbird-client.nix
./nginx-upstream-monitoring.nix
./oauth2-proxy.nix
./promtail.nix
./secrets.nix

View file

@ -8,6 +8,13 @@
mkOption
types
;
defaultOptions = {
network = mkOption {
type = types.str;
description = "The network to which this endpoint is associated.";
};
};
in {
options = {
globals = mkOption {
@ -97,120 +104,94 @@ in {
monitoring = {
ping = mkOption {
type = types.attrsOf (types.submodule {
options = {
hostv4 = mkOption {
type = types.nullOr types.str;
description = "The IP/hostname to ping via ipv4.";
default = null;
};
options =
defaultOptions
// {
hostv4 = mkOption {
type = types.nullOr types.str;
description = "The IP/hostname to ping via ipv4.";
default = null;
};
hostv6 = mkOption {
type = types.nullOr types.str;
description = "The IP/hostname to ping via ipv6.";
default = null;
hostv6 = mkOption {
type = types.nullOr types.str;
description = "The IP/hostname to ping via ipv6.";
default = null;
};
};
location = mkOption {
type = types.str;
description = "A location tag added to this metric.";
};
network = mkOption {
type = types.str;
description = "The network to which this endpoint is associated.";
};
};
});
};
http = mkOption {
type = types.attrsOf (types.submodule {
options = {
url = mkOption {
type = types.str;
description = "The url to connect to.";
};
options =
defaultOptions
// {
url = mkOption {
type = types.either (types.listOf types.str) types.str;
description = "The url to connect to.";
};
location = mkOption {
type = types.str;
description = "A location tag added to this metric.";
};
expectedStatus = mkOption {
type = types.int;
default = 200;
description = "The HTTP status code to expect.";
};
network = mkOption {
type = types.str;
description = "The network to which this endpoint is associated.";
};
expectedBodyRegex = mkOption {
type = types.nullOr types.str;
description = "A regex pattern to expect in the body.";
default = null;
};
expectedStatus = mkOption {
type = types.int;
default = 200;
description = "The HTTP status code to expect.";
skipTlsVerification = mkOption {
type = types.bool;
description = "Skip tls verification when using https.";
default = false;
};
};
expectedBodyRegex = mkOption {
type = types.nullOr types.str;
description = "A regex pattern to expect in the body.";
default = null;
};
};
});
};
dns = mkOption {
type = types.attrsOf (types.submodule {
options = {
server = mkOption {
type = types.str;
description = "The DNS server to query.";
};
options =
defaultOptions
// {
server = mkOption {
type = types.str;
description = "The DNS server to query.";
};
domain = mkOption {
type = types.str;
description = "The domain to query.";
};
domain = mkOption {
type = types.str;
description = "The domain to query.";
};
record-type = mkOption {
type = types.str;
description = "The record type to query.";
default = "A";
record-type = mkOption {
type = types.str;
description = "The record type to query.";
default = "A";
};
};
location = mkOption {
type = types.str;
description = "A location tag added to this metric.";
};
network = mkOption {
type = types.str;
description = "The network to which this endpoint is associated.";
};
};
});
};
tcp = mkOption {
type = types.attrsOf (types.submodule {
options = {
host = mkOption {
type = types.str;
description = "The IP/hostname to connect to.";
};
options =
defaultOptions
// {
host = mkOption {
type = types.str;
description = "The IP/hostname to connect to.";
};
port = mkOption {
type = types.port;
description = "The port to connect to.";
port = mkOption {
type = types.port;
description = "The port to connect to.";
};
};
location = mkOption {
type = types.str;
description = "A location tag added to this metric.";
};
network = mkOption {
type = types.str;
description = "The network to which this endpoint is associated.";
};
};
});
};
};

View file

@ -0,0 +1,81 @@
{
config,
lib,
...
}: let
inherit
(lib)
attrNames
filterAttrs
flip
mapAttrs'
mkOption
nameValuePair
types
;
in {
options.services.nginx.upstreams = mkOption {
type = types.attrsOf (types.submodule {
options.monitoring = {
enable = mkOption {
type = types.bool;
description = "Whether to add a global monitoring entry for this upstream";
default = false;
};
path = mkOption {
type = types.str;
description = "The path to query.";
default = "";
};
expectedStatus = mkOption {
type = types.int;
default = 200;
description = "The HTTP status code to expect.";
};
expectedBodyRegex = mkOption {
type = types.nullOr types.str;
description = "A regex pattern to expect in the body.";
default = null;
};
useHttps = mkOption {
type = types.bool;
description = "Whether to use https to connect to this upstream when monitoring";
default = false;
};
skipTlsVerification = mkOption {
type = types.bool;
description = "Skip tls verification when using https.";
default = false;
};
};
});
};
config = let
monitoredUpstreams = filterAttrs (_: x: x.monitoring.enable) config.services.nginx.upstreams;
in {
globals.monitoring.http = flip mapAttrs' monitoredUpstreams (
upstreamName: upstream: let
schema =
if upstream.monitoring.useHttps
then "https"
else "http";
in
nameValuePair "${config.node.name}-upstream-${upstreamName}" {
url = map (server: "${schema}://${server}${upstream.monitoring.path}") (attrNames upstream.servers);
network = "local-${config.node.name}";
inherit
(upstream.monitoring)
expectedBodyRegex
expectedStatus
skipTlsVerification
;
}
);
};
}

View file

@ -21,6 +21,7 @@
optional
optionalAttrs
optionals
toList
types
;
@ -44,16 +45,14 @@ in {
description = "Additional secrets to replace in pre-start. The attr name will be searched and replaced in the config with the value read from the given file.";
};
globalMonitoring = {
enable = mkEnableOption "monitor the global infrastructure from this node.";
availableNetworks = mkOption {
type = types.listOf types.str;
example = ["internet"];
description = ''
The networks that can be reached from this node.
Only global entries with a matching network will be monitored from here.
'';
};
availableMonitoringNetworks = mkOption {
type = types.listOf types.str;
example = ["internet"];
description = ''
Any of the global monitoring definitions which has a network from this list
will automatically be monitored via telegraf. Set this to any networks that
can be reached from this node. This includes `local-<node.name>` by default.
'';
};
influxdb2 = {
@ -87,6 +86,9 @@ in {
};
config = mkIf (!minimal && cfg.enable) {
# Monitor anything that can only be monitored from this node
meta.telegraf.availableMonitoringNetworks = ["local-${config.node.name}"];
assertions = [
{
assertion = !config.boot.isContainer;
@ -185,6 +187,75 @@ in {
};
temp = {};
wireguard = {};
ping = concatLists (flip mapAttrsToList globals.monitoring.ping (
name: pingCfg:
optionals (elem pingCfg.network cfg.availableMonitoringNetworks) (
concatLists (forEach ["hostv4" "hostv6"] (
attr:
optional (pingCfg.${attr} != null) {
method = "native";
urls = [pingCfg.${attr}];
ipv4 = attr == "hostv4";
ipv6 = attr == "hostv6";
tags = {
inherit name;
inherit (pingCfg) network;
ip_version =
if attr == "hostv4"
then "v4"
else "v6";
};
fieldinclude = [
"percent_packet_loss"
"average_response_ms"
];
}
))
)
));
http_response = concatLists (flip mapAttrsToList globals.monitoring.http (
name: httpCfg:
optional (elem httpCfg.network cfg.availableMonitoringNetworks) {
urls = toList httpCfg.url;
method = "GET";
response_status_code = httpCfg.expectedStatus;
response_string_match = mkIf (httpCfg.expectedBodyRegex != null) httpCfg.expectedBodyRegex;
insecure_skip_verify = httpCfg.skipTlsVerification;
follow_redirects = true;
tags = {
inherit name;
inherit (httpCfg) network;
};
}
));
dns_query = concatLists (flip mapAttrsToList globals.monitoring.dns (
name: dnsCfg:
optional (elem dnsCfg.network cfg.availableMonitoringNetworks) {
servers = [dnsCfg.server];
domains = [dnsCfg.domain];
record_type = dnsCfg.record-type;
tags = {
inherit name;
inherit (dnsCfg) network;
};
}
));
net_response = concatLists (flip mapAttrsToList globals.monitoring.tcp (
name: tcpCfg:
optional (elem tcpCfg.network cfg.availableMonitoringNetworks) {
address = "${tcpCfg.host}:${toString tcpCfg.port}";
protocol = "tcp";
tags = {
inherit name;
inherit (tcpCfg) network;
};
fieldexclude = ["result_type" "string_found"];
}
));
}
// optionalAttrs config.services.smartd.enable {
sensors = {};
@ -200,74 +271,6 @@ in {
}
// optionalAttrs (config.networking.wireless.enable || config.networking.wireless.iwd.enable) {
wireless = {};
}
// optionalAttrs cfg.globalMonitoring.enable {
ping = concatLists (flip mapAttrsToList globals.monitoring.ping (
name: pingCfg:
optionals (elem pingCfg.network cfg.globalMonitoring.availableNetworks) (
concatLists (forEach ["hostv4" "hostv6"] (
attr:
optional (pingCfg.${attr} != null) {
method = "native";
urls = [pingCfg.${attr}];
ipv4 = attr == "hostv4";
ipv6 = attr == "hostv6";
tags = {
inherit name;
inherit (pingCfg) location network;
ip_version =
if attr == "hostv4"
then "v4"
else "v6";
};
fieldpass = [
"percent_packet_loss"
"average_response_ms"
];
}
))
)
));
http_response = concatLists (flip mapAttrsToList globals.monitoring.http (
name: httpCfg:
optional (elem httpCfg.network cfg.globalMonitoring.availableNetworks) {
urls = [httpCfg.url];
method = "GET";
response_status_code = httpCfg.expectedStatus;
response_string_match = mkIf (httpCfg.expectedBodyRegex != null) httpCfg.expectedBodyRegex;
tags = {
inherit name;
inherit (httpCfg) location network;
};
}
));
dns_query = concatLists (flip mapAttrsToList globals.monitoring.dns (
name: dnsCfg:
optional (elem dnsCfg.network cfg.globalMonitoring.availableNetworks) {
servers = [dnsCfg.server];
domains = [dnsCfg.domain];
record_type = dnsCfg.record-type;
tags = {
inherit name;
inherit (dnsCfg) location network;
};
}
));
net_response = concatLists (flip mapAttrsToList globals.monitoring.tcp (
name: tcpCfg:
optional (elem tcpCfg.network cfg.globalMonitoring.availableNetworks) {
address = "${tcpCfg.host}:${toString tcpCfg.port}";
protocol = "tcp";
tags = {
inherit name;
inherit (tcpCfg) location network;
};
fieldexclude = ["result_type" "string_found"];
}
));
};
};
};