diff --git a/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml index 8494b62e6ff0..c8f63fecf133 100644 --- a/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml +++ b/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml @@ -233,6 +233,13 @@ services.kanata. + + + karma, + an alert dashboard for Prometheus Alertmanager. Available as + services.karma + + languagetool, diff --git a/nixos/doc/manual/release-notes/rl-2211.section.md b/nixos/doc/manual/release-notes/rl-2211.section.md index a5ba4841f549..5a2b92c7d39a 100644 --- a/nixos/doc/manual/release-notes/rl-2211.section.md +++ b/nixos/doc/manual/release-notes/rl-2211.section.md @@ -84,6 +84,8 @@ In addition to numerous new and upgraded packages, this release has the followin - [kanata](https://github.com/jtroo/kanata), a tool to improve keyboard comfort and usability with advanced customization. Available as [services.kanata](options.html#opt-services.kanata.enable). +- [karma](https://github.com/prymitive/karma), an alert dashboard for Prometheus Alertmanager. Available as [services.karma](options.html#opt-services.karma.enable) + - [languagetool](https://languagetool.org/), a multilingual grammar, style, and spell checker. Available as [services.languagetool](options.html#opt-services.languagetool.enable). diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index dec66e395aad..c08632061a9d 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -682,6 +682,7 @@ ./services/monitoring/heapster.nix ./services/monitoring/incron.nix ./services/monitoring/kapacitor.nix + ./services/monitoring/karma.nix ./services/monitoring/kthxbye.nix ./services/monitoring/loki.nix ./services/monitoring/longview.nix diff --git a/nixos/modules/services/monitoring/karma.nix b/nixos/modules/services/monitoring/karma.nix new file mode 100644 index 000000000000..85dbc81f443f --- /dev/null +++ b/nixos/modules/services/monitoring/karma.nix @@ -0,0 +1,128 @@ +{ config, pkgs, lib, ... }: +with lib; +let + cfg = config.services.karma; + yaml = pkgs.formats.yaml { }; +in +{ + options.services.karma = { + enable = mkEnableOption (mdDoc "the Karma dashboard service"); + + package = mkOption { + type = types.package; + default = pkgs.karma; + defaultText = literalExpression "pkgs.karma"; + description = mdDoc '' + The Karma package that should be used. + ''; + }; + + configFile = mkOption { + type = types.path; + default = yaml.generate "karma.yaml" cfg.settings; + defaultText = "A configuration file generated from the provided nix attributes settings option."; + description = mdDoc '' + A YAML config file which can be used to configure karma instead of the nix-generated file. + ''; + example = "/etc/karma/karma.conf"; + }; + + environment = mkOption { + type = with types; attrsOf str; + default = {}; + description = mdDoc '' + Additional environment variables to provide to karma. + ''; + example = { + ALERTMANAGER_URI = "https://alertmanager.example.com"; + ALERTMANAGER_NAME= "single"; + }; + }; + + openFirewall = mkOption { + type = types.bool; + default = false; + description = mdDoc '' + Whether to open ports in the firewall needed for karma to function. + ''; + }; + + extraOptions = mkOption { + type = with types; listOf str; + default = []; + description = mdDoc '' + Extra command line options. + ''; + example = [ + "--alertmanager.timeout 10s" + ]; + }; + + settings = mkOption { + type = types.submodule { + freeformType = yaml.type; + + options.listen = { + address = mkOption { + type = types.str; + default = "127.0.0.1"; + description = mdDoc '' + Hostname or IP to listen on. + ''; + example = "[::]"; + }; + + port = mkOption { + type = types.port; + default = 8080; + description = mdDoc '' + HTTP port to listen on. + ''; + example = 8182; + }; + }; + }; + default = { + listen = { + address = "127.0.0.1"; + }; + }; + description = mdDoc '' + Karma dashboard configuration as nix attributes. + + Reference: + ''; + example = { + listen = { + address = "192.168.1.4"; + port = "8000"; + prefix = "/dashboard"; + }; + alertmanager = { + interval = "15s"; + servers = [ + { + name = "prod"; + uri = "http://alertmanager.example.com"; + } + ]; + }; + }; + }; + }; + + config = mkIf cfg.enable { + systemd.services.karma = { + description = "Alert dashboard for Prometheus Alertmanager"; + wantedBy = [ "multi-user.target" ]; + environment = cfg.environment; + serviceConfig = { + Type = "simple"; + DynamicUser = true; + Restart = "on-failure"; + ExecStart = "${pkgs.karma}/bin/karma --config.file ${cfg.configFile} ${concatStringsSep " " cfg.extraOptions}"; + }; + }; + networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.settings.listen.port ]; + }; +} diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 36c51b573100..a872ec86db3b 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -299,6 +299,7 @@ in { k3s = handleTest ./k3s {}; kafka = handleTest ./kafka.nix {}; kanidm = handleTest ./kanidm.nix {}; + karma = handleTest ./karma.nix {}; kbd-setfont-decompress = handleTest ./kbd-setfont-decompress.nix {}; kbd-update-search-paths-patch = handleTest ./kbd-update-search-paths-patch.nix {}; kea = handleTest ./kea.nix {}; diff --git a/nixos/tests/karma.nix b/nixos/tests/karma.nix new file mode 100644 index 000000000000..5ac2983b8aa3 --- /dev/null +++ b/nixos/tests/karma.nix @@ -0,0 +1,84 @@ +import ./make-test-python.nix ({ lib, pkgs, ... }: { + name = "karma"; + nodes = { + server = { ... }: { + services.prometheus.alertmanager = { + enable = true; + logLevel = "debug"; + port = 9093; + openFirewall = true; + configuration = { + global = { + resolve_timeout = "1m"; + }; + route = { + # Root route node + receiver = "test"; + group_by = ["..."]; + continue = false; + group_wait = "1s"; + group_interval="15s"; + repeat_interval = "24h"; + }; + receivers = [ + { + name = "test"; + webhook_configs = [ + { + url = "http://localhost:1234"; + send_resolved = true; + max_alerts = 0; + } + ]; + } + ]; + }; + }; + services.karma = { + enable = true; + openFirewall = true; + settings = { + listen = { + address = "0.0.0.0"; + port = 8081; + }; + alertmanager = { + servers = [ + { + name = "alertmanager"; + uri = "https://127.0.0.1:9093"; + } + ]; + }; + karma.name = "test-dashboard"; + log.config = true; + log.requests = true; + log.timestamp = true; + }; + }; + }; + }; + + testScript = '' + start_all() + + with subtest("Wait for server to come up"): + + server.wait_for_unit("alertmanager.service") + server.wait_for_unit("karma.service") + + server.sleep(5) # wait for both services to settle + + server.wait_for_open_port(9093) + server.wait_for_open_port(8081) + + with subtest("Test alertmanager readiness"): + server.succeed("curl -s http://127.0.0.1:9093/-/ready") + + # Karma only starts serving the dashboard once it has established connectivity to all alertmanagers in its config + # Therefore, this will fail if karma isn't able to reach alertmanager + server.succeed("curl -s http://127.0.0.1:8081") + + server.shutdown() + ''; +})