feat(monitoring): more status endpoints

This commit is contained in:
arcnmx 2024-06-01 11:22:28 -07:00
parent ebfd1f5a9a
commit 23b746191f
27 changed files with 344 additions and 138 deletions

View file

@ -1,7 +1,7 @@
{ config, lib, pkgs, ... }:
let
inherit (lib) types mkIf mkOption mkEnableOption mkPackageOption mkDefault;
inherit (lib) types mkIf mkOption mkEnableOption mkPackageOption mkOptionDefault;
cfg = config.services.gatus;
@ -206,6 +206,8 @@ in {
'';
};
ui = {
hide-conditions =
mkEnableOption "hiding the condition results on the UI";
hide-hostname =
mkEnableOption "hiding the hostname in the result";
hide-url = mkEnableOption "hiding the URL in the results";
@ -221,7 +223,7 @@ in {
};
};
};
config = { name = mkDefault name; };
config = { name = mkOptionDefault name; };
}));
default = { };
};
@ -316,9 +318,9 @@ in {
StateDirectory = "gatus";
LogsDirectory = "gatus";
EnvironmentFile =
mkIf (cfg.environmentFile != null) cfg.environmentFile;
mkIf (cfg.environmentFile != null) [ cfg.environmentFile ];
AmbientCapabilities = "CAP_NET_RAW"; # needed for ICMP probes
AmbientCapabilities = [ "CAP_NET_RAW" ]; # needed for ICMP probes
DevicePolicy = "closed";
LockPersonality = true;
MemoryDenyWriteExecute = true;
@ -337,13 +339,15 @@ in {
ProtectProc = "invisible";
ProtectSystem = "strict";
RemoveIPC = true;
RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
UMask = "0077";
ExecStart = "${cfg.package}/bin/gatus";
ExecStart = [
(lib.getExe cfg.package)
];
};
};
@ -359,4 +363,4 @@ in {
};
meta.maintainers = with lib.maintainers; [ christoph-heiss ];
}
}

View file

@ -12,7 +12,7 @@
nodeExporterSystems =
filter (
system:
system.config.access.online.enable
system.config.exports.prometheus.exporter.enable
&& system.config.exports.prometheus.exporter.services != []
)
(attrValues systems);

View file

@ -162,20 +162,22 @@
service ? system.exports.services.${serviceName},
portName ? "default",
port ? service.ports.${portName},
host ? access.${getAddressFor} system.name network,
defaultPort ? null,
network ? "lan",
scheme ? null,
getAddressFor ? "getAddressFor",
}: let
scheme' =
if scheme == null
then port.protocol
else scheme;
if scheme == null then "${port.protocol}://"
else if scheme == "" then ""
else "${scheme}://";
port' =
if !port.enable
then throw "${system.name}.exports.services.${service.name}.ports.${portName} isn't enabled"
else if port.port == defaultPort then ""
else ":${toString port.port}";
host = access.${getAddressFor} system.name network;
url = "${scheme'}://${mkAddress6 host}${port'}";
url = "${scheme'}${mkAddress6 host}${port'}";
in
assert service.enable; url;
};

View file

