about summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
authorFrederik Rietdijk <fridh@fridh.nl>2019-09-06 22:46:05 +0200
committerFrederik Rietdijk <fridh@fridh.nl>2019-09-06 22:46:05 +0200
commit66bc7fc1b3e7a85a2cfde9bb121498a181d411a4 (patch)
treefa53c32dfef1265496170172a28a3c71bb32a655 /nixos
parentf9237f315264a0ccb8b50ff4fa6ff456239e4dc1 (diff)
parentcfe51be04f8b7c36fe9f71ca5835bd683ede087f (diff)
downloadnixlib-66bc7fc1b3e7a85a2cfde9bb121498a181d411a4.tar
nixlib-66bc7fc1b3e7a85a2cfde9bb121498a181d411a4.tar.gz
nixlib-66bc7fc1b3e7a85a2cfde9bb121498a181d411a4.tar.bz2
nixlib-66bc7fc1b3e7a85a2cfde9bb121498a181d411a4.tar.lz
nixlib-66bc7fc1b3e7a85a2cfde9bb121498a181d411a4.tar.xz
nixlib-66bc7fc1b3e7a85a2cfde9bb121498a181d411a4.tar.zst
nixlib-66bc7fc1b3e7a85a2cfde9bb121498a181d411a4.zip
Merge master into staging-next
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/release-notes/rl-1909.xml35
-rw-r--r--nixos/modules/module-list.nix2
-rw-r--r--nixos/modules/programs/system-config-printer.nix32
-rw-r--r--nixos/modules/rename.nix3
-rw-r--r--nixos/modules/services/desktops/system-config-printer.nix38
-rw-r--r--nixos/modules/services/monitoring/prometheus/default.nix544
-rw-r--r--nixos/modules/services/monitoring/thanos.nix16
-rw-r--r--nixos/modules/services/networking/murmur.nix2
-rw-r--r--nixos/modules/services/x11/desktop-managers/gnome3.nix3
-rw-r--r--nixos/modules/services/x11/desktop-managers/mate.nix3
-rw-r--r--nixos/modules/services/x11/desktop-managers/pantheon.nix6
-rw-r--r--nixos/modules/services/x11/desktop-managers/plasma5.nix3
-rw-r--r--nixos/modules/services/x11/desktop-managers/xfce4-14.nix3
-rw-r--r--nixos/modules/virtualisation/railcar.nix14
-rw-r--r--nixos/tests/all-tests.nix1
-rw-r--r--nixos/tests/prometheus-2.nix239
-rw-r--r--nixos/tests/prometheus.nix255
17 files changed, 511 insertions, 688 deletions
diff --git a/nixos/doc/manual/release-notes/rl-1909.xml b/nixos/doc/manual/release-notes/rl-1909.xml
index ee6ef883068e..ee3b03581529 100644
--- a/nixos/doc/manual/release-notes/rl-1909.xml
+++ b/nixos/doc/manual/release-notes/rl-1909.xml
@@ -144,6 +144,32 @@
      but will make sure that the given printers are configured as declared.
     </para>
    </listitem>
+   <listitem>
+    <para>
+     There is a new <xref linkend="opt-services.system-config-printer.enable"/> and <xref linkend="opt-programs.system-config-printer.enable"/> module
+     for the program of the same name. If you previously had <literal>system-config-printer</literal> enabled through some other
+     means you should migrate to using one of these modules.
+    </para>
+    <itemizedlist>
+     <para>If you're a user of the following desktopManager modules no action is needed:</para>
+     <listitem>
+      <para><option>services.xserver.desktopManager.plasma5</option></para>
+     </listitem>
+     <listitem>
+      <para><option>services.xserver.desktopManager.gnome3</option></para>
+     </listitem>
+     <listitem>
+      <para><option>services.xserver.desktopManager.pantheon</option></para>
+     </listitem>
+     <listitem>
+      <para><option>services.xserver.desktopManager.mate</option></para>
+      <para>
+       Note Mate uses <literal>programs.system-config-printer</literal> as it doesn't
+       use it as a service, but its graphical interface directly.
+      </para>
+     </listitem>
+    </itemizedlist>
+   </listitem>
   </itemizedlist>
 
  </section>
@@ -438,7 +464,14 @@
      <literal>packetbeat5</literal>) of the ELK-stack and Elastic beats have been removed.
     </para>
    </listitem>
-
+   <listitem>
+    <para>
+     For NixOS 19.03, both Prometheus 1 and 2 were available to allow for
+     a seamless transition from version 1 to 2 with existing setups.
+     Because Prometheus 1 is no longer developed, it was removed.
+     Prometheus 2 is now configured with <literal>services.prometheus</literal>.
+    </para>
+   </listitem>
   </itemizedlist>
  </section>
 
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index fe28cf7fa492..c21973faa89f 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -151,6 +151,7 @@
   ./programs/sysdig.nix
   ./programs/systemtap.nix
   ./programs/sway.nix
+  ./programs/system-config-printer.nix
   ./programs/thefuck.nix
   ./programs/tmux.nix
   ./programs/tsm-client.nix
@@ -309,6 +310,7 @@
   ./services/desktops/gnome3/tracker.nix
   ./services/desktops/gnome3/tracker-miners.nix
   ./services/desktops/profile-sync-daemon.nix
+  ./services/desktops/system-config-printer.nix
   ./services/desktops/telepathy.nix
   ./services/desktops/tumbler.nix
   ./services/desktops/zeitgeist.nix
