From 23b746191f1a5d03e4aeae720cad3db8e52b6492 Mon Sep 17 00:00:00 2001 From: arcnmx Date: Sat, 1 Jun 2024 11:22:28 -0700 Subject: [PATCH] feat(monitoring): more status endpoints --- modules/nixos/gatus.nix | 18 +-- .../nixos/monitoring/ingest/prometheus.nix | 2 +- modules/system/access.nix | 12 +- modules/system/exports/deluge.nix | 19 ++- modules/system/exports/dnsmasq.nix | 28 ++++- modules/system/exports/freeipa.nix | 11 +- modules/system/exports/freepbx.nix | 27 ++-- modules/system/exports/invidious.nix | 8 +- modules/system/exports/keycloak.nix | 14 ++- modules/system/exports/ldap.nix | 14 ++- modules/system/exports/monitoring.nix | 60 +++++++-- modules/system/exports/mosquitto.nix | 14 ++- modules/system/exports/motion.nix | 13 +- modules/system/exports/nginx.nix | 23 ++-- modules/system/exports/openwebrx.nix | 6 +- modules/system/exports/plex.nix | 26 ++-- modules/system/exports/services.nix | 12 ++ modules/system/exports/unifi.nix | 20 +-- modules/system/exports/vaultwarden.nix | 15 ++- modules/system/exports/vouch.nix | 14 ++- modules/system/exports/zigbee2mqtt.nix | 2 +- nixos/monitoring/gatus.nix | 117 ++++++++++++++---- nixos/nginx.nix | 2 +- systems/hakurei/default.nix | 1 + systems/kitchencam/default.nix | 2 + systems/kuwubernetes/default.nix | 1 + systems/litterbox/default.nix | 1 + 27 files changed, 344 insertions(+), 138 deletions(-) diff --git a/modules/nixos/gatus.nix b/modules/nixos/gatus.nix index eff7145d..60dc151e 100644 --- a/modules/nixos/gatus.nix +++ b/modules/nixos/gatus.nix @@ -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 ]; -} \ No newline at end of file +} diff --git a/modules/nixos/monitoring/ingest/prometheus.nix b/modules/nixos/monitoring/ingest/prometheus.nix index 809618b8..f63ed941 100644 --- a/modules/nixos/monitoring/ingest/prometheus.nix +++ b/modules/nixos/monitoring/ingest/prometheus.nix @@ -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); diff --git a/modules/system/access.nix b/modules/system/access.nix index d3ac580e..3f91a059 100644 --- a/modules/system/access.nix +++ b/modules/system/access.nix @@ -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; }; diff --git a/modules/system/exports/deluge.nix b/modules/system/exports/deluge.nix index 8c20b812..6f0e125c 100644 --- a/modules/system/exports/deluge.nix +++ b/modules/system/exports/deluge.nix @@ -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; + }; }; }; }; diff --git a/modules/system/exports/dnsmasq.nix b/modules/system/exports/dnsmasq.nix index c0554b13..ae76cf58 100644 --- a/modules/system/exports/dnsmasq.nix +++ b/modules/system/exports/dnsmasq.nix @@ -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"; }; }; diff --git a/modules/system/exports/freeipa.nix b/modules/system/exports/freeipa.nix index 0de9c818..f77d7b54 100644 --- a/modules/system/exports/freeipa.nix +++ b/modules/system/exports/freeipa.nix @@ -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"; }; }; diff --git a/modules/system/exports/freepbx.nix b/modules/system/exports/freepbx.nix index 423d94eb..c654701c 100644 --- a/modules/system/exports/freepbx.nix +++ b/modules/system/exports/freepbx.nix @@ -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"; }; }; diff --git a/modules/system/exports/invidious.nix b/modules/system/exports/invidious.nix index 3e0c221c..b4b74f66 100644 --- a/modules/system/exports/invidious.nix +++ b/modules/system/exports/invidious.nix @@ -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; }; }; } diff --git a/modules/system/exports/keycloak.nix b/modules/system/exports/keycloak.nix index 791e2d82..0e4d49b9 100644 --- a/modules/system/exports/keycloak.nix +++ b/modules/system/exports/keycloak.nix @@ -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; }; }; }; diff --git a/modules/system/exports/ldap.nix b/modules/system/exports/ldap.nix index dc2d0c43..40647ead 100644 --- a/modules/system/exports/ldap.nix +++ b/modules/system/exports/ldap.nix @@ -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; }; }; }; diff --git a/modules/system/exports/monitoring.nix b/modules/system/exports/monitoring.nix index 303b819d..aebb888f 100644 --- a/modules/system/exports/monitoring.nix +++ b/modules/system/exports/monitoring.nix @@ -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 [ diff --git a/modules/system/exports/mosquitto.nix b/modules/system/exports/mosquitto.nix index 3dc2e07f..80d95be3 100644 --- a/modules/system/exports/mosquitto.nix +++ b/modules/system/exports/mosquitto.nix @@ -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; }; }; }; diff --git a/modules/system/exports/motion.nix b/modules/system/exports/motion.nix index eaff7e97..de539373 100644 --- a/modules/system/exports/motion.nix +++ b/modules/system/exports/motion.nix @@ -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; }; }; }; diff --git a/modules/system/exports/nginx.nix b/modules/system/exports/nginx.nix index 71150cb2..e970bc2c 100644 --- a/modules/system/exports/nginx.nix +++ b/modules/system/exports/nginx.nix @@ -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"; }; diff --git a/modules/system/exports/openwebrx.nix b/modules/system/exports/openwebrx.nix index 2d9eb55b..b2da4ca6 100644 --- a/modules/system/exports/openwebrx.nix +++ b/modules/system/exports/openwebrx.nix @@ -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; }; }; }; diff --git a/modules/system/exports/plex.nix b/modules/system/exports/plex.nix index f345bfa8..16f64167 100644 --- a/modules/system/exports/plex.nix +++ b/modules/system/exports/plex.nix @@ -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"; }; }; diff --git a/modules/system/exports/services.nix b/modules/system/exports/services.nix index d3892d78..19c798d2 100644 --- a/modules/system/exports/services.nix +++ b/modules/system/exports/services.nix @@ -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"]; }; diff --git a/modules/system/exports/unifi.nix b/modules/system/exports/unifi.nix index dd75b269..ebbb5785 100644 --- a/modules/system/exports/unifi.nix +++ b/modules/system/exports/unifi.nix @@ -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"; }; }; diff --git a/modules/system/exports/vaultwarden.nix b/modules/system/exports/vaultwarden.nix index 6446ec34..c5aa8070 100644 --- a/modules/system/exports/vaultwarden.nix +++ b/modules/system/exports/vaultwarden.nix @@ -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"; + }; }; }; }; diff --git a/modules/system/exports/vouch.nix b/modules/system/exports/vouch.nix index 9b873728..f49c934c 100644 --- a/modules/system/exports/vouch.nix +++ b/modules/system/exports/vouch.nix @@ -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"; + }; + }; }; }; } diff --git a/modules/system/exports/zigbee2mqtt.nix b/modules/system/exports/zigbee2mqtt.nix index 7013de2d..bc7d3490 100644 --- a/modules/system/exports/zigbee2mqtt.nix +++ b/modules/system/exports/zigbee2mqtt.nix @@ -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, ...}: { diff --git a/nixos/monitoring/gatus.nix b/nixos/monitoring/gatus.nix index 01990a7c..18d59938 100644 --- a/nixos/monitoring/gatus.nix +++ b/nixos/monitoring/gatus.nix @@ -6,31 +6,58 @@ ... }: let inherit (gensokyo-zone) systems; - inherit (gensokyo-zone.lib) mkAlmostOptionDefault unmerged; - inherit (lib.modules) mkMerge mkOptionDefault; + inherit (gensokyo-zone.lib) mkAddress6 mkAlmostOptionDefault unmerged; + inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault; inherit (lib.attrsets) attrValues nameValuePair listToAttrs; inherit (lib.lists) filter length optional concatMap; + inherit (lib.strings) hasPrefix hasInfix optionalString concatStringsSep match; cfg = config.services.gatus; - statusSystems = filter (system: system.config.access.online.enable) (attrValues systems); + statusSystems = filter (system: system.config.exports.status.enable) (attrValues systems); mapSystem = system: let statusServices = map (serviceName: system.config.exports.services.${serviceName}) system.config.exports.status.services; - in concatMap (mkServiceEndpoint system) statusServices; + serviceEndpoints = concatMap (mkServiceEndpoint system) statusServices; + systemEndpoint = mkSystemEndpoint system; + in serviceEndpoints ++ [ systemEndpoint ]; mkPortEndpoint = { system, service, port, unique }: let inherit (port.status) gatus; - name = if unique - then service.displayName - else "${service.displayName}: ${port.name}"; - conf = { - url = mkOptionDefault (access.proxyUrlFor { - inherit service port; - system = system.config; - scheme = gatus.protocol; - #network = port.listen; - }); + hasId = service.id != service.name; + displayName = service.displayName + optionalString (!unique && port.displayName != null) "/${port.displayName}"; + name = concatStringsSep "-" ([ + service.name + ] ++ optional hasId service.id ++ [ + port.name + system.config.name + ]); + #network = port.listen; + network = "lan"; + protocolOverrides = { + dns = { + # XXX: they're lying when they say "You may optionally prefix said DNS IPs with dns://" + scheme = ""; + }; + starttls.host = system.config.access.fqdn; }; - in nameValuePair name ({ ... }: { - imports = - optional port.status.alert.enable alertingConfigAlerts + urlConf = { + inherit service port network; + system = system.config; + scheme = gatus.protocol; + ${if gatus.client.network != "ip" then "getAddressFor" else null} = { + ip = "getAddressFor"; + ip4 = "getAddress4For"; + ip6 = "getAddress6For"; + }.${gatus.client.network}; + } // protocolOverrides.${gatus.protocol} or { }; + url = access.proxyUrlFor urlConf + optionalString (gatus.http.path != "/") gatus.http.path; + conf = { + enabled = mkIf (gatus.protocol == "starttls") (mkAlmostOptionDefault false); + name = mkAlmostOptionDefault displayName; + group = mkAlmostOptionDefault groups.services; + url = mkOptionDefault url; + client.network = mkAlmostOptionDefault gatus.client.network; + }; + in nameValuePair name (_: { + imports = [ alertingConfig ] + ++ optional port.status.alert.enable alertingConfigAlerts ++ optional (gatus.protocol == "http" || gatus.protocol == "https") alertingConfigHttp; config = mkMerge [ @@ -45,13 +72,31 @@ in map (port: mkPortEndpoint { inherit system service port unique; }) gatusPorts; + mkSystemEndpoint = system: let + inherit (system.config.exports) status; + network = "lan"; + getAddressFor = if system.config.network.networks.local.address4 or null != null then "getAddress4For" else "getAddressFor"; + addr = access.${getAddressFor} system.config.name network; + addrIs6 = hasInfix ":" addr; + in nameValuePair "ping-${system.config.name}" (_: { + imports = [ alertingConfig ] + ++ optional status.alert.enable alertingConfigAlerts; + config = { + name = mkAlmostOptionDefault system.config.name; + # XXX: it can't seem to ping ipv6 for some reason..? :< + enabled = mkIf addrIs6 (mkAlmostOptionDefault false); + client.network = mkIf addrIs6 (mkAlmostOptionDefault "ip6"); + group = mkAlmostOptionDefault (groups.forSystem system); + url = mkOptionDefault "icmp://${mkAddress6 addr}"; + }; + }); alertingConfigAlerts = { alerts = [ { type = "discord"; send-on-resolved = true; description = "Healthcheck failed."; - failure-threshold = 1; + failure-threshold = 10; success-threshold = 3; } ]; @@ -60,9 +105,39 @@ # Common interval for refreshing all basic HTTP endpoints interval = mkAlmostOptionDefault "30s"; }; + alertingConfig = { config, ... }: let + isLan = match ''.*(::|10\.|127\.|\.(local|int|tail)\.).*'' config.url != null; + isDns = hasPrefix "dns://" config.url || config.dns.query-name or null != null; + in { + conditions = mkOptionDefault [ + "[CONNECTED] == true" + ]; + ui = mkMerge [ + (mkIf isDns { + hide-conditions = mkAlmostOptionDefault true; + }) + (mkIf isLan { + hide-hostname = mkAlmostOptionDefault true; + hide-url = mkAlmostOptionDefault true; + }) + ]; + client = { + # XXX: no way to specify SSL hostname/SNI separately from the url :< + insecure = mkAlmostOptionDefault true; + }; + }; + groups = { + services = "Services"; + systems = "Systems"; + forSystem = system: let + node = systems.${system.config.proxmox.node.name}.config; + in if system.config.proxmox.enabled then "${groups.systems}/${node.name}" + else groups.systems; + }; in { - sops.secrets.gatus_environment_file = { - sopsFile = ../secrets/gatus.yaml; + sops.secrets.gatus_environment_file = mkIf cfg.enable { + sopsFile = mkDefault ../secrets/gatus.yaml; + owner = cfg.user; }; services.gatus = { enable = true; @@ -101,7 +176,7 @@ in { }; }; - networking.firewall.interfaces.lan.allowedTCPPorts = [ + networking.firewall.interfaces.lan.allowedTCPPorts = mkIf cfg.enable [ cfg.settings.web.port ]; } diff --git a/nixos/nginx.nix b/nixos/nginx.nix index a4d90dab..123f1c25 100644 --- a/nixos/nginx.nix +++ b/nixos/nginx.nix @@ -44,7 +44,7 @@ in { serverName = null; default = mkDefault true; reuseport = mkDefault true; - locations."/".extraConfig = mkDefault '' + locations."/".extraConfig = '' return 404; ''; }; diff --git a/systems/hakurei/default.nix b/systems/hakurei/default.nix index f474aecd..00a9231f 100644 --- a/systems/hakurei/default.nix +++ b/systems/hakurei/default.nix @@ -22,6 +22,7 @@ samba.enable = true; vouch-proxy = { enable = true; + displayName = "Vouch Proxy/local"; id = "login.local"; }; nginx = let diff --git a/systems/kitchencam/default.nix b/systems/kitchencam/default.nix index 5f19260b..cf44dab3 100644 --- a/systems/kitchencam/default.nix +++ b/systems/kitchencam/default.nix @@ -28,4 +28,6 @@ _: { }; }; }; + # XXX: currently unplugged :< + access.online.enable = false; } diff --git a/systems/kuwubernetes/default.nix b/systems/kuwubernetes/default.nix index 781f28d7..9fa4bb67 100644 --- a/systems/kuwubernetes/default.nix +++ b/systems/kuwubernetes/default.nix @@ -5,6 +5,7 @@ _: { ./nixos.nix ]; ci.allowFailure = true; + access.online.enable = false; proxmox = { vm = { id = 201; diff --git a/systems/litterbox/default.nix b/systems/litterbox/default.nix index ccdbc6a9..1dc55b5e 100644 --- a/systems/litterbox/default.nix +++ b/systems/litterbox/default.nix @@ -5,6 +5,7 @@ _: { arch = "x86_64"; type = "NixOS"; ci.allowFailure = true; + access.online.enable = false; modules = [ ./nixos.nix ];