summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2014-09-18 22:28:35 +0200
committerEelco Dolstra <eelco.dolstra@logicblox.com>2014-09-18 22:28:35 +0200
commit91ec6e0d90073b9ca3d8931261142bda12a29093 (patch)
tree3c083a5d153c7fa928505da807b61d7719f91390 /nixos
parentf32e964cc44de8b4259873be383f6ba60af4ec1e (diff)
parentaa67e95bb5845323ed1b4b9c516b6efb762fc243 (diff)
downloadnixlib-91ec6e0d90073b9ca3d8931261142bda12a29093.tar
nixlib-91ec6e0d90073b9ca3d8931261142bda12a29093.tar.gz
nixlib-91ec6e0d90073b9ca3d8931261142bda12a29093.tar.bz2
nixlib-91ec6e0d90073b9ca3d8931261142bda12a29093.tar.lz
nixlib-91ec6e0d90073b9ca3d8931261142bda12a29093.tar.xz
nixlib-91ec6e0d90073b9ca3d8931261142bda12a29093.tar.zst
nixlib-91ec6e0d90073b9ca3d8931261142bda12a29093.zip
Merge remote-tracking branch 'origin/master' into staging
Diffstat (limited to 'nixos')
-rw-r--r--nixos/modules/config/pulseaudio.nix5
-rw-r--r--nixos/modules/misc/ids.nix1
-rwxr-xr-xnixos/modules/module-list.nix4
-rw-r--r--nixos/modules/services/amqp/rabbitmq.nix4
-rw-r--r--nixos/modules/services/databases/influxdb.nix5
-rw-r--r--nixos/modules/services/databases/mongodb.nix54
-rw-r--r--nixos/modules/services/hardware/pommed.nix38
-rw-r--r--nixos/modules/services/logging/syslog-ng.nix11
-rw-r--r--nixos/modules/services/monitoring/collectd.nix116
-rw-r--r--nixos/modules/services/monitoring/graphite.nix211
-rw-r--r--nixos/modules/services/networking/firewall.nix366
-rw-r--r--nixos/modules/services/networking/nat.nix114
-rw-r--r--nixos/modules/services/networking/znc.nix1
-rw-r--r--nixos/modules/services/search/elasticsearch.nix5
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/default.nix20
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/per-server-options.nix14
-rw-r--r--nixos/modules/services/x11/desktop-managers/default.nix2
-rw-r--r--nixos/modules/services/x11/desktop-managers/e19.nix94
-rw-r--r--nixos/modules/services/x11/desktop-managers/gnome3.nix2
-rw-r--r--nixos/modules/services/x11/display-managers/default.nix7
-rw-r--r--nixos/modules/system/boot/systemd-unit-options.nix9
-rw-r--r--nixos/modules/system/boot/systemd.nix6
-rw-r--r--nixos/modules/tasks/filesystems/nfs.nix12
-rw-r--r--nixos/modules/virtualisation/libvirtd.nix4
-rw-r--r--nixos/release.nix55
25 files changed, 832 insertions, 328 deletions
diff --git a/nixos/modules/config/pulseaudio.nix b/nixos/modules/config/pulseaudio.nix
index fb5715022b78..297b3a82d6c1 100644
--- a/nixos/modules/config/pulseaudio.nix
+++ b/nixos/modules/config/pulseaudio.nix
@@ -71,8 +71,7 @@ in {
       };
 
       configFile = mkOption {
-        type = types.uniq types.path;
-        default = "${cfg.package}/etc/pulse/default.pa";
+        type = types.path;
         description = ''
           The path to the configuration the PulseAudio server
           should use. By default, the "default.pa" configuration
@@ -112,6 +111,8 @@ in {
         target = "pulse/client.conf";
         source = clientConf;
       };
+
+      hardware.pulseaudio.configFile = mkDefault "${cfg.package}/etc/pulse/default.pa";
     }
 
     (mkIf cfg.enable {
diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix
index 37531ad1cdfd..cdce7d1a893e 100644
--- a/nixos/modules/misc/ids.nix
+++ b/nixos/modules/misc/ids.nix
@@ -151,6 +151,7 @@
       dnsmasq = 141;
       uhub = 142;
       yandexdisk=143;
+      collectd=144;
 
       # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399!
 
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index e40d08c8ecfe..25827656608d 100755
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -85,7 +85,8 @@
   ./services/amqp/activemq/default.nix
   ./services/amqp/rabbitmq.nix
   ./services/audio/alsa.nix
-  ./services/audio/fuppes.nix
+  # Disabled as fuppes it does no longer builds.
+  # ./services/audio/fuppes.nix
   ./services/audio/mpd.nix
   ./services/audio/mopidy.nix
   ./services/backup/almir.nix
@@ -178,6 +179,7 @@
   ./services/misc/uhub.nix
   ./services/misc/zookeeper.nix
   ./services/monitoring/apcupsd.nix
+  ./services/monitoring/collectd.nix
   ./services/monitoring/dd-agent.nix
   ./services/monitoring/graphite.nix
   ./services/monitoring/monit.nix
diff --git a/nixos/modules/services/amqp/rabbitmq.nix b/nixos/modules/services/amqp/rabbitmq.nix
index a930098bfeec..77487ec1ab91 100644
--- a/nixos/modules/services/amqp/rabbitmq.nix
+++ b/nixos/modules/services/amqp/rabbitmq.nix
@@ -89,6 +89,8 @@ in {
       wantedBy = [ "multi-user.target" ];
       after = [ "network-interfaces.target" ];
 
+      path = [ pkgs.rabbitmq_server ];
+
       environment = {
         RABBITMQ_MNESIA_BASE = "${cfg.dataDir}/mnesia";
         RABBITMQ_NODE_IP_ADDRESS = cfg.listenAddress;
@@ -119,6 +121,8 @@ in {
         mkdir -p /var/log/rabbitmq && chmod 0700 /var/log/rabbitmq
         chown rabbitmq:rabbitmq /var/log/rabbitmq
       '';
+
+      postStart = mkBefore "until rabbitmqctl status; do sleep 1; done";
     };
 
   };
diff --git a/nixos/modules/services/databases/influxdb.nix b/nixos/modules/services/databases/influxdb.nix
index 61fe96d5d641..b57ccebae16e 100644
--- a/nixos/modules/services/databases/influxdb.nix
+++ b/nixos/modules/services/databases/influxdb.nix
@@ -224,6 +224,11 @@ in
         mkdir -m 0770 -p ${cfg.dataDir}
         if [ "$(id -u)" = 0 ]; then chown -R ${cfg.user}:${cfg.group} ${cfg.dataDir}; fi
       '';
+      postStart = mkBefore ''
+        until ${pkgs.curl}/bin/curl -s -o /dev/null 'http://${cfg.bindAddress}:${toString cfg.apiPort}/'; do
+          sleep 1;
+        done
+      '';
     };
 
     users.extraUsers = optional (cfg.user == "influxdb") {
diff --git a/nixos/modules/services/databases/mongodb.nix b/nixos/modules/services/databases/mongodb.nix
index fe82ca430e13..02e44ad88704 100644
--- a/nixos/modules/services/databases/mongodb.nix
+++ b/nixos/modules/services/databases/mongodb.nix
@@ -15,9 +15,11 @@ let
     bind_ip = ${cfg.bind_ip}
     ${optionalString cfg.quiet "quiet = true"}
     dbpath = ${cfg.dbpath}
-    logpath = ${cfg.logpath}
-    logappend = ${b2s cfg.logappend}
+    syslog = true
+    fork = true
+    pidfilepath = ${cfg.pidFile}
     ${optionalString (cfg.replSetName != "") "replSet = ${cfg.replSetName}"}
+    ${cfg.extraConfig}
   '';
 
 in
@@ -65,14 +67,9 @@ in
         description = "Location where MongoDB stores its files";
       };
 
-      logpath = mkOption {
-        default = "/var/log/mongodb/mongod.log";
-        description = "Location where MongoDB stores its logfile";
-      };
-
-      logappend = mkOption {
-        default = true;
-        description = "Append logfile instead over overwriting";
+      pidFile = mkOption {
+        default = "/var/run/mongodb.pid";
+        description = "Location of MongoDB pid file";
       };
 
       replSetName = mkOption {
@@ -82,6 +79,14 @@ in
           Otherwise, leave empty to run as single node.
         '';
       };
+
+      extraConfig = mkOption {
+        default = "";
+        example = ''
+          nojournal = true
+        '';
+        description = "MongoDB extra configuration";
+      };
     };
 
   };
@@ -99,22 +104,6 @@ in
 
     environment.systemPackages = [ mongodb ];
 
-    systemd.services.mongodb_init =
-      { description = "MongoDB server initialisation";
-
-        wantedBy = [ "mongodb.service" ];
-        before = [ "mongodb.service" ];
-
-        serviceConfig.Type = "oneshot";
-
-        script = ''
-          if ! test -e ${cfg.dbpath}; then
-              install -d -m0700 -o ${cfg.user} ${cfg.dbpath}
-              install -d -m0755 -o ${cfg.user} `dirname ${cfg.logpath}`
-          fi
-        '';
-      };
-
     systemd.services.mongodb =
       { description = "MongoDB server";
 
@@ -124,7 +113,20 @@ in
         serviceConfig = {
           ExecStart = "${mongodb}/bin/mongod --quiet --config ${mongoCnf}";
           User = cfg.user;
+          PIDFile = cfg.pidFile;
+          Type = "forking";
+          TimeoutStartSec=120; # intial creating of journal can take some time
+          PermissionsStartOnly = true;
         };
+
+        preStart = ''
+          if ! test -e ${cfg.dbpath}; then
+              install -d -m0700 -o ${cfg.user} ${cfg.dbpath}
+          fi
+          if ! test -e ${cfg.pidFile}; then
+              install -D -o ${cfg.user} /dev/null ${cfg.pidFile}
+          fi
+        '';
       };
 
   };
