about summary refs log tree commit diff
path: root/nixpkgs/nixos/tests/prometheus-exporters.nix
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/nixos/tests/prometheus-exporters.nix')
-rw-r--r--nixpkgs/nixos/tests/prometheus-exporters.nix558
1 files changed, 358 insertions, 200 deletions
diff --git a/nixpkgs/nixos/tests/prometheus-exporters.nix b/nixpkgs/nixos/tests/prometheus-exporters.nix
index 9aa430c25a4f..69a9a6b23218 100644
--- a/nixpkgs/nixos/tests/prometheus-exporters.nix
+++ b/nixpkgs/nixos/tests/prometheus-exporters.nix
@@ -1,65 +1,65 @@
 { system ? builtins.currentSystem
-, config ? {}
+, config ? { }
 , pkgs ? import ../.. { inherit system config; }
 }:
 
 let
   inherit (import ../lib/testing-python.nix { inherit system pkgs; }) makeTest;
   inherit (pkgs.lib) concatStringsSep maintainers mapAttrs mkMerge
-                     removeSuffix replaceChars singleton splitString;
+    removeSuffix replaceChars singleton splitString;
 
-/*
- * The attrset `exporterTests` contains one attribute
- * for each exporter test. Each of these attributes
- * is expected to be an attrset containing:
- *
- *  `exporterConfig`:
- *    this attribute set contains config for the exporter itself
- *
- *  `exporterTest`
- *    this attribute set contains test instructions
- *
- *  `metricProvider` (optional)
- *    this attribute contains additional machine config
- *
- *  `nodeName` (optional)
- *    override an incompatible testnode name
- *
- *  Example:
- *    exporterTests.<exporterName> = {
- *      exporterConfig = {
- *        enable = true;
- *      };
- *      metricProvider = {
- *        services.<metricProvider>.enable = true;
- *      };
- *      exporterTest = ''
- *        wait_for_unit("prometheus-<exporterName>-exporter.service")
- *        wait_for_open_port("1234")
- *        succeed("curl -sSf 'localhost:1234/metrics'")
- *      '';
- *    };
- *
- *  # this would generate the following test config:
- *
- *    nodes.<exporterName> = {
- *      services.prometheus.<exporterName> = {
- *        enable = true;
- *      };
- *      services.<metricProvider>.enable = true;
- *    };
- *
- *    testScript = ''
- *      <exporterName>.start()
- *      <exporterName>.wait_for_unit("prometheus-<exporterName>-exporter.service")
- *      <exporterName>.wait_for_open_port("1234")
- *      <exporterName>.succeed("curl -sSf 'localhost:1234/metrics'")
- *      <exporterName>.shutdown()
- *    '';
- */
+  /*
+    * The attrset `exporterTests` contains one attribute
+    * for each exporter test. Each of these attributes
+    * is expected to be an attrset containing:
+    *
+    *  `exporterConfig`:
+    *    this attribute set contains config for the exporter itself
+    *
+    *  `exporterTest`
+    *    this attribute set contains test instructions
+    *
+    *  `metricProvider` (optional)
+    *    this attribute contains additional machine config
+    *
+    *  `nodeName` (optional)
+    *    override an incompatible testnode name
+    *
+    *  Example:
+    *    exporterTests.<exporterName> = {
+    *      exporterConfig = {
+    *        enable = true;
+    *      };
+    *      metricProvider = {
+    *        services.<metricProvider>.enable = true;
+    *      };
+    *      exporterTest = ''
+    *        wait_for_unit("prometheus-<exporterName>-exporter.service")
+    *        wait_for_open_port("1234")
+    *        succeed("curl -sSf 'localhost:1234/metrics'")
+    *      '';
+    *    };
+    *
+    *  # this would generate the following test config:
+    *
+    *    nodes.<exporterName> = {
+    *      services.prometheus.<exporterName> = {
+    *        enable = true;
+    *      };
+    *      services.<metricProvider>.enable = true;
+    *    };
+    *
+    *    testScript = ''
+    *      <exporterName>.start()
+    *      <exporterName>.wait_for_unit("prometheus-<exporterName>-exporter.service")
+    *      <exporterName>.wait_for_open_port("1234")
+    *      <exporterName>.succeed("curl -sSf 'localhost:1234/metrics'")
+    *      <exporterName>.shutdown()
+    *    '';
+  */
 
   exporterTests = {
-     apcupsd = {
+    apcupsd = {
       exporterConfig = {
         enable = true;
       };
@@ -71,7 +71,7 @@ let
         wait_for_open_port(3551)
         wait_for_unit("prometheus-apcupsd-exporter.service")
         wait_for_open_port(9162)
-        succeed("curl -sSf http://localhost:9162/metrics | grep -q 'apcupsd_info'")
+        succeed("curl -sSf http://localhost:9162/metrics | grep 'apcupsd_info'")
       '';
     };
 
@@ -85,7 +85,7 @@ let
         wait_for_unit("prometheus-artifactory-exporter.service")
         wait_for_open_port(9531)
         succeed(
-            "curl -sSf http://localhost:9531/metrics | grep -q 'artifactory_up'"
+            "curl -sSf http://localhost:9531/metrics | grep 'artifactory_up'"
         )
       '';
     };
@@ -106,7 +106,7 @@ let
         wait_for_unit("prometheus-bind-exporter.service")
         wait_for_open_port(9119)
         succeed(
-            "curl -sSf http://localhost:9119/metrics | grep -q 'bind_query_recursions_total 0'"
+            "curl -sSf http://localhost:9119/metrics | grep 'bind_query_recursions_total 0'"
         )
       '';
     };
