about summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
authorFrederik Rietdijk <fridh@fridh.nl>2018-08-09 18:28:15 +0200
committerFrederik Rietdijk <fridh@fridh.nl>2018-08-09 18:28:15 +0200
commitd9fa74ba7891cfae4a029ee79dd29e4ab3425385 (patch)
tree82f79c8dc3d5cf7108055155e6332f64485b0acf /nixos
parent8b834605628fabd43b1b26a1724fb22c83150e2d (diff)
parent8c7fa1e836b8929d29c7ec34f968a3eef11e69de (diff)
downloadnixlib-d9fa74ba7891cfae4a029ee79dd29e4ab3425385.tar
nixlib-d9fa74ba7891cfae4a029ee79dd29e4ab3425385.tar.gz
nixlib-d9fa74ba7891cfae4a029ee79dd29e4ab3425385.tar.bz2
nixlib-d9fa74ba7891cfae4a029ee79dd29e4ab3425385.tar.lz
nixlib-d9fa74ba7891cfae4a029ee79dd29e4ab3425385.tar.xz
nixlib-d9fa74ba7891cfae4a029ee79dd29e4ab3425385.tar.zst
nixlib-d9fa74ba7891cfae4a029ee79dd29e4ab3425385.zip
Merge master into staging
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/release-notes/rl-1809.xml30
-rw-r--r--nixos/modules/installer/cd-dvd/installation-cd-base.nix3
-rw-r--r--nixos/modules/installer/cd-dvd/sd-image-aarch64.nix3
-rw-r--r--nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix3
-rw-r--r--nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix3
-rw-r--r--nixos/modules/installer/netboot/netboot-base.nix3
-rw-r--r--nixos/modules/installer/tools/nixos-generate-config.pl7
-rw-r--r--nixos/modules/misc/ids.nix2
-rw-r--r--nixos/modules/module-list.nix1
-rw-r--r--nixos/modules/profiles/installation-device.nix4
-rw-r--r--nixos/modules/rename.nix1
-rw-r--r--nixos/modules/services/databases/cassandra.nix643
-rw-r--r--nixos/modules/services/databases/foundationdb.xml52
-rw-r--r--nixos/modules/services/hardware/fwupd.nix7
-rw-r--r--nixos/modules/services/misc/disnix.nix2
-rw-r--r--nixos/modules/services/misc/docker-registry.nix37
-rw-r--r--nixos/modules/services/misc/dysnomia.nix10
-rw-r--r--nixos/modules/services/monitoring/graphite.nix20
-rw-r--r--nixos/modules/services/monitoring/netdata.nix4
-rw-r--r--nixos/modules/services/networking/zerotierone.nix15
-rw-r--r--nixos/modules/services/system/cloud-init.nix13
-rw-r--r--nixos/modules/services/x11/desktop-managers/plasma5.nix2
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix2
-rw-r--r--nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py1
-rw-r--r--nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix34
-rw-r--r--nixos/modules/system/boot/luksroot.nix337
-rw-r--r--nixos/modules/system/boot/stage-1.nix8
-rw-r--r--nixos/modules/system/boot/systemd.nix5
-rw-r--r--nixos/modules/tasks/trackpoint.nix15
-rw-r--r--nixos/release.nix1
-rw-r--r--nixos/tests/acme.nix4
-rw-r--r--nixos/tests/cassandra.nix89
-rw-r--r--nixos/tests/netdata.nix8
33 files changed, 739 insertions, 630 deletions
diff --git a/nixos/doc/manual/release-notes/rl-1809.xml b/nixos/doc/manual/release-notes/rl-1809.xml
index 62aaec4ac5df..d527984f5ef1 100644
--- a/nixos/doc/manual/release-notes/rl-1809.xml
+++ b/nixos/doc/manual/release-notes/rl-1809.xml
@@ -75,6 +75,20 @@ $ nix-instantiate -E '(import &lt;nixpkgsunstable&gt; {}).gitFull'
   <itemizedlist>
    <listitem>
     <para>
+     The <varname>services.cassandra</varname> module has been reworked and
+     was rewritten from scratch. The service has succeeding tests for
+     the versions 2.1, 2.2, 3.0 and 3.11 of <link
+     xlink:href="https://cassandra.apache.org/">Apache Cassandra</link>.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     There is a new <varname>services.foundationdb</varname> module for deploying
+     <link xlink:href="https://www.foundationdb.org">FoundationDB</link> clusters.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
      When enabled the <literal>iproute2</literal> will copy the files expected
      by ip route (e.g., <filename>rt_tables</filename>) in
      <filename>/run/iproute2</filename>. This allows to write aliases for
@@ -115,6 +129,12 @@ $ nix-instantiate -E '(import &lt;nixpkgsunstable&gt; {}).gitFull'
   <itemizedlist>
    <listitem>
     <para>
+     The deprecated <varname>services.cassandra</varname> module has
+     seen a complete rewrite. (See above.)
+    </para>
+   </listitem>
+   <listitem>
+    <para>
      <literal>lib.strict</literal> is removed. Use
      <literal>builtins.seq</literal> instead.
     </para>
@@ -170,6 +190,16 @@ $ nix-instantiate -E '(import &lt;nixpkgsunstable&gt; {}).gitFull'
       which indicates that the nix output hash will be used as tag.
     </para>
    </listitem>
+   <listitem>
+    <para>
+      Options
+      <literal>boot.initrd.luks.devices.<replaceable>name</replaceable>.yubikey.ramfsMountPoint</literal>
+      <literal>boot.initrd.luks.devices.<replaceable>name</replaceable>.yubikey.storage.mountPoint</literal>
+      were removed. <literal>luksroot.nix</literal> module never supported more than one YubiKey at
+      a time anyway, hence those options never had any effect. You should be able to remove them
+      from your config without any issues.
+    </para>
+   </listitem>
   </itemizedlist>
  </section>
 
diff --git a/nixos/modules/installer/cd-dvd/installation-cd-base.nix b/nixos/modules/installer/cd-dvd/installation-cd-base.nix
index 36024ce9f45e..1453e8082b0d 100644
--- a/nixos/modules/installer/cd-dvd/installation-cd-base.nix
+++ b/nixos/modules/installer/cd-dvd/installation-cd-base.nix
@@ -29,8 +29,5 @@ with lib;
   # Add Memtest86+ to the CD.
   boot.loader.grub.memtest86.enable = true;
 
-  # Allow the user to log in as root without a password.
-  users.users.root.initialHashedPassword = "";
-
   system.stateVersion = mkDefault "18.03";
 }
diff --git a/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix b/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix
index 4eb28434e192..bd6cf029967c 100644
--- a/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix
+++ b/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix
@@ -33,9 +33,6 @@ in
   # Also increase the amount of CMA to ensure the virtual console on the RPi3 works.
   boot.kernelParams = ["cma=32M" "console=ttyS0,115200n8" "console=ttyAMA0,115200n8" "console=tty0"];
 
-  # FIXME: this probably should be in installation-device.nix
-  users.users.root.initialHashedPassword = "";
-
   sdImage = {
     populateBootCommands = let
       configTxt = pkgs.writeText "config.txt" ''
diff --git a/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix b/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix
index 0d595503f193..0c89eb533359 100644
--- a/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix
+++ b/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix
@@ -34,9 +34,6 @@ in
   # - ttySAC2: for Exynos (ODROID-XU3)
   boot.kernelParams = ["console=ttyS0,115200n8" "console=ttymxc0,115200n8" "console=ttyAMA0,115200n8" "console=ttyO0,115200n8" "console=ttySAC2,115200n8" "console=tty0"];
 
-  # FIXME: this probably should be in installation-device.nix
-  users.users.root.initialHashedPassword = "";
-
   sdImage = {
     populateBootCommands = let
       configTxt = pkgs.writeText "config.txt" ''
diff --git a/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix b/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix
index aa52844288ca..78ea3f1a205c 100644
--- a/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix
+++ b/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix
@@ -27,9 +27,6 @@ in
   boot.consoleLogLevel = lib.mkDefault 7;
   boot.kernelPackages = pkgs.linuxPackages_rpi;
 
-  # FIXME: this probably should be in installation-device.nix
-  users.users.root.initialHashedPassword = "";
-
   sdImage = {
     populateBootCommands = let
       configTxt = pkgs.writeText "config.txt" ''
diff --git a/nixos/modules/installer/netboot/netboot-base.nix b/nixos/modules/installer/netboot/netboot-base.nix
index da7d760ad2fc..7e66a49c7391 100644
--- a/nixos/modules/installer/netboot/netboot-base.nix
+++ b/nixos/modules/installer/netboot/netboot-base.nix
@@ -14,7 +14,4 @@ with lib;
       ../../profiles/base.nix
       ../../profiles/installation-device.nix
     ];
-
-  # Allow the user to log in as root without a password.
-  users.users.root.initialHashedPassword = "";
 }
diff --git a/nixos/modules/installer/tools/nixos-generate-config.pl b/nixos/modules/installer/tools/nixos-generate-config.pl
index cbe145d5a330..bb201d97ded1 100644
--- a/nixos/modules/installer/tools/nixos-generate-config.pl
+++ b/nixos/modules/installer/tools/nixos-generate-config.pl
@@ -537,6 +537,13 @@ if ($showHardwareConfig) {
   boot.loader.systemd-boot.enable = true;
   boot.loader.efi.canTouchEfiVariables = true;
 EOF
+        } elsif (-e "/boot/extlinux") {
+            $bootLoaderConfig = <<EOF;
+  # Use the extlinux boot loader. (NixOS wants to enable GRUB by default)
+  boot.loader.grub.enable = false;
+  # Enables the generation of /boot/extlinux/extlinux.conf
+  boot.loader.generic-extlinux-compatible.enable = true;
+EOF
         } elsif ($virt ne "systemd-nspawn") {
             $bootLoaderConfig = <<EOF;
   # Use the GRUB 2 boot loader.
diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix
index f73660ed99de..40445c3b960a 100644
--- a/nixos/modules/misc/ids.nix
+++ b/nixos/modules/misc/ids.nix
@@ -324,6 +324,7 @@
       hadoop = 297;
       hydron = 298;
       cfssl = 299;
+      cassandra = 300;
 
       # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399!
 
@@ -608,6 +609,7 @@
       hadoop = 297;
       hydron = 298;
       cfssl = 299;
+      cassandra = 300;
 
       # When adding a gid, make sure it doesn't match an existing
       # uid. Users and groups with the same name should have equal
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 5f96336de672..73173dd4e24b 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -201,6 +201,7 @@
   ./services/databases/4store-endpoint.nix
   ./services/databases/4store.nix
   ./services/databases/aerospike.nix
+  ./services/databases/cassandra.nix
   ./services/databases/clickhouse.nix
   ./services/databases/couchdb.nix
   ./services/databases/firebird.nix
diff --git a/nixos/modules/profiles/installation-device.nix b/nixos/modules/profiles/installation-device.nix
index 43f06c219f82..57d947b52684 100644
--- a/nixos/modules/profiles/installation-device.nix
+++ b/nixos/modules/profiles/installation-device.nix
@@ -86,5 +86,9 @@ with lib;
     networking.firewall.logRefusedConnections = mkDefault false;
 
     environment.systemPackages = [ pkgs.vim ];
+
+
+    # Allow the user to log in as root without a password.
+    users.users.root.initialHashedPassword = "";
   };
 }
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix
index 40f66ccb26b2..75f02ea78e64 100644
--- a/nixos/modules/rename.nix
+++ b/nixos/modules/rename.nix
@@ -9,7 +9,6 @@ with lib;
     (mkRenamedOptionModule [ "system" "nixos" "stateVersion" ] [ "system" "stateVersion" ])
     (mkRenamedOptionModule [ "system" "nixos" "defaultChannel" ] [ "system" "defaultChannel" ])
 
