<commit_before>{ config, lib, pkgs, ... }:

with lib;

let
  cfg = config.services.cassandra;
  defaultUser = "cassandra";
  cassandraConfig = flip recursiveUpdate cfg.extraConfig
    ({ commitlog_sync = "batch";
       commitlog_sync_batch_window_in_ms = 2;
       start_native_transport = cfg.allowClients;
       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 cfg.listenAddress == null
        then { listen_interface = cfg.listenInterface; }
        else { listen_address = cfg.listenAddress; }
    ) // (
      if cfg.rpcAddress == null
        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";
      cassandraLogbackConfig = pkgs.writeText "logback.xml" cfg.logbackConfig;
      buildCommand = ''
        mkdir -p "$out"

        echo "$cassandraYaml" > "$out/cassandra.yaml"
        ln -s "$cassandraEnvPkg" "$out/cassandra-env.sh"
        ln -s "$cassandraLogbackConfig" "$out/logback.xml"
      '';
    };
in {
  options.services.cassandra = {
    enable = mkEnableOption ''
      Apache Cassandra – Scalable and highly available database.
    '';
    user = mkOption {
      type = types.str;
      default = defaultUser;
      description = "Run Apache Cassandra under this user.";
    };
    group = mkOption {
      type = types.str;
      default = defaultUser;
      description = "Run Apache Cassandra under this group.";
    };
    homeDir = mkOption {
      type = types.path;
      default = "/var/lib/cassandra";
      description = ''
        Home directory for Apache Cassandra.
      '';
    };
    package = mkOption {
      type = types.package;
      default = pkgs.cassandra;
      defaultText = "pkgs.cassandra";
      example = literalExample "pkgs.cassandra_3_11";
      description = ''
        The Apache Cassandra package to use.
      '';
    };
    jvmOpts = mkOption {
      type = types.listOf types.str;
      default = [];
      description = ''
        Populate the JVM_OPT environment variable.
      '';
    };
    listenAddress = mkOption {
      type = types.nullOr types.str;
      default = "127.0.0.1";
      example = literalExample "null";
      description = ''
        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.
      '';
    };
    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.
      '';
    };
    rpcAddress = mkOption {
      type = types.nullOr types.str;
      default = "127.0.0.1";
      example = literalExample "null";
      description = ''
        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.
      '';
    };
    rpcInterface = mkOption {
      type = types.nullOr types.str;
      default = null;
      example = "eth1";
      description = ''
        Set rpcAddress OR rpcInterface, not both. Interfaces must
        correspond to a single address, IP aliasing is not supported.
      '';
    };
    logbackConfig = mkOption {
      type = types.lines;
      default = ''
        <configuration scan="false">
          <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
              <pattern>%-5level %date{HH:mm:ss,SSS} %msg%n</pattern>
            </encoder>
          </appender>

          <root level="INFO">
            <appender-ref ref="STDOUT" />
          </root>

          <logger name="com.thinkaurelius.thrift" level="ERROR"/>
        </configuration>
      '';
      description = ''
        XML logback configuration for cassandra
      '';
    };
    allowClients = mkOption {
      type = types.bool;
      default = true;
      description = ''
        Enables or disables the native transport server (CQL binary protocol).
        This server uses the same address as the <literal>rpcAddress</literal>,
        but the port it uses is not <literal>rpc_port</literal> but
        <literal>native_transport_port</literal>. See the official Cassandra
        docs for more information on these variables and set them using<commit_msg>nixos/cassandra: Allow setting of seed addresses<commit_after>{ config, lib, pkgs, ... }:

with lib;

let
  cfg = config.services.cassandra;
  defaultUser = "cassandra";
  cassandraConfig = flip recursiveUpdate cfg.extraConfig
    ({ commitlog_sync = "batch";
       commitlog_sync_batch_window_in_ms = 2;
       start_native_transport = cfg.allowClients;
       partitioner = "org.apache.cassandra.dht.Murmur3Partitioner";
       endpoint_snitch = "SimpleSnitch";
       seed_provider =
         [{ class_name = "org.apache.cassandra.locator.SimpleSeedProvider";
            parameters = [ { seeds = concatStringsSep "," cfg.seedAddresses; } ];
         }];
       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 cfg.listenAddress == null
        then { listen_interface = cfg.listenInterface; }
        else { listen_address = cfg.listenAddress; }
    ) // (
      if cfg.rpcAddress == null
        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";
      cassandraLogbackConfig = pkgs.writeText "logback.xml" cfg.logbackConfig;
      buildCommand = ''
        mkdir -p "$out"

        echo "$cassandraYaml" > "$out/cassandra.yaml"
        ln -s "$cassandraEnvPkg" "$out/cassandra-env.sh"
        ln -s "$cassandraLogbackConfig" "$out/logback.xml"
      '';
    };
in {
  options.services.cassandra = {
    enable = mkEnableOption ''
      Apache Cassandra – Scalable and highly available database.
    '';
    user = mkOption {
      type = types.str;
      default = defaultUser;
      description = "Run Apache Cassandra under this user.";
    };
    group = mkOption {
      type = types.str;
      default = defaultUser;
      description = "Run Apache Cassandra under this group.";
    };
    homeDir = mkOption {
      type = types.path;
      default = "/var/lib/cassandra";
      description = ''
        Home directory for Apache Cassandra.
      '';
    };
    package = mkOption {
      type = types.package;
      default = pkgs.cassandra;
      defaultText = "pkgs.cassandra";
      example = literalExample "pkgs.cassandra_3_11";
      description = ''
        The Apache Cassandra package to use.
      '';
    };
    jvmOpts = mkOption {
      type = types.listOf types.str;
      default = [];
      description = ''
        Populate the JVM_OPT environment variable.
      '';
    };
    listenAddress = mkOption {
      type = types.nullOr types.str;
      default = "127.0.0.1";
      example = literalExample "null";
      description = ''
        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.
      '';
    };
    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.
      '';
    };
    rpcAddress = mkOption {
      type = types.nullOr types.str;
      default = "127.0.0.1";
      example = literalExample "null";
      description = ''
        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.
      '';
    };
    rpcInterface = mkOption {
      type = types.nullOr types.str;
      default = null;
      example = "eth1";
      description = ''
        Set rpcAddress OR rpcInterface, not both. Interfaces must
        correspond to a single address, IP aliasing is not supported.
      '';
    };
    logbackConfig = mkOption {
      type = types.lines;
      default = ''
        <configuration scan="false">
          <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
              <pattern>%-5level %date{HH:mm:ss,SSS} %msg%n</pattern>
            </encoder>
          </appender>

          <root level="INFO">
            <appender-ref ref="STDOUT" />
          </root>

          <logger name="com.thinkaurelius.thrift" level="ERROR"/>
        </configuration>
      '';
      description = ''
        XML logback configuration for cassandra
      '';
    };
    seedAddresses = mkOption {
      type = types.listOf types.str;
      default = [ "127.0.0.1" ];
      description = ''
        The addresses of hosts designated as contact points in the cluster. A
        joining node contacts one of the nodes in the seeds list to learn the
        topology of the ring.
        Set to 127.0.0.1 for a single node cluster.
      '';
    };
    allowClients = mkOption {
      type = types.bool;
      default = true;
      description = ''
        Enables or disables the native transport server (CQL binary protocol).
        This server uses the same address as the <literal>rpcAddress</literal>,
        but the port it uses is not <literal>rpc_port</literal> but
        <literal>native_transport_port</literal>. See the official Cassandra
        docs for more information on these variables and set them using
{'fraction_non_alphanumeric': 0.0987258594438657, 'fraction_numerical': 0.0068915778507893264, 'mean_word_length': 2.260188087774295, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 4}, 'pii_count': 13, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3622990', 'n_tokens_mistral': 3591, 'n_tokens_neox': 3540, 'n_words': 1035}