diff --git a/nixos/modules/services/hardware/pommed.nix b/nixos/modules/services/hardware/pommed.nix
index 04db46999b0a..a24557b40ba1 100644
--- a/nixos/modules/services/hardware/pommed.nix
+++ b/nixos/modules/services/hardware/pommed.nix
@@ -4,30 +4,34 @@ with lib;
 
 {
 
-  options.services.hardware.pommed = {
-    enable = mkOption {
-      default = false;
-       description = ''
-        Whether to use the pommed tool to handle Apple laptop keyboard hotkeys.
-      '';
+  options = {
+
+    services.hardware.pommed = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to use the pommed tool to handle Apple laptop keyboard hotkeys.
+        '';
+      };
+
+      configFile = mkOption {
+        type = types.path;
+        description = ''
+          The path to the <filename>pommed.conf</filename> file.
+        '';
+      };
     };
 
-    configFile = mkOption {
-      default = "${pkgs.pommed}/etc/pommed.conf";
-      description = ''
-        The contents of the pommed.conf file.
-      '';
-    };
   };
 
   config = mkIf config.services.hardware.pommed.enable {
     environment.systemPackages = [ pkgs.polkit ];
 
-    environment.etc = [
-      { source = config.services.hardware.pommed.configFile;
-        target = "pommed.conf";
-      }
-    ];
+    environment.etc."pommed.conf".source = config.services.hardware.pommed.configFile;
+
+    services.hardware.pommed.configFile = "${pkgs.pommed}/etc/pommed.conf";
 
     services.dbus.packages = [ pkgs.pommed ];
 
diff --git a/nixos/modules/services/logging/syslog-ng.nix b/nixos/modules/services/logging/syslog-ng.nix
index 0b3f0cabb007..4a16b19134a0 100644
--- a/nixos/modules/services/logging/syslog-ng.nix
+++ b/nixos/modules/services/logging/syslog-ng.nix
@@ -18,7 +18,7 @@ let
 
   syslogngOptions = [
     "--foreground"
-    "--module-path=${concatStringsSep ":" (["${pkgs.syslogng}/lib/syslog-ng"] ++ cfg.extraModulePaths)}"
+    "--module-path=${concatStringsSep ":" (["${cfg.package}/lib/syslog-ng"] ++ cfg.extraModulePaths)}"
     "--cfgfile=${syslogngConfig}"
     "--control=${ctrlSocket}"
     "--persist-file=${persistFile}"
@@ -37,6 +37,13 @@ in {
           Whether to enable the syslog-ng daemon.
         '';
       };
+      package = mkOption {
+        type = types.package;
+        default = pkgs.syslogng;
+        description = ''
+          The package providing syslog-ng binaries.
+        '';
+      };
       serviceName = mkOption {
         type = types.str;
         default = "syslog-ng";
@@ -77,7 +84,7 @@ in {
         Sockets = "syslog.socket";
         StandardOutput = "null";
         Restart = "on-failure";
-        ExecStart = "${pkgs.syslogng}/sbin/syslog-ng ${concatStringsSep " " syslogngOptions}";
+        ExecStart = "${cfg.package}/sbin/syslog-ng ${concatStringsSep " " syslogngOptions}";
       };
     };
   };
diff --git a/nixos/modules/services/monitoring/collectd.nix b/nixos/modules/services/monitoring/collectd.nix
new file mode 100644
index 000000000000..717c2c481683
--- /dev/null
+++ b/nixos/modules/services/monitoring/collectd.nix
@@ -0,0 +1,116 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.collectd;
+
+  conf = pkgs.writeText "collectd.conf" ''
+    BaseDir "${cfg.dataDir}"
+    PIDFile "${cfg.pidFile}"
+    AutoLoadPlugin ${if cfg.autoLoadPlugin then "true" else "false"}
+    Hostname ${config.networking.hostName}
+
+    LoadPlugin syslog
+    <Plugin "syslog">
+      LogLevel "info"
+      NotifyLevel "OKAY"
+    </Plugin>
+
+    ${concatMapStrings (f: ''
+    Include "${f}"
+    '') cfg.include}
+
+    ${cfg.extraConfig}
+  '';
+
+in {
+  options.services.collectd = with types; {
+    enable = mkOption {
+      default = false;
+      description = ''
+        Whether to enable collectd agent.
+      '';
+      type = bool;
+    };
+
+    user = mkOption {
+      default = "collectd";
+      description = ''
+        User under which to run collectd.
+      '';
+      type = nullOr str;
+    };
+
+    dataDir = mkOption {
+      default = "/var/lib/collectd";
+      description = ''
+        Data directory for collectd agent.
+      '';
+      type = path;
+    };
+
+    pidFile = mkOption {
+      default = "/var/run/collectd.pid";
+      description = ''
+        Location of collectd pid file.
+      '';
+      type = path;
+    };
+
+    autoLoadPlugin = mkOption {
+      default = false;
+      description = ''
+        Enable plugin autoloading.
+      '';
+      type = bool;
+    };
+
+    include = mkOption {
+      default = [];
+      description = ''
+        Additional paths to load config from.
+      '';
+      type = listOf str;
+    };
+
+    extraConfig = mkOption {
+      default = "";
+      description = ''
+        Extra configuration for collectd.
+      '';
+      type = lines;
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.collectd = {
+      description = "Collectd Monitoring Agent";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+
+      serviceConfig = {
+        ExecStart = "${pkgs.collectd}/sbin/collectd -C ${conf} -P ${cfg.pidFile}";
+        Type = "forking";
+        PIDFile = cfg.pidFile;
+        User = optional (cfg.user!="root") cfg.user;
+        PermissionsStartOnly = true;
+      };
+
+      preStart = ''
+        mkdir -m 0700 -p ${cfg.dataDir}
+        install -D /dev/null ${cfg.pidFile}
+        if [ "$(id -u)" = 0 ]; then
+          chown -R ${cfg.user} ${cfg.dataDir};
+          chown ${cfg.user} ${cfg.pidFile}
+        fi
+      '';
+    }; 
+
+    users.extraUsers = optional (cfg.user == "collectd") {
+      name = "collectd";
+      uid = config.ids.uids.collectd;
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/graphite.nix b/nixos/modules/services/monitoring/graphite.nix
index dbfe0ee182a0..3d97c31b7a17 100644
--- a/nixos/modules/services/monitoring/graphite.nix
+++ b/nixos/modules/services/monitoring/graphite.nix
@@ -8,6 +8,22 @@ let
 
   dataDir = cfg.dataDir;
 
+  graphiteApiConfig = pkgs.writeText "graphite-api.yaml" ''
+    time_zone: ${config.time.timeZone}
+    search_index: ${dataDir}/index
+    ${optionalString (cfg.api.finders != []) ''finders:''}
+    ${concatMapStringsSep "\n" (f: "  - " + f.moduleName) cfg.api.finders}
+    ${optionalString (cfg.api.functions != []) ''functions:''}
+    ${concatMapStringsSep "\n" (f: "  - " + f) cfg.api.functions}
+    ${cfg.api.extraConfig}
+  '';
+
+  seyrenConfig = {
+    SEYREN_URL = cfg.seyren.seyrenUrl;
+    MONGO_URL = cfg.seyren.mongoUrl;
+    GRAPHITE_URL = cfg.seyren.graphiteUrl;
+  } // cfg.seyren.extraConfig;
+
   configDir = pkgs.buildEnv {
     name = "graphite-config";
     paths = lists.filter (el: el != null) [
@@ -65,6 +81,72 @@ in {
       };
     };
 
+    api = {
+      enable = mkOption {
+        description = "Whether to enable graphite api.";
+        default = false;
+        type = types.uniq types.bool;
+      };
+
+      finders = mkOption {
+        description = "List of finder plugins load.";
+        default = [];
+        example = [ pkgs.python27Packages.graphite_influxdb ];
+        type = types.listOf types.package;
+      };
+
+      functions = mkOption {
+        description = "List of functions to load.";
+        default = [
+          "graphite_api.functions.SeriesFunctions"
+          "graphite_api.functions.PieFunctions"
+        ];
+        type = types.listOf types.str;
+      };
+
+      host = mkOption {
+        description = "Graphite web service listen address.";
+        default = "127.0.0.1";
+        type = types.str;
+      };
+
+      port = mkOption {
+        description = "Graphite api service port.";
+        default = 8080;
+        type = types.int;
+      };
+
+      package = mkOption {
+        description = "Package to use for graphite api.";
+        default = pkgs.python27Packages.graphite_api;
+        type = types.package;
+      };
+
+      extraConfig = mkOption {
+        description = "Extra configuration for graphite api.";
+        default = ''
+          whisper:
+            directories:
+                - ${dataDir}/whisper
+        '';
+        example = literalExample ''
+          allowed_origins:
+            - dashboard.example.com
+          cheat_times: true
+          influxdb:
+            host: localhost
+            port: 8086
+            user: influxdb
+            pass: influxdb
+            db: metrics
+          cache:
+            CACHE_TYPE: 'filesystem'
+            CACHE_DIR: '/tmp/graphite-api-cache'
+        '';
+        type = types.str;
+      };
+    };
+
     carbon = {
       config = mkOption {
         description = "Content of carbon configuration file.";
@@ -172,11 +254,65 @@ in {
         '';
       };
     };
+
+    seyren = {
+      enable = mkOption {
+        description = "Whether to enable seyren service.";
+        default = false;
+        type = types.uniq types.bool;
+      };
+
+      port = mkOption {
+        description = "Seyren listening port.";
+        default = 8081;
+        type = types.int;
+      };
+
+      seyrenUrl = mkOption {
+        default = "http://localhost:${toString cfg.seyren.port}/";
+        description = "Host where seyren is accessible.";
+        type = types.str;
+      };
+
+      graphiteUrl = mkOption {
+        default = "http://${cfg.web.host}:${toString cfg.web.port}";
+        description = "Host where graphite service runs.";
+        type = types.str;
+      };
+
+      mongoUrl = mkOption {
+        default = "mongodb://${config.services.mongodb.bind_ip}:27017/seyren";
+        description = "Mongodb connection string.";
+        type = types.str;
+      };
+
+      extraConfig = mkOption {
+        default = {};
+        description = ''
+          Extra seyren configuration. See
+          <link xlink:href='https://github.com/scobal/seyren#config' />
+        '';
+        type = types.attrsOf types.str;
+        example = literalExample ''
+          {
+            GRAPHITE_USERNAME = "user";
+            GRAPHITE_PASSWORD = "pass"; 
+          }
+        '';
+      };
+    };
   };
 
   ###### implementation
 
-  config = mkIf (cfg.carbon.enableAggregator || cfg.carbon.enableCache || cfg.carbon.enableRelay || cfg.web.enable) {
+  config = mkIf (
+    cfg.carbon.enableAggregator ||
+    cfg.carbon.enableCache ||
+    cfg.carbon.enableRelay ||
+    cfg.web.enable ||
+    cfg.api.enable ||
+    cfg.seyren.enable
+  ) {
     systemd.services.carbonCache = {
       enable = cfg.carbon.enableCache;
       description = "Graphite Data Storage Backend";
@@ -189,10 +325,6 @@ in {
         Group = "graphite";
         PermissionsStartOnly = true;
       };
-      restartTriggers = [
-        pkgs.pythonPackages.carbon
-        configDir
-      ];
       preStart = ''
         mkdir -p ${cfg.dataDir}/whisper
         chmod 0700 ${cfg.dataDir}/whisper
@@ -211,10 +343,6 @@ in {
         User = "graphite";
         Group = "graphite";
       };
-      restartTriggers = [
-        pkgs.pythonPackages.carbon
-        configDir
-      ];
     };
 
     systemd.services.carbonRelay = {
@@ -228,10 +356,6 @@ in {
         User = "graphite";
         Group = "graphite";
       };
-      restartTriggers = [
-        pkgs.pythonPackages.carbon
-        configDir
-      ];
     };
 
     systemd.services.graphiteWeb = {
@@ -243,7 +367,7 @@ in {
       environment = {
         PYTHONPATH = "${pkgs.python27Packages.graphite_web}/lib/python2.7/site-packages";
         DJANGO_SETTINGS_MODULE = "graphite.settings";
-        GRAPHITE_CONF_DIR = "/etc/graphite/";
+        GRAPHITE_CONF_DIR = configDir;
         GRAPHITE_STORAGE_DIR = dataDir;
       };
       serviceConfig = {
@@ -271,11 +395,64 @@ in {
           chown -R graphite:graphite ${cfg.dataDir}
         fi
       '';
-      restartTriggers = [
-        pkgs.python27Packages.graphite_web
-      ];
     };
 
+    systemd.services.graphiteApi = {
+      enable = cfg.api.enable;
+      description = "Graphite Api Interface";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network-interfaces.target" ];
+      environment = {
+        PYTHONPATH =
+          "${cfg.api.package}/lib/python2.7/site-packages:" +
+          concatMapStringsSep ":" (f: f + "/lib/python2.7/site-packages") cfg.api.finders;
+        GRAPHITE_API_CONFIG = graphiteApiConfig;
+        LD_LIBRARY_PATH = "${pkgs.cairo}/lib";
+      };
+      serviceConfig = {
+        ExecStart = ''
+          ${pkgs.python27Packages.waitress}/bin/waitress-serve \
+          --host=${cfg.api.host} --port=${toString cfg.api.port} \
+          graphite_api.app:app 
+        '';
+        User = "graphite";
+        Group = "graphite";
+        PermissionsStartOnly = true;
+      };
+      preStart = ''
+        if ! test -e ${dataDir}/db-created; then
+          mkdir -p ${dataDir}/cache/
+          chmod 0700 ${dataDir}/cache/
+
+          touch ${dataDir}/db-created
+
+          chown -R graphite:graphite ${cfg.dataDir}
+        fi
+      '';
+    };
+
+    systemd.services.seyren = {
+      enable = cfg.seyren.enable;
+      description = "Graphite Alerting Dashboard";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network-interfaces.target" "mongodb.service" ];
+      environment = seyrenConfig;
+      serviceConfig = {
+        ExecStart = "${pkgs.seyren}/bin/seyren -httpPort ${toString cfg.seyren.port}";
+        WorkingDirectory = dataDir;
+        User = "graphite";
+        Group = "graphite"; 
+      };
+      preStart = ''
+        if ! test -e ${dataDir}/db-created; then
+          mkdir -p ${dataDir}
+          chown -R graphite:graphite ${dataDir}
+        fi
+      '';
+    };
+
+    services.mongodb.enable = mkDefault cfg.seyren.enable;
+
     environment.systemPackages = [
       pkgs.pythonPackages.carbon
       pkgs.python27Packages.graphite_web
diff --git a/nixos/modules/services/networking/firewall.nix b/nixos/modules/services/networking/firewall.nix
index 42914bfe5d62..68aac3d30de1 100644
--- a/nixos/modules/services/networking/firewall.nix
+++ b/nixos/modules/services/networking/firewall.nix
@@ -37,6 +37,180 @@ let
       }
     '';
 
+  writeShScript = name: text: let dir = pkgs.writeScriptBin name ''
+    #! ${pkgs.stdenv.shell} -e
+    ${text}
+  ''; in "${dir}/bin/${name}";
+
+  startScript = writeShScript "firewall-start" ''
+    ${helpers}
+
+    # Flush the old firewall rules.  !!! Ideally, updating the
+    # firewall would be atomic.  Apparently that's possible
+    # with iptables-restore.
+    ip46tables -D INPUT -j nixos-fw 2> /dev/null || true
+    for chain in nixos-fw nixos-fw-accept nixos-fw-log-refuse nixos-fw-refuse FW_REFUSE; do
+      ip46tables -F "$chain" 2> /dev/null || true
+      ip46tables -X "$chain" 2> /dev/null || true
+    done
+
+
+    # The "nixos-fw-accept" chain just accepts packets.
+    ip46tables -N nixos-fw-accept
+    ip46tables -A nixos-fw-accept -j ACCEPT
+
+
+    # The "nixos-fw-refuse" chain rejects or drops packets.
+    ip46tables -N nixos-fw-refuse
+
+    ${if cfg.rejectPackets then ''
+      # Send a reset for existing TCP connections that we've
+      # somehow forgotten about.  Send ICMP "port unreachable"
+      # for everything else.
+      ip46tables -A nixos-fw-refuse -p tcp ! --syn -j REJECT --reject-with tcp-reset
+      ip46tables -A nixos-fw-refuse -j REJECT
+    '' else ''
+      ip46tables -A nixos-fw-refuse -j DROP
+    ''}
+
+
+    # The "nixos-fw-log-refuse" chain performs logging, then
+    # jumps to the "nixos-fw-refuse" chain.
+    ip46tables -N nixos-fw-log-refuse
+
+    ${optionalString cfg.logRefusedConnections ''
+      ip46tables -A nixos-fw-log-refuse -p tcp --syn -j LOG --log-level info --log-prefix "rejected connection: "
+    ''}
+    ${optionalString (cfg.logRefusedPackets && !cfg.logRefusedUnicastsOnly) ''
+      ip46tables -A nixos-fw-log-refuse -m pkttype --pkt-type broadcast \
+        -j LOG --log-level info --log-prefix "rejected broadcast: "
+      ip46tables -A nixos-fw-log-refuse -m pkttype --pkt-type multicast \
+        -j LOG --log-level info --log-prefix "rejected multicast: "
+    ''}
+    ip46tables -A nixos-fw-log-refuse -m pkttype ! --pkt-type unicast -j nixos-fw-refuse
+    ${optionalString cfg.logRefusedPackets ''
+      ip46tables -A nixos-fw-log-refuse \
+        -j LOG --log-level info --log-prefix "rejected packet: "
+    ''}
+    ip46tables -A nixos-fw-log-refuse -j nixos-fw-refuse
+
+
+    # The "nixos-fw" chain does the actual work.
+    ip46tables -N nixos-fw
+
+    # Perform a reverse-path test to refuse spoofers
+    # For now, we just drop, as the raw table doesn't have a log-refuse yet
+    ${optionalString (kernelHasRPFilter && cfg.checkReversePath) ''
+      if ! ip46tables -A PREROUTING -t raw -m rpfilter --invert -j DROP; then
+        echo "<2>failed to initialise rpfilter support" >&2
+      fi
+    ''}
+
+    # Accept all traffic on the trusted interfaces.
+    ${flip concatMapStrings cfg.trustedInterfaces (iface: ''
+      ip46tables -A nixos-fw -i ${iface} -j nixos-fw-accept
+    '')}
+
+    # Accept packets from established or related connections.
+    ip46tables -A nixos-fw -m conntrack --ctstate ESTABLISHED,RELATED -j nixos-fw-accept
+
+    # Accept connections to the allowed TCP ports.
+    ${concatMapStrings (port:
+        ''
+          ip46tables -A nixos-fw -p tcp --dport ${toString port} -j nixos-fw-accept
+        ''
+      ) cfg.allowedTCPPorts
+    }
+
+    # Accept connections to the allowed TCP port ranges.
+    ${concatMapStrings (rangeAttr:
+        let range = toString rangeAttr.from + ":" + toString rangeAttr.to; in
+        ''
+          ip46tables -A nixos-fw -p tcp --dport ${range} -j nixos-fw-accept
+        ''
+      ) cfg.allowedTCPPortRanges
+    }
+
+    # Accept packets on the allowed UDP ports.
+    ${concatMapStrings (port:
+        ''
+          ip46tables -A nixos-fw -p udp --dport ${toString port} -j nixos-fw-accept
+        ''
+      ) cfg.allowedUDPPorts
+    }
+
+    # Accept packets on the allowed UDP port ranges.
+    ${concatMapStrings (rangeAttr:
+        let range = toString rangeAttr.from + ":" + toString rangeAttr.to; in
+        ''
+          ip46tables -A nixos-fw -p udp --dport ${range} -j nixos-fw-accept
+        ''
+      ) cfg.allowedUDPPortRanges
+    }
+
+    # Accept IPv4 multicast.  Not a big security risk since
+    # probably nobody is listening anyway.
+    #iptables -A nixos-fw -d 224.0.0.0/4 -j nixos-fw-accept
+
+    # Optionally respond to ICMPv4 pings.
+    ${optionalString cfg.allowPing ''
+      iptables -w -A nixos-fw -p icmp --icmp-type echo-request ${optionalString (cfg.pingLimit != null)
+        "-m limit ${cfg.pingLimit} "
+      }-j nixos-fw-accept
+    ''}
+
+    # Accept all ICMPv6 messages except redirects and node
+    # information queries (type 139).  See RFC 4890, section
+    # 4.4.
+    ${optionalString config.networking.enableIPv6 ''
+      ip6tables -A nixos-fw -p icmpv6 --icmpv6-type redirect -j DROP
+      ip6tables -A nixos-fw -p icmpv6 --icmpv6-type 139 -j DROP
+      ip6tables -A nixos-fw -p icmpv6 -j nixos-fw-accept
+    ''}
+
+    ${cfg.extraCommands}
+
+    # Reject/drop everything else.
+    ip46tables -A nixos-fw -j nixos-fw-log-refuse
+
+
+    # Enable the firewall.
+    ip46tables -A INPUT -j nixos-fw
+  '';
+
+  stopScript = writeShScript "firewall-stop" ''
+    ${helpers}
+
+    # Clean up in case reload fails
+    ip46tables -D INPUT -j nixos-drop 2>/dev/null || true
+
+    # Clean up after added ruleset
+    ip46tables -D INPUT -j nixos-fw 2>/dev/null || true
+
+    ${cfg.extraStopCommands}
+  '';
+
+  reloadScript = writeShScript "firewall-reload" ''
+    ${helpers}
+
+    # Create a unique drop rule
+    ip46tables -D INPUT -j nixos-drop 2>/dev/null || true
+    ip46tables -F nixos-drop 2>/dev/null || true
+    ip46tables -X nixos-drop 2>/dev/null || true
+    ip46tables -N nixos-drop
+    ip46tables -A nixos-drop -j DROP
+
+    # Don't allow traffic to leak out until the script has completed
+    ip46tables -A INPUT -j nixos-drop
+    if ${startScript}; then
+      ip46tables -D INPUT -j nixos-drop 2>/dev/null || true
+    else
+      echo "Failed to reload firewall... Stopping"
+      ${stopScript}
+      exit 1
+    fi
+  '';
+
   kernelPackages = config.boot.kernelPackages;
 
   kernelHasRPFilter = kernelPackages.kernel.features.netfilterRPFilter or false;
@@ -240,6 +414,18 @@ in
         '';
     };
 
+    networking.firewall.extraStopCommands = mkOption {
+      type = types.lines;
+      default = "";
+      example = "iptables -P INPUT ACCEPT";
+      description =
+        ''
+          Additional shell commands executed as part of the firewall
+          shutdown script.  These are executed just after the removal
+          of the nixos input rule, or if the service enters a failed state.
+        '';
+    };
+
   };
 
 
@@ -264,166 +450,28 @@ in
                      message = "This kernel does not support disabling conntrack helpers"; }
                  ];
 
-    systemd.services.firewall =
-      { description = "Firewall";
-
-        wantedBy = [ "network.target" ];
-        after = [ "network-interfaces.target" "systemd-modules-load.service" ];
-
-        path = [ pkgs.iptables ];
-
-        # FIXME: this module may also try to load kernel modules, but
-        # containers don't have CAP_SYS_MODULE. So the host system had
-        # better have all necessary modules already loaded.
-        unitConfig.ConditionCapability = "CAP_NET_ADMIN";
-
-        serviceConfig.Type = "oneshot";
-        serviceConfig.RemainAfterExit = true;
-
-        script =
-          ''
-            ${helpers}
-
-            # Flush the old firewall rules.  !!! Ideally, updating the
-            # firewall would be atomic.  Apparently that's possible
-            # with iptables-restore.
-            ip46tables -D INPUT -j nixos-fw 2> /dev/null || true
-            for chain in nixos-fw nixos-fw-accept nixos-fw-log-refuse nixos-fw-refuse FW_REFUSE; do
-              ip46tables -F "$chain" 2> /dev/null || true
-              ip46tables -X "$chain" 2> /dev/null || true
-            done
-
-
-            # The "nixos-fw-accept" chain just accepts packets.
-            ip46tables -N nixos-fw-accept
-            ip46tables -A nixos-fw-accept -j ACCEPT
-
-
-            # The "nixos-fw-refuse" chain rejects or drops packets.
-            ip46tables -N nixos-fw-refuse
-
-            ${if cfg.rejectPackets then ''
-              # Send a reset for existing TCP connections that we've
-              # somehow forgotten about.  Send ICMP "port unreachable"
-              # for everything else.
-              ip46tables -A nixos-fw-refuse -p tcp ! --syn -j REJECT --reject-with tcp-reset
-              ip46tables -A nixos-fw-refuse -j REJECT
-            '' else ''
-              ip46tables -A nixos-fw-refuse -j DROP
-            ''}
-
-
-            # The "nixos-fw-log-refuse" chain performs logging, then
-            # jumps to the "nixos-fw-refuse" chain.
-            ip46tables -N nixos-fw-log-refuse
-
-            ${optionalString cfg.logRefusedConnections ''
-              ip46tables -A nixos-fw-log-refuse -p tcp --syn -j LOG --log-level info --log-prefix "rejected connection: "
-            ''}
-            ${optionalString (cfg.logRefusedPackets && !cfg.logRefusedUnicastsOnly) ''
-              ip46tables -A nixos-fw-log-refuse -m pkttype --pkt-type broadcast \
-                -j LOG --log-level info --log-prefix "rejected broadcast: "
-              ip46tables -A nixos-fw-log-refuse -m pkttype --pkt-type multicast \
-                -j LOG --log-level info --log-prefix "rejected multicast: "
-            ''}
-            ip46tables -A nixos-fw-log-refuse -m pkttype ! --pkt-type unicast -j nixos-fw-refuse
-            ${optionalString cfg.logRefusedPackets ''
-              ip46tables -A nixos-fw-log-refuse \
-                -j LOG --log-level info --log-prefix "rejected packet: "
-            ''}
-            ip46tables -A nixos-fw-log-refuse -j nixos-fw-refuse
-
-
-            # The "nixos-fw" chain does the actual work.
-            ip46tables -N nixos-fw
-
-            # Perform a reverse-path test to refuse spoofers
-            # For now, we just drop, as the raw table doesn't have a log-refuse yet
-            ${optionalString (kernelHasRPFilter && cfg.checkReversePath) ''
-              if ! ip46tables -A PREROUTING -t raw -m rpfilter --invert -j DROP; then
-                echo "<2>failed to initialise rpfilter support" >&2
-              fi
-            ''}
-
-            # Accept all traffic on the trusted interfaces.
-            ${flip concatMapStrings cfg.trustedInterfaces (iface: ''
-              ip46tables -A nixos-fw -i ${iface} -j nixos-fw-accept
-            '')}
-
-            # Accept packets from established or related connections.
-            ip46tables -A nixos-fw -m conntrack --ctstate ESTABLISHED,RELATED -j nixos-fw-accept
-
-            # Accept connections to the allowed TCP ports.
-            ${concatMapStrings (port:
-                ''
-                  ip46tables -A nixos-fw -p tcp --dport ${toString port} -j nixos-fw-accept
-                ''
-              ) cfg.allowedTCPPorts
-            }
-
-            # Accept connections to the allowed TCP port ranges.
-            ${concatMapStrings (rangeAttr:
-                let range = toString rangeAttr.from + ":" + toString rangeAttr.to; in
-                ''
-                  ip46tables -A nixos-fw -p tcp --dport ${range} -j nixos-fw-accept
-                ''
-              ) cfg.allowedTCPPortRanges
-            }
-
-            # Accept packets on the allowed UDP ports.
-            ${concatMapStrings (port:
-                ''
-                  ip46tables -A nixos-fw -p udp --dport ${toString port} -j nixos-fw-accept
-                ''
-              ) cfg.allowedUDPPorts
-            }
-
-            # Accept packets on the allowed UDP port ranges.
-            ${concatMapStrings (rangeAttr:
-                let range = toString rangeAttr.from + ":" + toString rangeAttr.to; in
-                ''
-                  ip46tables -A nixos-fw -p udp --dport ${range} -j nixos-fw-accept
-                ''
-              ) cfg.allowedUDPPortRanges
-            }
-
-            # Accept IPv4 multicast.  Not a big security risk since
-            # probably nobody is listening anyway.
-            #iptables -A nixos-fw -d 224.0.0.0/4 -j nixos-fw-accept
-
-            # Optionally respond to ICMPv4 pings.
-            ${optionalString cfg.allowPing ''
-              iptables -w -A nixos-fw -p icmp --icmp-type echo-request ${optionalString (cfg.pingLimit != null)
-                "-m limit ${cfg.pingLimit} "
-              }-j nixos-fw-accept
-            ''}
-
-            # Accept all ICMPv6 messages except redirects and node
-            # information queries (type 139).  See RFC 4890, section
-            # 4.4.
-            ${optionalString config.networking.enableIPv6 ''
-              ip6tables -A nixos-fw -p icmpv6 --icmpv6-type redirect -j DROP
-              ip6tables -A nixos-fw -p icmpv6 --icmpv6-type 139 -j DROP
-              ip6tables -A nixos-fw -p icmpv6 -j nixos-fw-accept
-            ''}
-
-            ${cfg.extraCommands}
-
-            # Reject/drop everything else.
-            ip46tables -A nixos-fw -j nixos-fw-log-refuse
-
-
-            # Enable the firewall.
-            ip46tables -A INPUT -j nixos-fw
-          '';
-
-        postStop =
-          ''
-            ${helpers}
-            ip46tables -D INPUT -j nixos-fw || true
-            #ip46tables -P INPUT ACCEPT
-          '';
+    systemd.services.firewall = {
+      description = "Firewall";
+      wantedBy = [ "network.target" ];
+      after = [ "network-interfaces.target" "systemd-modules-load.service" ];
+
+      path = [ pkgs.iptables ];
+
+      # FIXME: this module may also try to load kernel modules, but
+      # containers don't have CAP_SYS_MODULE. So the host system had
+      # better have all necessary modules already loaded.
+      unitConfig.ConditionCapability = "CAP_NET_ADMIN";
+
+      reloadIfChanged = true;
+
+      serviceConfig = {
+        Type = "oneshot";
+        RemainAfterExit = true;
+        ExecStart = "@${startScript} firewall-start";
+        ExecReload = "@${reloadScript} firewall-reload";
+        ExecStop = "@${stopScript} firewall-stop";
       };
+    };
 
   };
 
diff --git a/nixos/modules/services/networking/nat.nix b/nixos/modules/services/networking/nat.nix
index 4a4c06503c29..35e376e7b3a6 100644
--- a/nixos/modules/services/networking/nat.nix
+++ b/nixos/modules/services/networking/nat.nix
@@ -12,6 +12,41 @@ let
 
   dest = if cfg.externalIP == null then "-j MASQUERADE" else "-j SNAT --to-source ${cfg.externalIP}";
 
+  flushNat = ''
+    iptables -w -t nat -F PREROUTING
+    iptables -w -t nat -F POSTROUTING
+    iptables -w -t nat -X
+  '';
+
+  setupNat = ''
+    # We can't match on incoming interface in POSTROUTING, so
+    # mark packets coming from the external interfaces.
+    ${concatMapStrings (iface: ''
+      iptables -w -t nat -A PREROUTING \
+        -i '${iface}' -j MARK --set-mark 1
+    '') cfg.internalInterfaces}
+
+    # NAT the marked packets.
+    ${optionalString (cfg.internalInterfaces != []) ''
+      iptables -w -t nat -A POSTROUTING -m mark --mark 1 \
+        -o ${cfg.externalInterface} ${dest}
+    ''}
+
+    # NAT packets coming from the internal IPs.
+    ${concatMapStrings (range: ''
+      iptables -w -t nat -A POSTROUTING \
+        -s '${range}' -o ${cfg.externalInterface} ${dest}
+    '') cfg.internalIPs}
+
+    # NAT from external ports to internal ports.
+    ${concatMapStrings (fwd: ''
+      iptables -w -t nat -A PREROUTING \
+        -i ${cfg.externalInterface} -p tcp \
+        --dport ${builtins.toString fwd.sourcePort} \
+        -j DNAT --to-destination ${fwd.destination}
+    '') cfg.forwardPorts}
+  '';
+
 in
 
 {
@@ -109,57 +144,34 @@ in
 
     environment.systemPackages = [ pkgs.iptables ];
 
-    boot.kernelModules = [ "nf_nat_ftp" ];
-
-    jobs.nat =
-      { description = "Network Address Translation";
-
-        startOn = "started network-interfaces";
-
-        path = [ pkgs.iptables ];
-
-        preStart =
-          ''
-            iptables -w -t nat -F PREROUTING
-            iptables -w -t nat -F POSTROUTING
-            iptables -w -t nat -X
-
-            # We can't match on incoming interface in POSTROUTING, so
-            # mark packets coming from the external interfaces.
-            ${concatMapStrings (iface: ''
-              iptables -w -t nat -A PREROUTING \
-                -i '${iface}' -j MARK --set-mark 1
-            '') cfg.internalInterfaces}
-
-            # NAT the marked packets.
-            ${optionalString (cfg.internalInterfaces != []) ''
-              iptables -w -t nat -A POSTROUTING -m mark --mark 1 \
-                -o ${cfg.externalInterface} ${dest}
-            ''}
-
-            # NAT packets coming from the internal IPs.
-            ${concatMapStrings (range: ''
-              iptables -w -t nat -A POSTROUTING \
-                -s '${range}' -o ${cfg.externalInterface} ${dest}
-            '') cfg.internalIPs}
-
-            # NAT from external ports to internal ports.
-            ${concatMapStrings (fwd: ''
-              iptables -w -t nat -A PREROUTING \
-                -i ${cfg.externalInterface} -p tcp \
-                --dport ${builtins.toString fwd.sourcePort} \
-                -j DNAT --to-destination ${fwd.destination}
-            '') cfg.forwardPorts}
-
-            echo 1 > /proc/sys/net/ipv4/ip_forward
-          '';
-
-        postStop =
-          ''
-            iptables -w -t nat -F PREROUTING
-            iptables -w -t nat -F POSTROUTING
-            iptables -w -t nat -X
-          '';
+    boot = {
+      kernelModules = [ "nf_nat_ftp" ];
+      kernel.sysctl = mkOverride 99 {
+        "net.ipv4.conf.all.forwarding" = true;
+        "net.ipv4.conf.default.forwarding" = true;
       };
+    };
+
+    networking.firewall = mkIf config.networking.firewall.enable {
+      extraCommands = mkMerge [ (mkBefore flushNat) setupNat ];
+      extraStopCommands = flushNat;
+    };
+
+    systemd.services =  mkIf (!config.networking.firewall.enable) { nat = {
+      description = "Network Address Translation";
+      wantedBy = [ "network.target" ];
+      after = [ "network-interfaces.target" "systemd-modules-load.service" ];
+      path = [ pkgs.iptables ];
+      unitConfig.ConditionCapability = "CAP_NET_ADMIN";
+
+      serviceConfig = {
+        Type = "oneshot";
+        RemainAfterExit = true;
+      };
+
+      script = flushNat + setupNat;
+
+      postStop = flushNat;
+    }; };
   };
 }
diff --git a/nixos/modules/services/networking/znc.nix b/nixos/modules/services/networking/znc.nix
index 9b26b2b32448..b39aea04521b 100644
--- a/nixos/modules/services/networking/znc.nix
+++ b/nixos/modules/services/networking/znc.nix
@@ -305,7 +305,6 @@ in
         uid = config.ids.uids.znc;
         home = cfg.dataDir;
         createHome = true;
-        createUser = true;
       };
  
     users.extraGroups = optional (cfg.user == defaultUser)
diff --git a/nixos/modules/services/search/elasticsearch.nix b/nixos/modules/services/search/elasticsearch.nix
index b74ef4370d76..12f163db463d 100644
--- a/nixos/modules/services/search/elasticsearch.nix
+++ b/nixos/modules/services/search/elasticsearch.nix
@@ -135,6 +135,11 @@ in {
         rm ${cfg.dataDir}/plugins || true
         ln -s ${esPlugins}/plugins ${cfg.dataDir}/plugins
       '';
+      postStart = mkBefore ''
+        until ${pkgs.curl}/bin/curl -s -o /dev/null ${cfg.host}:${toString cfg.port}; do
+          sleep 1
+        done
+      '';
     };
 
     environment.systemPackages = [ pkgs.elasticsearch ];
diff --git a/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix
index 9ac28373dacb..85458a2ab565 100644
--- a/nixos/modules/services/web-servers/apache-httpd/default.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/default.nix
@@ -208,16 +208,12 @@ let
       </Directory>
     '';
 
-    robotsTxt = pkgs.writeText "robots.txt" ''
-      ${# If this is a vhost, the include the entries for the main server as well.
-        if isMainServer then ""
-        else concatMapStrings (svc: svc.robotsEntries) mainSubservices}
-      ${concatMapStrings (svc: svc.robotsEntries) subservices}
-    '';
-
-    robotsConf = ''
-      Alias /robots.txt ${robotsTxt}
-    '';
+    robotsTxt =
+      concatStringsSep "\n" (filter (x: x != "") (
+        # If this is a vhost, the include the entries for the main server as well.
+        (if isMainServer then [] else [mainCfg.robotsEntries] ++ map (svc: svc.robotsEntries) mainSubservices)
+        ++ [cfg.robotsEntries]
+        ++ (map (svc: svc.robotsEntries) subservices)));
 
   in ''
     ServerName ${serverInfo.canonicalName}
@@ -245,7 +241,9 @@ let
       CustomLog ${mainCfg.logDir}/access_log-${cfg.hostName} ${cfg.logFormat}
     '' else ""}
 
-    ${robotsConf}
+    ${optionalString (robotsTxt != "") ''
+      Alias /robots.txt ${pkgs.writeText "robots.txt" robotsTxt}
+    ''}
 
     ${if isMainServer || maybeDocumentRoot != null then documentRootConf else ""}
 
diff --git a/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix b/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix
index b8e863345398..76f55a63e326 100644
--- a/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix
@@ -142,9 +142,19 @@ with lib;
     type = types.str;
     default = "common";
     example = "combined";
-    description = "
+    description = ''
       Log format for Apache's log files. Possible values are: combined, common, referer, agent.
-    ";
+    '';
+  };
+
+  robotsEntries = mkOption {
+    type = types.lines;
+    default = "";
+    example = "Disallow: /foo/";
+    description = ''
+      Specification of pages to be ignored by web crawlers. See <link
+      xlink:href='http://www.robotstxt.org/'/> for details.
+    '';
   };
 
 }
diff --git a/nixos/modules/services/x11/desktop-managers/default.nix b/nixos/modules/services/x11/desktop-managers/default.nix
index c62beca60d84..ebdb2ad06491 100644
--- a/nixos/modules/services/x11/desktop-managers/default.nix
+++ b/nixos/modules/services/x11/desktop-managers/default.nix
@@ -19,7 +19,7 @@ in
   # E.g., if KDE is enabled, it supersedes xterm.
   imports = [
     ./none.nix ./xterm.nix ./xfce.nix ./kde4.nix
-    ./e17.nix ./e18.nix ./gnome3.nix ./xbmc.nix
+    ./e17.nix ./e18.nix ./e19.nix ./gnome3.nix ./xbmc.nix
   ];
 
   options = {
diff --git a/nixos/modules/services/x11/desktop-managers/e19.nix b/nixos/modules/services/x11/desktop-managers/e19.nix
new file mode 100644
index 000000000000..dd9becb0f6ca
--- /dev/null
+++ b/nixos/modules/services/x11/desktop-managers/e19.nix
@@ -0,0 +1,94 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+
+  xcfg = config.services.xserver;
+  cfg = xcfg.desktopManager.e19;
+  e19_enlightenment = pkgs.e19.enlightenment.override { set_freqset_setuid = true; };
+
+in
+
+{
+  options = {
+
+    services.xserver.desktopManager.e19.enable = mkOption {
+      default = false;
+      example = true;
+      description = "Enable the E19 desktop environment.";
+    };
+
+  };
+
+  config = mkIf (xcfg.enable && cfg.enable) {
+
+    environment.systemPackages = [
+      pkgs.e19.efl pkgs.e19.evas pkgs.e19.emotion pkgs.e19.elementary e19_enlightenment
+      pkgs.e19.terminology pkgs.e19.econnman
+      pkgs.xorg.xauth # used by kdesu
+      pkgs.gtk # To get GTK+'s themes.
+      pkgs.tango-icon-theme
+      pkgs.shared_mime_info
+      pkgs.gnome.gnomeicontheme
+      pkgs.xorg.xcursorthemes
+    ];
+
+    environment.pathsToLink = [ "/etc/enlightenment" "/etc/xdg" "/share/enlightenment" "/share/elementary" "/share/applications" "/share/locale" "/share/icons" "/share/themes" "/share/mime" "/share/desktop-directories" ];
+
+    services.xserver.desktopManager.session = [
+    { name = "E19";
+      start = ''
+        # Set GTK_DATA_PREFIX so that GTK+ can find the themes
+        export GTK_DATA_PREFIX=${config.system.path}
+        # find theme engines
+        export GTK_PATH=${config.system.path}/lib/gtk-3.0:${config.system.path}/lib/gtk-2.0
+        export XDG_MENU_PREFIX=enlightenment
+
+        # make available for D-BUS user services
+        #export XDG_DATA_DIRS=$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}:${config.system.path}/share:${pkgs.e19.efl}/share
+
+        # Update user dirs as described in http://freedesktop.org/wiki/Software/xdg-user-dirs/
+        ${pkgs.xdg-user-dirs}/bin/xdg-user-dirs-update
+
+        ${e19_enlightenment}/bin/enlightenment_start
+        waitPID=$!
+      '';
+    }];
+
+    security.setuidPrograms = [ "e19_freqset" ];
+
+    environment.etc = singleton
+      { source = "${pkgs.xkeyboard_config}/etc/X11/xkb";
+        target = "X11/xkb";
+      };
+
+    fonts.fonts = [ pkgs.dejavu_fonts pkgs.ubuntu_font_family ];
+
+    services.udisks2.enable = true;
+    services.upower.enable = config.powerManagement.enable;
+
+    #services.dbus.packages = [ pkgs.efl ]; # dbus-1 folder is not in /etc but in /share, so needs fixing first
+
+    systemd.user.services.efreet =
+      { enable = true;
+        description = "org.enlightenment.Efreet";
+        serviceConfig =
+          { ExecStart = "${pkgs.e19.efl}/bin/efreetd";
+            StandardOutput = "null";
+          };
+      };
+
+    systemd.user.services.ethumb =
+      { enable = true;
+        description = "org.enlightenment.Ethumb";
+        serviceConfig =
+          { ExecStart = "${pkgs.e19.efl}/bin/ethumbd";
+            StandardOutput = "null";
+          };
+      };
+
+
+  };
+
+}
diff --git a/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix
index 633b6f4960a6..3c13e866eb17 100644
--- a/nixos/modules/services/x11/desktop-managers/gnome3.nix
+++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix
@@ -77,7 +77,7 @@ in {
     services.gnome3.tracker.enable = mkDefault true;
     hardware.pulseaudio.enable = mkDefault true;
     services.telepathy.enable = mkDefault true;
-    networking.networkmanager.enable = true;
+    networking.networkmanager.enable = mkDefault true;
     services.upower.enable = config.powerManagement.enable;
     services.upower.package = gnome3.upower;
 
diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix
index 6e61576f501f..004ea6ef49ac 100644
--- a/nixos/modules/services/x11/display-managers/default.nix
+++ b/nixos/modules/services/x11/display-managers/default.nix
@@ -169,7 +169,6 @@ in
 
       xserverBin = mkOption {
         type = types.path;
-        default = "${xorg.xorgserver}/bin/X";
         description = "Path to the X server used by display managers.";
       };
 
@@ -280,4 +279,10 @@ in
 
   };
 
+  config = {
+
+    services.xserver.displayManager.xserverBin = "${xorg.xorgserver}/bin/X";
+
+  };
+
 }
diff --git a/nixos/modules/system/boot/systemd-unit-options.nix b/nixos/modules/system/boot/systemd-unit-options.nix
index a6183c47eb1b..48c3564ba078 100644
--- a/nixos/modules/system/boot/systemd-unit-options.nix
+++ b/nixos/modules/system/boot/systemd-unit-options.nix
@@ -230,6 +230,15 @@ in rec {
       '';
     };
 
+    reload = mkOption {
+      type = types.lines;
+      default = "";
+      description = ''
+        Shell commands executed when the service's main process
+        is reloaded.
+      '';
+    };
+
     preStop = mkOption {
       type = types.lines;
       default = "";
diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix
index 366faf1b73de..13d6c6d7990a 100644
--- a/nixos/modules/system/boot/systemd.nix
+++ b/nixos/modules/system/boot/systemd.nix
@@ -246,6 +246,12 @@ let
               ${config.postStart}
             '';
           })
+        (mkIf (config.reload != "")
+          { serviceConfig.ExecReload = makeJobScript "${name}-reload" ''
+              #! ${pkgs.stdenv.shell} -e
+              ${config.reload}
+            '';
+          })
         (mkIf (config.preStop != "")
           { serviceConfig.ExecStop = makeJobScript "${name}-pre-stop" ''
               #! ${pkgs.stdenv.shell} -e
diff --git a/nixos/modules/tasks/filesystems/nfs.nix b/nixos/modules/tasks/filesystems/nfs.nix
index c902b9e07905..16752ce7e1b5 100644
--- a/nixos/modules/tasks/filesystems/nfs.nix
+++ b/nixos/modules/tasks/filesystems/nfs.nix
@@ -54,12 +54,16 @@ in
 
   ###### implementation
 
-  config = mkIf (any (fs: fs == "nfs" || fs == "nfs4") config.boot.supportedFilesystems) ({
+  config = mkIf (any (fs: fs == "nfs" || fs == "nfs4") config.boot.supportedFilesystems) {
 
     services.rpcbind.enable = true;
 
     system.fsPackages = [ pkgs.nfsUtils ];
 
+    boot.extraModprobeConfig = mkIf (cfg.lockdPort != null) ''
+      options lockd nlm_udpport=${toString cfg.lockdPort} nlm_tcpport=${toString cfg.lockdPort}
+    '';
+
     boot.kernelModules = [ "sunrpc" ];
 
     boot.initrd.kernelModules = mkIf inInitrd [ "nfs" ];
@@ -117,9 +121,5 @@ in
         serviceConfig.Restart = "always";
       };
 
-  } // mkIf (cfg.lockdPort != null) {
-    boot.extraModprobeConfig = ''
-      options lockd nlm_udpport=${toString cfg.lockdPort} nlm_tcpport=${toString cfg.lockdPort}
-    '';
-  });
+  };
 }
diff --git a/nixos/modules/virtualisation/libvirtd.nix b/nixos/modules/virtualisation/libvirtd.nix
index 318460f4c2cf..2d03f0544b67 100644
--- a/nixos/modules/virtualisation/libvirtd.nix
+++ b/nixos/modules/virtualisation/libvirtd.nix
@@ -129,12 +129,12 @@ in
             # config file. But this path can unfortunately be garbage collected
             # while still being used by the virtual machine. So update the
             # emulator path on each startup to something valid (re-scan $PATH).
-            for file in /etc/libvirt/qemu/*.xml; do
+            for file in /etc/libvirt/qemu/*.xml /etc/libvirt/lxc/*.xml; do
                 test -f "$file" || continue
                 # get (old) emulator path from config file
                 emulator=$(grep "^[[:space:]]*<emulator>" "$file" | sed 's,^[[:space:]]*<emulator>\(.*\)</emulator>.*,\1,')
                 # get a (definitely) working emulator path by re-scanning $PATH
-                new_emulator=$(command -v $(basename "$emulator"))
+                new_emulator=$(PATH=${pkgs.libvirt}/libexec:$PATH command -v $(basename "$emulator"))
                 # write back
                 sed -i "s,^[[:space:]]*<emulator>.*,    <emulator>$new_emulator</emulator> <!-- WARNING: emulator dirname is auto-updated by the nixos libvirtd module -->," "$file"
             done
diff --git a/nixos/release.nix b/nixos/release.nix
index d8cc1c8291bd..b3039afb18c1 100644
--- a/nixos/release.nix
+++ b/nixos/release.nix
@@ -11,7 +11,9 @@ let
 
   forAllSystems = pkgs.lib.genAttrs supportedSystems;
 
-  callTest = fn: args: forAllSystems (system: import fn ({ inherit system; } // args));
+  scrubDrv = drv: let res = { inherit (drv) drvPath outPath type name; outputName = "out"; out = res; }; in res;
+
+  callTest = fn: args: forAllSystems (system: scrubDrv (import fn ({ inherit system; } // args)));
 
   pkgs = import nixpkgs { system = "x86_64-linux"; };
 
@@ -40,7 +42,7 @@ let
 
     in
       # Declare the ISO as a build product so that it shows up in Hydra.
-      runCommand "nixos-iso-${config.system.nixosVersion}"
+      scrubDrv (runCommand "nixos-iso-${config.system.nixosVersion}"
         { meta = {
             description = "NixOS installation CD (${description}) - ISO image for ${system}";
             maintainers = map (x: lib.getAttr x lib.maintainers) maintainers;
@@ -51,7 +53,7 @@ let
         ''
           mkdir -p $out/nix-support
           echo "file iso" $iso/iso/*.iso* >> $out/nix-support/hydra-build-products
-        ''; # */
+        ''); # */
 
 
   makeSystemTarball =
@@ -78,14 +80,17 @@ let
         };
 
 