@@ -135,7 +135,7 @@ let
         wait_for_unit("prometheus-bird-exporter.service")
         wait_for_open_port(9324)
         wait_until_succeeds(
-            "curl -sSf http://localhost:9324/metrics | grep -q 'MyObviousTestString'"
+            "curl -sSf http://localhost:9324/metrics | grep 'MyObviousTestString'"
         )
       '';
     };
@@ -154,7 +154,7 @@ let
         wait_for_unit("prometheus-bitcoin-exporter.service")
         wait_for_unit("bitcoind-default.service")
         wait_for_open_port(9332)
-        succeed("curl -sSf http://localhost:9332/metrics | grep -q '^bitcoin_blocks '")
+        succeed("curl -sSf http://localhost:9332/metrics | grep '^bitcoin_blocks '")
       '';
     };
 
@@ -172,7 +172,7 @@ let
         wait_for_unit("prometheus-blackbox-exporter.service")
         wait_for_open_port(9115)
         succeed(
-            "curl -sSf 'http://localhost:9115/probe?target=localhost&module=icmp_v6' | grep -q 'probe_success 1'"
+            "curl -sSf 'http://localhost:9115/probe?target=localhost&module=icmp_v6' | grep 'probe_success 1'"
         )
       '';
     };
@@ -192,20 +192,21 @@ let
           "plugin":"testplugin",
           "time":DATE
         }]
-        ''; in ''
-        wait_for_unit("prometheus-collectd-exporter.service")
-        wait_for_open_port(9103)
-        succeed(
-            'echo \'${postData}\'> /tmp/data.json'
-        )
-        succeed('sed -ie "s DATE $(date +%s) " /tmp/data.json')
-        succeed(
-            "curl -sSfH 'Content-Type: application/json' -X POST --data @/tmp/data.json localhost:9103/collectd"
-        )
-        succeed(
-            "curl -sSf localhost:9103/metrics | grep -q 'collectd_testplugin_gauge{instance=\"testhost\"} 23'"
-        )
-      '';
+      ''; in
+        ''
+          wait_for_unit("prometheus-collectd-exporter.service")
+          wait_for_open_port(9103)
+          succeed(
+              'echo \'${postData}\'> /tmp/data.json'
+          )
+          succeed('sed -ie "s DATE $(date +%s) " /tmp/data.json')
+          succeed(
+              "curl -sSfH 'Content-Type: application/json' -X POST --data @/tmp/data.json localhost:9103/collectd"
+          )
+          succeed(
+              "curl -sSf localhost:9103/metrics | grep 'collectd_testplugin_gauge{instance=\"testhost\"} 23'"
+          )
+        '';
     };
 
     dnsmasq = {
@@ -219,7 +220,7 @@ let
       exporterTest = ''
         wait_for_unit("prometheus-dnsmasq-exporter.service")
         wait_for_open_port(9153)
-        succeed("curl -sSf http://localhost:9153/metrics | grep -q 'dnsmasq_leases 0'")
+        succeed("curl -sSf http://localhost:9153/metrics | grep 'dnsmasq_leases 0'")
       '';
     };
 
@@ -234,7 +235,7 @@ let
         wait_for_unit("prometheus-domain-exporter.service")
         wait_for_open_port(9222)
         succeed(
-            "curl -sSf 'http://localhost:9222/probe?target=nixos.org' | grep -q 'domain_probe_success 0'"
+            "curl -sSf 'http://localhost:9222/probe?target=nixos.org' | grep 'domain_probe_success 0'"
         )
       '';
     };
@@ -253,12 +254,13 @@ let
         wait_for_unit("prometheus-dovecot-exporter.service")
         wait_for_open_port(9166)
         succeed(
-            "curl -sSf http://localhost:9166/metrics | grep -q 'dovecot_up{scope=\"global\"} 1'"
+            "curl -sSf http://localhost:9166/metrics | grep 'dovecot_up{scope=\"global\"} 1'"
         )
       '';
     };
 