diff --git a/nixos/modules/programs/system-config-printer.nix b/nixos/modules/programs/system-config-printer.nix
new file mode 100644
index 000000000000..34592dd7064b
--- /dev/null
+++ b/nixos/modules/programs/system-config-printer.nix
@@ -0,0 +1,32 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+{
+
+  ###### interface
+
+  options = {
+
+    programs.system-config-printer = {
+
+      enable = mkEnableOption "system-config-printer, a Graphical user interface for CUPS administration";
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf config.programs.system-config-printer.enable {
+
+    environment.systemPackages = [
+      pkgs.system-config-printer
+    ];
+
+    services.system-config-printer.enable = true;
+
+  };
+
+}
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix
index 1fa91f05030d..d1303f90ad8d 100644
--- a/nixos/modules/rename.nix
+++ b/nixos/modules/rename.nix
@@ -52,10 +52,11 @@ with lib;
     (mkRemovedOptionModule [ "services" "misc" "nzbget" "openFirewall" ] "The port used by nzbget is managed through the web interface so you should adjust your firewall rules accordingly.")
     (mkRemovedOptionModule [ "services" "prometheus" "alertmanager" "user" ] "The alertmanager service is now using systemd's DynamicUser mechanism which obviates a user setting.")
     (mkRemovedOptionModule [ "services" "prometheus" "alertmanager" "group" ] "The alertmanager service is now using systemd's DynamicUser mechanism which obviates a group setting.")
-    (mkRemovedOptionModule [ "services" "prometheus2" "alertmanagerURL" ] ''
+    (mkRemovedOptionModule [ "services" "prometheus" "alertmanagerURL" ] ''
       Due to incompatibility, the alertmanagerURL option has been removed,
       please use 'services.prometheus2.alertmanagers' instead.
     '')
+    (mkRenamedOptionModule [ "services" "prometheus2" ] [ "services" "prometheus" ])
     (mkRenamedOptionModule [ "services" "tor" "relay" "portSpec" ] [ "services" "tor" "relay" "port" ])
     (mkRenamedOptionModule [ "services" "vmwareGuest" ] [ "virtualisation" "vmware" "guest" ])
     (mkRenamedOptionModule [ "jobs" ] [ "systemd" "services" ])
diff --git a/nixos/modules/services/desktops/system-config-printer.nix b/nixos/modules/services/desktops/system-config-printer.nix
new file mode 100644
index 000000000000..8a80be266b20
--- /dev/null
+++ b/nixos/modules/services/desktops/system-config-printer.nix
@@ -0,0 +1,38 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.system-config-printer = {
+
+      enable = mkEnableOption "system-config-printer, a service for CUPS administration used by printing interfaces";
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf config.services.system-config-printer.enable {
+
+    services.dbus.packages = [
+      pkgs.system-config-printer
+    ];
+
+    systemd.packages = [
+      pkgs.system-config-printer
+    ];
+
+    services.udev.packages = [
+      pkgs.system-config-printer
+    ];
+
+  };
+
+}
diff --git a/nixos/modules/services/monitoring/prometheus/default.nix b/nixos/modules/services/monitoring/prometheus/default.nix
index 647d67533b89..191c0bff9c84 100644
--- a/nixos/modules/services/monitoring/prometheus/default.nix
+++ b/nixos/modules/services/monitoring/prometheus/default.nix
@@ -4,37 +4,14 @@ with lib;
 
 let
   cfg = config.services.prometheus;
-  cfg2 = config.services.prometheus2;
-  promUser = "prometheus";
-  promGroup = "prometheus";
-
-  stateDir =
-    if cfg.stateDir != null
-    then cfg.stateDir
-    else
-      if cfg.dataDir != null
-      then
-        # This assumes /var/lib/ is a prefix of cfg.dataDir.
-        # This is checked as an assertion below.
-        removePrefix stateDirBase cfg.dataDir
-      else "prometheus";
-  stateDirBase = "/var/lib/";
-  workingDir  = stateDirBase + stateDir;
-  workingDir2 = stateDirBase + cfg2.stateDir;
 
-  # a wrapper that verifies that the configuration is valid
-  promtoolCheck = what: name: file: pkgs.runCommand "${name}-${what}-checked"
-    { buildInputs = [ cfg.package ]; } ''
-    ln -s ${file} $out
-    promtool ${what} $out
-  '';
+  workingDir = "/var/lib/" + cfg.stateDir;
 
-  # a wrapper that verifies that the configuration is valid for
-  # prometheus 2
-  prom2toolCheck = what: name: file:
+  # a wrapper that verifies that the configuration is valid
+  promtoolCheck = what: name: file:
     pkgs.runCommand
       "${name}-${replaceStrings [" "] [""] what}-checked"
-      { buildInputs = [ cfg2.package ]; } ''
+      { buildInputs = [ cfg.package ]; } ''
     ln -s ${file} $out
     promtool ${what} $out
   '';
@@ -45,61 +22,34 @@ let
       echo '${builtins.toJSON x}' | ${pkgs.jq}/bin/jq . > $out
     '';
 
-  # This becomes the main config file for Prometheus 1
+  generatedPrometheusYml = writePrettyJSON "prometheus.yml" promConfig;
+
+  # This becomes the main config file for Prometheus
   promConfig = {
     global = filterValidPrometheus cfg.globalConfig;
-    rule_files = map (promtoolCheck "check-rules" "rules") (cfg.ruleFiles ++ [
+    rule_files = map (promtoolCheck "check rules" "rules") (cfg.ruleFiles ++ [
       (pkgs.writeText "prometheus.rules" (concatStringsSep "\n" cfg.rules))
     ]);
     scrape_configs = filterValidPrometheus cfg.scrapeConfigs;
+    alerting = {
+      inherit (cfg) alertmanagers;
+    };
   };
 
-  generatedPrometheusYml = writePrettyJSON "prometheus.yml" promConfig;
-
   prometheusYml = let
     yml = if cfg.configText != null then
       pkgs.writeText "prometheus.yml" cfg.configText
       else generatedPrometheusYml;
-    in promtoolCheck "check-config" "prometheus.yml" yml;
+    in promtoolCheck "check config" "prometheus.yml" yml;
 
   cmdlineArgs = cfg.extraFlags ++ [
-    "-storage.local.path=${workingDir}/metrics"
-    "-config.file=${prometheusYml}"
-    "-web.listen-address=${cfg.listenAddress}"
-    "-alertmanager.notification-queue-capacity=${toString cfg.alertmanagerNotificationQueueCapacity}"
-    "-alertmanager.timeout=${toString cfg.alertmanagerTimeout}s"
+    "--storage.tsdb.path=${workingDir}/data/"
+    "--config.file=${prometheusYml}"
+    "--web.listen-address=${cfg.listenAddress}"
+    "--alertmanager.notification-queue-capacity=${toString cfg.alertmanagerNotificationQueueCapacity}"
+    "--alertmanager.timeout=${toString cfg.alertmanagerTimeout}s"
   ] ++
-  optional (cfg.alertmanagerURL != []) "-alertmanager.url=${concatStringsSep "," cfg.alertmanagerURL}" ++
-  optional (cfg.webExternalUrl != null) "-web.external-url=${cfg.webExternalUrl}";
-
-  # This becomes the main config file for Prometheus 2
-  promConfig2 = {
-    global = filterValidPrometheus cfg2.globalConfig;
-    rule_files = map (prom2toolCheck "check rules" "rules") (cfg2.ruleFiles ++ [
-      (pkgs.writeText "prometheus.rules" (concatStringsSep "\n" cfg2.rules))
-    ]);
-    scrape_configs = filterValidPrometheus cfg2.scrapeConfigs;
-    alerting = {
-      inherit (cfg2) alertmanagers;
-    };
-  };
-
-  generatedPrometheus2Yml = writePrettyJSON "prometheus.yml" promConfig2;
-
-  prometheus2Yml = let
-    yml = if cfg2.configText != null then
-      pkgs.writeText "prometheus.yml" cfg2.configText
-      else generatedPrometheus2Yml;
-    in prom2toolCheck "check config" "prometheus.yml" yml;
-
-  cmdlineArgs2 = cfg2.extraFlags ++ [
-    "--storage.tsdb.path=${workingDir2}/data/"
-    "--config.file=${prometheus2Yml}"
-    "--web.listen-address=${cfg2.listenAddress}"
-    "--alertmanager.notification-queue-capacity=${toString cfg2.alertmanagerNotificationQueueCapacity}"
-    "--alertmanager.timeout=${toString cfg2.alertmanagerTimeout}s"
-  ] ++
-  optional (cfg2.webExternalUrl != null) "--web.external-url=${cfg2.webExternalUrl}";
+  optional (cfg.webExternalUrl != null) "--web.external-url=${cfg.webExternalUrl}";
 
   filterValidPrometheus = filterAttrsListRecursive (n: v: !(n == "_module" || v == null));
   filterAttrsListRecursive = pred: x:
@@ -514,343 +464,159 @@ let
   };
 
 in {
-  options = {
-    services.prometheus = {
-
-      enable = mkOption {
-        type = types.bool;
-        default = false;
-        description = ''
-          Enable the Prometheus monitoring daemon.
-        '';
-      };
-
-      package = mkOption {
-        type = types.package;
-        default = pkgs.prometheus;
-        defaultText = "pkgs.prometheus";
-        description = ''
-          The prometheus package that should be used.
-        '';
-      };
-
-      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.nullOr types.path;
-        default = null;
-        description = ''
-          Directory to store Prometheus metrics data.
-          This option is deprecated, please use <option>services.prometheus.stateDir</option>.
-        '';
-      };
-
-      stateDir = mkOption {
-        type = types.nullOr types.str;
-        default = null;
-        description = ''
-          Directory below <literal>${stateDirBase}</literal> to store Prometheus metrics data.
-          This directory will be created automatically using systemd's StateDirectory mechanism.
-          Defaults to <literal>prometheus</literal>.
-        '';
-      };
-
-      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 = {};
-        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.
-        '';
-      };
+  options.services.prometheus = {
 
-      scrapeConfigs = mkOption {
-        type = types.listOf promTypes.scrape_config;
-        default = [];
-        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).
-        '';
-      };
-
-      webExternalUrl = mkOption {
-        type = types.nullOr types.str;
-        default = null;
-        example = "https://example.com/";
-        description = ''
-          The URL under which Prometheus is externally reachable (for example,
-          if Prometheus is served via a reverse proxy).
-        '';
-      };
+    enable = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Enable the Prometheus monitoring daemon.
+      '';
     };
-    services.prometheus2 = {
 
-      enable = mkOption {
-        type = types.bool;
-        default = false;
-        description = ''
-          Enable the Prometheus 2 monitoring daemon.
-        '';
-      };
+    package = mkOption {
+      type = types.package;
+      default = pkgs.prometheus;
+      defaultText = "pkgs.prometheus";
+      description = ''
+        The prometheus package that should be used.
+      '';
+    };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.prometheus_2;
-        defaultText = "pkgs.prometheus_2";
-        description = ''
-          The prometheus2 package that should be used.
-        '';
-      };
+    listenAddress = mkOption {
+      type = types.str;
+      default = "0.0.0.0:9090";
+      description = ''
+        Address to listen on for the web interface, API, and telemetry.
+      '';
+    };
 
-      listenAddress = mkOption {
-        type = types.str;
-        default = "0.0.0.0:9090";
-        description = ''
-          Address to listen on for the web interface, API, and telemetry.
-        '';
-      };
+    stateDir = mkOption {
+      type = types.str;
+      default = "prometheus2";
+      description = ''
+        Directory below <literal>/var/lib</literal> to store Prometheus metrics data.
+        This directory will be created automatically using systemd's StateDirectory mechanism.
+      '';
+    };
 
-      stateDir = mkOption {
-        type = types.str;
-        default = "prometheus2";
-        description = ''
-          Directory below <literal>${stateDirBase}</literal> to store Prometheus metrics data.
-          This directory will be created automatically using systemd's StateDirectory mechanism.
-          Defaults to <literal>prometheus2</literal>.
-        '';
-      };
+    extraFlags = mkOption {
+      type = types.listOf types.str;
+      default = [];
+      description = ''
+        Extra commandline options when launching Prometheus.
+      '';
+    };
 
-      extraFlags = mkOption {
-        type = types.listOf types.str;
-        default = [];
-        description = ''
-          Extra commandline options when launching Prometheus 2.
-        '';
-      };
+    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.
+      '';
+    };
 
-      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 = {};
+      description = ''
+        Parameters that are valid in all  configuration contexts. They
+        also serve as defaults for other configuration sections
+      '';
+    };
 
-      globalConfig = mkOption {
-        type = promTypes.globalConfig;
-        default = {};
-        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.
+      '';
+    };
 
-      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.
+      '';
+    };
 
-      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 = [];
+      description = ''
+        A list of scrape configurations.
+      '';
+    };
 