-    (mkRenamedOptionModule [ "dysnomia" ] [ "services" "dysnomia" ])
     (mkRenamedOptionModule [ "environment" "x11Packages" ] [ "environment" "systemPackages" ])
     (mkRenamedOptionModule [ "environment" "enableBashCompletion" ] [ "programs" "bash" "enableCompletion" ])
     (mkRenamedOptionModule [ "environment" "nix" ] [ "nix" "package" ])
diff --git a/nixos/modules/services/databases/cassandra.nix b/nixos/modules/services/databases/cassandra.nix
index 09b3fbd8a62a..86e74d5d5ab4 100644
--- a/nixos/modules/services/databases/cassandra.nix
+++ b/nixos/modules/services/databases/cassandra.nix
@@ -4,445 +4,288 @@ with lib;
 
 let
   cfg = config.services.cassandra;
-  cassandraPackage = cfg.package.override {
-    jre = cfg.jre;
-  };
-  cassandraUser = {
-    name = cfg.user;
-    home = "/var/lib/cassandra";
-    description = "Cassandra role user";
-  };
-
-  cassandraRackDcProperties = ''
-    dc=${cfg.dc}
-    rack=${cfg.rack}
-  '';
-
-  cassandraConf = ''
-    cluster_name: ${cfg.clusterName}
-    num_tokens: 256
-    auto_bootstrap: ${boolToString cfg.autoBootstrap}
-    hinted_handoff_enabled: ${boolToString cfg.hintedHandOff}
-    hinted_handoff_throttle_in_kb: ${builtins.toString cfg.hintedHandOffThrottle}
-    max_hints_delivery_threads: 2
-    max_hint_window_in_ms: 10800000 # 3 hours
-    authenticator: ${cfg.authenticator}
-    authorizer: ${cfg.authorizer}
-    permissions_validity_in_ms: 2000
-    partitioner: org.apache.cassandra.dht.Murmur3Partitioner
-    data_file_directories:
-    ${builtins.concatStringsSep "\n" (map (v: "  - "+v) cfg.dataDirs)}
-    commitlog_directory: ${cfg.commitLogDirectory}
-    disk_failure_policy: stop
-    key_cache_size_in_mb:
-    key_cache_save_period: 14400
-    row_cache_size_in_mb: 0
-    row_cache_save_period: 0
-    saved_caches_directory: ${cfg.savedCachesDirectory}
-    commitlog_sync: ${cfg.commitLogSync}
-    commitlog_sync_period_in_ms: ${builtins.toString cfg.commitLogSyncPeriod}
-    commitlog_segment_size_in_mb: 32
-    seed_provider:
-      - class_name: org.apache.cassandra.locator.SimpleSeedProvider
-        parameters:
-          - seeds: "${builtins.concatStringsSep "," cfg.seeds}"
-    concurrent_reads: ${builtins.toString cfg.concurrentReads}
-    concurrent_writes: ${builtins.toString cfg.concurrentWrites}
-    memtable_flush_queue_size: 4
-    trickle_fsync: false
-    trickle_fsync_interval_in_kb: 10240
-    storage_port: 7000
-    ssl_storage_port: 7001
-    listen_address: ${cfg.listenAddress}
-    start_native_transport: true
-    native_transport_port: 9042
-    start_rpc: true
-    rpc_address: ${cfg.rpcAddress}
-    rpc_port: 9160
-    rpc_keepalive: true
-    rpc_server_type: sync
-    thrift_framed_transport_size_in_mb: 15
-    incremental_backups: ${boolToString cfg.incrementalBackups}
-    snapshot_before_compaction: false
-    auto_snapshot: true
-    column_index_size_in_kb: 64
-    in_memory_compaction_limit_in_mb: 64
-    multithreaded_compaction: false
-    compaction_throughput_mb_per_sec: 16
-    compaction_preheat_key_cache: true
-    read_request_timeout_in_ms: 10000
-    range_request_timeout_in_ms: 10000
-    write_request_timeout_in_ms: 10000
-    cas_contention_timeout_in_ms: 1000
-    truncate_request_timeout_in_ms: 60000
-    request_timeout_in_ms: 10000
-    cross_node_timeout: false
-    endpoint_snitch: ${cfg.snitch}
-    dynamic_snitch_update_interval_in_ms: 100
-    dynamic_snitch_reset_interval_in_ms: 600000
-    dynamic_snitch_badness_threshold: 0.1
-    request_scheduler: org.apache.cassandra.scheduler.NoScheduler
-    server_encryption_options:
-      internode_encryption: ${cfg.internodeEncryption}
-      keystore: ${cfg.keyStorePath}
-      keystore_password: ${cfg.keyStorePassword}
-      truststore: ${cfg.trustStorePath}
-      truststore_password: ${cfg.trustStorePassword}
-    client_encryption_options:
-      enabled: ${boolToString cfg.clientEncryption}
-      keystore: ${cfg.keyStorePath}
-      keystore_password: ${cfg.keyStorePassword}
-    internode_compression: all
-    inter_dc_tcp_nodelay: false
-    preheat_kernel_page_cache: false
-    streaming_socket_timeout_in_ms: ${toString cfg.streamingSocketTimoutInMS}
-  '';
-
-  cassandraLog = ''
-    log4j.rootLogger=${cfg.logLevel},stdout
-    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-    log4j.appender.stdout.layout.ConversionPattern=%5p [%t] %d{HH:mm:ss,SSS} %m%n
-  '';
-
-  cassandraConfFile = pkgs.writeText "cassandra.yaml" cassandraConf;
-  cassandraLogFile = pkgs.writeText "log4j-server.properties" cassandraLog;
-  cassandraRackFile = pkgs.writeText "cassandra-rackdc.properties" cassandraRackDcProperties;
-
-  cassandraEnvironment = {
-    CASSANDRA_HOME = cassandraPackage;
-    JAVA_HOME = cfg.jre;
-    CASSANDRA_CONF = "/etc/cassandra";
-  };
+  defaultUser = "cassandra";
+  cassandraConfig = flip recursiveUpdate cfg.extraConfig
+    ({ commitlog_sync = "batch";
+       commitlog_sync_batch_window_in_ms = 2;
+       partitioner = "org.apache.cassandra.dht.Murmur3Partitioner";
+       endpoint_snitch = "SimpleSnitch";
+       seed_provider =
+         [{ class_name = "org.apache.cassandra.locator.SimpleSeedProvider";
+            parameters = [ { seeds = "127.0.0.1"; } ];
+         }];
+       data_file_directories = [ "${cfg.homeDir}/data" ];
+       commitlog_directory = "${cfg.homeDir}/commitlog";
+       saved_caches_directory = "${cfg.homeDir}/saved_caches";
+     } // (if builtins.compareVersions cfg.package.version "3" >= 0
+             then { hints_directory = "${cfg.homeDir}/hints"; }
+             else {})
+    );
+  cassandraConfigWithAddresses = cassandraConfig //
+    ( if isNull cfg.listenAddress
+        then { listen_interface = cfg.listenInterface; }
+        else { listen_address = cfg.listenAddress; }
+    ) // (
+      if isNull cfg.rpcAddress
+        then { rpc_interface = cfg.rpcInterface; }
+        else { rpc_address = cfg.rpcAddress; }
+    );
+  cassandraEtc = pkgs.stdenv.mkDerivation
+    { name = "cassandra-etc";
+      cassandraYaml = builtins.toJSON cassandraConfigWithAddresses;
+      cassandraEnvPkg = "${cfg.package}/conf/cassandra-env.sh";
+      buildCommand = ''
+        mkdir -p "$out"
 
+        echo "$cassandraYaml" > "$out/cassandra.yaml"
+        ln -s "$cassandraEnvPkg" "$out/cassandra-env.sh"
+      '';
+    };
 in {
-
-  ###### interface
-
   options.services.cassandra = {
-    enable = mkOption {
-      description = "Whether to enable cassandra.";
-      default = false;
-      type = types.bool;
-    };
-    package = mkOption {
-      description = "Cassandra package to use.";
-      default = pkgs.cassandra;
-      defaultText = "pkgs.cassandra";
-      type = types.package;
-    };
-    jre = mkOption {
-      description = "JRE package to run cassandra service.";
-      default = pkgs.jre;
-      defaultText = "pkgs.jre";
-      type = types.package;
-    };
+    enable = mkEnableOption ''
+      Apache Cassandra – Scalable and highly available database.
+    '';
     user = mkOption {
-      description = "User that runs cassandra service.";
-      default = "cassandra";
-      type = types.string;
+      type = types.str;
+      default = defaultUser;
+      description = "Run Apache Cassandra under this user.";
     };
     group = mkOption {
-      description = "Group that runs cassandra service.";
-      default = "cassandra";
-      type = types.string;
-    };
-    envFile = mkOption {
-      description = "path to cassandra-env.sh";
-      default = "${cassandraPackage}/conf/cassandra-env.sh";
-      defaultText = "\${cassandraPackage}/conf/cassandra-env.sh";
-      type = types.path;
-    };
-    clusterName = mkOption {
-      description = "set cluster name";
-      default = "cassandra";
-      example = "prod-cluster0";
-      type = types.string;
-    };
-    commitLogDirectory = mkOption {
-      description = "directory for commit logs";
-      default = "/var/lib/cassandra/commit_log";
-      type = types.string;
-    };
-    savedCachesDirectory = mkOption {
-      description = "directory for saved caches";
-      default = "/var/lib/cassandra/saved_caches";
-      type = types.string;
-    };
-    hintedHandOff = mkOption {
-      description = "enable hinted handoff";
-      default = true;
-      type = types.bool;
-    };
-    hintedHandOffThrottle = mkOption {
-      description = "hinted hand off throttle rate in kb";
-      default = 1024;
-      type = types.int;
-    };
-    commitLogSync = mkOption {
-      description = "commitlog sync method";
-      default = "periodic";
       type = types.str;
-      example = "batch";
-    };
-    commitLogSyncPeriod = mkOption {
-      description = "commitlog sync period in ms ";
-      default = 10000;
-      type = types.int;
+      default = defaultUser;
+      description = "Run Apache Cassandra under this group.";
     };
-    envScript = mkOption {
-      default = "${cassandraPackage}/conf/cassandra-env.sh";
-      defaultText = "\${cassandraPackage}/conf/cassandra-env.sh";
+    homeDir = mkOption {
       type = types.path;
-      description = "Supply your own cassandra-env.sh rather than using the default";
-    };
-    extraParams = mkOption {
-      description = "add additional lines to cassandra-env.sh";
-      default = [];
-      example = [''JVM_OPTS="$JVM_OPTS -Dcassandra.available_processors=1"''];
-      type = types.listOf types.str;
-    };
-    dataDirs = mkOption {
-      type = types.listOf types.path;
-      default = [ "/var/lib/cassandra/data" ];
-      description = "Data directories for cassandra";
-    };
-    logLevel = mkOption {
-      type = types.str;
-      default = "INFO";
-      description = "default logging level for log4j";
-    };
-    internodeEncryption = mkOption {
-      description = "enable internode encryption";
-      default = "none";
-      example = "all";
-      type = types.str;
-    };
-    clientEncryption = mkOption {
-      description = "enable client encryption";
-      default = false;
-      type = types.bool;
-    };
-    trustStorePath = mkOption {
-      description = "path to truststore";
-      default = ".conf/truststore";
-      type = types.str;
-    };
-    keyStorePath = mkOption {
-      description = "path to keystore";
-      default = ".conf/keystore";
-      type = types.str;
-    };
-    keyStorePassword = mkOption {
-      description = "password to keystore";
-      default = "cassandra";
-      type = types.str;
+      default = "/var/lib/cassandra";
+      description = ''
+        Home directory for Apache Cassandra.
+      '';
     };
-    trustStorePassword = mkOption {
-      description = "password to truststore";
-      default = "cassandra";
-      type = types.str;
+    package = mkOption {
+      type = types.package;
+      default = pkgs.cassandra;
+      defaultText = "pkgs.cassandra";
+      example = literalExample "pkgs.cassandra_3_11";
+      description = ''
+        The Apache Cassandra package to use.
+      '';
     };
-    seeds = mkOption {
-      description = "password to truststore";
-      default = [ "127.0.0.1" ];
+    jvmOpts = mkOption {
       type = types.listOf types.str;
-    };
-    concurrentWrites = mkOption {
-      description = "number of concurrent writes allowed";
-      default = 32;
-      type = types.int;
-    };
-    concurrentReads = mkOption {
-      description = "number of concurrent reads allowed";
-      default = 32;
-      type = types.int;
+      default = [];
+      description = ''
+        Populate the JVM_OPT environment variable.
+      '';
     };
     listenAddress = mkOption {
-      description = "listen address";
-      default = "localhost";
-      type = types.str;
-    };
-    rpcAddress = mkOption {
-      description = "rpc listener address";
-      default = "localhost";
-      type = types.str;
-    };
-    incrementalBackups = mkOption {
-      description = "enable incremental backups";
-      default = false;
-      type = types.bool;
-    };
-    snitch = mkOption {
-      description = "snitch to use for topology discovery";
-      default = "GossipingPropertyFileSnitch";
-      example = "Ec2Snitch";
-      type = types.str;
-    };
-    dc = mkOption {
-      description = "datacenter for use in topology configuration";
-      default = "DC1";
-      example = "DC1";
-      type = types.str;
-    };
-    rack = mkOption {
-      description = "rack for use in topology configuration";
-      default = "RAC1";
-      example = "RAC1";
-      type = types.str;
-    };
-    authorizer = mkOption {
-      description = "
-        Authorization backend, implementing IAuthorizer; used to limit access/provide permissions
-      ";
-      default = "AllowAllAuthorizer";
-      example = "CassandraAuthorizer";
-      type = types.str;
-    };
-    authenticator = mkOption {
-      description = "
-        Authentication backend, implementing IAuthenticator; used to identify users
-      ";
-      default = "AllowAllAuthenticator";
-      example = "PasswordAuthenticator";
-      type = types.str;
-    };
-    autoBootstrap = mkOption {
-      description = "It makes new (non-seed) nodes automatically migrate the right data to themselves.";
-      default = true;
-      type = types.bool;
-    };
-    streamingSocketTimoutInMS = mkOption {
-      description = "Enable or disable socket timeout for streaming operations";
-      default = 3600000; #CASSANDRA-8611
-      example = 120;
-      type = types.int;
-    };
-    repairStartAt = mkOption {
-      default = "Sun";
-      type = types.string;
+      type = types.nullOr types.str;
+      default = "127.0.0.1";
+      example = literalExample "null";
       description = ''
-      Defines realtime (i.e. wallclock) timers with calendar event
-      expressions. For more details re: systemd OnCalendar at
-      https://www.freedesktop.org/software/systemd/man/systemd.time.html#Displaying%20Time%20Spans
+        Address or interface to bind to and tell other Cassandra nodes
+        to connect to. You _must_ change this if you want multiple
+        nodes to be able to communicate!
+
+        Set listenAddress OR listenInterface, not both.
+
+        Leaving it blank leaves it up to
+        InetAddress.getLocalHost(). This will always do the Right
+        Thing _if_ the node is properly configured (hostname, name
+        resolution, etc), and the Right Thing is to use the address
+        associated with the hostname (it might not be).
+
+        Setting listen_address to 0.0.0.0 is always wrong.
       '';
-      example = ["weekly" "daily" "08:05:40" "mon,fri *-1/2-1,3 *:30:45"];
     };
-    repairRandomizedDelayInSec = mkOption {
-      default = 0;
-      type = types.int;
-      description = ''Delay the timer by a randomly selected, evenly distributed
-      amount of time between 0 and the specified time value. re: systemd timer
-      RandomizedDelaySec for more details
+    listenInterface = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      example = "eth1";
+      description = ''
+        Set listenAddress OR listenInterface, not both. Interfaces
+        must correspond to a single address, IP aliasing is not
+        supported.
       '';
     };
-    repairPostStop = mkOption {
-      default = null;
-      type = types.nullOr types.string;
+    rpcAddress = mkOption {
+      type = types.nullOr types.str;
+      default = "127.0.0.1";
+      example = literalExample "null";
       description = ''
-      Run a script when repair is over. One can use it to send statsd events, email, etc.
+        The address or interface to bind the native transport server to.
+
+        Set rpcAddress OR rpcInterface, not both.
+
+        Leaving rpcAddress blank has the same effect as on
+        listenAddress (i.e. it will be based on the configured hostname
+        of the node).
+
+        Note that unlike listenAddress, you can specify 0.0.0.0, but you
+        must also set extraConfig.broadcast_rpc_address to a value other
+        than 0.0.0.0.
+
+        For security reasons, you should not expose this port to the
+        internet. Firewall it if needed.
       '';
     };
-    repairPostStart = mkOption {
+    rpcInterface = mkOption {
+      type = types.nullOr types.str;
       default = null;
-      type = types.nullOr types.string;
+      example = "eth1";
       description = ''
-      Run a script when repair starts. One can use it to send statsd events, email, etc.
-      It has same semantics as systemd ExecStopPost; So, if it fails, unit is consisdered
-      failed.
+        Set rpcAddress OR rpcInterface, not both. Interfaces must
+        correspond to a single address, IP aliasing is not supported.
       '';
     };
-  };
 
-  ###### implementation
-
-  config = mkIf cfg.enable {
+    extraConfig = mkOption {
+      type = types.attrs;
+      default = {};
+      example =
+        { commitlog_sync_batch_window_in_ms = 3;
+        };
+      description = ''
+        Extra options to be merged into cassandra.yaml as nix attribute set.
+      '';
+    };
+    fullRepairInterval = mkOption {
+      type = types.nullOr types.str;
+      default = "3w";
+      example = literalExample "null";
+      description = ''
+          Set the interval how often full repairs are run, i.e.
+          `nodetool repair --full` is executed. See
+          https://cassandra.apache.org/doc/latest/operating/repair.html
+          for more information.
 
-    environment.etc."cassandra/cassandra-rackdc.properties" = {
-      source = cassandraRackFile;
+          Set to `null` to disable full repairs.
+        '';
     };
-    environment.etc."cassandra/cassandra.yaml" = {
-      source = cassandraConfFile;
+    fullRepairOptions = mkOption {
+      type = types.listOf types.str;
+      default = [];
+      example = [ "--partitioner-range" ];
+      description = ''
+          Options passed through to the full repair command.
+        '';
     };
-    environment.etc."cassandra/log4j-server.properties" = {
-      source = cassandraLogFile;
+    incrementalRepairInterval = mkOption {
+      type = types.nullOr types.str;
+      default = "3d";
+      example = literalExample "null";
+      description = ''
+          Set the interval how often incremental repairs are run, i.e.
+          `nodetool repair` is executed. See
+          https://cassandra.apache.org/doc/latest/operating/repair.html
+          for more information.
+
+          Set to `null` to disable incremental repairs.
+        '';
     };
-    environment.etc."cassandra/cassandra-env.sh" = {
-      text = ''
-        ${builtins.readFile cfg.envFile}
-        ${concatStringsSep "\n" cfg.extraParams}
-      '';
+    incrementalRepairOptions = mkOption {
+      type = types.listOf types.string;
+      default = [];
+      example = [ "--partitioner-range" ];
+      description = ''
+          Options passed through to the incremental repair command.
+        '';
     };
-    systemd.services.cassandra = {
-      description = "Cassandra Daemon";
-      wantedBy = [ "multi-user.target" ];
-      after = [ "network.target" ];
-      environment = cassandraEnvironment;
-      restartTriggers = [ cassandraConfFile cassandraLogFile cassandraRackFile ];
-      serviceConfig = {
-
-        User = cfg.user;
-        PermissionsStartOnly = true;
-        LimitAS = "infinity";
-        LimitNOFILE = "100000";
-        LimitNPROC = "32768";
-        LimitMEMLOCK = "infinity";
+  };
 
-      };
-      script = ''
-         ${cassandraPackage}/bin/cassandra -f
-        '';
-      path = [
-        cfg.jre
-        cassandraPackage
-        pkgs.coreutils
+  config = mkIf cfg.enable {
+    assertions =
+      [ { assertion =
+            ((isNull cfg.listenAddress)
+             || (isNull cfg.listenInterface)
+            ) && !((isNull cfg.listenAddress)
+                   && (isNull cfg.listenInterface)
+                  );
+          message = "You have to set either listenAddress or listenInterface";
+        }
+        { assertion =
+            ((isNull cfg.rpcAddress)
+             || (isNull cfg.rpcInterface)
+            ) && !((isNull cfg.rpcAddress)
+                   && (isNull cfg.rpcInterface)
+                  );
+          message = "You have to set either rpcAddress or rpcInterface";
+        }
       ];
-      preStart = ''
-        mkdir -m 0700 -p /etc/cassandra/triggers
-        mkdir -m 0700 -p /var/lib/cassandra /var/log/cassandra
-        chown ${cfg.user} /var/lib/cassandra /var/log/cassandra /etc/cassandra/triggers
-      '';
-      postStart = ''
-        sleep 2
-        while ! nodetool status >/dev/null 2>&1; do
-          sleep 2
-        done
-        nodetool status
-      '';
+    users = mkIf (cfg.user == defaultUser) {
+      extraUsers."${defaultUser}" =
+        {  group = cfg.group;
+           home = cfg.homeDir;
+           createHome = true;
+           uid = config.ids.uids.cassandra;
+           description = "Cassandra service user";
+        };
+      extraGroups."${defaultUser}".gid = config.ids.gids.cassandra;
     };
 
-    environment.systemPackages = [ cassandraPackage ];
-
-    networking.firewall.allowedTCPPorts = [
-      7000
-      7001
-      9042
-      9160
-    ];
-
-    users.users.cassandra =
-      if config.ids.uids ? "cassandra"
-      then { uid = config.ids.uids.cassandra; } // cassandraUser
-      else cassandraUser ;
-
-    boot.kernel.sysctl."vm.swappiness" = pkgs.lib.mkOptionDefault 0;
+    systemd.services.cassandra =
+      { description = "Apache Cassandra service";
+        after = [ "network.target" ];
+        environment =
+          { CASSANDRA_CONF = "${cassandraEtc}";
+            JVM_OPTS = builtins.concatStringsSep " " cfg.jvmOpts;
+          };
+        wantedBy = [ "multi-user.target" ];
+        serviceConfig =
+          { User = cfg.user;
+            Group = cfg.group;
+            ExecStart = "${cfg.package}/bin/cassandra -f";
+            SuccessExitStatus = 143;
+          };
+      };
 
-    systemd.timers."cassandra-repair" = {
-      timerConfig = {
-        OnCalendar = "${toString cfg.repairStartAt}";
-        RandomizedDelaySec = cfg.repairRandomizedDelayInSec;
+    systemd.services.cassandra-full-repair =
+      { description = "Perform a full repair on this Cassandra node";
+        after = [ "cassandra.service" ];
+        requires = [ "cassandra.service" ];
+        serviceConfig =
+          { User = cfg.user;
+            Group = cfg.group;
+            ExecStart =
+              lib.concatStringsSep " "
+                ([ "${cfg.package}/bin/nodetool" "repair" "--full"
+                 ] ++ cfg.fullRepairOptions);
+          };
+      };
+    systemd.timers.cassandra-full-repair =
+      mkIf (!isNull cfg.fullRepairInterval) {
+        description = "Schedule full repairs on Cassandra";
+        wantedBy = [ "timers.target" ];
+        timerConfig =
+          { OnBootSec = cfg.fullRepairInterval;
+            OnUnitActiveSec = cfg.fullRepairInterval;
+            Persistent = true;
+          };
       };
-    };
 
-    systemd.services."cassandra-repair" = {
-      description = "Cassandra repair daemon";
-      environment = cassandraEnvironment;
-      script = "${cassandraPackage}/bin/nodetool repair -pr";
-      postStop = mkIf (cfg.repairPostStop != null) cfg.repairPostStop;
-      postStart = mkIf (cfg.repairPostStart != null) cfg.repairPostStart;
-      serviceConfig = {
-        User = cfg.user;
+    systemd.services.cassandra-incremental-repair =
+      { description = "Perform an incremental repair on this cassandra node.";
+        after = [ "cassandra.service" ];
+        requires = [ "cassandra.service" ];
+        serviceConfig =
+          { User = cfg.user;
+            Group = cfg.group;
+            ExecStart =
+              lib.concatStringsSep " "
+                ([ "${cfg.package}/bin/nodetool" "repair"
+                 ] ++ cfg.incrementalRepairOptions);
+          };
+      };
+    systemd.timers.cassandra-incremental-repair =
+      mkIf (!isNull cfg.incrementalRepairInterval) {
+        description = "Schedule incremental repairs on Cassandra";
+        wantedBy = [ "timers.target" ];
+        timerConfig =
+          { OnBootSec = cfg.incrementalRepairInterval;
+            OnUnitActiveSec = cfg.incrementalRepairInterval;
+            Persistent = true;
+          };
       };
-    };
   };
 }
diff --git a/nixos/modules/services/databases/foundationdb.xml b/nixos/modules/services/databases/foundationdb.xml
index 51fe9ae3f910..f4090c492764 100644
--- a/nixos/modules/services/databases/foundationdb.xml
+++ b/nixos/modules/services/databases/foundationdb.xml
@@ -12,12 +12,10 @@
 
 <para><emphasis>Maintainer:</emphasis> Austin Seipp</para>
 
-<para><emphasis>Available version(s):</emphasis> 5.1.x</para>
+<para><emphasis>Available version(s):</emphasis> 5.1.x, 5.2.x, 6.0.x</para>
 
-<para>FoundationDB (or "FDB") is a distributed, open source, high performance,
-transactional key-value store. It can store petabytes of data and deliver
-exceptional performance while maintaining consistency and ACID semantics
-(serializable transactions) over a large cluster.</para>
+<para>FoundationDB (or "FDB") is an open source, distributed, transactional
+key-value store.</para>
 
 <section><title>Configuring and basic setup</title>
 
@@ -26,12 +24,12 @@ exceptional performance while maintaining consistency and ACID semantics
 
 <programlisting>
 services.foundationdb.enable = true;
-services.foundationdb.package = pkgs.foundationdb51; # FoundationDB 5.1.x
+services.foundationdb.package = pkgs.foundationdb52; # FoundationDB 5.2.x
 </programlisting>
 </para>
 
 <para>The <option>services.foundationdb.package</option> option is required,
-and must always be specified. Because FoundationDB network protocols and
+and must always be specified. Due to the fact FoundationDB network protocols and
 on-disk storage formats may change between (major) versions, and upgrades must
 be explicitly handled by the user, you must always manually specify this
 yourself so that the NixOS module will use the proper version. Note that minor,
@@ -70,6 +68,40 @@ fdb>
 </programlisting>
 </para>
 
+<para>You can also write programs using the available client libraries.
+For example, the following Python program can be run in order to grab the
+cluster status, as a quick example. (This example uses
+<command>nix-shell</command> shebang support to automatically supply the
+necessary Python modules).
+
+<programlisting>
+a@link> cat fdb-status.py
+#! /usr/bin/env nix-shell
+#! nix-shell -i python -p python pythonPackages.foundationdb52
+
+import fdb
+import json
+
+def main():
+    fdb.api_version(520)
+    db = fdb.open()
+
+    @fdb.transactional
+    def get_status(tr):
+        return str(tr['\xff\xff/status/json'])
+
+    obj = json.loads(get_status(db))
+    print('FoundationDB available: %s' % obj['client']['database_status']['available'])
+
+if __name__ == "__main__":
+    main()
+a@link> chmod +x fdb-status.py
+a@link> ./fdb-status.py
+FoundationDB available: True
+a@link>
+</programlisting>
+</para>
+
 <para>FoundationDB is run under the <command>foundationdb</command> user and
 group by default, but this may be changed in the NixOS configuration. The
 systemd unit <command>foundationdb.service</command> controls the
@@ -295,7 +327,6 @@ only undergone fairly basic testing of all the available functionality.</para>
       individual <command>fdbserver</command> processes. Currently, all server
       processes inherit all the global <command>fdbmonitor</command> settings.
       </para></listitem>
-  <listitem><para>Python bindings are not currently installed.</para></listitem>
   <listitem><para>Ruby bindings are not currently installed.</para></listitem>
   <listitem><para>Go bindings are not currently installed.</para></listitem>
 </itemizedlist>
@@ -306,8 +337,9 @@ only undergone fairly basic testing of all the available functionality.</para>
 
 <para>NixOS's FoundationDB module allows you to configure all of the most
 relevant configuration options for <command>fdbmonitor</command>, matching it
-quite closely. For a complete list of all options, check <command>man
-configuration.nix</command>.</para>
+quite closely. A complete list of options for the FoundationDB module may be
+found <link linkend="opt-services.foundationdb.enable">here</link>. You should
+also read the FoundationDB documentation as well.</para>
 
 </section>
 
diff --git a/nixos/modules/services/hardware/fwupd.nix b/nixos/modules/services/hardware/fwupd.nix
index d97d690920a6..7743f81fd622 100644
--- a/nixos/modules/services/hardware/fwupd.nix
+++ b/nixos/modules/services/hardware/fwupd.nix
@@ -71,6 +71,13 @@ in {
           BlacklistPlugins=${lib.concatStringsSep ";" cfg.blacklistPlugins}
         '';
       };
+      "fwupd/uefi.conf" = {
+        source = pkgs.writeText "uefi.conf" ''
+          [uefi]
+          OverrideESPMountPoint=${config.boot.loader.efi.efiSysMountPoint}
+        '';
+      };
+
     } // originalEtc // extraTrustedKeys;
 
     services.dbus.packages = [ pkgs.fwupd ];
diff --git a/nixos/modules/services/misc/disnix.nix b/nixos/modules/services/misc/disnix.nix
index bb3ac1ecf075..c21cb2afc3ca 100644
--- a/nixos/modules/services/misc/disnix.nix
+++ b/nixos/modules/services/misc/disnix.nix
@@ -47,7 +47,7 @@ in
   ###### implementation
 
   config = mkIf cfg.enable {
-    services.dysnomia.enable = true;
+    dysnomia.enable = true;
 
     environment.systemPackages = [ pkgs.disnix ] ++ optional cfg.useWebServiceInterface pkgs.DisnixWebService;
 
diff --git a/nixos/modules/services/misc/docker-registry.nix b/nixos/modules/services/misc/docker-registry.nix
index 08031d33c131..9a3966ab30aa 100644
--- a/nixos/modules/services/misc/docker-registry.nix
+++ b/nixos/modules/services/misc/docker-registry.nix
@@ -5,6 +5,43 @@ with lib;
 let
   cfg = config.services.dockerRegistry;
 
+  blobCache = if cfg.enableRedisCache
+    then "redis"
+    else "inmemory";
+
+  registryConfig = {
+    version =  "0.1";
+    log.fields.service = "registry";
+    storage = {
+      cache.blobdescriptor = blobCache;
+      filesystem.rootdirectory = cfg.storagePath;
+      delete.enabled = cfg.enableDelete;
+    };
+    http = {
+      addr = ":${builtins.toString cfg.port}";
+      headers.X-Content-Type-Options = ["nosniff"];
+    };
+    health.storagedriver = {
+      enabled = true;
+      interval = "10s";
+      threshold = 3;
+    };
+  };
+
+  registryConfig.redis = mkIf cfg.enableRedisCache {
+    addr = "${cfg.redisUrl}";
+    password = "${cfg.redisPassword}";
+    db = 0;
+    dialtimeout = "10ms";
+    readtimeout = "10ms";
+    writetimeout = "10ms";
+    pool = {
+      maxidle = 16;
+      maxactive = 64;
+      idletimeout = "300s";
+    };
+  };
+
   configFile = pkgs.writeText "docker-registry-config.yml" (builtins.toJSON (recursiveUpdate registryConfig cfg.extraConfig));
 
 in {
diff --git a/nixos/modules/services/misc/dysnomia.nix b/nixos/modules/services/misc/dysnomia.nix
index ba74b18b6970..61ea822890ed 100644
--- a/nixos/modules/services/misc/dysnomia.nix
+++ b/nixos/modules/services/misc/dysnomia.nix
@@ -3,7 +3,7 @@
 with lib;
 
 let
-  cfg = config.services.dysnomia;
+  cfg = config.dysnomia;
 
   printProperties = properties:
     concatMapStrings (propertyName:
@@ -69,7 +69,7 @@ let
 in
 {
   options = {
-    services.dysnomia = {
+    dysnomia = {
 
       enable = mkOption {
         type = types.bool;
@@ -142,7 +142,7 @@ in
 
     environment.systemPackages = [ cfg.package ];
 
-    services.dysnomia.package = pkgs.dysnomia.override (origArgs: {
+    dysnomia.package = pkgs.dysnomia.override (origArgs: {
       enableApacheWebApplication = config.services.httpd.enable;
       enableAxis2WebService = config.services.tomcat.axis2.enable;
       enableEjabberdDump = config.services.ejabberd.enable;
@@ -153,7 +153,7 @@ in
       enableMongoDatabase = config.services.mongodb.enable;
     });
 
-    services.dysnomia.properties = {
+    dysnomia.properties = {
       hostname = config.networking.hostName;
       inherit (config.nixpkgs.localSystem) system;
 
@@ -171,7 +171,7 @@ in
       }}");
     };
 
-    services.dysnomia.containers = lib.recursiveUpdate ({
+    dysnomia.containers = lib.recursiveUpdate ({
       process = {};
       wrapper = {};
     }
diff --git a/nixos/modules/services/monitoring/graphite.nix b/nixos/modules/services/monitoring/graphite.nix
index cdfd746bc5a3..cdc98b407e90 100644
--- a/nixos/modules/services/monitoring/graphite.nix
+++ b/nixos/modules/services/monitoring/graphite.nix
@@ -57,12 +57,6 @@ let
     --nodaemon --syslog --prefix=${name} --pidfile /run/${name}/${name}.pid ${name}
   '';
 
-  mkPidFileDir = name: ''
-    mkdir -p /run/${name}
-    chmod 0700 /run/${name}
-    chown -R graphite:graphite /run/${name}
-  '';
-
   carbonEnv = {
     PYTHONPATH = let
       cenv = pkgs.python.buildEnv.override {
@@ -412,18 +406,16 @@ in {
         after = [ "network.target" ];
         environment = carbonEnv;
         serviceConfig = {
+          RuntimeDirectory = name;
           ExecStart = "${pkgs.pythonPackages.twisted}/bin/twistd ${carbonOpts name}";
           User = "graphite";
           Group = "graphite";
           PermissionsStartOnly = true;
           PIDFile="/run/${name}/${name}.pid";
         };
-        preStart = mkPidFileDir name + ''
-
-          mkdir -p ${cfg.dataDir}/whisper
-          chmod 0700 ${cfg.dataDir}/whisper
-          chown graphite:graphite ${cfg.dataDir}
-          chown graphite:graphite ${cfg.dataDir}/whisper
+        preStart = ''
+          install -dm0700 -o graphite -g graphite ${cfg.dataDir}
+          install -dm0700 -o graphite -g graphite ${cfg.dataDir}/whisper
         '';
       };
     })
@@ -436,12 +428,12 @@ in {
         after = [ "network.target" ];
         environment = carbonEnv;
         serviceConfig = {
+          RuntimeDirectory = name;
           ExecStart = "${pkgs.pythonPackages.twisted}/bin/twistd ${carbonOpts name}";
           User = "graphite";
           Group = "graphite";
           PIDFile="/run/${name}/${name}.pid";
         };
-        preStart = mkPidFileDir name;
       };
     })
 
@@ -452,12 +444,12 @@ in {
         after = [ "network.target" ];
         environment = carbonEnv;
         serviceConfig = {
+          RuntimeDirectory = name;
           ExecStart = "${pkgs.pythonPackages.twisted}/bin/twistd ${carbonOpts name}";
           User = "graphite";
           Group = "graphite";
           PIDFile="/run/${name}/${name}.pid";
         };
-        preStart = mkPidFileDir name;
       };
     })
 
diff --git a/nixos/modules/services/monitoring/netdata.nix b/nixos/modules/services/monitoring/netdata.nix
index eefddf5a206b..edcaa10d969d 100644
--- a/nixos/modules/services/monitoring/netdata.nix
+++ b/nixos/modules/services/monitoring/netdata.nix
@@ -14,6 +14,10 @@ let
     global = {
       "plugins directory" = "${wrappedPlugins}/libexec/netdata/plugins.d ${pkgs.netdata}/libexec/netdata/plugins.d";
     };
+    web = {
+      "web files owner" = "root";
+      "web files group" = "root";
+    };
   };
   mkConfig = generators.toINI {} (recursiveUpdate localConfig cfg.config);
   configFile = pkgs.writeText "netdata.conf" (if cfg.configText != null then cfg.configText else mkConfig);
diff --git a/nixos/modules/services/networking/zerotierone.nix b/nixos/modules/services/networking/zerotierone.nix
index 4c1ee75d536c..a4cd368397e7 100644
--- a/nixos/modules/services/networking/zerotierone.nix
+++ b/nixos/modules/services/networking/zerotierone.nix
@@ -17,6 +17,15 @@ in
     '';
   };
 
+  options.services.zerotierone.port = mkOption {
+    default = 9993;
+    example = 9993;
+    type = types.int;
+    description = ''
+      Network port used by ZeroTier.
+    '';
+  };
+
   options.services.zerotierone.package = mkOption {
     default = pkgs.zerotierone;
     defaultText = "pkgs.zerotierone";
@@ -40,7 +49,7 @@ in
         touch "/var/lib/zerotier-one/networks.d/${netId}.conf"
       '') cfg.joinNetworks);
       serviceConfig = {
-        ExecStart = "${cfg.package}/bin/zerotier-one";
+        ExecStart = "${cfg.package}/bin/zerotier-one -p${toString cfg.port}";
         Restart = "always";
         KillMode = "process";
       };
@@ -49,8 +58,8 @@ in
     # ZeroTier does not issue DHCP leases, but some strangers might...
     networking.dhcpcd.denyInterfaces = [ "zt*" ];
 
-    # ZeroTier receives UDP transmissions on port 9993 by default
-    networking.firewall.allowedUDPPorts = [ 9993 ];
+    # ZeroTier receives UDP transmissions
+    networking.firewall.allowedUDPPorts = [ cfg.port ];
 
     environment.systemPackages = [ cfg.package ];
   };
diff --git a/nixos/modules/services/system/cloud-init.nix b/nixos/modules/services/system/cloud-init.nix
index d513e44dcfba..1a700828ce77 100644
--- a/nixos/modules/services/system/cloud-init.nix
+++ b/nixos/modules/services/system/cloud-init.nix
@@ -104,8 +104,9 @@ in
     systemd.services.cloud-init =
       { description = "Initial cloud-init job (metadata service crawler)";
         wantedBy = [ "multi-user.target" ];
-        wants = [ "local-fs.target" "cloud-init-local.service" "sshd.service" "sshd-keygen.service" ];
-        after = [ "local-fs.target" "network.target" "cloud-init-local.service" ];
+        wants = [ "local-fs.target" "network-online.target" "cloud-init-local.service"
+                  "sshd.service" "sshd-keygen.service" ];
+        after = [ "local-fs.target" "network-online.target" "cloud-init-local.service" ];
         before = [ "sshd.service" "sshd-keygen.service" ];
         requires = [ "network.target "];
         path = path;
@@ -121,8 +122,8 @@ in
     systemd.services.cloud-config =
       { description = "Apply the settings specified in cloud-config";
         wantedBy = [ "multi-user.target" ];
-        wants = [ "network.target" ];
-        after = [ "network.target" "syslog.target" "cloud-config.target" ];
+        wants = [ "network-online.target" ];
+        after = [ "network-online.target" "syslog.target" "cloud-config.target" ];
 
         path = path;
         serviceConfig =
@@ -137,8 +138,8 @@ in
     systemd.services.cloud-final =
       { description = "Execute cloud user/final scripts";
         wantedBy = [ "multi-user.target" ];
-        wants = [ "network.target" ];
-        after = [ "network.target" "syslog.target" "cloud-config.service" "rc-local.service" ];
+        wants = [ "network-online.target" ];
+        after = [ "network-online.target" "syslog.target" "cloud-config.service" "rc-local.service" ];
         requires = [ "cloud-config.target" ];
         path = path;
         serviceConfig =
diff --git a/nixos/modules/services/x11/desktop-managers/plasma5.nix b/nixos/modules/services/x11/desktop-managers/plasma5.nix
index 17733aa7e4f6..83d1957a646a 100644
--- a/nixos/modules/services/x11/desktop-managers/plasma5.nix
+++ b/nixos/modules/services/x11/desktop-managers/plasma5.nix
@@ -224,7 +224,7 @@ in
       # Update the start menu for each user that has `isNormalUser` set.
       system.activationScripts.plasmaSetup = stringAfter [ "users" "groups" ]
         (concatStringsSep "\n"
-          (mapAttrsToList (name: value: "${pkgs.su}/bin/su ${name} -c kbuildsycoca5")
+          (mapAttrsToList (name: value: "${pkgs.su}/bin/su ${name} -c ${pkgs.libsForQt5.kservice}/bin/kbuildsycoca5")
             (filterAttrs (n: v: v.isNormalUser) config.users.users)));
     })
   ];
diff --git a/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix b/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix
index cfa38f175dd3..013956c05466 100644
--- a/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix
@@ -23,7 +23,7 @@ let
       makeWrapper ${pkgs.lightdm_gtk_greeter}/sbin/lightdm-gtk-greeter \
         $out/greeter \
         --prefix PATH : "${pkgs.glibc.bin}/bin" \
-        --set GDK_PIXBUF_MODULE_FILE "${pkgs.gdk_pixbuf.out}/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache" \
+        --set GDK_PIXBUF_MODULE_FILE "${pkgs.librsvg.out}/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache" \
         --set GTK_PATH "${theme}:${pkgs.gtk3.out}" \
         --set GTK_EXE_PREFIX "${theme}" \
         --set GTK_DATA_PREFIX "${theme}" \
diff --git a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py
index 3333569c36be..1dc888c58227 100644
--- a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py
+++ b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py
@@ -43,6 +43,7 @@ def write_loader_conf(profile, generation):
             f.write("default nixos-generation-%d\n" % (generation))
         if not @editor@:
             f.write("editor 0");
+        f.write("console-mode @consoleMode@\n");
     os.rename("@efiSysMountPoint@/loader/loader.conf.tmp", "@efiSysMountPoint@/loader/loader.conf")
 
 def profile_path(profile, generation, name):
diff --git a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix
index a5a88a99be8f..feed863efd66 100644
--- a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix
+++ b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix
@@ -22,6 +22,8 @@ let
 
     editor = if cfg.editor then "True" else "False";
 
+    inherit (cfg) consoleMode;
+
     inherit (efi) efiSysMountPoint canTouchEfiVariables;
   };
 in {
@@ -52,6 +54,38 @@ in {
         compatibility.
       '';
     };
+
+    consoleMode = mkOption {
+      default = "keep";
+
+      type = types.enum [ "0" "1" "2" "auto" "max" "keep" ];
+
+      description = ''
+        The resolution of the console. The following values are valid:
+        </para>
+        <para>
+        <itemizedlist>
+          <listitem><para>
+            <literal>"0"</literal>: Standard UEFI 80x25 mode
+          </para></listitem>
+          <listitem><para>
+            <literal>"1"</literal>: 80x50 mode, not supported by all devices
+          </para></listitem>
+          <listitem><para>
+            <literal>"2"</literal>: The first non-standard mode provided by the device firmware, if any
+          </para></listitem>
+          <listitem><para>
+            <literal>"auto"</literal>: Pick a suitable mode automatically using heuristics
+          </para></listitem>
+          <listitem><para>
+            <literal>"max"</literal>: Pick the highest-numbered available mode
+          </para></listitem>
+          <listitem><para>
+            <literal>"keep"</literal>: Keep the mode selected by firmware (the default)
+          </para></listitem>
+        </itemizedlist>
+      '';
+    };
   };
 
   config = mkIf cfg.enable {
diff --git a/nixos/modules/system/boot/luksroot.nix b/nixos/modules/system/boot/luksroot.nix
index 7ebfdb134d7d..27c1f891f485 100644
--- a/nixos/modules/system/boot/luksroot.nix
+++ b/nixos/modules/system/boot/luksroot.nix
@@ -5,61 +5,171 @@ with lib;
 let
   luks = config.boot.initrd.luks;
 
-  openCommand = name': { name, device, header, keyFile, keyFileSize, allowDiscards, yubikey, fallbackToPassword, ... }: assert name' == name; ''
+  commonFunctions = ''
+    die() {
+      echo "$@" >&2
+      exit 1
+    }
 
-    # Wait for a target (e.g. device, keyFile, header, ...) to appear.
     wait_target() {
         local name="$1"
         local target="$2"
+        local secs="''${3:-10}"
+        local desc="''${4:-$name $target to appear}"
 
         if [ ! -e $target ]; then
-            echo -n "Waiting 10 seconds for $name $target to appear"
+            echo -n "Waiting $secs seconds for $desc..."
             local success=false;
-            for try in $(seq 10); do
+            for try in $(seq $secs); do
                 echo -n "."
                 sleep 1
-                if [ -e $target ]; then success=true break; fi
+                if [ -e $target ]; then
+                    success=true
+                    break
+                fi
             done
-            if [ $success = true ]; then
+            if [ $success == true ]; then
                 echo " - success";
+                return 0
             else
                 echo " - failure";
+                return 1
             fi
         fi
+        return 0
     }
 
+    wait_yubikey() {
+      local secs="''${1:-10}"
+
+      ykinfo -v 1>/dev/null 2>&1
+      if [ $? != 0 ]; then
+          echo -n "Waiting $secs seconds for Yubikey to appear..."
+          local success=false
+          for try in $(seq $secs); do
+              echo -n .
+              sleep 1
+              ykinfo -v 1>/dev/null 2>&1
+              if [ $? == 0 ]; then
+                  success=true
+                  break
+              fi
+          done
+          if [ $success == true ]; then
+              echo " - success";
+              return 0
+          else
+              echo " - failure";
+              return 1
+          fi
+      fi
+      return 0
+    }
+  '';
+
+  preCommands = ''
+    # A place to store crypto things
+
+    # A ramfs is used here to ensure that the file used to update
+    # the key slot with cryptsetup will never get swapped out.
+    # Warning: Do NOT replace with tmpfs!
+    mkdir -p /crypt-ramfs
+    mount -t ramfs none /crypt-ramfs
+
+    # For Yubikey salt storage
+    mkdir -p /crypt-storage
+
+    # Disable all input echo for the whole stage. We could use read -s
+    # instead but that would ocasionally leak characters between read
+    # invocations.
+    stty -echo
+  '';
+
+  postCommands = ''
+    stty echo
+    umount /crypt-storage 2>/dev/null
+    umount /crypt-ramfs 2>/dev/null
+  '';
+
+  openCommand = name': { name, device, header, keyFile, keyFileSize, keyFileOffset, allowDiscards, yubikey, fallbackToPassword, ... }: assert name' == name;
+  let
+    csopen   = "cryptsetup luksOpen ${device} ${name} ${optionalString allowDiscards "--allow-discards"} ${optionalString (header != null) "--header=${header}"}";
+    cschange = "cryptsetup luksChangeKey ${device} ${optionalString (header != null) "--header=${header}"}";
+  in ''
     # Wait for luksRoot (and optionally keyFile and/or header) to appear, e.g.
     # if on a USB drive.
-    wait_target "device" ${device}
-
-    ${optionalString (keyFile != null) ''
-      wait_target "key file" ${keyFile}
-    ''}
+    wait_target "device" ${device} || die "${device} is unavailable"
 
     ${optionalString (header != null) ''
-      wait_target "header" ${header}
+      wait_target "header" ${header} || die "${header} is unavailable"
     ''}
 
+    do_open_passphrase() {
+        local passphrase
+
+        while true; do
+            echo -n "Passphrase for ${device}: "
+            passphrase=
+            while true; do
+                if [ -e /crypt-ramfs/passphrase ]; then
+                    echo "reused"
+                    passphrase=$(cat /crypt-ramfs/passphrase)
+                    break
+                else
+                    # ask cryptsetup-askpass
+                    echo -n "${device}" > /crypt-ramfs/device
+
+                    # and try reading it from /dev/console with a timeout
+                    IFS= read -t 1 -r passphrase
+                    if [ -n "$passphrase" ]; then
+                       ${if luks.reusePassphrases then ''
+                         # remember it for the next device
+                         echo -n "$passphrase" > /crypt-ramfs/passphrase
+                       '' else ''
+                         # Don't save it to ramfs. We are very paranoid
+                       ''}
+                       echo
+                       break
+                    fi
+                fi
+            done
+            echo -n "Verifiying passphrase for ${device}..."
+            echo -n "$passphrase" | ${csopen} --key-file=-
+            if [ $? == 0 ]; then
+                echo " - success"
+                ${if luks.reusePassphrases then ''
+                  # we don't rm here because we might reuse it for the next device
+                '' else ''
+                  rm -f /crypt-ramfs/passphrase
+                ''}
+                break
+            else
+                echo " - failure"
+                # ask for a different one
+                rm -f /crypt-ramfs/passphrase
+            fi
+        done
+    }
+
+    # LUKS
     open_normally() {
-        echo luksOpen ${device} ${name} ${optionalString allowDiscards "--allow-discards"} \
-          ${optionalString (header != null) "--header=${header}"} \
-          > /.luksopen_args
-        ${optionalString (keyFile != null) ''
-        ${optionalString fallbackToPassword "if [ -e ${keyFile} ]; then"}
-            echo " --key-file=${keyFile} ${optionalString (keyFileSize != null) "--keyfile-size=${toString keyFileSize}"}" \
-              >> /.luksopen_args
-        ${optionalString fallbackToPassword ''
+        ${if (keyFile != null) then ''
+        if wait_target "key file" ${keyFile}; then
+            ${csopen} --key-file=${keyFile} \
+              ${optionalString (keyFileSize != null) "--keyfile-size=${toString keyFileSize}"} \
+              ${optionalString (keyFileOffset != null) "--keyfile-offset=${toString keyFileOffset}"}
         else
-            echo "keyfile ${keyFile} not found -- fallback to interactive unlocking"
+            ${if fallbackToPassword then "echo" else "die"} "${keyFile} is unavailable"
+            echo " - failing back to interactive password prompt"
+            do_open_passphrase
         fi
+        '' else ''
+        do_open_passphrase
         ''}
-        ''}
-        cryptsetup-askpass
-        rm /.luksopen_args
     }
 
-    ${optionalString (luks.yubikeySupport && (yubikey != null)) ''
-
+    ${if luks.yubikeySupport && (yubikey != null) then ''
+    # Yubikey
     rbtohex() {
         ( od -An -vtx1 | tr -d ' \n' )
     }
@@ -68,8 +178,7 @@ let
         ( tr '[:lower:]' '[:upper:]' | sed -e 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf )
     }
 
-    open_yubikey() {
-
+    do_open_yubikey() {
         # Make all of these local to this function
         # to prevent their values being leaked
         local salt
@@ -85,19 +194,18 @@ let
         local new_response
         local new_k_luks
 
-        mkdir -p ${yubikey.storage.mountPoint}
-        mount -t ${yubikey.storage.fsType} ${toString yubikey.storage.device} ${yubikey.storage.mountPoint}
+        mount -t ${yubikey.storage.fsType} ${yubikey.storage.device} /crypt-storage || \
+          die "Failed to mount Yubikey salt storage device"
 
-        salt="$(cat ${yubikey.storage.mountPoint}${yubikey.storage.path} | sed -n 1p | tr -d '\n')"
-        iterations="$(cat ${yubikey.storage.mountPoint}${yubikey.storage.path} | sed -n 2p | tr -d '\n')"
+        salt="$(cat /crypt-storage${yubikey.storage.path} | sed -n 1p | tr -d '\n')"
+        iterations="$(cat /crypt-storage${yubikey.storage.path} | sed -n 2p | tr -d '\n')"
         challenge="$(echo -n $salt | openssl-wrap dgst -binary -sha512 | rbtohex)"
         response="$(ykchalresp -${toString yubikey.slot} -x $challenge 2>/dev/null)"
 
         for try in $(seq 3); do
-
             ${optionalString yubikey.twoFactor ''
             echo -n "Enter two-factor passphrase: "
-            read -s k_user
+            read -r k_user
             echo
             ''}
 
@@ -107,9 +215,9 @@ let
                 k_luks="$(echo | pbkdf2-sha512 ${toString yubikey.keyLength} $iterations $response | rbtohex)"
             fi
 
-            echo -n "$k_luks" | hextorb | cryptsetup luksOpen ${device} ${name} ${optionalString allowDiscards "--allow-discards"} --key-file=-
+            echo -n "$k_luks" | hextorb | ${csopen} --key-file=-
 
-            if [ $? == "0" ]; then
+            if [ $? == 0 ]; then
                 opened=true
                 break
             else
@@ -118,11 +226,7 @@ let
             fi
         done
 
-        if [ "$opened" == false ]; then
-            umount ${yubikey.storage.mountPoint}
-            echo "Maximum authentication errors reached"
-            exit 1
-        fi
+        [ "$opened" == false ] && die "Maximum authentication errors reached"
 
         echo -n "Gathering entropy for new salt (please enter random keys to generate entropy if this blocks for long)..."
         for i in $(seq ${toString yubikey.saltLength}); do
@@ -147,67 +251,50 @@ let
             new_k_luks="$(echo | pbkdf2-sha512 ${toString yubikey.keyLength} $new_iterations $new_response | rbtohex)"
         fi
 
-        mkdir -p ${yubikey.ramfsMountPoint}
-        # A ramfs is used here to ensure that the file used to update
-        # the key slot with cryptsetup will never get swapped out.
-        # Warning: Do NOT replace with tmpfs!
-        mount -t ramfs none ${yubikey.ramfsMountPoint}
+        echo -n "$new_k_luks" | hextorb > /crypt-ramfs/new_key
+        echo -n "$k_luks" | hextorb | ${cschange} --key-file=- /crypt-ramfs/new_key
 
-        echo -n "$new_k_luks" | hextorb > ${yubikey.ramfsMountPoint}/new_key
-        echo -n "$k_luks" | hextorb | cryptsetup luksChangeKey ${device} --key-file=- ${yubikey.ramfsMountPoint}/new_key
-
-        if [ $? == "0" ]; then
-            echo -ne "$new_salt\n$new_iterations" > ${yubikey.storage.mountPoint}${yubikey.storage.path}
+        if [ $? == 0 ]; then
+            echo -ne "$new_salt\n$new_iterations" > /crypt-storage${yubikey.storage.path}
         else
             echo "Warning: Could not update LUKS key, current challenge persists!"
         fi
 
-        rm -f ${yubikey.ramfsMountPoint}/new_key
-        umount ${yubikey.ramfsMountPoint}
-        rm -rf ${yubikey.ramfsMountPoint}
+        rm -f /crypt-ramfs/new_key
+        umount /crypt-storage
+    }
 
-        umount ${yubikey.storage.mountPoint}
+    open_yubikey() {
+        if wait_yubikey ${toString yubikey.gracePeriod}; then
+            do_open_yubikey
+        else
+            echo "No yubikey found, falling back to non-yubikey open procedure"
+            open_normally
+        fi
     }
 
-    ${optionalString (yubikey.gracePeriod > 0) ''
-    echo -n "Waiting ${toString yubikey.gracePeriod} seconds as grace..."
-    for i in $(seq ${toString yubikey.gracePeriod}); do
-        sleep 1
-        echo -n .
-    done
-    echo "ok"
+    open_yubikey
+    '' else ''
+    open_normally
     ''}
+  '';
 
-    yubikey_missing=true
-    ykinfo -v 1>/dev/null 2>&1
-    if [ $? != "0" ]; then
-        echo -n "waiting 10 seconds for yubikey to appear..."
-        for try in $(seq 10); do
-            sleep 1
-            ykinfo -v 1>/dev/null 2>&1
-            if [ $? == "0" ]; then
-                yubikey_missing=false
-                break
-            fi
-            echo -n .
-        done
-        echo "ok"
-    else
-        yubikey_missing=false
-    fi
-
-    if [ "$yubikey_missing" == true ]; then
-        echo "no yubikey found, falling back to non-yubikey open procedure"
-        open_normally
-    else
-        open_yubikey
-    fi
-    ''}
+  askPass = pkgs.writeScriptBin "cryptsetup-askpass" ''
+    #!/bin/sh
 
-    # open luksRoot and scan for logical volumes
-    ${optionalString ((!luks.yubikeySupport) || (yubikey == null)) ''
-    open_normally
-    ''}
+    ${commonFunctions}
+
+    while true; do
+        wait_target "luks" /crypt-ramfs/device 10 "LUKS to request a passphrase" || die "Passphrase is not requested now"
+        device=$(cat /crypt-ramfs/device)
+
+        echo -n "Passphrase for $device: "
+        IFS= read -rs passphrase
+        echo
+
+        rm /crypt-ramfs/device
+        echo -n "$passphrase" > /crypt-ramfs/passphrase
+    done
   '';
 
   preLVM = filterAttrs (n: v: v.preLVM) luks.devices;
@@ -255,6 +342,22 @@ in
       '';
     };
 
+    boot.initrd.luks.reusePassphrases = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        When opening a new LUKS device try reusing last successful
+        passphrase.
+
+        Useful for mounting a number of devices that use the same
+        passphrase without retyping it several times.
+
+        Such setup can be useful if you use <command>cryptsetup
+        luksSuspend</command>. Different LUKS devices will still have
+        different master keys even when using the same passphrase.
+      '';
+    };
+
     boot.initrd.luks.devices = mkOption {
       default = { };
       example = { "luksroot".device = "/dev/disk/by-uuid/430e9eff-d852-4f68-aa3b-2fa3599ebe08"; };
@@ -316,6 +419,19 @@ in
             '';
           };
 
+          keyFileOffset = mkOption {
+            default = null;
+            example = 4096;
+            type = types.nullOr types.int;
+            description = ''
+              The offset of the key file. Use this in combination with
+              <literal>keyFileSize</literal> to use part of a file as key file
+              (often the case if a raw device or partition is used as a key file).
+              If not specified, the key begins at the first byte of
+              <literal>keyFile</literal>.
+            '';
+          };
+
           # FIXME: get rid of this option.
           preLVM = mkOption {
             default = true;
@@ -383,15 +499,9 @@ in
                 };
 
                 gracePeriod = mkOption {
-                  default = 2;
+                  default = 10;
                   type = types.int;
-                  description = "Time in seconds to wait before attempting to find the Yubikey.";
-                };
-
-                ramfsMountPoint = mkOption {
-                  default = "/crypt-ramfs";
-                  type = types.str;
-                  description = "Path where the ramfs used to update the LUKS key will be mounted during early boot.";
+                  description = "Time in seconds to wait for the Yubikey.";
                 };
 
                 /* TODO: Add to the documentation of the current module:
@@ -414,12 +524,6 @@ in
                     description = "The filesystem of the unencrypted device.";
                   };
 
-                  mountPoint = mkOption {
-                    default = "/crypt-storage";
-                    type = types.str;
-                    description = "Path where the unencrypted device will be mounted during early boot.";
-                  };
-
                   path = mkOption {
                     default = "/crypt-storage/default";
                     type = types.str;
@@ -432,8 +536,8 @@ in
               };
             });
           };
-
-        }; }));
+        };
+      }));
     };
 
     boot.initrd.luks.yubikeySupport = mkOption {
@@ -463,18 +567,8 @@ in
     # copy the cryptsetup binary and it's dependencies
     boot.initrd.extraUtilsCommands = ''
       copy_bin_and_libs ${pkgs.cryptsetup}/bin/cryptsetup
-
-      cat > $out/bin/cryptsetup-askpass <<EOF
-      #!$out/bin/sh -e
-      if [ -e /.luksopen_args ]; then
-        cryptsetup \$(cat /.luksopen_args)
-        killall -q cryptsetup
-      else
-        echo "Passphrase is not requested now"
-        exit 1
-      fi
-      EOF
-      chmod +x $out/bin/cryptsetup-askpass
+      copy_bin_and_libs ${askPass}/bin/cryptsetup-askpass
+      sed -i s,/bin/sh,$out/bin/sh, $out/bin/cryptsetup-askpass
 
       ${optionalString luks.yubikeySupport ''
         copy_bin_and_libs ${pkgs.yubikey-personalization}/bin/ykchalresp
@@ -506,8 +600,9 @@ in
       ''}
     '';
 
-    boot.initrd.preLVMCommands = concatStrings (mapAttrsToList openCommand preLVM);
-    boot.initrd.postDeviceCommands = concatStrings (mapAttrsToList openCommand postLVM);
+    boot.initrd.preFailCommands = postCommands;
+    boot.initrd.preLVMCommands = commonFunctions + preCommands + concatStrings (mapAttrsToList openCommand preLVM) + postCommands;
+    boot.initrd.postDeviceCommands = commonFunctions + preCommands + concatStrings (mapAttrsToList openCommand postLVM) + postCommands;
 
     environment.systemPackages = [ pkgs.cryptsetup ];
   };
diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix
index 35062d891b8b..f58b68cb3353 100644
--- a/nixos/modules/system/boot/stage-1.nix
+++ b/nixos/modules/system/boot/stage-1.nix
@@ -248,6 +248,14 @@ let
 
     isExecutable = true;
 
+    postInstall = ''
+      echo checking syntax
+      # check both with bash
+      ${pkgs.bash}/bin/sh -n $target
+      # and with ash shell, just in case
+      ${extraUtils}/bin/ash -n $target
+    '';
+
     inherit udevRules extraUtils modulesClosure;
 
     inherit (config.boot) resumeDevice;
diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix
index 737d1c10db87..12e029ae57f8 100644
--- a/nixos/modules/system/boot/systemd.nix
+++ b/nixos/modules/system/boot/systemd.nix
@@ -190,9 +190,8 @@ let
     ];
 
   makeJobScript = name: text:
-    let mkScriptName =  s: (replaceChars [ "\\" ] [ "-" ] (shellEscape s) );
-        x = pkgs.writeTextFile { name = "unit-script"; executable = true; destination = "/bin/${mkScriptName name}"; inherit text; };
-    in "${x}/bin/${mkScriptName name}";
+    let mkScriptName =  s: "unit-script-" + (replaceChars [ "\\" "@" ] [ "-" "_" ] (shellEscape s) );
+    in  pkgs.writeTextFile { name = mkScriptName name; executable = true; inherit text; };
 
   unitConfig = { config, ... }: {
     config = {
diff --git a/nixos/modules/tasks/trackpoint.nix b/nixos/modules/tasks/trackpoint.nix
index 3575a291b2b4..b154cf9f5f08 100644
--- a/nixos/modules/tasks/trackpoint.nix
+++ b/nixos/modules/tasks/trackpoint.nix
@@ -55,6 +55,15 @@ with lib;
         '';
       };
 
+      device = mkOption {
+        default = "TPPS/2 IBM TrackPoint";
+        type = types.str;
+        description = ''
+          The device name of the trackpoint. You can check with xinput.
+          Some newer devices (example x1c6) use "TPPS/2 Elan TrackPoint".
+        '';
+      };
+
     };
 
   };
@@ -68,12 +77,12 @@ with lib;
     (mkIf cfg.enable {
       services.udev.extraRules =
       ''
-        ACTION=="add|change", SUBSYSTEM=="input", ATTR{name}=="TPPS/2 IBM TrackPoint", ATTR{device/speed}="${toString cfg.speed}", ATTR{device/sensitivity}="${toString cfg.sensitivity}"
+        ACTION=="add|change", SUBSYSTEM=="input", ATTR{name}=="${cfg.device}", ATTR{device/speed}="${toString cfg.speed}", ATTR{device/sensitivity}="${toString cfg.sensitivity}"
       '';
 
       system.activationScripts.trackpoint =
         ''
-          ${config.systemd.package}/bin/udevadm trigger --attr-match=name="TPPS/2 IBM TrackPoint"
+          ${config.systemd.package}/bin/udevadm trigger --attr-match=name="${cfg.device}"
         '';
     })
 
@@ -81,7 +90,7 @@ with lib;
       services.xserver.inputClassSections =
         [''
         Identifier "Trackpoint Wheel Emulation"
-          MatchProduct "${if cfg.fakeButtons then "PS/2 Generic Mouse" else "ETPS/2 Elantech TrackPoint|Elantech PS/2 TrackPoint|TPPS/2 IBM TrackPoint|DualPoint Stick|Synaptics Inc. Composite TouchPad / TrackPoint|ThinkPad USB Keyboard with TrackPoint|USB Trackpoint pointing device|Composite TouchPad / TrackPoint"}"
+          MatchProduct "${if cfg.fakeButtons then "PS/2 Generic Mouse" else "ETPS/2 Elantech TrackPoint|Elantech PS/2 TrackPoint|TPPS/2 IBM TrackPoint|DualPoint Stick|Synaptics Inc. Composite TouchPad / TrackPoint|ThinkPad USB Keyboard with TrackPoint|USB Trackpoint pointing device|Composite TouchPad / TrackPoint|${cfg.device}"}"
           MatchDevicePath "/dev/input/event*"
           Option "EmulateWheel" "true"
           Option "EmulateWheelButton" "2"
diff --git a/nixos/release.nix b/nixos/release.nix
index 007859259b17..649517130e0e 100644
--- a/nixos/release.nix
+++ b/nixos/release.nix
@@ -277,6 +277,7 @@ in rec {
   tests.docker-tools = callTestOnMatchingSystems ["x86_64-linux"] tests/docker-tools.nix {};
   tests.docker-tools-overlay = callTestOnMatchingSystems ["x86_64-linux"] tests/docker-tools-overlay.nix {};
   tests.docker-edge = callTestOnMatchingSystems ["x86_64-linux"] tests/docker-edge.nix {};
+  tests.docker-registry = callTest tests/docker-registry.nix {};
   tests.dovecot = callTest tests/dovecot.nix {};
   tests.dnscrypt-proxy = callTestOnMatchingSystems ["x86_64-linux"] tests/dnscrypt-proxy.nix {};
   tests.ecryptfs = callTest tests/ecryptfs.nix {};
diff --git a/nixos/tests/acme.nix b/nixos/tests/acme.nix
index 6d728b387e14..c7fd4910e072 100644
--- a/nixos/tests/acme.nix
+++ b/nixos/tests/acme.nix
@@ -12,7 +12,9 @@ let
         '';
       });
 
-      pythonPackages = (super.python.override {
+      # Override certifi so that it accepts fake certificate for Let's Encrypt
+      # Need to override the attribute used by simp_le, which is python3Packages
+      python3Packages = (super.python3.override {
         packageOverrides = lib.const (pysuper: {
           certifi = pysuper.certifi.overridePythonAttrs (attrs: {
             postPatch = (attrs.postPatch or "") + ''
diff --git a/nixos/tests/cassandra.nix b/nixos/tests/cassandra.nix
index ca8f35ef3bff..60d0c6d76068 100644
--- a/nixos/tests/cassandra.nix
+++ b/nixos/tests/cassandra.nix
@@ -1,68 +1,71 @@
 import ./make-test.nix ({ pkgs, ...}:
 let
-  user = "cassandra";
-  nodeCfg = nodes: selfIP: cassandraOpts:
-    {
-      services.cassandra = {
-        enable = true;
-        listenAddress = selfIP;
-        rpcAddress = "0.0.0.0";
-        seeds = [ "192.168.1.1" ];
-        package = pkgs.cassandra_2_0;
-        jre = pkgs.openjdk;
-        clusterName = "ci ahoy";
-        authenticator = "PasswordAuthenticator";
-        authorizer = "CassandraAuthorizer";
-        user = user;
-      } // cassandraOpts;
-      nixpkgs.config.allowUnfree = true;
+  # Change this to test a different version of Cassandra:
+  testPackage = pkgs.cassandra;
+  cassandraCfg = 
+    { enable = true;
+      listenAddress = null;
+      listenInterface = "eth1";
+      rpcAddress = null;
+      rpcInterface = "eth1";
+      extraConfig =
+        { start_native_transport = true;
+          seed_provider =
+            [{ class_name = "org.apache.cassandra.locator.SimpleSeedProvider";
+               parameters = [ { seeds = "cass0"; } ];
+            }];
+        };
+      package = testPackage;
+    };
+  nodeCfg = extra: {pkgs, config, ...}:
+    { environment.systemPackages = [ testPackage ];
+      networking.firewall.enable = false;
+      services.cassandra = cassandraCfg // extra;
       virtualisation.memorySize = 1024;
     };
-
 in
 {
   name = "cassandra-ci";
 
   nodes = {
-    cass0 = { nodes, ... }: nodeCfg nodes "192.168.1.1" {};
-    cass1 = { nodes, ... }: nodeCfg nodes "192.168.1.2" {};
-    cass2 = { nodes, ... }: nodeCfg nodes "192.168.1.3" {
-      extraParams = [
-        ''JVM_OPTS="$JVM_OPTS -Dcassandra.replace_address=192.168.1.2"''
-      ];
-      listenAddress = "192.168.1.3";
-    };
+    cass0 = nodeCfg {};
+    cass1 = nodeCfg {};
+    cass2 = nodeCfg { jvmOpts = [ "-Dcassandra.replace_address=cass1" ]; };
   };
 
   testScript = ''
-    subtest "start seed", sub {
+    subtest "timers exist", sub {
+      $cass0->succeed("systemctl list-timers | grep cassandra-full-repair.timer");
+      $cass0->succeed("systemctl list-timers | grep cassandra-incremental-repair.timer");
+    };
+    subtest "can connect via cqlsh", sub {
       $cass0->waitForUnit("cassandra.service");
-      $cass0->waitForOpenPort(9160);
-      $cass0->execute("echo show version | cqlsh localhost -u cassandra -p cassandra");
-      sleep 2;
-      $cass0->succeed("echo show version | cqlsh localhost -u cassandra -p cassandra");
-      $cass1->start;
+      $cass0->waitUntilSucceeds("nc -z cass0 9042");
+      $cass0->succeed("echo 'show version;' | cqlsh cass0");
     };
-    subtest "cassandra user/group", sub {
-      $cass0->succeed("id \"${user}\" >/dev/null");
-      $cass1->succeed("id \"${user}\" >/dev/null");
+    subtest "nodetool is operational", sub {
+      $cass0->waitForUnit("cassandra.service");
+      $cass0->waitUntilSucceeds("nc -z localhost 7199");
+      $cass0->succeed("nodetool status --resolve-ip | egrep '^UN[[:space:]]+cass0'");
     };
-    subtest "bring up cassandra cluster", sub {
+    subtest "bring up cluster", sub {
       $cass1->waitForUnit("cassandra.service");
-      $cass0->waitUntilSucceeds("nodetool status | grep -c UN  | grep 2");
+      $cass1->waitUntilSucceeds("nodetool status | egrep -c '^UN' | grep 2");
+      $cass0->succeed("nodetool status --resolve-ip | egrep '^UN[[:space:]]+cass1'");
     };
     subtest "break and fix node", sub {
-      $cass0->block;
-      $cass0->waitUntilSucceeds("nodetool status | grep -c DN  | grep 1");
-      $cass0->unblock;
-      $cass0->waitUntilSucceeds("nodetool status | grep -c UN  | grep 2");
+      $cass1->block;
+      $cass0->waitUntilSucceeds("nodetool status --resolve-ip | egrep -c '^DN[[:space:]]+cass1'");
+      $cass0->succeed("nodetool status | egrep -c '^UN'  | grep 1");
+      $cass1->unblock;
+      $cass1->waitUntilSucceeds("nodetool status | egrep -c '^UN'  | grep 2");
+      $cass0->succeed("nodetool status | egrep -c '^UN'  | grep 2");
     };
     subtest "replace crashed node", sub {
       $cass1->crash;
-      $cass2->start;
       $cass2->waitForUnit("cassandra.service");
-      $cass0->waitUntilFails("nodetool status | grep UN  | grep 192.168.1.2");
-      $cass0->waitUntilSucceeds("nodetool status | grep UN | grep 192.168.1.3");
+      $cass0->waitUntilFails("nodetool status --resolve-ip | egrep '^UN[[:space:]]+cass1'");
+      $cass0->waitUntilSucceeds("nodetool status --resolve-ip | egrep '^UN[[:space:]]+cass2'");
     };
   '';
 })
diff --git a/nixos/tests/netdata.nix b/nixos/tests/netdata.nix
index c56506ba2874..eb45db6f04c3 100644
--- a/nixos/tests/netdata.nix
+++ b/nixos/tests/netdata.nix
@@ -19,8 +19,12 @@ import ./make-test.nix ({ pkgs, ...} : {
     startAll;
 
     $netdata->waitForUnit("netdata.service");
-    # check if netdata can read disk ops for root owned processes. 
-    # if > 0, successful. verifies both netdata working and 
+
+    # check if the netdata main page loads.
+    $netdata->succeed("curl --fail http://localhost:19999/");
+
+    # check if netdata can read disk ops for root owned processes.
+    # if > 0, successful. verifies both netdata working and
     # apps.plugin has elevated capabilities.
     my $cmd = <<'CMD';
     curl -s http://localhost:19999/api/v1/data\?chart=users.pwrites | \