-    fritzbox = { # TODO add proper test case
+    fritzbox = {
+      # TODO add proper test case
       exporterConfig = {
         enable = true;
       };
@@ -266,7 +268,7 @@ let
         wait_for_unit("prometheus-fritzbox-exporter.service")
         wait_for_open_port(9133)
         succeed(
-            "curl -sSf http://localhost:9133/metrics | grep -q 'fritzbox_exporter_collect_errors 0'"
+            "curl -sSf http://localhost:9133/metrics | grep 'fritzbox_exporter_collect_errors 0'"
         )
       '';
     };
@@ -288,9 +290,9 @@ let
         wait_for_unit("prometheus-jitsi-exporter.service")
         wait_for_open_port(9700)
         wait_until_succeeds(
-            'journalctl -eu prometheus-jitsi-exporter.service -o cat | grep -q "key=participants"'
+            'journalctl -eu prometheus-jitsi-exporter.service -o cat | grep "key=participants"'
         )
-        succeed("curl -sSf 'localhost:9700/metrics' | grep -q 'jitsi_participants 0'")
+        succeed("curl -sSf 'localhost:9700/metrics' | grep 'jitsi_participants 0'")
       '';
     };
 
@@ -300,7 +302,7 @@ let
         url = "http://localhost";
         configFile = pkgs.writeText "json-exporter-conf.json" (builtins.toJSON {
           metrics = [
-            { name = "json_test_metric"; path = "$.test"; }
+            { name = "json_test_metric"; path = "{ .test }"; }
           ];
         });
       };
@@ -319,7 +321,58 @@ let
         wait_for_unit("prometheus-json-exporter.service")
         wait_for_open_port(7979)
         succeed(
-            "curl -sSf 'localhost:7979/probe?target=http://localhost' | grep -q 'json_test_metric 1'"
+            "curl -sSf 'localhost:7979/probe?target=http://localhost' | grep 'json_test_metric 1'"
+        )
+      '';
+    };
+
+    kea = {
+      exporterConfig = {
+        enable = true;
+        controlSocketPaths = [
+          "/run/kea/kea-dhcp6.sock"
+        ];
+      };
+      metricProvider = {
+        users.users.kea = {
+          isSystemUser = true;
+        };
+        users.groups.kea = {};
+
+        systemd.services.prometheus-kea-exporter.after = [ "kea-dhcp6.service" ];
+
+        systemd.services.kea-dhcp6 = let
+          configFile = pkgs.writeText "kea-dhcp6.conf" (builtins.toJSON {
+            Dhcp6 = {
+              "control-socket" = {
+                "socket-type" = "unix";
+                "socket-name" = "/run/kea/kea-dhcp6.sock";
+              };
+            };
+          });
+        in
+        {
+          after = [ "network.target" ];
+          wantedBy = [ "multi-user.target" ];
+
+          serviceConfig = {
+            DynamicUser = false;
+            User = "kea";
+            Group = "kea";
+            ExecStart = "${pkgs.kea}/bin/kea-dhcp6 -c ${configFile}";
+            StateDirectory = "kea";
+            RuntimeDirectory = "kea";
+            UMask = "0007";
+          };
+        };
+      };
+      exporterTest = ''
+        wait_for_unit("kea-dhcp6.service")
+        wait_for_file("/run/kea/kea-dhcp6.sock")
+        wait_for_unit("prometheus-kea-exporter.service")
+        wait_for_open_port(9547)
+        succeed(
+            "curl --fail localhost:9547/metrics | grep 'packets_received_total'"
         )
       '';
     };
@@ -332,13 +385,48 @@ let
         services.knot = {
           enable = true;
           extraArgs = [ "-v" ];
+          extraConfig = ''
+            server:
+              listen: 127.0.0.1@53
+
+            template:
+              - id: default
+                global-module: mod-stats
+                dnssec-signing: off
+                zonefile-sync: -1
+                journal-db: /var/lib/knot/journal
+                kasp-db: /var/lib/knot/kasp
+                timer-db: /var/lib/knot/timer
+                zonefile-load: difference
+                storage: ${pkgs.buildEnv {
+                  name = "foo";
+                  paths = [
+                    (pkgs.writeTextDir "test.zone" ''
+                      @ SOA ns.example.com. noc.example.com. 2019031301 86400 7200 3600000 172800
+                      @       NS      ns1
+                      @       NS      ns2
+                      ns1     A       192.168.0.1
+                    '')
+                  ];
+                }}
+
+            mod-stats:
+              - id: custom
+                edns-presence: on
+                query-type: on
+
+            zone:
+              - domain: test
+                file: test.zone
+                module: mod-stats/custom
+          '';
         };
       };
       exporterTest = ''
         wait_for_unit("knot.service")
         wait_for_unit("prometheus-knot-exporter.service")
         wait_for_open_port(9433)
-        succeed("curl -sSf 'localhost:9433' | grep -q 'knot_server_zone_count 0.0'")
+        succeed("curl -sSf 'localhost:9433' | grep 'knot_server_zone_count 1.0'")
       '';
     };
 
@@ -353,10 +441,10 @@ let
         wait_for_unit("prometheus-keylight-exporter.service")
         wait_for_open_port(9288)
         succeed(
-            "curl -sS --write-out '%{http_code}' -o /dev/null http://localhost:9288/metrics | grep -q '400'"
+            "curl -sS --write-out '%{http_code}' -o /dev/null http://localhost:9288/metrics | grep '400'"
         )
         succeed(
-            "curl -sS --write-out '%{http_code}' -o /dev/null http://localhost:9288/metrics?target=nosuchdevice | grep -q '500'"
+            "curl -sS --write-out '%{http_code}' -o /dev/null http://localhost:9288/metrics?target=nosuchdevice | grep '500'"
         )
       '';
     };