-      scrapeConfigs = mkOption {
-        type = types.listOf promTypes.scrape_config;
-        default = [];
-        description = ''
-          A list of scrape configurations.
-        '';
-      };
+    alertmanagers = mkOption {
+      type = types.listOf types.attrs;
+      example = literalExample ''
+        [ {
+          scheme = "https";
+          path_prefix = "/alertmanager";
+          static_configs = [ {
+            targets = [
+              "prometheus.domain.tld"
+            ];
+          } ];
+        } ]
+      '';
+      default = [];
+      description = ''
+        A list of alertmanagers to send alerts to.
+        See <link xlink:href="https://prometheus.io/docs/prometheus/latest/configuration/configuration/#alertmanager_config">the official documentation</link> for more information.
+      '';
+    };
 
-      alertmanagers = mkOption {
-        type = types.listOf types.attrs;
-        example = literalExample ''
-          [ {
-            scheme = "https";
-            path_prefix = "/alertmanager";
-            static_configs = [ {
-              targets = [
-                "prometheus.domain.tld"
-              ];
-            } ];
-          } ]
-        '';
-        default = [];
-        description = ''
-          A list of alertmanagers to send alerts to.
-          See <link xlink:href="https://prometheus.io/docs/prometheus/latest/configuration/configuration/#alertmanager_config">the official documentation</link> for more information.
-        '';
-      };
+    alertmanagerNotificationQueueCapacity = mkOption {
+      type = types.int;
+      default = 10000;
+      description = ''
+        The capacity of the queue for pending alert manager notifications.
+      '';
+    };
 