@ -3,11 +3,11 @@
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
inherit (lib.modules) mkIf;
inherit (lib.attrsets) mapAttrs;
in {
config.exports.services.deluge = {config, ...}: {
displayName = mkAlmostOptionDefault "Deluge";
nixos = {
serviceAttr = "deluge";
assertions = let
@ -32,14 +32,23 @@ in {
];
};
defaults.port.listen = mkAlmostOptionDefault "lan";
ports = mapAttrs (_: mapAlmostOptionDefaults) {
ports = let
gatus.client.network = mkAlmostOptionDefault "ip4";
in {
default = {
port = 58846;
port = mkAlmostOptionDefault 58846;
transport = "tcp";
status = {
inherit gatus;
};
};
web = {
port = 8112;
port = mkAlmostOptionDefault 8112;
protocol = "http";
status = {
inherit gatus;
enable = mkAlmostOptionDefault true;
};
};
};
};

View file

@ -3,22 +3,38 @@
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.attrsets) mapAttrs;
inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
inherit (lib.modules) mkOptionDefault;
in {
config.exports.services.dnsmasq = {config, ...}: {
config.exports.services.dnsmasq = {system, config, ...}: {
displayName = mkAlmostOptionDefault "Dnsmasq";
id = mkAlmostOptionDefault "dns";
nixos = {
serviceAttr = "dnsmasq";
};
defaults.port.listen = mkAlmostOptionDefault "lan";
ports = mapAttrs (_: mapAlmostOptionDefaults) {
ports = {
default = {
port = 53;
port = mkAlmostOptionDefault 53;
transport = "udp";
status = {
enable = mkAlmostOptionDefault true;
gatus = {
protocol = "dns";
settings = {
dns = {
query-type = mkOptionDefault "A";
query-name = mkOptionDefault system.access.fqdn;
};
conditions = mkOptionDefault [
"[BODY] == ${system.network.networks.local.address4}"
];
};
};
};
};
tcp = {
port = config.ports.default.port;
port = mkAlmostOptionDefault config.ports.default.port;
transport = "tcp";
};
};

View file

@ -3,18 +3,19 @@
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.attrsets) mapAttrs;
inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
in {
config.exports.services.freeipa = {
displayName = mkAlmostOptionDefault "FreeIPA";
id = mkAlmostOptionDefault "ipa";
ports = mapAttrs (_: mapAlmostOptionDefaults) {
ports = {
default = {
port = 443;
port = mkAlmostOptionDefault 443;
protocol = "https";
status.enable = mkAlmostOptionDefault true;
};
redirect = {
port = 80;
port = mkAlmostOptionDefault 80;
protocol = "http";
};
};

View file

@ -3,34 +3,41 @@
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.attrsets) mapAttrs;
inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
in {
config.exports.services.freepbx = {
config.exports.services.freepbx = {config, ...}: {
displayName = mkAlmostOptionDefault "FreePBX";
id = mkAlmostOptionDefault "pbx";
ports = mapAttrs (_: mapAlmostOptionDefaults) {
ports = {
http = {
port = 80;
displayName = mkAlmostOptionDefault null;
port = mkAlmostOptionDefault 80;
protocol = "http";
status.enable = mkAlmostOptionDefault true;
};
https = {
port = 443;
port = mkAlmostOptionDefault 443;
protocol = "https";
};
ucp = {
port = 8001;
port = mkAlmostOptionDefault 8001;
protocol = "http";
displayName = mkAlmostOptionDefault "UCP";
status = {
enable = mkAlmostOptionDefault config.ports.http.status.enable;
gatus.client.network = mkAlmostOptionDefault "ip4";
};
};
ucp-ssl = {
port = 8003;
port = mkAlmostOptionDefault 8003;
protocol = "https";
};
asterisk = {
port = 8088;
port = mkAlmostOptionDefault 8088;
protocol = "http";
};
asterisk-ssl = {
port = 8089;
port = mkAlmostOptionDefault 8089;
protocol = "https";
};
};

View file

@ -3,10 +3,11 @@
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
inherit (lib.modules) mkIf;
in {
config.exports.services.invidious = {config, ...}: {
displayName = mkAlmostOptionDefault "Invidious";
id = mkAlmostOptionDefault "yt";
nixos = {
serviceAttr = "invidious";
@ -17,9 +18,10 @@ in {
})
];
};
ports.default = mapAlmostOptionDefaults {
port = 3000;
ports.default = {
port = mkAlmostOptionDefault 3000;
protocol = "http";
status.enable = mkAlmostOptionDefault true;
};
};
}

View file

@ -3,11 +3,11 @@
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
inherit (lib.modules) mkIf;
inherit (lib.attrsets) mapAttrs;
in {
config.exports.services.keycloak = {config, ...}: {
displayName = mkAlmostOptionDefault "Keycloak";
id = mkAlmostOptionDefault "sso";
nixos = {
serviceAttr = "keycloak";
@ -28,15 +28,17 @@ in {
}))
];
};
ports = mapAttrs (_: mapAlmostOptionDefaults) {
ports = {
http = {
enable = !config.ports.https.enable;
port = 8080;
enable = mkAlmostOptionDefault (!config.ports.https.enable);
port = mkAlmostOptionDefault 8080;
protocol = "http";
status.enable = mkAlmostOptionDefault true;
};
https = {
port = 8443;
port = mkAlmostOptionDefault 8443;
protocol = "https";
status.enable = mkAlmostOptionDefault config.ports.http.status.enable;
};
};
};

View file

@ -3,21 +3,23 @@
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.attrsets) mapAttrs;
inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
in {
config.exports.services.ldap = {config, ...}: {
displayName = mkAlmostOptionDefault "LDAP";
defaults.port.listen = mkAlmostOptionDefault "lan";
ports = mapAttrs (_: mapAlmostOptionDefaults) {
ports = {
default = {
port = 389;
port = mkAlmostOptionDefault 389;
transport = "tcp";
starttls = true;
starttls = mkAlmostOptionDefault true;
status.enable = mkAlmostOptionDefault true;
};
ssl = {
port = 636;
port = mkAlmostOptionDefault 636;
ssl = true;
listen = "wan";
status.enable = mkAlmostOptionDefault config.ports.default.status.enable;
};
};
};

View file

@ -1,5 +1,5 @@
let
portModule = {config, gensokyo-zone, lib, ...}: let
portModule = {system, config, gensokyo-zone, lib, ...}: let
inherit (gensokyo-zone.lib) unmerged;
inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkMerge mkOptionDefault;
@ -12,24 +12,40 @@ let
enable = mkEnableOption "status checks";
alert = {
enable = mkEnableOption "health check alerts" // {
default = true;
default = system.exports.status.alert.enable;
};
};
gatus = {
enable = mkEnableOption "gatus" // {
default = true;
};
settings = mkOption {
type = unmerged.types.attrs;
client = {
network = mkOption {
type = enum [ "ip" "ip4" "ip6" ];
default = "ip";
};
};
http = {
path = mkOption {
type = str;
default = "/";
};
statusCondition = mkOption {
type = nullOr str;
};
};
protocol = mkOption {
type = str;
};
settings = mkOption {
type = unmerged.types.attrs;
};
};
};
};
config = {
status.gatus = let
cfg = config.status.gatus;
defaultProtocol =
if config.protocol != null then mkOptionDefault config.protocol
else if config.starttls then mkOptionDefault "starttls"
@ -38,20 +54,26 @@ let
else mkIf false (throw "unreachable");
in {
protocol = defaultProtocol;
http.statusCondition = mkOptionDefault (
if cfg.protocol == "http" || cfg.protocol == "https" then "[STATUS] == 200"
else null
);
settings = mkMerge [
{
conditions = mkMerge [
(mkIf (config.ssl || config.starttls) (mkOptionDefault [
"[CERTIFICATE_EXPIRATION] > 72h"
]))
(mkOptionDefault [
"[CONNECTED] == true"
])
];
}
(mkIf (config.protocol == "http" || config.protocol == "https") {
(mkIf (cfg.http.statusCondition != null) {
conditions = mkOptionDefault [
"[STATUS] == 200"
cfg.http.statusCondition
];
})
(mkIf (cfg.protocol == "dns") {
conditions = mkOptionDefault [
"[DNS_RCODE] == NOERROR"
];
})
];
@ -121,7 +143,7 @@ in
...
}: let
inherit (gensokyo-zone.lib) mapListToAttrs mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.options) mkOption;
inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkOptionDefault;
inherit (lib.attrsets) attrNames filterAttrs nameValuePair;
mkExporter = {
@ -156,11 +178,24 @@ in
in {
options.exports = with lib.types; {
prometheus = {
exporter.services = mkOption {
type = listOf str;
exporter = {
enable = mkEnableOption "prometheus ingress" // {
default = config.access.online.enable;
};
services = mkOption {
type = listOf str;
};
};
};
status = {
enable = mkEnableOption "status checks" // {
default = config.access.online.enable;
};
alert = {
enable = mkEnableOption "health check alerts" // {
default = config.access.online.enable && config.type == "NixOS";
};
};
services = mkOption {
type = listOf str;
};
@ -184,6 +219,7 @@ in
config.exports.services =
{
prometheus = {config, ...}: {
displayName = mkAlmostOptionDefault "Prometheus";
nixos = {
serviceAttr = "prometheus";
assertions = mkIf config.enable [

View file

@ -3,13 +3,13 @@
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
inherit (lib.modules) mkIf;
inherit (lib.attrsets) mapAttrs;
inherit (lib.lists) all imap0;
inherit (lib.trivial) id;
in {
config.exports.services.mosquitto = {config, ...}: {
displayName = mkAlmostOptionDefault "Mosquitto";
id = mkAlmostOptionDefault "mqtt";
nixos = {
serviceAttr = "mosquitto";
@ -28,15 +28,17 @@ in {
];
};
defaults.port.listen = mkAlmostOptionDefault "lan";
ports = mapAttrs (_: mapAlmostOptionDefaults) {
ports = {
default = {
port = 1883;
port = mkAlmostOptionDefault 1883;
transport = "tcp";
status.enable = mkAlmostOptionDefault true;
};
ssl = {
enable = false;
port = 8883;
enable = mkAlmostOptionDefault false;
port = mkAlmostOptionDefault 8883;
ssl = true;
status.enable = mkAlmostOptionDefault config.ports.default.status.enable;
};
};
};

View file

@ -3,19 +3,22 @@
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.attrsets) mapAttrs;
inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
in {
config.exports.services.motion = {config, ...}: {
displayName = mkAlmostOptionDefault "Motion";
defaults.port.listen = mkAlmostOptionDefault "lan";
ports = mapAttrs (_: mapAlmostOptionDefaults) {
ports = {
default = {
port = 8080;
port = mkAlmostOptionDefault 8080;
protocol = "http";
status.enable = mkAlmostOptionDefault true;
};
stream = {
port = 8081;
port = mkAlmostOptionDefault 8081;
protocol = "http";
displayName = mkAlmostOptionDefault "Stream";
status.enable = mkAlmostOptionDefault true;
};
};
};

View file

@ -7,7 +7,7 @@
inherit (lib.modules) mkIf;
inherit (lib.attrsets) mapAttrs;
in {
config.exports.services.nginx = {config, ...}: let
config.exports.services.nginx = {config, system, ...}: let
mkAssertion = f: nixosConfig: let
cfg = nixosConfig.services.nginx;
in
@ -25,6 +25,7 @@ in {
message = "proxied.port mismatch";
};
in {
displayName = mkAlmostOptionDefault "NGINX/${system.name}";
nixos = {
serviceAttr = "nginx";
assertions = mkIf config.enable (map mkAssertion [
@ -34,19 +35,27 @@ in {
]);
};
defaults.port.listen = mkAlmostOptionDefault "lan";
ports = mapAttrs (_: mapAlmostOptionDefaults) {
ports = {
http = {
port = 80;
port = mkAlmostOptionDefault 80;
protocol = "http";
status = {
enable = mkAlmostOptionDefault true;
gatus.http.statusCondition = mkAlmostOptionDefault "[STATUS] == any(200, 404)";
};
};
https = {
enable = false;
port = 443;
enable = mkAlmostOptionDefault false;
port = mkAlmostOptionDefault 443;
protocol = "https";
status = {
enable = mkAlmostOptionDefault config.ports.http.status.enable;
gatus.http.statusCondition = mkAlmostOptionDefault config.ports.http.status.gatus.http.statusCondition;
};
};
proxied = {
enable = false;
port = 9080;
enable = mkAlmostOptionDefault false;
port = mkAlmostOptionDefault 9080;
protocol = "http";
listen = "lan";
};

View file

@ -8,6 +8,7 @@
inherit (lib.attrsets) mapAttrs;
in {
config.exports.services.openwebrx = {config, ...}: {
displayName = mkAlmostOptionDefault "OpenWebRX";
id = mkAlmostOptionDefault "webrx";
nixos = {
serviceAttr = "openwebrx";
@ -25,10 +26,11 @@ in {
];
};
defaults.port.listen = mkAlmostOptionDefault "lan";
ports = mapAttrs (_: mapAlmostOptionDefaults) {
ports = {
default = {
port = 8073;
port = mkAlmostOptionDefault 8073;
protocol = "http";
status.enable = mkAlmostOptionDefault true;
};
};
};

View file

@ -3,43 +3,47 @@
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.attrsets) mapAttrs;
inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
in {
config.exports.services.plex = {
displayName = mkAlmostOptionDefault "Plex";
nixos.serviceAttr = "plex";
defaults.port.listen = mkAlmostOptionDefault "lan";
ports = mapAttrs (_: mapAlmostOptionDefaults) {
ports = {
default = {
port = 32400;
port = mkAlmostOptionDefault 32400;
protocol = "http";
status = {
enable = mkAlmostOptionDefault true;
gatus.http.statusCondition = mkAlmostOptionDefault "[STATUS] == 401";
};
};
roku = {
port = 8324;
port = mkAlmostOptionDefault 8324;
transport = "tcp";
};
dlna-tcp = {
port = 32469;
port = mkAlmostOptionDefault 32469;
transport = "tcp";
};
dlna-udp = {
port = 1900;
port = mkAlmostOptionDefault 1900;
transport = "udp";
};
gdm0 = {
port = 32410;
port = mkAlmostOptionDefault 32410;
transport = "udp";
};
gdm1 = {
port = 32412;
port = mkAlmostOptionDefault 32412;
transport = "udp";
};
gdm2 = {
port = 32413;
port = mkAlmostOptionDefault 32413;
transport = "udp";
};
gdm3 = {
port = 32414;
port = mkAlmostOptionDefault 32414;
transport = "udp";
};
};

View file

@ -14,6 +14,7 @@
cfg = config.exports;
portModule = {
config,
name,
service,
...
}: {
@ -23,6 +24,17 @@
// {
default = true;
};
name = mkOption {
type = str;
default = name;
};
displayName = mkOption {
type = nullOr str;
default =
if config.name == "default" then null
else if config.ssl && (config.name == "ssl" || config.name == "https") then "SSL"
else config.name;
};
listen = mkOption {
type = enum ["wan" "lan" "int" "localhost"];
};

View file

@ -3,47 +3,47 @@
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.attrsets) mapAttrs;
inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
in {
config.exports.services.unifi = {config, ...}: {
nixos.serviceAttr = "unifi";
defaults.port.listen = mkAlmostOptionDefault "lan";
ports = mapAttrs (_: mapAlmostOptionDefaults) {
ports = {
management = {
# remote login
port = 8443;
port = mkAlmostOptionDefault 8443;
protocol = "https";
listen = "int";
status.enable = mkAlmostOptionDefault true;
};
uap = {
# UAP to inform controller
port = 8080;
port = mkAlmostOptionDefault 8080;
transport = "tcp";
};
portal = {
# HTTP portal redirect, if guest portal is enabled
port = 8880;
port = mkAlmostOptionDefault 8880;
protocol = "http";
};
portal-secure = {
# HTTPS portal redirect
port = 8843;
port = mkAlmostOptionDefault 8843;
protocol = "https";
};
speedtest = {
# UniFi mobile speed test
port = 6789;
port = mkAlmostOptionDefault 6789;
transport = "tcp";
};
stun = {
port = 3478;
port = mkAlmostOptionDefault 3478;
transport = "udp";
listen = "wan";
};
discovery = {
# device discovery
port = 10001;
port = mkAlmostOptionDefault 10001;
transport = "udp";
};
};

View file

@ -3,9 +3,8 @@
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
inherit (lib.modules) mkIf;
inherit (lib.attrsets) mapAttrs;
in {
config.exports.services.vaultwarden = {config, ...}: {
id = mkAlmostOptionDefault "bw";
@ -27,14 +26,20 @@ in {
})
];
};
ports = mapAttrs (_: mapAlmostOptionDefaults) {
ports = {
default = {
port = 8222;
port = mkAlmostOptionDefault 8222;
protocol = "http";
status.enable = mkAlmostOptionDefault true;
};
websocket = {
port = 8223;
port = mkAlmostOptionDefault 8223;
protocol = "http";
displayName = mkAlmostOptionDefault "WebSocket";
status = {
enable = mkAlmostOptionDefault true;
gatus.protocol = "ws";
};
};
};
};

View file

@ -3,10 +3,11 @@
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
inherit (lib.modules) mkIf;
in {
config.exports.services.vouch-proxy = {config, ...}: {
displayName = mkAlmostOptionDefault "Vouch Proxy";
id = mkAlmostOptionDefault "login";
defaults.port.listen = mkAlmostOptionDefault "localhost";
nixos = {
@ -18,9 +19,16 @@ in {
})
];
};
ports.default = mapAlmostOptionDefaults {
port = 30746;
ports.default = {
port = mkAlmostOptionDefault 30746;
protocol = "http";
status = {
enable = mkAlmostOptionDefault true;
gatus.http = {
#path = "/validate";
statusCondition = mkAlmostOptionDefault "[STATUS] == 404";
};
};
};
};
}

View file

@ -3,7 +3,7 @@
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
inherit (lib.modules) mkIf;
in {
config.exports.services.zigbee2mqtt = {config, ...}: {