@@ -369,27 +457,27 @@ let
       };
       metricProvider = {
         systemd.services.prometheus-lnd-exporter.serviceConfig.DynamicUser = false;
-        services.bitcoind.enable = true;
-        services.bitcoind.extraConfig = ''
+        services.bitcoind.main.enable = true;
+        services.bitcoind.main.extraConfig = ''
           rpcauth=bitcoinrpc:e8fe33f797e698ac258c16c8d7aadfbe$872bdb8f4d787367c26bcfd75e6c23c4f19d44a69f5d1ad329e5adf3f82710f7
           bitcoind.zmqpubrawblock=tcp://127.0.0.1:28332
           bitcoind.zmqpubrawtx=tcp://127.0.0.1:28333
         '';
         systemd.services.lnd = {
           serviceConfig.ExecStart = ''
-          ${pkgs.lnd}/bin/lnd \
-            --datadir=/var/lib/lnd \
-            --tlscertpath=/var/lib/lnd/tls.cert \
-            --tlskeypath=/var/lib/lnd/tls.key \
-            --logdir=/var/log/lnd \
-            --bitcoin.active \
-            --bitcoin.mainnet \
-            --bitcoin.node=bitcoind \
-            --bitcoind.rpcuser=bitcoinrpc \
-            --bitcoind.rpcpass=hunter2 \
-            --bitcoind.zmqpubrawblock=tcp://127.0.0.1:28332 \
-            --bitcoind.zmqpubrawtx=tcp://127.0.0.1:28333 \
-            --readonlymacaroonpath=/var/lib/lnd/readonly.macaroon
+            ${pkgs.lnd}/bin/lnd \
+              --datadir=/var/lib/lnd \
+              --tlscertpath=/var/lib/lnd/tls.cert \
+              --tlskeypath=/var/lib/lnd/tls.key \
+              --logdir=/var/log/lnd \
+              --bitcoin.active \
+              --bitcoin.mainnet \
+              --bitcoin.node=bitcoind \
+              --bitcoind.rpcuser=bitcoinrpc \
+              --bitcoind.rpcpass=hunter2 \
+              --bitcoind.zmqpubrawblock=tcp://127.0.0.1:28332 \
+              --bitcoind.zmqpubrawtx=tcp://127.0.0.1:28333 \
+              --readonlymacaroonpath=/var/lib/lnd/readonly.macaroon
           '';
           serviceConfig.StateDirectory = "lnd";
           wantedBy = [ "multi-user.target" ];
@@ -401,7 +489,7 @@ let
         wait_for_open_port(10009)
         wait_for_unit("prometheus-lnd-exporter.service")
         wait_for_open_port(9092)
-        succeed("curl -sSf localhost:9092/metrics | grep -q '^promhttp_metric_handler'")
+        succeed("curl -sSf localhost:9092/metrics | grep '^promhttp_metric_handler'")
       '';
     };
 
@@ -411,14 +499,14 @@ let
         configuration = {
           monitoringInterval = "2s";
           mailCheckTimeout = "10s";
-          servers = [ {
+          servers = [{
             name = "testserver";
             server = "localhost";
             port = 25;
             from = "mail-exporter@localhost";
             to = "mail-exporter@localhost";
             detectionDir = "/var/spool/mail/mail-exporter/new";
-          } ];
+          }];
         };
       };
       metricProvider = {
@@ -443,7 +531,7 @@ let
         wait_for_unit("prometheus-mail-exporter.service")
         wait_for_open_port(9225)
         wait_until_succeeds(
-            "curl -sSf http://localhost:9225/metrics | grep -q 'mail_deliver_success{configname=\"testserver\"} 1'"
+            "curl -sSf http://localhost:9225/metrics | grep 'mail_deliver_success{configname=\"testserver\"} 1'"
         )
       '';
     };
@@ -483,7 +571,7 @@ let
         wait_for_unit("prometheus-mikrotik-exporter.service")
         wait_for_open_port(9436)
         succeed(
-            "curl -sSf http://localhost:9436/metrics | grep -q 'mikrotik_scrape_collector_success{device=\"router\"} 0'"
+            "curl -sSf http://localhost:9436/metrics | grep 'mikrotik_scrape_collector_success{device=\"router\"} 0'"
         )
       '';
     };
@@ -508,7 +596,7 @@ let
         wait_for_unit("prometheus-modemmanager-exporter.service")
         wait_for_open_port(9539)
         succeed(
-            "curl -sSf http://localhost:9539/metrics | grep -q 'modemmanager_info'"
+            "curl -sSf http://localhost:9539/metrics | grep 'modemmanager_info'"
         )
       '';
     };
