summary refs log tree commit diff
path: root/nixos/modules/services/monitoring
diff options
context:
space:
mode:
authorParnell Springmeyer <parnell@digitalmentat.com>2017-01-25 11:08:05 -0800
committerParnell Springmeyer <parnell@digitalmentat.com>2017-01-25 11:08:05 -0800
commitbae00e8aa8f3faff90e28e19cd5074b8c26d0d0e (patch)
tree56abaf30f11ad2f24b9fb7729f74c5fff50fbd93 /nixos/modules/services/monitoring
parent1f9494b752082ec3ac048e56d1c6364a2e23a675 (diff)
parent104c3db6594043dbb81005303f055b02145305a5 (diff)
downloadnixlib-bae00e8aa8f3faff90e28e19cd5074b8c26d0d0e.tar
nixlib-bae00e8aa8f3faff90e28e19cd5074b8c26d0d0e.tar.gz
nixlib-bae00e8aa8f3faff90e28e19cd5074b8c26d0d0e.tar.bz2
nixlib-bae00e8aa8f3faff90e28e19cd5074b8c26d0d0e.tar.lz
nixlib-bae00e8aa8f3faff90e28e19cd5074b8c26d0d0e.tar.xz
nixlib-bae00e8aa8f3faff90e28e19cd5074b8c26d0d0e.tar.zst
nixlib-bae00e8aa8f3faff90e28e19cd5074b8c26d0d0e.zip
setcap-wrapper: Merging with upstream master and resolving conflicts
Diffstat (limited to 'nixos/modules/services/monitoring')
-rw-r--r--nixos/modules/services/monitoring/bosun.nix2
-rw-r--r--nixos/modules/services/monitoring/cadvisor.nix1
-rw-r--r--nixos/modules/services/monitoring/collectd.nix5
-rw-r--r--nixos/modules/services/monitoring/graphite.nix18
-rw-r--r--nixos/modules/services/monitoring/monit.nix13
-rw-r--r--nixos/modules/services/monitoring/munin.nix1
-rw-r--r--nixos/modules/services/monitoring/nagios.nix2
-rw-r--r--nixos/modules/services/monitoring/prometheus/alertmanager.nix116
-rw-r--r--nixos/modules/services/monitoring/prometheus/blackbox-exporter.nix67
-rw-r--r--nixos/modules/services/monitoring/prometheus/default.nix465
-rw-r--r--nixos/modules/services/monitoring/prometheus/json-exporter.nix74
-rw-r--r--nixos/modules/services/monitoring/prometheus/nginx-exporter.nix78
-rw-r--r--nixos/modules/services/monitoring/prometheus/node-exporter.nix81
-rw-r--r--nixos/modules/services/monitoring/prometheus/snmp-exporter.nix127
-rw-r--r--nixos/modules/services/monitoring/prometheus/varnish-exporter.nix61
-rw-r--r--nixos/modules/services/monitoring/riemann-tools.nix1
-rw-r--r--nixos/modules/services/monitoring/smartd.nix3
-rw-r--r--nixos/modules/services/monitoring/telegraf.nix71
-rw-r--r--nixos/modules/services/monitoring/ups.nix10
-rw-r--r--nixos/modules/services/monitoring/zabbix-agent.nix1
20 files changed, 1173 insertions, 24 deletions
diff --git a/nixos/modules/services/monitoring/bosun.nix b/nixos/modules/services/monitoring/bosun.nix
index 9a1e790d3ab6..496838a131ba 100644
--- a/nixos/modules/services/monitoring/bosun.nix
+++ b/nixos/modules/services/monitoring/bosun.nix
@@ -107,7 +107,7 @@ in {
       };
 
       extraConfig = mkOption {
-        type = types.string;
+        type = types.lines;
         default = "";
         description = ''
           Extra configuration options for Bosun. You should describe your
diff --git a/nixos/modules/services/monitoring/cadvisor.nix b/nixos/modules/services/monitoring/cadvisor.nix
index a67df158be47..8ae8b12056ce 100644
--- a/nixos/modules/services/monitoring/cadvisor.nix
+++ b/nixos/modules/services/monitoring/cadvisor.nix
@@ -90,6 +90,7 @@ in {
             ${optionalString cfg.storageDriverSecure "-storage_driver_secure"}
           ''}
         '';
+        TimeoutStartSec=300;
       };
     };
 
diff --git a/nixos/modules/services/monitoring/collectd.nix b/nixos/modules/services/monitoring/collectd.nix
index 3c3d83c66ed0..641da60e9adc 100644
--- a/nixos/modules/services/monitoring/collectd.nix
+++ b/nixos/modules/services/monitoring/collectd.nix
@@ -9,7 +9,7 @@ let
     BaseDir "${cfg.dataDir}"
     PIDFile "${cfg.pidFile}"
     AutoLoadPlugin ${if cfg.autoLoadPlugin then "true" else "false"}
-    Hostname ${config.networking.hostName}
+    Hostname "${config.networking.hostName}"
 
     LoadPlugin syslog
     <Plugin "syslog">
@@ -108,7 +108,8 @@ in {
       };
 
       preStart = ''
-        mkdir -m 0700 -p ${cfg.dataDir}
+        mkdir -p ${cfg.dataDir}
+        chmod 755 ${cfg.dataDir}
         install -D /dev/null ${cfg.pidFile}
         if [ "$(id -u)" = 0 ]; then
           chown -R ${cfg.user} ${cfg.dataDir};
