summary refs log tree commit diff
path: root/nixos/modules/services/networking/ejabberd.nix
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules/services/networking/ejabberd.nix')
-rw-r--r--nixos/modules/services/networking/ejabberd.nix192
1 files changed, 107 insertions, 85 deletions
diff --git a/nixos/modules/services/networking/ejabberd.nix b/nixos/modules/services/networking/ejabberd.nix
index 28b8e234a5c..7af11f37a43 100644
--- a/nixos/modules/services/networking/ejabberd.nix
+++ b/nixos/modules/services/networking/ejabberd.nix
@@ -6,9 +6,16 @@ let
 
   cfg = config.services.ejabberd;
 
-in
+  ctlcfg = pkgs.writeText "ejabberdctl.cfg" ''
+    ERL_EPMD_ADDRESS=127.0.0.1
+    ${cfg.ctlConfig}
+  '';
 
-{
+  ectl = ''${cfg.package}/bin/ejabberdctl ${if cfg.configFile == null then "" else "--config ${cfg.configFile}"} --ctl-config "${ctlcfg}" --spool "${cfg.spoolDir}" --logs "${cfg.logsDir}"'';
+
+  dumps = lib.concatMapStringsSep " " lib.escapeShellArg cfg.loadDumps;
+
+in {
 
   ###### interface
 
@@ -17,33 +24,57 @@ in
     services.ejabberd = {
 
       enable = mkOption {
+        type = types.bool;
         default = false;
         description = "Whether to enable ejabberd server";
       };
 
+      package = mkOption {
+        type = types.package;
+        default = pkgs.ejabberd;
+        description = "ejabberd server package to use";
+      };
+
+      user = mkOption {
+        type = types.str;
+        default = "ejabberd";
+        description = "User under which ejabberd is ran";
+      };
+
+      group = mkOption {
+        type = types.str;
+        default = "ejabberd";
+        description = "Group under which ejabberd is ran";
+      };
+
       spoolDir = mkOption {
+        type = types.path;
         default = "/var/lib/ejabberd";
         description = "Location of the spooldir of ejabberd";
       };
 
       logsDir = mkOption {
+        type = types.path;
         default = "/var/log/ejabberd";
         description = "Location of the logfile directory of ejabberd";
       };
 
-      confDir = mkOption {
-        default = "/var/ejabberd";
-        description = "Location of the config directory of ejabberd";
+      configFile = mkOption {
+        type = types.nullOr types.path;
+        description = "Configuration file for ejabberd in YAML format";
+        default = null;
       };
 
-      virtualHosts = mkOption {
-        default = "\"localhost\"";
-        description = "Virtualhosts that ejabberd should host. Hostnames are surrounded with doublequotes and separated by commas";
+      ctlConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = "Configuration of ejabberdctl";
       };
 
       loadDumps = mkOption {
+        type = types.listOf types.path;
         default = [];
-        description = "Configuration dump that should be loaded on the first startup";
+        description = "Configuration dumps that should be loaded on the first startup";
         example = literalExample "[ ./myejabberd.dump ]";
       };
     };
@@ -54,84 +85,75 @@ in
   ###### implementation
 
   config = mkIf cfg.enable {
-    environment.systemPackages = [ pkgs.ejabberd ];
-
-    jobs.ejabberd =
-      { description = "EJabberd server";
-
-        startOn = "started network-interfaces";
-        stopOn = "stopping network-interfaces";
-
-        environment = {
-          PATH = "$PATH:${pkgs.ejabberd}/sbin:${pkgs.ejabberd}/bin:${pkgs.coreutils}/bin:${pkgs.bash}/bin:${pkgs.gnused}/bin";
-        };
-
-        preStart =
-          ''
-            PATH="$PATH:${pkgs.ejabberd}/sbin:${pkgs.ejabberd}/bin:${pkgs.coreutils}/bin:${pkgs.bash}/bin:${pkgs.gnused}/bin";
-	    
-            # Initialise state data
-            mkdir -p ${cfg.logsDir}
-
-            if ! test -d ${cfg.spoolDir}
-            then
-                initialize=1
-                cp -av ${pkgs.ejabberd}/var/lib/ejabberd /var/lib
-            fi
-
-            if ! test -d ${cfg.confDir}
-            then
-                mkdir -p ${cfg.confDir}
-                cp ${pkgs.ejabberd}/etc/ejabberd/* ${cfg.confDir}
-                sed -e 's|{hosts, \["localhost"\]}.|{hosts, \[${cfg.virtualHosts}\]}.|' ${pkgs.ejabberd}/etc/ejabberd/ejabberd.cfg > ${cfg.confDir}/ejabberd.cfg
-            fi
-
-            ejabberdctl --config-dir ${cfg.confDir} --logs ${cfg.logsDir} --spool ${cfg.spoolDir} start
-
-            ${if cfg.loadDumps == [] then "" else
-              ''
-                if [ "$initialize" = "1" ]
-                then
-                    # Wait until the ejabberd server is available for use
-                    count=0
-                    while ! ejabberdctl --config-dir ${cfg.confDir} --logs ${cfg.logsDir} --spool ${cfg.spoolDir} status
-                    do
-                        if [ $count -eq 30 ]
-                        then
-                            echo "Tried 30 times, giving up..."
-                            exit 1
-                        fi
-
-                        echo "Ejabberd daemon not yet started. Waiting for 1 second..."
-                        count=$((count++))
-                        sleep 1
-                    done
-
-                    ${concatMapStrings (dump:
-                      ''
-                        echo "Importing dump: ${dump}"
-
-                        if [ -f ${dump} ]
-                        then
-                            ejabberdctl --config-dir ${cfg.confDir} --logs ${cfg.logsDir} --spool ${cfg.spoolDir} load ${dump}
-                        elif [ -d ${dump} ]
-                        then
-                            for i in ${dump}/ejabberd-dump/*
-                            do
-                                ejabberdctl --config-dir ${cfg.confDir} --logs ${cfg.logsDir} --spool ${cfg.spoolDir} load $i
-                            done
-                        fi
-                      '') cfg.loadDumps}
-                fi
-              ''}
-          '';
-
-        postStop =
-          ''
-            ejabberdctl --config-dir ${cfg.confDir} --logs ${cfg.logsDir} --spool ${cfg.spoolDir} stop
-          '';
+    environment.systemPackages = [ cfg.package ];
+
+    users.extraUsers = optionalAttrs (cfg.user == "ejabberd") (singleton
+      { name = "ejabberd";
+        group = cfg.group;
+        home = cfg.spoolDir;
+        createHome = true;
+        uid = config.ids.uids.ejabberd;
+      });
+
+    users.extraGroups = optionalAttrs (cfg.group == "ejabberd") (singleton
+      { name = "ejabberd";
+        gid = config.ids.gids.ejabberd;
+      });
+
+    systemd.services.ejabberd = {
+      description = "ejabberd server";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+      path = [ pkgs.findutils pkgs.coreutils ];
+
+      serviceConfig = {
+        Type = "forking";
+        # FIXME: runit is used for `chpst` -- can we get rid of this?
+        ExecStop = ''${pkgs.runit}/bin/chpst -u "${cfg.user}:${cfg.group}" ${ectl} stop'';
+        ExecReload = ''${pkgs.runit}/bin/chpst -u "${cfg.user}:${cfg.group}" ${ectl} reload_config'';
+        User = cfg.user;
+        Group = cfg.group;
+        PermissionsStartOnly = true;
       };
 
+      preStart = ''
+        mkdir -p -m750 "${cfg.logsDir}"
+        chown "${cfg.user}:${cfg.group}" "${cfg.logsDir}"
+
+        mkdir -p -m750 "/var/lock/ejabberdctl"
+        chown "${cfg.user}:${cfg.group}" "/var/lock/ejabberdctl"
+
+        mkdir -p -m750 "${cfg.spoolDir}"
+        chown -R "${cfg.user}:${cfg.group}" "${cfg.spoolDir}"
+      '';
+
+      script = ''
+        [ -z "$(ls -A '${cfg.spoolDir}')" ] && firstRun=1
+
+        ${ectl} start
+
+        count=0
+        while ! ${ectl} status >/dev/null 2>&1; do
+          if [ $count -eq 30 ]; then
+            echo "ejabberd server hasn't started in 30 seconds, giving up"
+            exit 1
+          fi
+
+          count=$((count++))
+          sleep 1
+        done
+
+        if [ -n "$firstRun" ]; then
+          for src in ${dumps}; do
+            find "$src" -type f | while read dump; do
+              echo "Loading configuration dump at $dump"
+              ${ectl} load "$dump"
+            done
+          done
+        fi
+      '';
+    };
+
     security.pam.services.ejabberd = {};
 
   };