@@ -520,15 +608,17 @@ let
         url = "http://localhost";
       };
       metricProvider = {
-        systemd.services.nc-pwfile = let
-          passfile = (pkgs.writeText "pwfile" "snakeoilpw");
-        in {
-          requiredBy = [ "prometheus-nextcloud-exporter.service" ];
-          before = [ "prometheus-nextcloud-exporter.service" ];
-          serviceConfig.ExecStart = ''
-            ${pkgs.coreutils}/bin/install -o nextcloud-exporter -m 0400 ${passfile} /var/nextcloud-pwfile
-          '';
-        };
+        systemd.services.nc-pwfile =
+          let
+            passfile = (pkgs.writeText "pwfile" "snakeoilpw");
+          in
+          {
+            requiredBy = [ "prometheus-nextcloud-exporter.service" ];
+            before = [ "prometheus-nextcloud-exporter.service" ];
+            serviceConfig.ExecStart = ''
+              ${pkgs.coreutils}/bin/install -o nextcloud-exporter -m 0400 ${passfile} /var/nextcloud-pwfile
+            '';
+          };
         services.nginx = {
           enable = true;
           virtualHosts."localhost" = {
@@ -544,7 +634,7 @@ let
         wait_for_unit("nginx.service")
         wait_for_unit("prometheus-nextcloud-exporter.service")
         wait_for_open_port(9205)
-        succeed("curl -sSf http://localhost:9205/metrics | grep -q 'nextcloud_up 1'")
+        succeed("curl -sSf http://localhost:9205/metrics | grep 'nextcloud_up 1'")
       '';
     };
 
@@ -563,7 +653,7 @@ let
         wait_for_unit("nginx.service")
         wait_for_unit("prometheus-nginx-exporter.service")
         wait_for_open_port(9113)
-        succeed("curl -sSf http://localhost:9113/metrics | grep -q 'nginx_up 1'")
+        succeed("curl -sSf http://localhost:9113/metrics | grep 'nginx_up 1'")
       '';
     };
 
@@ -585,7 +675,7 @@ let
                 syslog = {
                   listen_address = "udp://127.0.0.1:10000";
                   format = "rfc3164";
-                  tags = ["nginx"];
+                  tags = [ "nginx" ];
                 };
               };
             }
@@ -618,12 +708,12 @@ let
         succeed("curl http://localhost")
         execute("sleep 1")
         succeed(
-            "curl -sSf http://localhost:9117/metrics | grep 'filelogger_http_response_count_total' | grep -q 1"
+            "curl -sSf http://localhost:9117/metrics | grep 'filelogger_http_response_count_total' | grep 1"
         )
         succeed("curl http://localhost:81")
         execute("sleep 1")
         succeed(
-            "curl -sSf http://localhost:9117/metrics | grep 'syslogger_http_response_count_total' | grep -q 1"
+            "curl -sSf http://localhost:9117/metrics | grep 'syslogger_http_response_count_total' | grep 1"
         )
       '';
     };
@@ -636,7 +726,7 @@ let
         wait_for_unit("prometheus-node-exporter.service")
         wait_for_open_port(9100)
         succeed(
-            "curl -sSf http://localhost:9100/metrics | grep -q 'node_exporter_build_info{.\\+} 1'"
+            "curl -sSf http://localhost:9100/metrics | grep 'node_exporter_build_info{.\\+} 1'"
         )
       '';
     };
@@ -696,7 +786,7 @@ let
         wait_for_open_port(389)
         wait_for_open_port(9330)
         wait_until_succeeds(
-            "curl -sSf http://localhost:9330/metrics | grep -q 'openldap_scrape{result=\"ok\"} 1'"
+            "curl -sSf http://localhost:9330/metrics | grep 'openldap_scrape{result=\"ok\"} 1'"
         )
       '';
     };
@@ -705,10 +795,10 @@ let
       exporterConfig = {
         enable = true;
         group = "openvpn";
-        statusPaths = ["/run/openvpn-test"];
+        statusPaths = [ "/run/openvpn-test" ];
       };
       metricProvider = {
-        users.groups.openvpn = {};
+        users.groups.openvpn = { };
         services.openvpn.servers.test = {
           config = ''
             dev tun
@@ -722,7 +812,7 @@ let
       exporterTest = ''
         wait_for_unit("openvpn-test.service")
         wait_for_unit("prometheus-openvpn-exporter.service")
-        succeed("curl -sSf http://localhost:9176/metrics | grep -q 'openvpn_up{.*} 1'")
+        succeed("curl -sSf http://localhost:9176/metrics | grep 'openvpn_up{.*} 1'")
       '';
     };
 
@@ -738,9 +828,9 @@ let
         wait_for_file("/var/lib/postfix/queue/public/showq")
         wait_for_open_port(9154)
         succeed(
-            "curl -sSf http://localhost:9154/metrics | grep -q 'postfix_smtpd_connects_total 0'"
+            "curl -sSf http://localhost:9154/metrics | grep 'postfix_smtpd_connects_total 0'"
         )
-        succeed("curl -sSf http://localhost:9154/metrics | grep -q 'postfix_up{.*} 1'")
+        succeed("curl -sSf http://localhost:9154/metrics | grep 'postfix_up{.*} 1'")
       '';
     };
 