-      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).
+      '';
+    };
 
-      alertmanagerTimeout = mkOption {
-        type = types.int;
-        default = 10;
-        description = ''
-          Alert manager HTTP API timeout (in seconds).
-        '';
-      };
+    webExternalUrl = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      example = "https://example.com/";
+      description = ''
+        The URL under which Prometheus is externally reachable (for example,
+        if Prometheus is served via a reverse proxy).
+      '';
+    };
+  };
 
-      webExternalUrl = mkOption {
-        type = types.nullOr types.str;
-        default = null;
-        example = "https://example.com/";
-        description = ''
-          The URL under which Prometheus is externally reachable (for example,
-          if Prometheus is served via a reverse proxy).
-        '';
-      };
+  config = mkIf cfg.enable {
+    users.groups.prometheus.gid = config.ids.gids.prometheus;
+    users.users.prometheus = {
+      description = "Prometheus daemon user";
+      uid = config.ids.uids.prometheus;
+      group = "prometheus";
     };
-   };
-
-  config = mkMerge [
-    (mkIf (cfg.enable || cfg2.enable) {
-      users.groups.${promGroup}.gid = config.ids.gids.prometheus;
-      users.users.${promUser} = {
-        description = "Prometheus daemon user";
-        uid = config.ids.uids.prometheus;
-        group = promGroup;
+    systemd.services.prometheus = {
+      wantedBy = [ "multi-user.target" ];
+      after    = [ "network.target" ];
+      serviceConfig = {
+        ExecStart = "${cfg.package}/bin/prometheus" +
+          optionalString (length cmdlineArgs != 0) (" \\\n  " +
+            concatStringsSep " \\\n  " cmdlineArgs);
+        User = "prometheus";
+        Restart  = "always";
+        WorkingDirectory = workingDir;
+        StateDirectory = cfg.stateDir;
       };
-    })
-    (mkIf cfg.enable {
-      warnings =
-        optional (cfg.dataDir != null) ''
-          The option services.prometheus.dataDir is deprecated, please use
-          services.prometheus.stateDir.
-        '';
-      assertions = [
-        {
-          assertion = !(cfg.dataDir != null && cfg.stateDir != null);
-          message =
-            "The options services.prometheus.dataDir and services.prometheus.stateDir" +
-            " can't both be set at the same time! It's recommended to only set the latter" +
-            " since the former is deprecated.";
-        }
-        {
-          assertion = cfg.dataDir != null -> hasPrefix stateDirBase cfg.dataDir;
-          message =
-            "The option services.prometheus.dataDir should have ${stateDirBase} as a prefix!";
-        }
-        {
-          assertion = cfg.stateDir != null -> !hasPrefix "/" cfg.stateDir;
-          message =
-            "The option services.prometheus.stateDir shouldn't be an absolute directory." +
-            " It should be a directory relative to ${stateDirBase}.";
-        }
-        {
-          assertion = cfg2.stateDir != null -> !hasPrefix "/" cfg2.stateDir;
-          message =
-            "The option services.prometheus2.stateDir shouldn't be an absolute directory." +
-            " It should be a directory relative to ${stateDirBase}.";
-        }
-      ];
-      systemd.services.prometheus = {
-        wantedBy = [ "multi-user.target" ];
-        after    = [ "network.target" ];
-        serviceConfig = {
-          ExecStart = "${cfg.package}/bin/prometheus" +
-            optionalString (length cmdlineArgs != 0) (" \\\n  " +
-              concatStringsSep " \\\n  " cmdlineArgs);
-          User = promUser;
-          Restart  = "always";
-          WorkingDirectory = workingDir;
-          StateDirectory = stateDir;
-        };
-      };
-    })
-    (mkIf cfg2.enable {
-      systemd.services.prometheus2 = {
-        wantedBy = [ "multi-user.target" ];
-        after    = [ "network.target" ];
-        serviceConfig = {
-          ExecStart = "${cfg2.package}/bin/prometheus" +
-            optionalString (length cmdlineArgs2 != 0) (" \\\n  " +
-              concatStringsSep " \\\n  " cmdlineArgs2);
-          User = promUser;
-          Restart  = "always";
-          WorkingDirectory = workingDir2;
-          StateDirectory = cfg2.stateDir;
-        };
-      };
-    })
-  ];
+    };
+  };
 }
