From 51c30821199f8b3170fdf5f54921f20a1082ad79 Mon Sep 17 00:00:00 2001
From: Andreas Rammhold <andreas@rammhold.de>
Date: Sun, 4 Nov 2018 19:27:43 +0100
Subject: [PATCH] nixos/prometheus: require one alertmanager configuration
 parameter

This commit adds an assertion that checks that either `configFile` or
`configuration` is configured for alertmanager. The alertmanager config
can not be an empty attributeset. The check executed with `amtool` fails
before the service even has the chance to start. We should probably not
allow a broken alertmanager configuration anyway.

This also introduces a test for alertmanager configuration that piggy
backs on the existing prometheus tests.
---
 .../monitoring/prometheus/alertmanager.nix    | 54 +++++++++++--------
 nixos/tests/prometheus.nix                    | 22 ++++++++
 2 files changed, 53 insertions(+), 23 deletions(-)

diff --git a/nixos/modules/services/monitoring/prometheus/alertmanager.nix b/nixos/modules/services/monitoring/prometheus/alertmanager.nix
index cec5bb8df864..43b4a41eaf33 100644
--- a/nixos/modules/services/monitoring/prometheus/alertmanager.nix
+++ b/nixos/modules/services/monitoring/prometheus/alertmanager.nix
@@ -57,8 +57,8 @@ in {
       };
 
       configuration = mkOption {
-        type = types.attrs;
-        default = {};
+        type = types.nullOr types.attrs;
+        default = null;
         description = ''
           Alertmanager configuration as nix attribute set.
         '';
@@ -136,26 +136,34 @@ in {
     };
   };
 
-
-  config = mkIf cfg.enable {
-    networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port;
-
-    systemd.services.alertmanager = {
-      wantedBy = [ "multi-user.target" ];
-      after    = [ "network.target" ];
-      script = ''
-        ${cfg.package}/bin/alertmanager \
-          ${concatStringsSep " \\\n  " cmdlineArgs}
-      '';
-
-      serviceConfig = {
-        User = cfg.user;
-        Group = cfg.group;
-        Restart  = "always";
-        PrivateTmp = true;
-        WorkingDirectory = "/tmp";
-        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+  config = mkMerge [
+    (mkIf cfg.enable {
+      assertions = singleton {
+        assertion = cfg.configuration != null || cfg.configText != null;
+        message = "Can not enable alertmanager without a configuration. "
+         + "Set either the `configuration` or `configText` attribute.";
       };
-    };
-  };
+    })
+    (mkIf cfg.enable {
+      networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port;
+
+      systemd.services.alertmanager = {
+        wantedBy = [ "multi-user.target" ];
+        after    = [ "network.target" ];
+        script = ''
+          ${cfg.package}/bin/alertmanager \
+            ${concatStringsSep " \\\n  " cmdlineArgs}
+        '';
+
+        serviceConfig = {
+          User = cfg.user;
+          Group = cfg.group;
+          Restart  = "always";
+          PrivateTmp = true;
+          WorkingDirectory = "/tmp";
+          ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+        };
+      };
+    })
+  ];
 }
diff --git a/nixos/tests/prometheus.nix b/nixos/tests/prometheus.nix
index 87a6510f40fd..f1b20a33d71e 100644
--- a/nixos/tests/prometheus.nix
+++ b/nixos/tests/prometheus.nix
@@ -13,6 +13,25 @@ import ./make-test.nix {
           }];
         }];
         rules = [ ''testrule = count(up{job="prometheus"})'' ];
+
+        # a very simple version of the alertmanager configuration just to see if
+        # configuration checks & service startup are working
+        alertmanager = {
+          enable = true;
+          listenAddress = "[::1]";
+          port = 9093;
+          configuration = {
+            route.receiver = "webhook";
+            receivers = [
+              {
+                name = "webhook";
+                webhook_configs = [
+                  { url = "http://localhost"; }
+                ];
+              }
+            ];
+          };
+        };
       };
     };
   };
@@ -22,5 +41,8 @@ import ./make-test.nix {
     $one->waitForUnit("prometheus.service");
     $one->waitForOpenPort(9090);
     $one->succeed("curl -s http://127.0.0.1:9090/metrics");
+    $one->waitForUnit("alertmanager.service");
+    $one->waitForOpenPort("9093");
+    $one->succeed("curl -f -s http://localhost:9093/");
   '';
 }