@@ -757,20 +847,39 @@ let
         wait_for_open_port(9187)
         wait_for_unit("postgresql.service")
         succeed(
-            "curl -sSf http://localhost:9187/metrics | grep -q 'pg_exporter_last_scrape_error 0'"
+            "curl -sSf http://localhost:9187/metrics | grep 'pg_exporter_last_scrape_error 0'"
         )
-        succeed("curl -sSf http://localhost:9187/metrics | grep -q 'pg_up 1'")
+        succeed("curl -sSf http://localhost:9187/metrics | grep 'pg_up 1'")
         systemctl("stop postgresql.service")
         succeed(
-            "curl -sSf http://localhost:9187/metrics | grep -qv 'pg_exporter_last_scrape_error 0'"
+            "curl -sSf http://localhost:9187/metrics | grep -v 'pg_exporter_last_scrape_error 0'"
         )
-        succeed("curl -sSf http://localhost:9187/metrics | grep -q 'pg_up 0'")
+        succeed("curl -sSf http://localhost:9187/metrics | grep 'pg_up 0'")
         systemctl("start postgresql.service")
         wait_for_unit("postgresql.service")
         succeed(
-            "curl -sSf http://localhost:9187/metrics | grep -q 'pg_exporter_last_scrape_error 0'"
+            "curl -sSf http://localhost:9187/metrics | grep 'pg_exporter_last_scrape_error 0'"
+        )
+        succeed("curl -sSf http://localhost:9187/metrics | grep 'pg_up 1'")
+      '';
+    };
+
+    process = {
+      exporterConfig = {
+        enable = true;
+        settings.process_names = [
+          # Remove nix store path from process name
+          { name = "{{.Matches.Wrapped}} {{ .Matches.Args }}"; cmdline = [ "^/nix/store[^ ]*/(?P<Wrapped>[^ /]*) (?P<Args>.*)" ]; }
+        ];
+      };
+      exporterTest = ''
+        wait_for_unit("prometheus-process-exporter.service")
+        wait_for_open_port(9256)
+        wait_until_succeeds(
+            "curl -sSf localhost:9256/metrics | grep -q '{}'".format(
+                'namedprocess_namegroup_cpu_seconds_total{groupname="process-exporter '
+            )
         )
-        succeed("curl -sSf http://localhost:9187/metrics | grep -q 'pg_up 1'")
       '';
     };
 
@@ -784,7 +893,7 @@ let
         wait_for_unit("prometheus-py-air-control-exporter.service")
         wait_for_open_port(9896)
         succeed(
-            "curl -sSf http://localhost:9896/metrics | grep -q 'py_air_control_sampling_error_total'"
+            "curl -sSf http://localhost:9896/metrics | grep 'py_air_control_sampling_error_total'"
         )
       '';
     };
@@ -799,7 +908,7 @@ let
         wait_for_unit("prometheus-redis-exporter.service")
         wait_for_open_port(6379)
         wait_for_open_port(9121)
-        wait_until_succeeds("curl -sSf localhost:9121/metrics | grep -q 'redis_up 1'")
+        wait_until_succeeds("curl -sSf localhost:9121/metrics | grep 'redis_up 1'")
       '';
     };
 
@@ -817,7 +926,7 @@ let
         wait_for_open_port(11334)
         wait_for_open_port(7980)
         wait_until_succeeds(
-            "curl -sSf 'localhost:7980/probe?target=http://localhost:11334/stat' | grep -q 'rspamd_scanned{host=\"rspamd\"} 0'"
+            "curl -sSf 'localhost:7980/probe?target=http://localhost:11334/stat' | grep 'rspamd_scanned{host=\"rspamd\"} 0'"
         )
       '';
     };
@@ -828,46 +937,66 @@ let
       };
       metricProvider = {
         # Mock rtl_433 binary to return a dummy metric stream.
-        nixpkgs.overlays = [ (self: super: {
-          rtl_433 = self.runCommand "rtl_433" {} ''
-            mkdir -p "$out/bin"
-            cat <<EOF > "$out/bin/rtl_433"
-            #!/bin/sh
-            while true; do
-              printf '{"time" : "2020-04-26 13:37:42", "model" : "zopieux", "id" : 55, "channel" : 3, "temperature_C" : 18.000}\n'
-              sleep 4
-            done
-            EOF
-            chmod +x "$out/bin/rtl_433"
-          '';
-        }) ];
+        nixpkgs.overlays = [
+          (self: super: {
+            rtl_433 = self.runCommand "rtl_433" { } ''
+              mkdir -p "$out/bin"
+              cat <<EOF > "$out/bin/rtl_433"
+              #!/bin/sh
+              while true; do
+                printf '{"time" : "2020-04-26 13:37:42", "model" : "zopieux", "id" : 55, "channel" : 3, "temperature_C" : 18.000}\n'
+                sleep 4
+              done
+              EOF
+              chmod +x "$out/bin/rtl_433"
+            '';
+          })
+        ];
       };
       exporterTest = ''
         wait_for_unit("prometheus-rtl_433-exporter.service")
         wait_for_open_port(9550)
         wait_until_succeeds(
-            "curl -sSf localhost:9550/metrics | grep -q '{}'".format(
+            "curl -sSf localhost:9550/metrics | grep '{}'".format(
                 'rtl_433_temperature_celsius{channel="3",id="55",location="",model="zopieux"} 18'
             )
         )
       '';
     };
 