diff --git a/nixos/modules/services/monitoring/thanos.nix b/nixos/modules/services/monitoring/thanos.nix
index 272c9429af1c..215cd43fd864 100644
--- a/nixos/modules/services/monitoring/thanos.nix
+++ b/nixos/modules/services/monitoring/thanos.nix
@@ -218,8 +218,8 @@ let
         toArgs = optionToArgs;
         option = mkOption {
           type = types.str;
-          default = "/var/lib/${config.services.prometheus2.stateDir}/data";
-          defaultText = "/var/lib/\${config.services.prometheus2.stateDir}/data";
+          default = "/var/lib/${config.services.prometheus.stateDir}/data";
+          defaultText = "/var/lib/\${config.services.prometheus.stateDir}/data";
           description = ''
             Data directory of TSDB.
           '';
@@ -679,22 +679,22 @@ in {
     (mkIf cfg.sidecar.enable {
       assertions = [
         {
-          assertion = config.services.prometheus2.enable;
+          assertion = config.services.prometheus.enable;
           message =
-            "Please enable services.prometheus2 when enabling services.thanos.sidecar.";
+            "Please enable services.prometheus when enabling services.thanos.sidecar.";
         }
         {
-          assertion = !(config.services.prometheus2.globalConfig.external_labels == null ||
-                        config.services.prometheus2.globalConfig.external_labels == {});
+          assertion = !(config.services.prometheus.globalConfig.external_labels == null ||
+                        config.services.prometheus.globalConfig.external_labels == {});
           message =
             "services.thanos.sidecar requires uniquely identifying external labels " +
             "to be configured in the Prometheus server. " +
-            "Please set services.prometheus2.globalConfig.external_labels.";
+            "Please set services.prometheus.globalConfig.external_labels.";
         }
       ];
       systemd.services.thanos-sidecar = {
         wantedBy = [ "multi-user.target" ];
-        after    = [ "network.target" "prometheus2.service" ];
+        after    = [ "network.target" "prometheus.service" ];
         serviceConfig = {
           User = "prometheus";
           Restart = "always";
diff --git a/nixos/modules/services/networking/murmur.nix b/nixos/modules/services/networking/murmur.nix
index 7ac4d0c6419d..082953d2f6ab 100644
--- a/nixos/modules/services/networking/murmur.nix
+++ b/nixos/modules/services/networking/murmur.nix
@@ -234,7 +234,7 @@ in
       extraConfig = mkOption {
         type = types.lines;
         default = "";
-        description = "Extra configuration to put into mumur.ini.";
+        description = "Extra configuration to put into murmur.ini.";
       };
     };
   };
diff --git a/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix
index 6f344f4121ba..09095294fb5f 100644
--- a/nixos/modules/services/x11/desktop-managers/gnome3.nix
+++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix
@@ -233,10 +233,9 @@ in
       services.gnome3.gnome-user-share.enable = mkDefault true;
       services.gnome3.rygel.enable = mkDefault true;
       services.gvfs.enable = true;
+      services.system-config-printer.enable = (mkIf config.services.printing.enable (mkDefault true));
       services.telepathy.enable = mkDefault true;
       systemd.packages = [ pkgs.gnome3.vino ];
-      services.dbus.packages =
-        optional config.services.printing.enable pkgs.system-config-printer;
 
       services.avahi.enable = mkDefault true;
 
diff --git a/nixos/modules/services/x11/desktop-managers/mate.nix b/nixos/modules/services/x11/desktop-managers/mate.nix
index a9ca945fc669..d7a871c9c704 100644
--- a/nixos/modules/services/x11/desktop-managers/mate.nix
+++ b/nixos/modules/services/x11/desktop-managers/mate.nix
@@ -98,6 +98,9 @@ in
     programs.bash.vteIntegration = mkDefault true;
     programs.zsh.vteIntegration = mkDefault true;
 
+    # Mate uses this for printing
+    programs.system-config-printer.enable = (mkIf config.services.printing.enable (mkDefault true));
+
     services.gnome3.at-spi2-core.enable = true;
     services.gnome3.gnome-keyring.enable = true;
     services.gnome3.gnome-settings-daemon.enable = true;
diff --git a/nixos/modules/services/x11/desktop-managers/pantheon.nix b/nixos/modules/services/x11/desktop-managers/pantheon.nix
index 5b82cb1f0262..e313a194c345 100644
--- a/nixos/modules/services/x11/desktop-managers/pantheon.nix
+++ b/nixos/modules/services/x11/desktop-managers/pantheon.nix
@@ -113,9 +113,9 @@ in
     services.colord.enable = mkDefault true;
     services.pantheon.files.enable = mkDefault true;
     services.tumbler.enable = mkDefault true;
-    services.dbus.packages = mkMerge [
-      ([ pkgs.pantheon.switchboard-plug-power ])
-      (mkIf config.services.printing.enable  ([pkgs.system-config-printer]) )
+    services.system-config-printer.enable = (mkIf config.services.printing.enable (mkDefault true));
+    services.dbus.packages = [
+      pkgs.pantheon.switchboard-plug-power
     ];
     services.pantheon.contractor.enable = mkDefault true;
     services.gnome3.at-spi2-core.enable = true;
diff --git a/nixos/modules/services/x11/desktop-managers/plasma5.nix b/nixos/modules/services/x11/desktop-managers/plasma5.nix
index a51f3c537ab7..862f6431b812 100644
--- a/nixos/modules/services/x11/desktop-managers/plasma5.nix
+++ b/nixos/modules/services/x11/desktop-managers/plasma5.nix
@@ -210,8 +210,7 @@ in
       # Enable helpful DBus services.
       services.udisks2.enable = true;
       services.upower.enable = config.powerManagement.enable;
-      services.dbus.packages =
-        mkIf config.services.printing.enable [ pkgs.system-config-printer ];
+      services.system-config-printer.enable = (mkIf config.services.printing.enable (mkDefault true));
 
       # Extra UDEV rules used by Solid
       services.udev.packages = [
diff --git a/nixos/modules/services/x11/desktop-managers/xfce4-14.nix b/nixos/modules/services/x11/desktop-managers/xfce4-14.nix
index 55c88223e788..57d1268d655a 100644
--- a/nixos/modules/services/x11/desktop-managers/xfce4-14.nix
+++ b/nixos/modules/services/x11/desktop-managers/xfce4-14.nix
@@ -137,8 +137,7 @@ in
     services.gvfs.enable = true;
     services.gvfs.package = pkgs.xfce.gvfs;
     services.tumbler.enable = true;
-    services.dbus.packages =
-      optional config.services.printing.enable pkgs.system-config-printer;
+    services.system-config-printer.enable = (mkIf config.services.printing.enable (mkDefault true));
     services.xserver.libinput.enable = mkDefault true; # used in xfce4-settings-manager
 
     # Enable default programs
diff --git a/nixos/modules/virtualisation/railcar.nix b/nixos/modules/virtualisation/railcar.nix
index 8b643e3b6d65..12da1c75fc38 100644
--- a/nixos/modules/virtualisation/railcar.nix
+++ b/nixos/modules/virtualisation/railcar.nix
@@ -25,7 +25,7 @@ let
   mount = with types; (submodule {
     options = {
       type = mkOption {
-        type = string;
+        type = str;
         default = "none";
         description = ''
           The type of the filesystem to be mounted.
@@ -37,11 +37,11 @@ let
         '';
       };
       source = mkOption {
-        type = string;
+        type = str;
         description = "Source for the in-container mount";
       };
       options = mkOption {
-        type = loaOf (string);
+        type = loaOf (str);
         default = [ "bind" ];
         description = ''
           Mount options of the filesystem to be used.
@@ -64,7 +64,7 @@ in
       type = with types; loaOf (submodule ({ name, config, ... }: {
         options = {
           cmd = mkOption {
-            type = types.string;
+            type = types.lines;
             description = "Command or script to run inside the container";
           };
 
@@ -83,19 +83,19 @@ in
           };
 
           runType = mkOption {
-            type = types.string;
+            type = types.str;
             default = "oneshot";
             description = "The systemd service run type";
           };
 
           os = mkOption {
-            type = types.string;
+            type = types.str;
             default = "linux";
             description = "OS type of the container";
           };
 
           arch = mkOption {
-            type = types.string;
+            type = types.str;
             default = "x86_64";
             description = "Computer architecture type of the container";
           };
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index 8ee4dfbf13bc..5eb8111aa6d3 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -224,7 +224,6 @@ in
   predictable-interface-names = handleTest ./predictable-interface-names.nix {};
   printing = handleTest ./printing.nix {};
   prometheus = handleTest ./prometheus.nix {};
-  prometheus2 = handleTest ./prometheus-2.nix {};
   prometheus-exporters = handleTest ./prometheus-exporters.nix {};
   prosody = handleTest ./xmpp/prosody.nix {};
   prosodyMysql = handleTest ./xmpp/prosody-mysql.nix {};
diff --git a/nixos/tests/prometheus-2.nix b/nixos/tests/prometheus-2.nix
deleted file mode 100644
index 219c47c73d95..000000000000
--- a/nixos/tests/prometheus-2.nix
+++ /dev/null
@@ -1,239 +0,0 @@
-let
-  grpcPort   = 19090;
-  queryPort  =  9090;
-  minioPort  =  9000;
-  pushgwPort =  9091;
-
-  s3 = {
-    accessKey = "BKIKJAA5BMMU2RHO6IBB";
-    secretKey = "V7f1CwQqAcwo80UEIJEjc5gVQUSSx5ohQ9GSrr12";
-  };
-
-  objstore.config = {
-    type = "S3";
-    config = {
-      bucket = "thanos-bucket";
-      endpoint = "s3:${toString minioPort}";
-      region =  "us-east-1";
-      access_key = s3.accessKey;
-      secret_key = s3.secretKey;
-      insecure = true;
-      signature_version2 = false;
-      encrypt_sse =  false;
-      put_user_metadata = {};
-      http_config = {
-        idle_conn_timeout = "0s";
-        insecure_skip_verify = false;
-      };
-      trace = {
-        enable = false;
-      };
-    };
-  };
-
-in import ./make-test.nix {
-  name = "prometheus-2";
-
-  nodes = {
-    prometheus = { pkgs, ... }: {
-      virtualisation.diskSize = 2 * 1024;
-      environment.systemPackages = [ pkgs.jq ];
-      networking.firewall.allowedTCPPorts = [ grpcPort ];
-      services.prometheus2 = {
-        enable = true;
-        scrapeConfigs = [
-          {
-            job_name = "prometheus";
-            static_configs = [
-              {
-                targets = [ "127.0.0.1:${toString queryPort}" ];
-                labels = { instance = "localhost"; };
-              }
-            ];
-          }
-          {
-            job_name = "pushgateway";
-            scrape_interval = "1s";
-            static_configs = [
-              {
-                targets = [ "127.0.0.1:${toString pushgwPort}" ];
-              }
-            ];
-          }
-        ];
-        rules = [
-          ''
-            groups:
-              - name: test
-                rules:
-                  - record: testrule
-                    expr: count(up{job="prometheus"})
-          ''
-        ];
-        globalConfig = {
-          external_labels = {
-            some_label = "required by thanos";
-          };
-        };
-        extraFlags = [
-          # Required by thanos
-          "--storage.tsdb.min-block-duration=5s"
-          "--storage.tsdb.max-block-duration=5s"
-        ];
-      };
-      services.prometheus.pushgateway = {
-        enable = true;
-        web.listen-address = ":${toString pushgwPort}";
-        persistMetrics = true;
-        persistence.interval = "1s";
-        stateDir = "prometheus-pushgateway";
-      };
-      services.thanos = {
-        sidecar = {
-          enable = true;
-          grpc-address = "0.0.0.0:${toString grpcPort}";
-          inherit objstore;
-        };
-
-        # TODO: Add some tests for these services:
-        #rule = {
-        #  enable = true;
-        #  http-address = "0.0.0.0:19194";
-        #  grpc-address = "0.0.0.0:19193";
-        #  query.addresses = [
-        #    "localhost:19191"
-        #  ];
-        #  labels = {
-        #    just = "some";
-        #    nice = "labels";
-        #  };
-        #};
-        #
-        #receive = {
-        #  http-address = "0.0.0.0:19195";
-        #  enable = true;
-        #  labels = {
-        #    just = "some";
-        #    nice = "labels";
-        #  };
-        #};
-      };
-    };
-
-    query = { pkgs, ... }: {
-      environment.systemPackages = [ pkgs.jq ];
-      services.thanos.query = {
-        enable = true;
-        http-address = "0.0.0.0:${toString queryPort}";
-        store.addresses = [
-          "prometheus:${toString grpcPort}"
-        ];
-      };
-    };
-
-    store = { pkgs, ... }: {
-      virtualisation.diskSize = 2 * 1024;
-      environment.systemPackages = with pkgs; [ jq thanos ];
-      services.thanos.store = {
-        enable = true;
-        http-address = "0.0.0.0:10902";
-        grpc-address = "0.0.0.0:${toString grpcPort}";
-        inherit objstore;
-        sync-block-duration = "1s";
-      };
-      services.thanos.compact = {
-        enable = true;
-        http-address = "0.0.0.0:10903";
-        inherit objstore;
-        consistency-delay = "5s";
-      };
-      services.thanos.query = {
-        enable = true;
-        http-address = "0.0.0.0:${toString queryPort}";
-        store.addresses = [
-          "localhost:${toString grpcPort}"
-        ];
-      };
-    };
-
-    s3 = { pkgs, ... } : {
-      # Minio requires at least 1GiB of free disk space to run.
-      virtualisation.diskSize = 2 * 1024;
-      networking.firewall.allowedTCPPorts = [ minioPort ];
-
-      services.minio = {
-        enable = true;
-        inherit (s3) accessKey secretKey;
-      };
-
-      environment.systemPackages = [ pkgs.minio-client ];
-    };
-  };
-
-  testScript = { nodes, ... } : ''
-    # Before starting the other machines we first make sure that our S3 service is online
-    # and has a bucket added for thanos:
-    $s3->start;
-    $s3->waitForUnit("minio.service");
-    $s3->waitForOpenPort(${toString minioPort});
-    $s3->succeed(
-      "mc config host add minio " .
-      "http://localhost:${toString minioPort} ${s3.accessKey} ${s3.secretKey} S3v4");
-    $s3->succeed("mc mb minio/thanos-bucket");
-
-    # Now that s3 has started we can start the other machines:
-    $prometheus->start;
-    $query->start;
-    $store->start;
-
-    # Check if prometheus responds to requests:
-    $prometheus->waitForUnit("prometheus2.service");
-    $prometheus->waitForOpenPort(${toString queryPort});
-    $prometheus->succeed("curl -s http://127.0.0.1:${toString queryPort}/metrics");
-
-    # Let's test if pushing a metric to the pushgateway succeeds:
-    $prometheus->waitForUnit("pushgateway.service");
-    $prometheus->succeed(
-      "echo 'some_metric 3.14' | " .
-      "curl --data-binary \@- http://127.0.0.1:${toString pushgwPort}/metrics/job/some_job");
-
-    # Now check whether that metric gets ingested by prometheus.
-    # Since we'll check for the metric several times on different machines
-    # we abstract the test using the following function:
-
-    # Function to check if the metric "some_metric" has been received and returns the correct value.
-    local *Machine::waitForMetric = sub {
-      my ($self) = @_;
-      $self->waitUntilSucceeds(
-        "curl -sf 'http://127.0.0.1:${toString queryPort}/api/v1/query?query=some_metric' " .
-        "| jq '.data.result[0].value[1]' | grep '\"3.14\"'");
-    };
-
-    $prometheus->waitForMetric;
-
-    # Let's test if the pushgateway persists metrics to the configured location.
-    $prometheus->waitUntilSucceeds("test -e /var/lib/prometheus-pushgateway/metrics");
-
-    # Test thanos
-    $prometheus->waitForUnit("thanos-sidecar.service");
-
-    # Test if the Thanos query service can correctly retrieve the metric that was send above.
-    $query->waitForUnit("thanos-query.service");
-    $query->waitForMetric;
-
-    # Test if the Thanos sidecar has correctly uploaded its TSDB to S3, if the
-    # Thanos storage service has correctly downloaded it from S3 and if the Thanos
-    # query service running on $store can correctly retrieve the metric:
-    $store->waitForUnit("thanos-store.service");
-    $store->waitForMetric;
-
-    $store->waitForUnit("thanos-compact.service");
-
-    # Test if the Thanos bucket command is able to retrieve blocks from the S3 bucket
-    # and check if the blocks have the correct labels:
-    $store->succeed(
-      "thanos bucket ls" .
-      " --objstore.config-file=${nodes.store.config.services.thanos.store.objstore.config-file}" .
-      " --output=json | jq .thanos.labels.some_label | grep 'required by thanos'");
-  '';
-}
diff --git a/nixos/tests/prometheus.nix b/nixos/tests/prometheus.nix
index f1b20a33d71e..52f61046be39 100644
--- a/nixos/tests/prometheus.nix
+++ b/nixos/tests/prometheus.nix
@@ -1,48 +1,239 @@
-import ./make-test.nix {
+let
+  grpcPort   = 19090;
+  queryPort  =  9090;
+  minioPort  =  9000;
+  pushgwPort =  9091;
+
+  s3 = {
+    accessKey = "BKIKJAA5BMMU2RHO6IBB";
+    secretKey = "V7f1CwQqAcwo80UEIJEjc5gVQUSSx5ohQ9GSrr12";
+  };
+
+  objstore.config = {
+    type = "S3";
+    config = {
+      bucket = "thanos-bucket";
+      endpoint = "s3:${toString minioPort}";
+      region =  "us-east-1";
+      access_key = s3.accessKey;
+      secret_key = s3.secretKey;
+      insecure = true;
+      signature_version2 = false;
+      encrypt_sse =  false;
+      put_user_metadata = {};
+      http_config = {
+        idle_conn_timeout = "0s";
+        insecure_skip_verify = false;
+      };
+      trace = {
+        enable = false;
+      };
+    };
+  };
+
+in import ./make-test.nix {
   name = "prometheus";
 
   nodes = {
-    one = { ... }: {
+    prometheus = { pkgs, ... }: {
+      virtualisation.diskSize = 2 * 1024;
+      environment.systemPackages = [ pkgs.jq ];
+      networking.firewall.allowedTCPPorts = [ grpcPort ];
       services.prometheus = {
         enable = true;
-        scrapeConfigs = [{
-          job_name = "prometheus";
-          static_configs = [{
-            targets = [ "127.0.0.1:9090" ];
-            labels = { instance = "localhost"; };
-          }];
-        }];
-        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 = [
+        scrapeConfigs = [
+          {
+            job_name = "prometheus";
+            static_configs = [
+              {
+                targets = [ "127.0.0.1:${toString queryPort}" ];
+                labels = { instance = "localhost"; };
+              }
+            ];
+          }
+          {
+            job_name = "pushgateway";
+            scrape_interval = "1s";
+            static_configs = [
               {
-                name = "webhook";
-                webhook_configs = [
-                  { url = "http://localhost"; }
-                ];
+                targets = [ "127.0.0.1:${toString pushgwPort}" ];
               }
             ];
+          }
+        ];
+        rules = [
+          ''
+            groups:
+              - name: test
+                rules:
+                  - record: testrule
+                    expr: count(up{job="prometheus"})
+          ''
+        ];
+        globalConfig = {
+          external_labels = {
+            some_label = "required by thanos";
           };
         };
+        extraFlags = [
+          # Required by thanos
+          "--storage.tsdb.min-block-duration=5s"
+          "--storage.tsdb.max-block-duration=5s"
+        ];
+      };
+      services.prometheus.pushgateway = {
+        enable = true;
+        web.listen-address = ":${toString pushgwPort}";
+        persistMetrics = true;
+        persistence.interval = "1s";
+        stateDir = "prometheus-pushgateway";
+      };
+      services.thanos = {
+        sidecar = {
+          enable = true;
+          grpc-address = "0.0.0.0:${toString grpcPort}";
+          inherit objstore;
+        };
+
+        # TODO: Add some tests for these services:
+        #rule = {
+        #  enable = true;
+        #  http-address = "0.0.0.0:19194";
+        #  grpc-address = "0.0.0.0:19193";
+        #  query.addresses = [
+        #    "localhost:19191"
+        #  ];
+        #  labels = {
+        #    just = "some";
+        #    nice = "labels";
+        #  };
+        #};
+        #
+        #receive = {
+        #  http-address = "0.0.0.0:19195";
+        #  enable = true;
+        #  labels = {
+        #    just = "some";
+        #    nice = "labels";
+        #  };
+        #};
+      };
+    };
+
+    query = { pkgs, ... }: {
+      environment.systemPackages = [ pkgs.jq ];
+      services.thanos.query = {
+        enable = true;
+        http-address = "0.0.0.0:${toString queryPort}";
+        store.addresses = [
+          "prometheus:${toString grpcPort}"
+        ];
       };
     };
+
+    store = { pkgs, ... }: {
+      virtualisation.diskSize = 2 * 1024;
+      environment.systemPackages = with pkgs; [ jq thanos ];
+      services.thanos.store = {
+        enable = true;
+        http-address = "0.0.0.0:10902";
+        grpc-address = "0.0.0.0:${toString grpcPort}";
+        inherit objstore;
+        sync-block-duration = "1s";
+      };
+      services.thanos.compact = {
+        enable = true;
+        http-address = "0.0.0.0:10903";
+        inherit objstore;
+        consistency-delay = "5s";
+      };
+      services.thanos.query = {
+        enable = true;
+        http-address = "0.0.0.0:${toString queryPort}";
+        store.addresses = [
+          "localhost:${toString grpcPort}"
+        ];
+      };
+    };
+
+    s3 = { pkgs, ... } : {
+      # Minio requires at least 1GiB of free disk space to run.
+      virtualisation.diskSize = 2 * 1024;
+      networking.firewall.allowedTCPPorts = [ minioPort ];
+
+      services.minio = {
+        enable = true;
+        inherit (s3) accessKey secretKey;
+      };
+
+      environment.systemPackages = [ pkgs.minio-client ];
+    };
   };
 
-  testScript = ''
-    startAll;
-    $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/");
+  testScript = { nodes, ... } : ''
+    # Before starting the other machines we first make sure that our S3 service is online
+    # and has a bucket added for thanos:
+    $s3->start;
+    $s3->waitForUnit("minio.service");
+    $s3->waitForOpenPort(${toString minioPort});
+    $s3->succeed(
+      "mc config host add minio " .
+      "http://localhost:${toString minioPort} ${s3.accessKey} ${s3.secretKey} S3v4");
+    $s3->succeed("mc mb minio/thanos-bucket");
+
+    # Now that s3 has started we can start the other machines:
+    $prometheus->start;
+    $query->start;
+    $store->start;
+
+    # Check if prometheus responds to requests:
+    $prometheus->waitForUnit("prometheus.service");
+    $prometheus->waitForOpenPort(${toString queryPort});
+    $prometheus->succeed("curl -s http://127.0.0.1:${toString queryPort}/metrics");
+
+    # Let's test if pushing a metric to the pushgateway succeeds:
+    $prometheus->waitForUnit("pushgateway.service");
+    $prometheus->succeed(
+      "echo 'some_metric 3.14' | " .
+      "curl --data-binary \@- http://127.0.0.1:${toString pushgwPort}/metrics/job/some_job");
+
+    # Now check whether that metric gets ingested by prometheus.
+    # Since we'll check for the metric several times on different machines
+    # we abstract the test using the following function:
+
+    # Function to check if the metric "some_metric" has been received and returns the correct value.
+    local *Machine::waitForMetric = sub {
+      my ($self) = @_;
+      $self->waitUntilSucceeds(
+        "curl -sf 'http://127.0.0.1:${toString queryPort}/api/v1/query?query=some_metric' " .
+        "| jq '.data.result[0].value[1]' | grep '\"3.14\"'");
+    };
+
+    $prometheus->waitForMetric;
+
+    # Let's test if the pushgateway persists metrics to the configured location.
+    $prometheus->waitUntilSucceeds("test -e /var/lib/prometheus-pushgateway/metrics");
+
+    # Test thanos
+    $prometheus->waitForUnit("thanos-sidecar.service");
+
+    # Test if the Thanos query service can correctly retrieve the metric that was send above.
+    $query->waitForUnit("thanos-query.service");
+    $query->waitForMetric;
+
+    # Test if the Thanos sidecar has correctly uploaded its TSDB to S3, if the
+    # Thanos storage service has correctly downloaded it from S3 and if the Thanos
+    # query service running on $store can correctly retrieve the metric:
+    $store->waitForUnit("thanos-store.service");
+    $store->waitForMetric;
+
+    $store->waitForUnit("thanos-compact.service");
+
+    # Test if the Thanos bucket command is able to retrieve blocks from the S3 bucket
+    # and check if the blocks have the correct labels:
+    $store->succeed(
+      "thanos bucket ls" .
+      " --objstore.config-file=${nodes.store.config.services.thanos.store.objstore.config-file}" .
+      " --output=json | jq .thanos.labels.some_label | grep 'required by thanos'");
   '';
 }