summary refs log tree commit diff
path: root/nixos/modules/services/amqp
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules/services/amqp')
-rw-r--r--nixos/modules/services/amqp/activemq/ActiveMQBroker.java19
-rw-r--r--nixos/modules/services/amqp/activemq/default.nix135
-rw-r--r--nixos/modules/services/amqp/rabbitmq.nix228
3 files changed, 382 insertions, 0 deletions
diff --git a/nixos/modules/services/amqp/activemq/ActiveMQBroker.java b/nixos/modules/services/amqp/activemq/ActiveMQBroker.java
new file mode 100644
index 00000000000..c0f5d16ea11
--- /dev/null
+++ b/nixos/modules/services/amqp/activemq/ActiveMQBroker.java
@@ -0,0 +1,19 @@
+import org.apache.activemq.broker.BrokerService;
+import org.apache.activemq.broker.BrokerFactory;
+import java.net.URI;
+
+public class ActiveMQBroker {
+
+  public static void main(String[] args) throws Throwable {
+    URI uri = new URI((args.length > 0) ? args[0] : "xbean:activemq.xml");
+    BrokerService broker = BrokerFactory.createBroker(uri);
+    broker.start();
+    if (broker.waitUntilStarted()) {
+      broker.waitUntilStopped();
+    } else {
+      System.out.println("Failed starting broker");
+      System.exit(-1);
+    };
+  }
+
+}
diff --git a/nixos/modules/services/amqp/activemq/default.nix b/nixos/modules/services/amqp/activemq/default.nix
new file mode 100644
index 00000000000..47669b05aa9
--- /dev/null
+++ b/nixos/modules/services/amqp/activemq/default.nix
@@ -0,0 +1,135 @@
+{ config, lib, pkgs, ... }:
+
+with pkgs;
+with lib;
+
+let
+
+  cfg = config.services.activemq;
+
+  activemqBroker = stdenv.mkDerivation {
+    name = "activemq-broker";
+    phases = [ "installPhase" ];
+    buildInputs = [ jdk ];
+    installPhase = ''
+      mkdir -p $out/lib
+      source ${activemq}/lib/classpath.env
+      export CLASSPATH
+      ln -s "${./ActiveMQBroker.java}" ActiveMQBroker.java
+      javac -d $out/lib ActiveMQBroker.java
+    '';
+  };
+
+in {
+
+  options = {
+    services.activemq = {
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Enable the Apache ActiveMQ message broker service.
+        '';
+      };
+      configurationDir = mkOption {
+        default = "${activemq}/conf";
+        defaultText = literalExpression ''"''${pkgs.activemq}/conf"'';
+        type = types.str;
+        description = ''
+          The base directory for ActiveMQ's configuration.
+          By default, this directory is searched for a file named activemq.xml,
+          which should contain the configuration for the broker service.
+        '';
+      };
+      configurationURI = mkOption {
+        type = types.str;
+        default = "xbean:activemq.xml";
+        description = ''
+          The URI that is passed along to the BrokerFactory to
+          set up the configuration of the ActiveMQ broker service.
+          You should not need to change this. For custom configuration,
+          set the <literal>configurationDir</literal> instead, and create
+          an activemq.xml configuration file in it.
+        '';
+      };
+      baseDir = mkOption {
+        type = types.str;
+        default = "/var/activemq";
+        description = ''
+          The base directory where ActiveMQ stores its persistent data and logs.
+          This will be overridden if you set "activemq.base" and "activemq.data"
+          in the <literal>javaProperties</literal> option. You can also override
+          this in activemq.xml.
+        '';
+      };
+      javaProperties = mkOption {
+        type = types.attrs;
+        default = { };
+        example = literalExpression ''
+          {
+            "java.net.preferIPv4Stack" = "true";
+          }
+        '';
+        apply = attrs: {
+          "activemq.base" = "${cfg.baseDir}";
+          "activemq.data" = "${cfg.baseDir}/data";
+          "activemq.conf" = "${cfg.configurationDir}";
+          "activemq.home" = "${activemq}";
+        } // attrs;
+        description = ''
+          Specifies Java properties that are sent to the ActiveMQ
+          broker service with the "-D" option. You can set properties
+          here to change the behaviour and configuration of the broker.
+          All essential properties that are not set here are automatically
+          given reasonable defaults.
+        '';
+      };
+      extraJavaOptions = mkOption {
+        type = types.separatedString " ";
+        default = "";
+        example = "-Xmx2G -Xms2G -XX:MaxPermSize=512M";
+        description = ''
+          Add extra options here that you want to be sent to the
+          Java runtime when the broker service is started.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    users.users.activemq = {
+      description = "ActiveMQ server user";
+      group = "activemq";
+      uid = config.ids.uids.activemq;
+    };
+
+    users.groups.activemq.gid = config.ids.gids.activemq;
+
+    systemd.services.activemq_init = {
+      wantedBy = [ "activemq.service" ];
+      partOf = [ "activemq.service" ];
+      before = [ "activemq.service" ];
+      serviceConfig.Type = "oneshot";
+      script = ''
+        mkdir -p "${cfg.javaProperties."activemq.data"}"
+        chown -R activemq "${cfg.javaProperties."activemq.data"}"
+      '';
+    };
+
+    systemd.services.activemq = {
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+      path = [ jre ];
+      serviceConfig.User = "activemq";
+      script = ''
+        source ${activemq}/lib/classpath.env
+        export CLASSPATH=${activemqBroker}/lib:${cfg.configurationDir}:$CLASSPATH
+        exec java \
+          ${concatStringsSep " \\\n" (mapAttrsToList (name: value: "-D${name}=${value}") cfg.javaProperties)} \
+          ${cfg.extraJavaOptions} ActiveMQBroker "${cfg.configurationURI}"
+      '';
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/amqp/rabbitmq.nix b/nixos/modules/services/amqp/rabbitmq.nix
new file mode 100644
index 00000000000..3255942fe43
--- /dev/null
+++ b/nixos/modules/services/amqp/rabbitmq.nix
@@ -0,0 +1,228 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.rabbitmq;
+
+  inherit (builtins) concatStringsSep;
+
+  config_file_content = lib.generators.toKeyValue { } cfg.configItems;
+  config_file = pkgs.writeText "rabbitmq.conf" config_file_content;
+
+  advanced_config_file = pkgs.writeText "advanced.config" cfg.config;
+
+in
+{
+  ###### interface
+  options = {
+    services.rabbitmq = {
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable the RabbitMQ server, an Advanced Message
+          Queuing Protocol (AMQP) broker.
+        '';
+      };
+
+      package = mkOption {
+        default = pkgs.rabbitmq-server;
+        type = types.package;
+        defaultText = literalExpression "pkgs.rabbitmq-server";
+        description = ''
+          Which rabbitmq package to use.
+        '';
+      };
+
+      listenAddress = mkOption {
+        default = "127.0.0.1";
+        example = "";
+        description = ''
+          IP address on which RabbitMQ will listen for AMQP
+          connections.  Set to the empty string to listen on all
+          interfaces.  Note that RabbitMQ creates a user named
+          <literal>guest</literal> with password
+          <literal>guest</literal> by default, so you should delete
+          this user if you intend to allow external access.
+
+          Together with 'port' setting it's mostly an alias for
+          configItems."listeners.tcp.1" and it's left for backwards
+          compatibility with previous version of this module.
+        '';
+        type = types.str;
+      };
+
+      port = mkOption {
+        default = 5672;
+        description = ''
+          Port on which RabbitMQ will listen for AMQP connections.
+        '';
+        type = types.port;
+      };
+
+      dataDir = mkOption {
+        type = types.path;
+        default = "/var/lib/rabbitmq";
+        description = ''
+          Data directory for rabbitmq.
+        '';
+      };
+
+      cookie = mkOption {
+        default = "";
+        type = types.str;
+        description = ''
+          Erlang cookie is a string of arbitrary length which must
+          be the same for several nodes to be allowed to communicate.
+          Leave empty to generate automatically.
+        '';
+      };
+
+      configItems = mkOption {
+        default = { };
+        type = types.attrsOf types.str;
+        example = literalExpression ''
+          {
+            "auth_backends.1.authn" = "rabbit_auth_backend_ldap";
+            "auth_backends.1.authz" = "rabbit_auth_backend_internal";
+          }
+        '';
+        description = ''
+          Configuration options in RabbitMQ's new config file format,
+          which is a simple key-value format that can not express nested
+          data structures. This is known as the <literal>rabbitmq.conf</literal> file,
+          although outside NixOS that filename may have Erlang syntax, particularly
+          prior to RabbitMQ 3.7.0.
+
+          If you do need to express nested data structures, you can use
+          <literal>config</literal> option. Configuration from <literal>config</literal>
+          will be merged into these options by RabbitMQ at runtime to
+          form the final configuration.
+
+          See https://www.rabbitmq.com/configure.html#config-items
+          For the distinct formats, see https://www.rabbitmq.com/configure.html#config-file-formats
+        '';
+      };
+
+      config = mkOption {
+        default = "";
+        type = types.str;
+        description = ''
+          Verbatim advanced configuration file contents using the Erlang syntax.
+          This is also known as the <literal>advanced.config</literal> file or the old config format.
+
+          <literal>configItems</literal> is preferred whenever possible. However, nested
+          data structures can only be expressed properly using the <literal>config</literal> option.
+
+          The contents of this option will be merged into the <literal>configItems</literal>
+          by RabbitMQ at runtime to form the final configuration.
+
+          See the second table on https://www.rabbitmq.com/configure.html#config-items
+          For the distinct formats, see https://www.rabbitmq.com/configure.html#config-file-formats
+        '';
+      };
+
+      plugins = mkOption {
+        default = [ ];
+        type = types.listOf types.str;
+        description = "The names of plugins to enable";
+      };
+
+      pluginDirs = mkOption {
+        default = [ ];
+        type = types.listOf types.path;
+        description = "The list of directories containing external plugins";
+      };
+
+      managementPlugin = {
+        enable = mkEnableOption "the management plugin";
+        port = mkOption {
+          default = 15672;
+          type = types.port;
+          description = ''
+            On which port to run the management plugin
+          '';
+        };
+      };
+    };
+  };
+
+
+  ###### implementation
+  config = mkIf cfg.enable {
+
+    # This is needed so we will have 'rabbitmqctl' in our PATH
+    environment.systemPackages = [ cfg.package ];
+
+    services.epmd.enable = true;
+
+    users.users.rabbitmq = {
+      description = "RabbitMQ server user";
+      home = "${cfg.dataDir}";
+      createHome = true;
+      group = "rabbitmq";
+      uid = config.ids.uids.rabbitmq;
+    };
+
+    users.groups.rabbitmq.gid = config.ids.gids.rabbitmq;
+
+    services.rabbitmq.configItems = {
+      "listeners.tcp.1" = mkDefault "${cfg.listenAddress}:${toString cfg.port}";
+    } // optionalAttrs cfg.managementPlugin.enable {
+      "management.tcp.port" = toString cfg.managementPlugin.port;
+      "management.tcp.ip" = cfg.listenAddress;
+    };
+
+    services.rabbitmq.plugins = optional cfg.managementPlugin.enable "rabbitmq_management";
+
+    systemd.services.rabbitmq = {
+      description = "RabbitMQ Server";
+
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" "epmd.socket" ];
+      wants = [ "network.target" "epmd.socket" ];
+
+      path = [
+        cfg.package
+        pkgs.coreutils # mkdir/chown/chmod for preStart
+      ];
+
+      environment = {
+        RABBITMQ_MNESIA_BASE = "${cfg.dataDir}/mnesia";
+        RABBITMQ_LOGS = "-";
+        SYS_PREFIX = "";
+        RABBITMQ_CONFIG_FILE = config_file;
+        RABBITMQ_PLUGINS_DIR = concatStringsSep ":" cfg.pluginDirs;
+        RABBITMQ_ENABLED_PLUGINS_FILE = pkgs.writeText "enabled_plugins" ''
+          [ ${concatStringsSep "," cfg.plugins} ].
+        '';
+      } // optionalAttrs (cfg.config != "") { RABBITMQ_ADVANCED_CONFIG_FILE = advanced_config_file; };
+
+      serviceConfig = {
+        ExecStart = "${cfg.package}/sbin/rabbitmq-server";
+        ExecStop = "${cfg.package}/sbin/rabbitmqctl shutdown";
+        User = "rabbitmq";
+        Group = "rabbitmq";
+        LogsDirectory = "rabbitmq";
+        WorkingDirectory = cfg.dataDir;
+        Type = "notify";
+        NotifyAccess = "all";
+        UMask = "0027";
+        LimitNOFILE = "100000";
+        Restart = "on-failure";
+        RestartSec = "10";
+        TimeoutStartSec = "3600";
+      };
+
+      preStart = ''
+        ${optionalString (cfg.cookie != "") ''
+            echo -n ${cfg.cookie} > ${cfg.dataDir}/.erlang.cookie
+            chmod 600 ${cfg.dataDir}/.erlang.cookie
+        ''}
+      '';
+    };
+
+  };
+
+}