+    script = {
+      exporterConfig = {
+        enable = true;
+        settings.scripts = [
+          { name = "success"; script = "sleep 1"; }
+        ];
+      };
+      exporterTest = ''
+        wait_for_unit("prometheus-script-exporter.service")
+        wait_for_open_port(9172)
+        wait_until_succeeds(
+            "curl -sSf 'localhost:9172/probe?name=success' | grep -q '{}'".format(
+                'script_success{script="success"} 1'
+            )
+        )
+      '';
+    };
+
     smokeping = {
       exporterConfig = {
         enable = true;
-        hosts = ["127.0.0.1"];
+        hosts = [ "127.0.0.1" ];
       };
       exporterTest = ''
         wait_for_unit("prometheus-smokeping-exporter.service")
         wait_for_open_port(9374)
         wait_until_succeeds(
-            "curl -sSf localhost:9374/metrics | grep '{}' | grep -qv ' 0$'".format(
+            "curl -sSf localhost:9374/metrics | grep '{}' | grep -v ' 0$'".format(
                 'smokeping_requests_total{host="127.0.0.1",ip="127.0.0.1"} '
             )
         )
         wait_until_succeeds(
-            "curl -sSf localhost:9374/metrics | grep -q '{}'".format(
+            "curl -sSf localhost:9374/metrics | grep '{}'".format(
                 'smokeping_response_ttl{host="127.0.0.1",ip="127.0.0.1"}'
             )
         )
@@ -885,7 +1014,7 @@ let
       exporterTest = ''
         wait_for_unit("prometheus-snmp-exporter.service")
         wait_for_open_port(9116)
-        succeed("curl -sSf localhost:9116/metrics | grep -q 'snmp_request_errors_total 0'")
+        succeed("curl -sSf localhost:9116/metrics | grep 'snmp_request_errors_total 0'")
       '';
     };
 
@@ -929,7 +1058,7 @@ let
       exporterTest = ''
         wait_for_unit("prometheus-sql-exporter.service")
         wait_for_open_port(9237)
-        succeed("curl http://localhost:9237/metrics | grep -c 'sql_points{' | grep -q 2")
+        succeed("curl http://localhost:9237/metrics | grep -c 'sql_points{' | grep 2")
       '';
     };
 
@@ -952,7 +1081,7 @@ let
         wait_for_open_port(80)
         wait_for_unit("prometheus-surfboard-exporter.service")
         wait_for_open_port(9239)
-        succeed("curl -sSf localhost:9239/metrics | grep -q 'surfboard_up 1'")
+        succeed("curl -sSf localhost:9239/metrics | grep 'surfboard_up 1'")
       '';
     };
 
@@ -965,7 +1094,7 @@ let
         wait_for_unit("prometheus-systemd-exporter.service")
         wait_for_open_port(9558)
         succeed(
-            "curl -sSf localhost:9558/metrics | grep -q '{}'".format(
+            "curl -sSf localhost:9558/metrics | grep '{}'".format(
                 'systemd_unit_state{name="basic.target",state="active",type="target"} 1'
             )
         )
@@ -980,30 +1109,53 @@ let
         # Note: this does not connect the test environment to the Tor network.
         # Client, relay, bridge or exit connectivity are disabled by default.
         services.tor.enable = true;
-        services.tor.controlPort = 9051;
+        services.tor.settings.ControlPort = 9051;
       };
       exporterTest = ''
         wait_for_unit("tor.service")
         wait_for_open_port(9051)
         wait_for_unit("prometheus-tor-exporter.service")
         wait_for_open_port(9130)
-        succeed("curl -sSf localhost:9130/metrics | grep -q 'tor_version{.\\+} 1'")
+        succeed("curl -sSf localhost:9130/metrics | grep 'tor_version{.\\+} 1'")
       '';
     };
 
     unifi-poller = {
       nodeName = "unifi_poller";
       exporterConfig.enable = true;
-      exporterConfig.controllers = [ { } ];
+      exporterConfig.controllers = [{ }];
       exporterTest = ''
         wait_for_unit("prometheus-unifi-poller-exporter.service")
         wait_for_open_port(9130)
         succeed(
-            "curl -sSf localhost:9130/metrics | grep -q 'unifipoller_build_info{.\\+} 1'"
+            "curl -sSf localhost:9130/metrics | grep 'unifipoller_build_info{.\\+} 1'"
         )
       '';
     };
 