diff --git a/nixos/modules/services/monitoring/graphite.nix b/nixos/modules/services/monitoring/graphite.nix
index 08fc3f04dbfc..c5352e5887da 100644
--- a/nixos/modules/services/monitoring/graphite.nix
+++ b/nixos/modules/services/monitoring/graphite.nix
@@ -167,7 +167,7 @@ in {
             CACHE_TYPE: 'filesystem'
             CACHE_DIR: '/tmp/graphite-api-cache'
         '';
-        type = types.str;
+        type = types.lines;
       };
     };
 
@@ -387,7 +387,7 @@ in {
       systemd.services.carbonCache = let name = "carbon-cache"; in {
         description = "Graphite Data Storage Backend";
         wantedBy = [ "multi-user.target" ];
-        after = [ "network-interfaces.target" ];
+        after = [ "network.target" ];
         environment = carbonEnv;
         serviceConfig = {
           ExecStart = "${pkgs.pythonPackages.twisted}/bin/twistd ${carbonOpts name}";
@@ -410,7 +410,7 @@ in {
         enable = cfg.carbon.enableAggregator;
         description = "Carbon Data Aggregator";
         wantedBy = [ "multi-user.target" ];
-        after = [ "network-interfaces.target" ];
+        after = [ "network.target" ];
         environment = carbonEnv;
         serviceConfig = {
           ExecStart = "${pkgs.pythonPackages.twisted}/bin/twistd ${carbonOpts name}";
@@ -426,7 +426,7 @@ in {
       systemd.services.carbonRelay = let name = "carbon-relay"; in {
         description = "Carbon Data Relay";
         wantedBy = [ "multi-user.target" ];
-        after = [ "network-interfaces.target" ];
+        after = [ "network.target" ];
         environment = carbonEnv;
         serviceConfig = {
           ExecStart = "${pkgs.pythonPackages.twisted}/bin/twistd ${carbonOpts name}";
@@ -448,7 +448,7 @@ in {
       systemd.services.graphiteWeb = {
         description = "Graphite Web Interface";
         wantedBy = [ "multi-user.target" ];
-        after = [ "network-interfaces.target" ];
+        after = [ "network.target" ];
         path = [ pkgs.perl ];
         environment = {
           PYTHONPATH = let
@@ -501,7 +501,7 @@ in {
       systemd.services.graphiteApi = {
         description = "Graphite Api Interface";
         wantedBy = [ "multi-user.target" ];
-        after = [ "network-interfaces.target" ];
+        after = [ "network.target" ];
         environment = {
           PYTHONPATH = let
               aenv = pkgs.python.buildEnv.override {
@@ -538,7 +538,7 @@ in {
       systemd.services.seyren = {
         description = "Graphite Alerting Dashboard";
         wantedBy = [ "multi-user.target" ];
-        after = [ "network-interfaces.target" "mongodb.service" ];
+        after = [ "network.target" "mongodb.service" ];
         environment = seyrenConfig;
         serviceConfig = {
           ExecStart = "${pkgs.seyren}/bin/seyren -httpPort ${toString cfg.seyren.port}";
@@ -561,7 +561,7 @@ in {
       systemd.services.graphitePager = {
         description = "Graphite Pager Alerting Daemon";
         wantedBy = [ "multi-user.target" ];
-        after = [ "network-interfaces.target" "redis.service" ];
+        after = [ "network.target" "redis.service" ];
         environment = {
           REDIS_URL = cfg.pager.redisUrl;
           GRAPHITE_URL = cfg.pager.graphiteUrl;
@@ -585,7 +585,7 @@ in {
         serviceConfig = {
           ExecStart = ''
             ${pkgs.pythonPackages.graphite_beacon}/bin/graphite-beacon \
-              --config ${pkgs.writeText "graphite-beacon.json" (builtins.toJSON cfg.beacon.config)}
+              --config=${pkgs.writeText "graphite-beacon.json" (builtins.toJSON cfg.beacon.config)}
           '';
           User = "graphite";
           Group = "graphite";
diff --git a/nixos/modules/services/monitoring/monit.nix b/nixos/modules/services/monitoring/monit.nix
index 704693969a35..e07ffd2e8b54 100644
--- a/nixos/modules/services/monitoring/monit.nix
+++ b/nixos/modules/services/monitoring/monit.nix
@@ -36,11 +36,16 @@ in
     ];
 
     systemd.services.monit = {
-      description = "Monit system watcher";
-      after = [ "network-interfaces.target" ];
+      description = "Pro-active monitoring utility for unix systems";
+      after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
-      script = "${pkgs.monit}/bin/monit -I -c /etc/monit.conf";
-      serviceConfig.Restart = "always";
+      serviceConfig = {
+        ExecStart = "${pkgs.monit}/bin/monit -I -c /etc/monit.conf";
+        ExecStop = "${pkgs.monit}/bin/monit -c /etc/monit.conf quit";
+        ExecReload = "${pkgs.monit}/bin/monit -c /etc/monit.conf reload";
+        KillMode = "process";
+        Restart = "always";
+      };
     };
   };
 }
diff --git a/nixos/modules/services/monitoring/munin.nix b/nixos/modules/services/monitoring/munin.nix
index 08ba161d38bd..a80565fa280b 100644
--- a/nixos/modules/services/monitoring/munin.nix
+++ b/nixos/modules/services/monitoring/munin.nix
@@ -100,6 +100,7 @@ in
 
       extraConfig = mkOption {
         default = "";
+        type = types.lines;
         description = ''
           <filename>munin-node.conf</filename> extra configuration. See
           <link xlink:href='http://munin-monitoring.org/wiki/munin-node.conf' />
diff --git a/nixos/modules/services/monitoring/nagios.nix b/nixos/modules/services/monitoring/nagios.nix
index f2f7710de9e7..4914c5db97d2 100644
--- a/nixos/modules/services/monitoring/nagios.nix
+++ b/nixos/modules/services/monitoring/nagios.nix
@@ -163,7 +163,7 @@ in
       description = "Nagios monitoring daemon";
       path     = [ pkgs.nagios ];
       wantedBy = [ "multi-user.target" ];
-      after    = [ "network-interfaces.target" ];
+      after    = [ "network.target" ];
 
       serviceConfig = {
         User = "nagios";
diff --git a/nixos/modules/services/monitoring/prometheus/alertmanager.nix b/nixos/modules/services/monitoring/prometheus/alertmanager.nix
new file mode 100644
index 000000000000..da2cd02eaa3b
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/alertmanager.nix
@@ -0,0 +1,116 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.prometheus.alertmanager;
+  mkConfigFile = pkgs.writeText "alertmanager.yml" (builtins.toJSON cfg.configuration);
+in {
+  options = {
+    services.prometheus.alertmanager = {
+      enable = mkEnableOption "Prometheus Alertmanager";
+
+      user = mkOption {
+        type = types.str;
+        default = "nobody";
+        description = ''
+          User name under which Alertmanager shall be run.
+        '';
+      };
+
+      group = mkOption {
+        type = types.str;
+        default = "nogroup";
+        description = ''
+          Group under which Alertmanager shall be run.
+        '';
+      };
+
+      configuration = mkOption {
+        type = types.attrs;
+        default = {};
+        description = ''
+          Alertmanager configuration as nix attribute set.
+        '';
+      };
+
+      logFormat = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          If set use a syslog logger or JSON logging.
+        '';
+      };
+
+      logLevel = mkOption {
+        type = types.enum ["debug" "info" "warn" "error" "fatal"];
+        default = "warn";
+        description = ''
+          Only log messages with the given severity or above.
+        '';
+      };
+
+      webExternalUrl = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          The URL under which Alertmanager is externally reachable (for example, if Alertmanager is served via a reverse proxy).
+          Used for generating relative and absolute links back to Alertmanager itself.
+          If the URL has a path portion, it will be used to prefix all HTTP endoints served by Alertmanager.
+          If omitted, relevant URL components will be derived automatically.
+        '';
+      };
+
+      listenAddress = mkOption {
+        type = types.str;
+        default = "";
+        description = ''
+          Address to listen on for the web interface and API.
+        '';
+      };
+
+      port = mkOption {
+        type = types.int;
+        default = 9093;
+        description = ''
+          Port to listen on for the web interface and API.
+        '';
+      };
+
+      openFirewall = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Open port in firewall for incoming connections.
+        '';
+      };
+    };
+  };
+
+
+  config = mkIf cfg.enable {
+    networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port;
+
+    systemd.services.alertmanager = {
+      wantedBy = [ "multi-user.target" ];
+      after    = [ "network.target" ];
+      script = ''
+        ${pkgs.prometheus-alertmanager.bin}/bin/alertmanager \
+        -config.file ${mkConfigFile} \
+        -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
+        -log.level ${cfg.logLevel} \
+        ${optionalString (cfg.webExternalUrl != null) ''-web.external-url ${cfg.webExternalUrl} \''}
+        ${optionalString (cfg.logFormat != null) "-log.format ${cfg.logFormat}"}
+      '';
+
+      serviceConfig = {
+        User = cfg.user;
+        Group = cfg.group;
+        Restart  = "always";
+        PrivateTmp = true;
+        WorkingDirectory = "/tmp";
+        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/prometheus/blackbox-exporter.nix b/nixos/modules/services/monitoring/prometheus/blackbox-exporter.nix
new file mode 100644
index 000000000000..7a343299c315
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/blackbox-exporter.nix
@@ -0,0 +1,67 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.prometheus.blackboxExporter;
+in {
+  options = {
+    services.prometheus.blackboxExporter = {
+      enable = mkEnableOption "prometheus blackbox exporter";
+
+      configFile = mkOption {
+        type = types.path;
+        description = ''
+          Path to configuration file.
+        '';
+      };
+
+      port = mkOption {
+        type = types.int;
+        default = 9115;
+        description = ''
+          Port to listen on.
+        '';
+      };
+
+      extraFlags = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          Extra commandline options when launching the blackbox exporter.
+        '';
+      };
+
+      openFirewall = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Open port in firewall for incoming connections.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port;
+
+    systemd.services.prometheus-blackbox-exporter = {
+      description = "Prometheus exporter for blackbox probes";
+      unitConfig.Documentation = "https://github.com/prometheus/blackbox_exporter";
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        User = "nobody";
+        Restart = "always";
+        PrivateTmp = true;
+        WorkingDirectory = /tmp;
+        ExecStart = ''
+          ${pkgs.prometheus-blackbox-exporter}/bin/blackbox_exporter \
+            -web.listen-address :${toString cfg.port} \
+            -config.file ${cfg.configFile} \
+            ${concatStringsSep " \\\n  " cfg.extraFlags}
+        '';
+        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/prometheus/default.nix b/nixos/modules/services/monitoring/prometheus/default.nix
new file mode 100644
index 000000000000..a07445ce167c
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/default.nix
@@ -0,0 +1,465 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.prometheus;
+  promUser = "prometheus";
+  promGroup = "prometheus";
+
+  # Get a submodule without any embedded metadata:
+  _filter = x: filterAttrs (k: v: k != "_module") x;
+
+  # Pretty-print JSON to a file
+  writePrettyJSON = name: x:
+    pkgs.runCommand name { } ''
+      echo '${builtins.toJSON x}' | ${pkgs.jq}/bin/jq . > $out
+    '';
+
+  # This becomes the main config file
+  promConfig = {
+    global = cfg.globalConfig;
+    rule_files = cfg.ruleFiles ++ [
+      (pkgs.writeText "prometheus.rules" (concatStringsSep "\n" cfg.rules))
+    ];
+    scrape_configs = cfg.scrapeConfigs;
+  };
+
+  generatedPrometheusYml = writePrettyJSON "prometheus.yml" promConfig;
+
+  prometheusYml =
+    if cfg.configText != null then
+      pkgs.writeText "prometheus.yml" cfg.configText
+    else generatedPrometheusYml;
+
+  cmdlineArgs = cfg.extraFlags ++ [
+    "-storage.local.path=${cfg.dataDir}/metrics"
+    "-config.file=${prometheusYml}"
+    "-web.listen-address=${cfg.listenAddress}"
+    "-alertmanager.notification-queue-capacity=${toString cfg.alertmanagerNotificationQueueCapacity}"
+    "-alertmanager.timeout=${toString cfg.alertmanagerTimeout}s"
+    (optionalString (cfg.alertmanagerURL != []) "-alertmanager.url=${concatStringsSep "," cfg.alertmanagerURL}")
+  ];
+
+  promTypes.globalConfig = types.submodule {
+    options = {
+      scrape_interval = mkOption {
+        type = types.str;
+        default = "1m";
+        description = ''
+          How frequently to scrape targets by default.
+        '';
+      };
+
+      scrape_timeout = mkOption {
+        type = types.str;
+        default = "10s";
+        description = ''
+          How long until a scrape request times out.
+        '';
+      };
+
+      evaluation_interval = mkOption {
+        type = types.str;
+        default = "1m";
+        description = ''
+          How frequently to evaluate rules by default.
+        '';
+      };
+
+      labels = mkOption {
+        type = types.attrsOf types.str;
+        default = {};
+        description = ''
+          The labels to add to any timeseries that this Prometheus instance
+          scrapes.
+        '';
+      };
+    };
+  };
+
+  promTypes.scrape_config = types.submodule {
+    options = {
+      job_name = mkOption {
+        type = types.str;
+        description = ''
+          The job name assigned to scraped metrics by default.
+        '';
+      };
+      scrape_interval = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          How frequently to scrape targets from this job. Defaults to the
+          globally configured default.
+        '';
+      };
+      scrape_timeout = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          Per-target timeout when scraping this job. Defaults to the
+          globally configured default.
+        '';
+      };
+      metrics_path = mkOption {
+        type = types.str;
+        default = "/metrics";
+        description = ''
+          The HTTP resource path on which to fetch metrics from targets.
+        '';
+      };
+      scheme = mkOption {
+        type = types.enum ["http" "https"];
+        default = "http";
+        description = ''
+          The URL scheme with which to fetch metrics from targets.
+        '';
+      };
+      basic_auth = mkOption {
+        type = types.nullOr (types.submodule {
+          options = {
+            username = mkOption {
+              type = types.str;
+              description = ''
+                HTTP username
+              '';
+            };
+            password = mkOption {
+              type = types.str;
+              description = ''
+                HTTP password
+              '';
+            };
+          };
+        });
+        default = null;
+        description = ''
+          Optional http login credentials for metrics scraping.
+        '';
+      };
+      dns_sd_configs = mkOption {
+        type = types.listOf promTypes.dns_sd_config;
+        default = [];
+        apply = x: map _filter x;
+        description = ''
+          List of DNS service discovery configurations.
+        '';
+      };
+      consul_sd_configs = mkOption {
+        type = types.listOf promTypes.consul_sd_config;
+        default = [];
+        apply = x: map _filter x;
+        description = ''
+          List of Consul service discovery configurations.
+        '';
+      };
+      file_sd_configs = mkOption {
+        type = types.listOf promTypes.file_sd_config;
+        default = [];
+        apply = x: map _filter x;
+        description = ''
+          List of file service discovery configurations.
+        '';
+      };
+      static_configs = mkOption {
+        type = types.listOf promTypes.static_config;
+        default = [];
+        apply = x: map _filter x;
+        description = ''
+          List of labeled target groups for this job.
+        '';
+      };
+      relabel_configs = mkOption {
+        type = types.listOf promTypes.relabel_config;
+        default = [];
+        apply = x: map _filter x;
+        description = ''
+          List of relabel configurations.
+        '';
+      };
+    };
+  };
+
+  promTypes.static_config = types.submodule {
+    options = {
+      targets = mkOption {
+        type = types.listOf types.str;
+        description = ''
+          The targets specified by the target group.
+        '';
+      };
+      labels = mkOption {
+        type = types.attrsOf types.str;
+        default = {};
+        description = ''
+          Labels assigned to all metrics scraped from the targets.
+        '';
+      };
+    };
+  };
+
+  promTypes.dns_sd_config = types.submodule {
+    options = {
+      names = mkOption {
+        type = types.listOf types.str;
+        description = ''
+          A list of DNS SRV record names to be queried.
+        '';
+      };
+      refresh_interval = mkOption {
+        type = types.str;
+        default = "30s";
+        description = ''
+          The time after which the provided names are refreshed.
+        '';
+      };
+    };
+  };
+
+  promTypes.consul_sd_config = types.submodule {
+    options = {
+      server = mkOption {
+        type = types.str;
+        description = "Consul server to query.";
+      };
+      token = mkOption {
+        type = types.nullOr types.str;
+        description = "Consul token";
+      };
+      datacenter = mkOption {
+        type = types.nullOr types.str;
+        description = "Consul datacenter";
+      };
+      scheme = mkOption {
+        type = types.nullOr types.str;
+        description = "Consul scheme";
+      };
+      username = mkOption {
+        type = types.nullOr types.str;
+        description = "Consul username";
+      };
+      password = mkOption {
+        type = types.nullOr types.str;
+        description = "Consul password";
+      };
+
+      services = mkOption {
+        type = types.listOf types.str;
+        description = ''
+          A list of services for which targets are retrieved.
+        '';
+      };
+      tag_separator = mkOption {
+        type = types.str;
+        default = ",";
+        description = ''
+          The string by which Consul tags are joined into the tag label.
+        '';
+      };
+    };
+  };
+
+  promTypes.file_sd_config = types.submodule {
+    options = {
+      files = mkOption {
+        type = types.listOf types.str;
+        description = ''
+          Patterns for files from which target groups are extracted. Refer
+          to the Prometheus documentation for permitted filename patterns
+          and formats.
+
+        '';
+      };
+      refresh_interval = mkOption {
+        type = types.str;
+        default = "30s";
+        description = ''
+          Refresh interval to re-read the files.
+        '';
+      };
+    };
+  };
+
+  promTypes.relabel_config = types.submodule {
+    options = {
+      source_labels = mkOption {
+        type = types.listOf types.str;
+        description = ''
+          The source labels select values from existing labels. Their content
+          is concatenated using the configured separator and matched against
+          the configured regular expression.
+        '';
+      };
+      separator = mkOption {
+        type = types.str;
+        default = ";";
+        description = ''
+          Separator placed between concatenated source label values.
+        '';
+      };
+      target_label = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          Label to which the resulting value is written in a replace action.
+          It is mandatory for replace actions.
+        '';
+      };
+      regex = mkOption {
+        type = types.str;
+        default = "(.*)";
+        description = ''
+          Regular expression against which the extracted value is matched.
+        '';
+      };
+      replacement = mkOption {
+        type = types.str;
+        default = "$1";
+        description = ''
+          Replacement value against which a regex replace is performed if the
+          regular expression matches.
+        '';
+      };
+      action = mkOption {
+        type = types.enum ["replace" "keep" "drop"];
+        default = "replace";
+        description = ''
+          Action to perform based on regex matching.
+        '';
+      };
+    };
+  };
+
+in {
+  options = {
+    services.prometheus = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Enable the Prometheus monitoring daemon.
+        '';
+      };
+
+      listenAddress = mkOption {
+        type = types.str;
+        default = "0.0.0.0:9090";
+        description = ''
+          Address to listen on for the web interface, API, and telemetry.
+        '';
+      };
+
+      dataDir = mkOption {
+        type = types.path;
+        default = "/var/lib/prometheus";
+        description = ''
+          Directory to store Prometheus metrics data.
+        '';
+      };
+
+      extraFlags = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          Extra commandline options when launching Prometheus.
+        '';
+      };
+
+      configText = mkOption {
+        type = types.nullOr types.lines;
+        default = null;
+        description = ''
+          If non-null, this option defines the text that is written to
+          prometheus.yml. If null, the contents of prometheus.yml is generated
+          from the structured config options.
+        '';
+      };
+
+      globalConfig = mkOption {
+        type = promTypes.globalConfig;
+        default = {};
+        apply = _filter;
+        description = ''
+          Parameters that are valid in all  configuration contexts. They
+          also serve as defaults for other configuration sections
+        '';
+      };
+
+      rules = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          Alerting and/or Recording rules to evaluate at runtime.
+        '';
+      };
+
+      ruleFiles = mkOption {
+        type = types.listOf types.path;
+        default = [];
+        description = ''
+          Any additional rules files to include in this configuration.
+        '';
+      };
+
+      scrapeConfigs = mkOption {
+        type = types.listOf promTypes.scrape_config;
+        default = [];
+        apply = x: map _filter x;
+        description = ''
+          A list of scrape configurations.
+        '';
+      };
+
+      alertmanagerURL = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          List of Alertmanager URLs to send notifications to.
+        '';
+      };
+
+      alertmanagerNotificationQueueCapacity = mkOption {
+        type = types.int;
+        default = 10000;
+        description = ''
+          The capacity of the queue for pending alert manager notifications.
+        '';
+      };
+
+      alertmanagerTimeout = mkOption {
+        type = types.int;
+        default = 10;
+        description = ''
+          Alert manager HTTP API timeout (in seconds).
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    users.extraGroups.${promGroup}.gid = config.ids.gids.prometheus;
+    users.extraUsers.${promUser} = {
+      description = "Prometheus daemon user";
+      uid = config.ids.uids.prometheus;
+      group = promGroup;
+      home = cfg.dataDir;
+      createHome = true;
+    };
+    systemd.services.prometheus = {
+      wantedBy = [ "multi-user.target" ];
+      after    = [ "network.target" ];
+      script = ''
+        #!/bin/sh
+        exec ${pkgs.prometheus}/bin/prometheus \
+          ${concatStringsSep " \\\n  " cmdlineArgs}
+      '';
+      serviceConfig = {
+        User = promUser;
+        Restart  = "always";
+        WorkingDirectory = cfg.dataDir;
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/prometheus/json-exporter.nix b/nixos/modules/services/monitoring/prometheus/json-exporter.nix
new file mode 100644
index 000000000000..6bc56df9834b
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/json-exporter.nix
@@ -0,0 +1,74 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.prometheus.jsonExporter;
+in {
+  options = {
+    services.prometheus.jsonExporter = {
+      enable = mkEnableOption "prometheus JSON exporter";
+
+      url = mkOption {
+        type = types.str;
+        description = ''
+          URL to scrape JSON from.
+        '';
+      };
+
+      configFile = mkOption {
+        type = types.path;
+        description = ''
+          Path to configuration file.
+        '';
+      };
+
+      port = mkOption {
+        type = types.int;
+        default = 7979;
+        description = ''
+          Port to listen on.
+        '';
+      };
+
+      extraFlags = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          Extra commandline options when launching the JSON exporter.
+        '';
+      };
+
+      openFirewall = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Open port in firewall for incoming connections.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port;
+
+    systemd.services.prometheus-json-exporter = {
+      description = "Prometheus exporter for JSON over HTTP";
+      unitConfig.Documentation = "https://github.com/kawamuray/prometheus-json-exporter";
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        User = "nobody";
+        Restart = "always";
+        PrivateTmp = true;
+        WorkingDirectory = /tmp;
+        ExecStart = ''
+          ${pkgs.prometheus-json-exporter}/bin/prometheus-json-exporter \
+            --port ${toString cfg.port} \
+            ${cfg.url} ${cfg.configFile} \
+            ${concatStringsSep " \\\n  " cfg.extraFlags}
+        '';
+        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/prometheus/nginx-exporter.nix b/nixos/modules/services/monitoring/prometheus/nginx-exporter.nix
new file mode 100644
index 000000000000..1ccafee3b18b
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/nginx-exporter.nix
@@ -0,0 +1,78 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.prometheus.nginxExporter;
+in {
+  options = {
+    services.prometheus.nginxExporter = {
+      enable = mkEnableOption "prometheus nginx exporter";
+
+      port = mkOption {
+        type = types.int;
+        default = 9113;
+        description = ''
+          Port to listen on.
+        '';
+      };
+
+      listenAddress = mkOption {
+        type = types.string;
+        default = "0.0.0.0";
+        description = ''
+          Address to listen on.
+        '';
+      };
+
+      scrapeUri = mkOption {
+        type = types.string;
+        default = "http://localhost/nginx_status";
+        description = ''
+          Address to access the nginx status page.
+          Can be enabled with services.nginx.statusPage = true.
+        '';
+      };
+
+      extraFlags = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          Extra commandline options when launching the nginx exporter.
+        '';
+      };
+
+      openFirewall = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Open port in firewall for incoming connections.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port;
+
+    systemd.services.prometheus-nginx-exporter = {
+      after = [ "network.target" "nginx.service" ];
+      description = "Prometheus exporter for nginx metrics";
+      unitConfig.Documentation = "https://github.com/discordianfish/nginx_exporter";
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        User = "nobody";
+        Restart  = "always";
+        PrivateTmp = true;
+        WorkingDirectory = /tmp;
+        ExecStart = ''
+          ${pkgs.prometheus-nginx-exporter}/bin/nginx_exporter \
+            -nginx.scrape_uri '${cfg.scrapeUri}' \
+            -telemetry.address ${cfg.listenAddress}:${toString cfg.port} \
+            ${concatStringsSep " \\\n  " cfg.extraFlags}
+        '';
+        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/prometheus/node-exporter.nix b/nixos/modules/services/monitoring/prometheus/node-exporter.nix
new file mode 100644
index 000000000000..0cf0b85afb57
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/node-exporter.nix
@@ -0,0 +1,81 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.prometheus.nodeExporter;
+  cmdlineArgs = cfg.extraFlags ++ [
+    "-web.listen-address=${cfg.listenAddress}"
+  ];
+in {
+  options = {
+    services.prometheus.nodeExporter = {
+      enable = mkEnableOption "prometheus node exporter";
+
+      port = mkOption {
+        type = types.int;
+        default = 9100;
+        description = ''
+          Port to listen on.
+        '';
+      };
+
+      listenAddress = mkOption {
+        type = types.string;
+        default = "0.0.0.0";
+        description = ''
+          Address to listen on.
+        '';
+      };
+
+      enabledCollectors = mkOption {
+        type = types.listOf types.string;
+        default = [];
+        example = ''[ "systemd" ]'';
+        description = ''
+          Collectors to enable, additionally to the defaults.
+        '';
+      };
+
+      extraFlags = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          Extra commandline options when launching the node exporter.
+        '';
+      };
+
+      openFirewall = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Open port in firewall for incoming connections.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port;
+
+    systemd.services.prometheus-node-exporter = {
+      description = "Prometheus exporter for machine metrics";
+      unitConfig.Documentation = "https://github.com/prometheus/node_exporter";
+      wantedBy = [ "multi-user.target" ];
+      script = ''
+        exec ${pkgs.prometheus-node-exporter}/bin/node_exporter \
+          ${optionalString (cfg.enabledCollectors != [])
+            ''-collectors.enabled ${concatStringsSep "," cfg.enabledCollectors}''} \
+          -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
+          ${concatStringsSep " \\\n  " cfg.extraFlags}
+      '';
+      serviceConfig = {
+        User = "nobody";
+        Restart  = "always";
+        PrivateTmp = true;
+        WorkingDirectory = /tmp;
+        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/prometheus/snmp-exporter.nix b/nixos/modules/services/monitoring/prometheus/snmp-exporter.nix
new file mode 100644
index 000000000000..fe33f8c1f04d
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/snmp-exporter.nix
@@ -0,0 +1,127 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.prometheus.snmpExporter;
+  mkConfigFile = pkgs.writeText "snmp.yml" (if cfg.configurationPath == null then builtins.toJSON cfg.configuration else builtins.readFile cfg.configurationPath);
+in {
+  options = {
+    services.prometheus.snmpExporter = {
+      enable = mkEnableOption "Prometheus snmp exporter";
+
+      user = mkOption {
+        type = types.str;
+        default = "nobody";
+        description = ''
+          User name under which snmp exporter shall be run.
+        '';
+      };
+
+      group = mkOption {
+        type = types.str;
+        default = "nogroup";
+        description = ''
+          Group under which snmp exporter shall be run.
+        '';
+      };
+
+      port = mkOption {
+        type = types.int;
+        default = 9116;
+        description = ''
+          Port to listen on.
+        '';
+      };
+
+      listenAddress = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          Address to listen on for web interface and telemetry.
+        '';
+      };
+
+      configurationPath = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        description = ''
+          Path to a snmp exporter configuration file. Mutually exclusive with 'configuration' option.
+        '';
+        example = "./snmp.yml";
+      };
+
+      configuration = mkOption {
+        type = types.nullOr types.attrs;
+        default = {};
+        description = ''
+          Snmp exporter configuration as nix attribute set. Mutually exclusive with 'configurationPath' option.
+        '';
+        example = ''
+          {
+            "default" = {
+              "version" = 2;
+              "auth" = {
+                "community" = "public";
+              };
+            };
+          };
+        '';
+      };
+
+      logFormat = mkOption {
+        type = types.str;
+        default = "logger:stderr";
+        description = ''
+          Set the log target and format.
+        '';
+      };
+
+      logLevel = mkOption {
+        type = types.enum ["debug" "info" "warn" "error" "fatal"];
+        default = "info";
+        description = ''
+          Only log messages with the given severity or above.
+        '';
+      };
+
+      openFirewall = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Open port in firewall for incoming connections.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port;
+
+    assertions = singleton
+      {
+        assertion = (cfg.configurationPath == null) != (cfg.configuration == null);
+        message = "Please ensure you have either 'configuration' or 'configurationPath' set!";
+      };
+
+    systemd.services.prometheus-snmp-exporter = {
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+      script = ''
+        ${pkgs.prometheus-snmp-exporter.bin}/bin/snmp_exporter \
+          -config.file ${mkConfigFile} \
+          -log.format ${cfg.logFormat} \
+          -log.level ${cfg.logLevel} \
+          -web.listen-address ${optionalString (cfg.listenAddress != null) cfg.listenAddress}:${toString cfg.port}
+      '';
+
+      serviceConfig = {
+        User = cfg.user;
+        Group = cfg.group;
+        Restart  = "always";
+        PrivateTmp = true;
+        WorkingDirectory = "/tmp";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/prometheus/varnish-exporter.nix b/nixos/modules/services/monitoring/prometheus/varnish-exporter.nix
new file mode 100644
index 000000000000..143ebb62aeac
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/varnish-exporter.nix
@@ -0,0 +1,61 @@
+{ config, pkgs, lib, ... }:
+
+# Shamelessly cribbed from nginx-exporter.nix. ~ C.
+with lib;
+
+let
+  cfg = config.services.prometheus.varnishExporter;
+in {
+  options = {
+    services.prometheus.varnishExporter = {
+      enable = mkEnableOption "prometheus Varnish exporter";
+
+      port = mkOption {
+        type = types.int;
+        default = 9131;
+        description = ''
+          Port to listen on.
+        '';
+      };
+
+      extraFlags = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          Extra commandline options when launching the Varnish exporter.
+        '';
+      };
+
+      openFirewall = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Open port in firewall for incoming connections.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port;
+
+    systemd.services.prometheus-varnish-exporter = {
+      description = "Prometheus exporter for Varnish metrics";
+      unitConfig.Documentation = "https://github.com/jonnenauha/prometheus_varnish_exporter";
+      wantedBy = [ "multi-user.target" ];
+      path = [ pkgs.varnish ];
+      script = ''
+        exec ${pkgs.prometheus-varnish-exporter}/bin/prometheus_varnish_exporter \
+          -web.listen-address :${toString cfg.port} \
+          ${concatStringsSep " \\\n  " cfg.extraFlags}
+      '';
+      serviceConfig = {
+        User = "nobody";
+        Restart = "always";
+        PrivateTmp = true;
+        WorkingDirectory = /tmp;
+        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/riemann-tools.nix b/nixos/modules/services/monitoring/riemann-tools.nix
index ce277f09464a..de858813a762 100644
--- a/nixos/modules/services/monitoring/riemann-tools.nix
+++ b/nixos/modules/services/monitoring/riemann-tools.nix
@@ -50,6 +50,7 @@ in {
 
     systemd.services.riemann-health = {
       wantedBy = [ "multi-user.target" ];
+      path = [ procps ];
       serviceConfig = {
         User = "riemanntools";
         ExecStart = "${healthLauncher}/bin/riemann-health";
diff --git a/nixos/modules/services/monitoring/smartd.nix b/nixos/modules/services/monitoring/smartd.nix
index b67519b3424c..99fd5c4d3674 100644
--- a/nixos/modules/services/monitoring/smartd.nix
+++ b/nixos/modules/services/monitoring/smartd.nix
@@ -197,8 +197,7 @@ in
       devices = mkOption {
         default = [];
         example = [ { device = "/dev/sda"; } { device = "/dev/sdb"; options = "-d sat"; } ];
-        type = types.listOf types.optionSet;
-        options = [ smartdOpts ];
+        type = with types; listOf (submodule smartdOpts);
         description = "List of devices to monitor.";
       };
 
diff --git a/nixos/modules/services/monitoring/telegraf.nix b/nixos/modules/services/monitoring/telegraf.nix
new file mode 100644
index 000000000000..49dc9d8143e6
--- /dev/null
+++ b/nixos/modules/services/monitoring/telegraf.nix
@@ -0,0 +1,71 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.telegraf;
+
+  configFile = pkgs.runCommand "config.toml" {
+    buildInputs = [ pkgs.remarshal ];
+  } ''
+    remarshal -if json -of toml \
+      < ${pkgs.writeText "config.json" (builtins.toJSON cfg.extraConfig)} \
+      > $out
+  '';
+in {
+  ###### interface
+  options = {
+    services.telegraf = {
+      enable = mkEnableOption "telegraf server";
+
+      package = mkOption {
+        default = pkgs.telegraf;
+        defaultText = "pkgs.telegraf";
+        description = "Which telegraf derivation to use";
+        type = types.package;
+      };
+
+      extraConfig = mkOption {
+        default = {};
+        description = "Extra configuration options for telegraf";
+        type = types.attrs;
+        example = {
+          outputs = {
+            influxdb = {
+              urls = ["http://localhost:8086"];
+              database = "telegraf";
+            };
+          };
+          inputs = {
+            statsd = {
+              service_address = ":8125";
+              delete_timings = true;
+            };
+          };
+        };
+      };
+    };
+  };
+
+
+  ###### implementation
+  config = mkIf config.services.telegraf.enable {
+    systemd.services.telegraf = {
+      description = "Telegraf Agent";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network-online.target" ];
+      serviceConfig = {
+        ExecStart=''${cfg.package}/bin/telegraf -config "${configFile}"'';
+        ExecReload="${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+        User = "telegraf";
+        Restart = "on-failure";
+      };
+    };
+
+    users.extraUsers = [{
+      name = "telegraf";
+      uid = config.ids.uids.telegraf;
+      description = "telegraf daemon user";
+    }];
+  };
+}
diff --git a/nixos/modules/services/monitoring/ups.nix b/nixos/modules/services/monitoring/ups.nix
index 5f80d547dbcb..c4c4ed227b35 100644
--- a/nixos/modules/services/monitoring/ups.nix
+++ b/nixos/modules/services/monitoring/ups.nix
@@ -169,8 +169,7 @@ in
           monitoring directly.  These are usually attached to serial ports,
           but USB devices are also supported.
         '';
-        type = types.attrsOf types.optionSet;
-        options = [ upsOptions ];
+        type = with types; attrsOf (submodule upsOptions);
       };
 
     };
@@ -182,7 +181,8 @@ in
 
     systemd.services.upsmon = {
       description = "Uninterruptible Power Supplies (Monitor)";
-      wantedBy = [ "ip-up.target" ];
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
       serviceConfig.Type = "forking";
       script = "${pkgs.nut}/sbin/upsmon";
       environment.NUT_CONFPATH = "/etc/nut/";
@@ -191,8 +191,8 @@ in
 
     systemd.services.upsd = {
       description = "Uninterruptible Power Supplies (Daemon)";
+      after = [ "network.target" "upsmon.service" ];
       wantedBy = [ "multi-user.target" ];
-      after = [ "network-interfaces.target" "upsmon.service" ];
       serviceConfig.Type = "forking";
       # TODO: replace 'root' by another username.
       script = "${pkgs.nut}/sbin/upsd -u root";
@@ -202,8 +202,8 @@ in
 
     systemd.services.upsdrv = {
       description = "Uninterruptible Power Supplies (Register all UPS)";
-      wantedBy = [ "multi-user.target" ];
       after = [ "upsd.service" ];
+      wantedBy = [ "multi-user.target" ];
       # TODO: replace 'root' by another username.
       script = ''${pkgs.nut}/bin/upsdrvctl -u root start'';
       serviceConfig = {
diff --git a/nixos/modules/services/monitoring/zabbix-agent.nix b/nixos/modules/services/monitoring/zabbix-agent.nix
index a943075be0c4..88a63b4bf161 100644
--- a/nixos/modules/services/monitoring/zabbix-agent.nix
+++ b/nixos/modules/services/monitoring/zabbix-agent.nix
@@ -53,6 +53,7 @@ in
 
       extraConfig = mkOption {
         default = "";
+        type = types.lines;
         description = ''
           Configuration that is injected verbatim into the configuration file.
         '';