-  makeClosure = module: forAllSystems (system: (import ./lib/eval-config.nix {
+  makeClosure = module: buildFromConfig module (config: config.system.build.toplevel);
+
+
+  buildFromConfig = module: sel: forAllSystems (system: scrubDrv (sel (import ./lib/eval-config.nix {
     inherit system;
-    modules = [ module ] ++ lib.singleton
+    modules = [ module versionModule ] ++ lib.singleton
       ({ config, lib, ... }:
       { fileSystems."/".device  = lib.mkDefault "/dev/sda1";
         boot.loader.grub.device = lib.mkDefault "/dev/sda";
       });
-  }).config.system.build.toplevel);
+  }).config));
 
 
 in rec {
@@ -122,9 +127,9 @@ in rec {
     };
 
 
-  manual = forAllSystems (system: (builtins.getAttr system iso_minimal).config.system.build.manual.manual);
-  manualPDF = iso_minimal.x86_64-linux.config.system.build.manual.manualPDF;
-  manpages = forAllSystems (system: (builtins.getAttr system iso_minimal).config.system.build.manual.manpages);
+  manual = buildFromConfig ({ pkgs, ... }: { }) (config: config.system.build.manual.manual);
+  manualPDF = (buildFromConfig ({ pkgs, ... }: { }) (config: config.system.build.manual.manualPDF)).x86_64-linux;
+  manpages = buildFromConfig ({ pkgs, ... }: { }) (config: config.system.build.manual.manpages);
 
 
   iso_minimal = forAllSystems (system: makeIso {
@@ -147,12 +152,6 @@ in rec {
     inherit system;
   });
 
-  iso_graphical_new_kernel = forAllSystems (system: makeIso {
-    module = ./modules/installer/cd-dvd/installation-cd-graphical-new-kernel.nix;
-    type = "graphical-new-kernel";
-    inherit system;
-  });
-
 
   # A bootable VirtualBox virtual appliance as an OVA file (i.e. packaged OVF).
   ova = forAllSystems (system:
@@ -171,7 +170,7 @@ in rec {
 
     in
       # Declare the OVA as a build product so that it shows up in Hydra.
-      runCommand "nixos-ova-${config.system.nixosVersion}-${system}"
+      scrubDrv (runCommand "nixos-ova-${config.system.nixosVersion}-${system}"
         { meta = {
             description = "NixOS VirtualBox appliance (${system})";
             maintainers = lib.maintainers.eelco;
@@ -182,7 +181,7 @@ in rec {
           mkdir -p $out/nix-support
           fn=$(echo $ova/*.ova)
           echo "file ova $fn" >> $out/nix-support/hydra-build-products
-        '' # */
+        '') # */
 
   );
 
@@ -222,17 +221,17 @@ in rec {
   tests.firefox = callTest tests/firefox.nix {};
   tests.firewall = callTest tests/firewall.nix {};
   tests.gnome3 = callTest tests/gnome3.nix {};
-  tests.installer.efi = forAllSystems (system: (import tests/installer.nix { inherit system; }).efi.test);
-  tests.installer.grub1 = forAllSystems (system: (import tests/installer.nix { inherit system; }).grub1.test);
-  tests.installer.lvm = forAllSystems (system: (import tests/installer.nix { inherit system; }).lvm.test);
-  tests.installer.rebuildCD = forAllSystems (system: (import tests/installer.nix { inherit system; }).rebuildCD.test);
-  tests.installer.separateBoot = forAllSystems (system: (import tests/installer.nix { inherit system; }).separateBoot.test);
-  tests.installer.simple = forAllSystems (system: (import tests/installer.nix { inherit system; }).simple.test);
-  tests.installer.simpleLabels = forAllSystems (system: (import tests/installer.nix { inherit system; }).simpleLabels.test);
-  tests.installer.simpleProvided = forAllSystems (system: (import tests/installer.nix { inherit system; }).simpleProvided.test);
-  tests.installer.btrfsSimple = forAllSystems (system: (import tests/installer.nix { inherit system; }).btrfsSimple.test);
-  tests.installer.btrfsSubvols = forAllSystems (system: (import tests/installer.nix { inherit system; }).btrfsSubvols.test);
-  tests.installer.btrfsSubvolDefault = forAllSystems (system: (import tests/installer.nix { inherit system; }).btrfsSubvolDefault.test);
+  tests.installer.efi = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).efi.test);
+  tests.installer.grub1 = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).grub1.test);
+  tests.installer.lvm = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).lvm.test);
+  tests.installer.rebuildCD = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).rebuildCD.test);
+  tests.installer.separateBoot = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).separateBoot.test);
+  tests.installer.simple = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).simple.test);
+  tests.installer.simpleLabels = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).simpleLabels.test);
+  tests.installer.simpleProvided = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).simpleProvided.test);
+  tests.installer.btrfsSimple = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).btrfsSimple.test);
+  tests.installer.btrfsSubvols = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).btrfsSubvols.test);
+  tests.installer.btrfsSubvolDefault = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).btrfsSubvolDefault.test);
   tests.influxdb = callTest tests/influxdb.nix {};
   tests.ipv6 = callTest tests/ipv6.nix {};
   tests.jenkins = callTest tests/jenkins.nix {};