+    unbound = {
+      exporterConfig = {
+        enable = true;
+        fetchType = "uds";
+        controlInterface = "/run/unbound/unbound.ctl";
+      };
+      metricProvider = {
+        services.unbound = {
+          enable = true;
+          localControlSocketPath = "/run/unbound/unbound.ctl";
+        };
+        systemd.services.prometheus-unbound-exporter.serviceConfig = {
+          SupplementaryGroups = [ "unbound" ];
+        };
+      };
+      exporterTest = ''
+        wait_for_unit("unbound.service")
+        wait_for_unit("prometheus-unbound-exporter.service")
+        wait_for_open_port(9167)
+        succeed("curl -sSf localhost:9167/metrics | grep 'unbound_up 1'")
+      '';
+    };
+
     varnish = {
       exporterConfig = {
         enable = true;
@@ -1029,58 +1181,64 @@ let
         wait_for_unit("prometheus-varnish-exporter.service")
         wait_for_open_port(6081)
         wait_for_open_port(9131)
-        succeed("curl -sSf http://localhost:9131/metrics | grep -q 'varnish_up 1'")
+        succeed("curl -sSf http://localhost:9131/metrics | grep 'varnish_up 1'")
       '';
     };
 
-    wireguard = let snakeoil = import ./wireguard/snakeoil-keys.nix; in {
-      exporterConfig.enable = true;
-      metricProvider = {
-        networking.wireguard.interfaces.wg0 = {
-          ips = [ "10.23.42.1/32" "fc00::1/128" ];
-          listenPort = 23542;
+    wireguard = let snakeoil = import ./wireguard/snakeoil-keys.nix; in
+      {
+        exporterConfig.enable = true;
+        metricProvider = {
+          networking.wireguard.interfaces.wg0 = {
+            ips = [ "10.23.42.1/32" "fc00::1/128" ];
+            listenPort = 23542;
 
-          inherit (snakeoil.peer0) privateKey;
+            inherit (snakeoil.peer0) privateKey;
 
-          peers = singleton {
-            allowedIPs = [ "10.23.42.2/32" "fc00::2/128" ];
+            peers = singleton {
+              allowedIPs = [ "10.23.42.2/32" "fc00::2/128" ];
 
-            inherit (snakeoil.peer1) publicKey;
+              inherit (snakeoil.peer1) publicKey;
+            };
           };
+          systemd.services.prometheus-wireguard-exporter.after = [ "wireguard-wg0.service" ];
         };
-        systemd.services.prometheus-wireguard-exporter.after = [ "wireguard-wg0.service" ];
+        exporterTest = ''
+          wait_for_unit("prometheus-wireguard-exporter.service")
+          wait_for_open_port(9586)
+          wait_until_succeeds(
+              "curl -sSf http://localhost:9586/metrics | grep '${snakeoil.peer1.publicKey}'"
+          )
+        '';
       };
-      exporterTest = ''
-        wait_for_unit("prometheus-wireguard-exporter.service")
-        wait_for_open_port(9586)
-        wait_until_succeeds(
-            "curl -sSf http://localhost:9586/metrics | grep '${snakeoil.peer1.publicKey}'"
-        )
-      '';
-    };
   };
 in
-mapAttrs (exporter: testConfig: (makeTest (let
-  nodeName = testConfig.nodeName or exporter;
+mapAttrs
+  (exporter: testConfig: (makeTest (
+    let
+      nodeName = testConfig.nodeName or exporter;
 
-in {
-  name = "prometheus-${exporter}-exporter";
+    in
+    {
+      name = "prometheus-${exporter}-exporter";
 
-  nodes.${nodeName} = mkMerge [{
-    services.prometheus.exporters.${exporter} = testConfig.exporterConfig;
-  } testConfig.metricProvider or {}];
+      nodes.${nodeName} = mkMerge [{
+        services.prometheus.exporters.${exporter} = testConfig.exporterConfig;
+      } testConfig.metricProvider or { }];
 
-  testScript = ''
-    ${nodeName}.start()
-    ${concatStringsSep "\n" (map (line:
-      if (builtins.substring 0 1 line == " " || builtins.substring 0 1 line == ")")
-      then line
-      else "${nodeName}.${line}"
-    ) (splitString "\n" (removeSuffix "\n" testConfig.exporterTest)))}
-    ${nodeName}.shutdown()
-  '';
+      testScript = ''
+        ${nodeName}.start()
+        ${concatStringsSep "\n" (map (line:
+          if (builtins.substring 0 1 line == " " || builtins.substring 0 1 line == ")")
+          then line
+          else "${nodeName}.${line}"
+        ) (splitString "\n" (removeSuffix "\n" testConfig.exporterTest)))}
+        ${nodeName}.shutdown()
+      '';
 
-  meta = with maintainers; {
-    maintainers = [ willibutz elseym ];
-  };
-}))) exporterTests
+      meta = with maintainers; {
+        maintainers = [ willibutz elseym ];
+      };
+    }
+  )))
+  exporterTests