aboutsummaryrefslogtreecommitdiff
path: root/modules/apps/cassandra
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2017-06-12 16:29:07 +0300
committerIgor Pashev <pashev.igor@gmail.com>2017-06-12 16:37:54 +0300
commiteedce5a106721e0d1e0275ba28af0f5ee0a5da62 (patch)
tree50e1b7a26486062515ce884dd6d8553bfd4f99f9 /modules/apps/cassandra
parent85ea46e3b26ce572d27fb4fbaea57ab06a7a845d (diff)
downloadnixsap-eedce5a106721e0d1e0275ba28af0f5ee0a5da62.tar.gz
Apache Cassandra: init
Add the `nixsap.apps.cassandra` application and Apache Cassandra 3.11 package along with Hyperic Sigar. The application runs in single node mode just fine. Clustering is not tested yet. This is PoC on Java applications. A Java application should comprise: 1. JRE 2. Class path 3. Library path A Java "package" should include all jar/classes/libraries needed to run the application. Using symbolic links to pull in dependencies is fine. This is much similar to nix "environments". Apache Cassandra is the first example of this approach. Using $out/share/java/ and $out/lib/jni is to help building such environments (also with nix-env).
Diffstat (limited to 'modules/apps/cassandra')
-rw-r--r--modules/apps/cassandra/default.nix110
-rw-r--r--modules/apps/cassandra/instance.nix243
2 files changed, 353 insertions, 0 deletions
diff --git a/modules/apps/cassandra/default.nix b/modules/apps/cassandra/default.nix
new file mode 100644
index 0000000..953acb3
--- /dev/null
+++ b/modules/apps/cassandra/default.nix
@@ -0,0 +1,110 @@
+{ config, lib, pkgs, ... }:
+
+let
+
+ inherit (builtins)
+ match ;
+
+ inherit (lib)
+ concatMapStringsSep concatStringsSep filterAttrs flatten foldAttrs foldl
+ mapAttrsToList mkOption ;
+
+ inherit (lib.types)
+ attrsOf submodule ;
+
+ explicit = filterAttrs (n: v: n != "_module" && v != null);
+ concatMapAttrsSep = s: f: attrs: concatStringsSep s (mapAttrsToList f attrs);
+
+ instances = explicit config.nixsap.apps.cassandra;
+ users = mapAttrsToList (_: i: i.user) instances;
+
+ keyrings =
+ let
+ ik = mapAttrsToList (n: i: { "${i.user}" = []; } ) instances;
+ in foldAttrs (l: r: l ++ r) [] ik;
+
+ mkService = name: cfg:
+ let
+
+ tmpdir = "${cfg.home}/tmp";
+ cp = concatStringsSep ":" cfg.classpath;
+
+ isDir = d: _: match ".*_director(y|ies)$" d != null;
+ directories = [ cfg.home ]
+ ++ flatten (mapAttrsToList (_: d: d) (filterAttrs isDir (explicit cfg.parameters)));
+
+ directories_sh = concatMapStringsSep " " (d: "'${d}'") directories;
+
+
+ start = pkgs.writeBashScriptBin "cassandra-${name}" ''
+ set -euo pipefail
+ umask 0027
+ export HOME='${cfg.home}'
+
+ rm -rf -- '${cfg.jre.properties.java.io.tmpdir}'
+ mkdir -p -- '${cfg.jre.properties.java.io.tmpdir}'
+
+ exec ${cfg.jre.package}/bin/java \
+ -Dcassandra.config='${cfg.jre.properties.cassandra.config}' \
+ -Djava.io.tmpdir='${cfg.jre.properties.java.io.tmpdir}' \
+ -Djava.library.path='${concatStringsSep ":" cfg.jre.properties.java.library.path}' \
+ -cp '${cp}' \
+ org.apache.cassandra.service.CassandraDaemon
+
+ '';
+
+ in {
+ "cassandra-${name}" = {
+ description = "Cassandra (${name}) distributed NoSQL database";
+ wantedBy = [ "multi-user.target" ];
+ after = [ "keys.target" "network.target" "local-fs.target" ];
+ preStart = ''
+ mkdir -p -- ${directories_sh}
+
+ find ${directories_sh} -not -type l \( \
+ -not -user '${cfg.user}' \
+ -or -not -group '${cfg.user}' \
+ -or \( -type d -not -perm -u=wrx,g=rx \) \
+ -or \( -type f -not -perm -u=rw,g=r \) \
+ \) \
+ -exec chown -c -- '${cfg.user}:${cfg.user}' {} + \
+ -exec chmod -c -- u=rwX,g=rX,o= {} +
+
+ '';
+
+ unitConfig = {
+ # XXX It can be running long before fail:
+ StartLimitBurst = 3;
+ StartLimitIntervalSec = 60;
+ };
+
+ serviceConfig = {
+ ExecStart = "${start}/bin/cassandra-${name}";
+ KillMode = "mixed";
+ PermissionsStartOnly = true;
+ Restart = "always";
+ TimeoutSec = 0;
+ User = cfg.user;
+ LimitAS = "infinity";
+ LimitMEMLOCK = "infinity";
+ LimitNOFILE = 10000;
+ LimitNPROC = 32768;
+ };
+ };
+ };
+
+in {
+
+ options.nixsap.apps.cassandra = mkOption {
+ description = "Cassandra instances";
+ default = {};
+ type = attrsOf (submodule (import ./instance.nix pkgs));
+ };
+
+ config = {
+ systemd.services = foldl (a: b: a//b) {} (mapAttrsToList mkService instances);
+ nixsap.deployment.keyrings = keyrings;
+ nixsap.system.users.daemons = users;
+ };
+
+}
diff --git a/modules/apps/cassandra/instance.nix b/modules/apps/cassandra/instance.nix
new file mode 100644
index 0000000..ab6a9d3
--- /dev/null
+++ b/modules/apps/cassandra/instance.nix
@@ -0,0 +1,243 @@
+pkgs:
+{ config, lib, name, ... }:
+
+let
+
+ inherit (builtins)
+ toJSON ;
+
+ inherit (lib)
+ filterAttrs mapAttrs mapAttrsToList mkOption ;
+
+ inherit (lib.types)
+ attrsOf bool enum int listOf nullOr package path str ;
+
+ explicit = filterAttrs (n: v: n != "_module" && v != null);
+
+ default = d: t: mkOption { type = t; default = d; };
+ optional = t: mkOption { type = nullOr t; default = null; };
+ readonly = d: t: mkOption { type = nullOr t; default = d; readOnly = true; };
+
+ params = config.parameters;
+
+ entries =
+ let
+ transform = n: v:
+ if n == "seed_provider" then
+ mapAttrsToList (p: o:
+ { class_name = p;
+ parameters = mapAttrsToList (a: b: { ${a} = b; }) o;
+ }
+ ) v
+ else v;
+ in mapAttrs transform (explicit params);
+
+ configFile = pkgs.runCommand "cassandra-${name}.yml" {} ''
+ ${pkgs.haskellPackages.yaml}/bin/json2yaml \
+ ${pkgs.writeText "cassandra-${name}.json" (toJSON entries)} > "$out"
+ '';
+
+
+in {
+ options = {
+
+ package = mkOption {
+ description = ''
+ The Cassandra package. This is a convenient way to set Java class
+ path and library path. The package should include `$out/share/java`
+ directory with all jars required to run Cassandra and `$out/lib/jni`
+ with all runtime libraries.
+ '';
+ default = pkgs.cassandra3;
+ type = package;
+ };
+
+ jre = {
+ package = mkOption {
+ description = "Java runtime package";
+ default = pkgs.jre8;
+ type = package;
+ };
+
+ # TODO: this should be generalized, see default.nix
+ properties = {
+ cassandra.config = readonly "file://${configFile}" str;
+ java.io.tmpdir = readonly "${config.home}/tmp" path;
+ java.library.path = default [ "${config.package}/lib/jni" ] (listOf path);
+ };
+ };
+
+ classpath = mkOption {
+ description = "Cassandra's Java class path";
+ type = listOf path;
+ default = [ "${config.package}/share/java/*" ];
+ };
+
+ user = mkOption {
+ description = "User to run as";
+ default = "cassandra-${name}";
+ type = str;
+ };
+
+ home = mkOption {
+ description = "Cassandra home directory";
+ default = "/cassandra/${name}";
+ type = path;
+ };
+
+ # XXX "Default" is missleading in Cassandra docs.
+ # XXX Parameters shall be defined in config file.
+ parameters = {
+ seed_provider = mkOption {
+ description = "Seed providers with paramaters";
+ type = attrsOf (attrsOf str);
+ default = {
+ "org.apache.cassandra.locator.SimpleSeedProvider" = {
+ seeds = "127.0.0.1";
+ };
+ };
+ };
+
+ # TBD: back_pressure_strategy
+ # TBD: client_encryption_options
+ # TBD: commitlog_compression
+ # TBD: hints_compression
+ # TBD: otc_coalescing_strategy
+ # TBD: seed_provider
+ # TBD: server_encryption_options
+ # TBD: transparent_data_encryption_options
+ allocate_tokens_for_keyspace = optional str;
+ authenticator = optional str;
+ authorizer = optional str;
+ auto_snapshot = optional bool;
+ back_pressure_enabled = optional bool;
+ batch_size_fail_threshold_in_kb = optional int;
+ batch_size_warn_threshold_in_kb = optional int;
+ batchlog_replay_throttle_in_kb = optional int;
+ broadcast_address = optional str;
+ broadcast_rpc_address = optional str;
+ buffer_pool_use_heap_if_exhausted = optional bool;
+ cas_contention_timeout_in_ms = optional int;
+ cdc_enabled = optional bool;
+ cdc_free_space_check_interval_ms = optional int;
+ cdc_raw_directory = readonly "${config.home}/cdc_raw" path;
+ cdc_total_space_in_mb = optional int;
+ cluster_name = default name str;
+ column_index_cache_size_in_kb = optional int;
+ column_index_size_in_kb = optional int;
+ commit_failure_policy = optional (enum ["die" "stop" "stop_commit" "ignore"]);
+ commitlog_directory = readonly "${config.home}/commitlog" path;
+ commitlog_segment_size_in_mb = optional int;
+ commitlog_sync = default "periodic" (enum ["periodic" "batch"]);
+ commitlog_sync_batch_window_in_ms = optional int;
+ commitlog_sync_period_in_ms = default 10000 int;
+ commitlog_total_space_in_mb = optional int;
+ compaction_large_partition_warning_threshold_mb = optional int;
+ compaction_throughput_mb_per_sec = optional int;
+ concurrent_compactors = optional int;
+ concurrent_counter_writes = optional int;
+ concurrent_materialized_view_writes = optional int;
+ concurrent_reads = optional int;
+ concurrent_writes = optional int;
+ counter_cache_keys_to_save = optional int;
+ counter_cache_save_period = optional int;
+ counter_cache_size_in_mb = optional int;
+ counter_write_request_timeout_in_ms = optional int;
+ credentials_update_interval_in_ms = optional int;
+ credentials_validity_in_ms = optional int;
+ cross_node_timeout = optional bool;
+ data_file_directories = readonly ["${config.home}/data"] (listOf path);
+ disk_failure_policy = optional (enum ["die" "stop_paranoid" "stop" "best_effort" "ignore"]);
+ disk_optimization_strategy = optional (enum ["ssd" "spinning"]);
+ dynamic_snitch_reset_interval_in_ms = optional int;
+ dynamic_snitch_update_interval_in_ms = optional int;
+ enable_scripted_user_defined_functions = optional bool;
+ enable_user_defined_functions = optional bool;
+ endpoint_snitch = default "SimpleSnitch" str;
+ file_cache_size_in_mb = optional int;
+ gc_log_threshold_in_ms = optional int;
+ gc_warn_threshold_in_ms = optional int;
+ hinted_handoff_disabled_datacenters = optional (listOf str);
+ hinted_handoff_enabled = optional bool;
+ hinted_handoff_throttle_in_kb = optional int;
+ hints_directory = readonly "${config.home}/hints" path;
+ hints_flush_period_in_ms = optional int;
+ ideal_consistency_level = optional str;
+ incremental_backups = optional bool;
+ index_summary_capacity_in_mb = optional int;
+ index_summary_resize_interval_in_minutes = optional int;
+ initial_token = optional str;
+ inter_dc_stream_throughput_outbound_megabits_per_sec = optional int;
+ inter_dc_tcp_nodelay = optional bool;
+ internode_authenticator = optional str;
+ internode_compression = optional (enum ["all" "dc" "none"]);
+ internode_recv_buff_size_in_bytes = optional int;
+ internode_send_buff_size_in_bytes = optional int;
+ key_cache_keys_to_save = optional int;
+ key_cache_save_period = optional int;
+ key_cache_size_in_mb = optional int;
+ listen_address = default "localhost" str; # TODO: Set listen_address OR listen_interface, not both.
+ listen_interface = optional str; # TODO: Set listen_address OR listen_interface, not both.
+ listen_interface_prefer_ipv6 = optional bool;
+ listen_on_broadcast_address = optional bool;
+ max_hint_window_in_ms = optional int;
+ max_hints_delivery_threads = optional int;
+ max_hints_file_size_in_mb = optional int;
+ max_value_size_in_mb = optional int;
+ memtable_allocation_type = optional (enum ["heap_buffers" "offheap_buffers" "offheap_objects"]);
+ memtable_flush_writers = optional int;
+ memtable_heap_space_in_mb = optional int;
+ memtable_offheap_space_in_mb = optional int;
+ native_transport_max_concurrent_connections = optional int;
+ native_transport_max_concurrent_connections_per_ip = optional int;
+ native_transport_max_frame_size_in_mb = optional int;
+ native_transport_max_threads = optional int;
+ native_transport_port = optional int;
+ native_transport_port_ssl = optional int;
+ num_tokens = optional int;
+ otc_backlog_expiration_interval_ms = optional int;
+ otc_coalescing_enough_coalesced_messages = optional int;
+ otc_coalescing_window_us = optional int;
+ partitioner = default "org.apache.cassandra.dht.Murmur3Partitioner" str;
+ permissions_update_interval_in_ms = optional int;
+ permissions_validity_in_ms = optional int;
+ phi_convict_threshold = optional int;
+ prepared_statements_cache_size_mb = optional int;
+ range_request_timeout_in_ms = optional int;
+ read_request_timeout_in_ms = optional int;
+ request_timeout_in_ms = optional int;
+ role_manager = optional str;
+ roles_update_interval_in_ms = optional int;
+ roles_validity_in_ms = optional int;
+ row_cache_class_name = optional str;
+ row_cache_keys_to_save = optional int;
+ row_cache_save_period = optional int;
+ row_cache_size_in_mb = optional int;
+ rpc_address = optional str; # TODO: Set rpc_address OR rpc_interface, not both.
+ rpc_interface = optional str; # TODO: Set rpc_address OR rpc_interface, not both.
+ rpc_interface_prefer_ipv6 = optional bool;
+ rpc_keepalive = optional bool;
+ saved_caches_directory = readonly "${config.home}/saved_caches" path;
+ slow_query_log_timeout_in_ms = optional int;
+ snapshot_before_compaction = optional bool;
+ ssl_storage_port = default 7001 int;
+ sstable_preemptive_open_interval_in_mb = optional int;
+ start_native_transport = optional bool;
+ storage_port = default 7000 int;
+ stream_throughput_outbound_megabits_per_sec = optional int;
+ streaming_connections_per_host = optional int;
+ streaming_keep_alive_period_in_secs = optional int;
+ tombstone_failure_threshold = optional int;
+ tombstone_warn_threshold = optional int;
+ tracetype_query_ttl = optional int;
+ tracetype_repair_ttl = optional int;
+ trickle_fsync = optional bool;
+ trickle_fsync_interval_in_kb = optional int;
+ truncate_request_timeout_in_ms = optional int;
+ unlogged_batch_across_partitions_warn_threshold = optional int;
+ windows_timer_interval = optional int;
+ write_request_timeout_in_ms = optional int;
+ };
+ };
+}
+