1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6 cfg = config.services.elasticsearch;
7
8 esConfig = ''
9 network.host: ${cfg.host}
10 network.port: ${toString cfg.port}
11 network.tcp.port: ${toString cfg.tcp_port}
12 cluster.name: ${cfg.cluster_name}
13 ${cfg.extraConf}
14 '';
15
16 configDir = pkgs.buildEnv {
17 name = "elasticsearch-config";
18 paths = [
19 (pkgs.writeTextDir "elasticsearch.yml" esConfig)
20 (pkgs.writeTextDir "logging.yml" cfg.logging)
21 ];
22 };
23
24 esPlugins = pkgs.buildEnv {
25 name = "elasticsearch-plugins";
26 paths = cfg.plugins;
27 };
28
29in {
30
31 ###### interface
32
33 options.services.elasticsearch = {
34 enable = mkOption {
35 description = "Whether to enable elasticsearch.";
36 default = false;
37 type = types.bool;
38 };
39
40 package = mkOption {
41 description = "Elasticsearch package to use.";
42 default = pkgs.elasticsearch;
43 type = types.package;
44 };
45
46 host = mkOption {
47 description = "Elasticsearch listen address.";
48 default = "127.0.0.1";
49 type = types.str;
50 };
51
52 port = mkOption {
53 description = "Elasticsearch port to listen for HTTP traffic.";
54 default = 9200;
55 type = types.int;
56 };
57
58 tcp_port = mkOption {
59 description = "Elasticsearch port for the node to node communication.";
60 default = 9300;
61 type = types.int;
62 };
63
64 cluster_name = mkOption {
65 description = "Elasticsearch name that identifies your cluster for auto-discovery.";
66 default = "elasticsearch";
67 type = types.str;
68 };
69
70 extraConf = mkOption {
71 description = "Extra configuration for elasticsearch.";
72 default = "";
73 type = types.str;
74 example = ''
75 node.name: "elasticsearch"
76 node.master: true
77 node.data: false
78 index.number_of_shards: 5
79 index.number_of_replicas: 1
80 '';
81 };
82
83 logging = mkOption {
84 description = "Elasticsearch logging configuration.";
85 default = ''
86 rootLogger: INFO, console
87 logger:
88 action: INFO
89 com.amazonaws: WARN
90 appender:
91 console:
92 type: console
93 layout:
94 type: consolePattern
95 conversionPattern: "[%d{ISO8601}][%-5p][%-25c] %m%n"
96 '';
97 type = types.str;
98 };
99
100 dataDir = mkOption {
101 type = types.path;
102 default = "/var/lib/elasticsearch";
103 description = ''
104 Data directory for elasticsearch.
105 '';
106 };
107
108 extraCmdLineOptions = mkOption {
109 description = "Extra command line options for the elasticsearch launcher.";
110 default = [];
111 type = types.listOf types.str;
112 example = [ "-Djava.net.preferIPv4Stack=true" ];
113 };
114
115 plugins = mkOption {
116 description = "Extra elasticsearch plugins";
117 default = [];
118 type = types.listOf types.package;
119 };
120
121 };
122
123 ###### implementation
124
125 config = mkIf cfg.enable {
126 systemd.services.elasticsearch = {
127 description = "Elasticsearch Daemon";
128 wantedBy = [ "multi-user.target" ];
129 after = [ "network-interfaces.target" ];
130 environment = { ES_HOME = cfg.dataDir; };
131 serviceConfig = {
132 ExecStart = "${cfg.package}/bin/elasticsearch -Des.path.conf=${configDir} ${toString cfg.extraCmdLineOptions}";
133 User = "elasticsearch";
134 PermissionsStartOnly = true;
135 };
136 preStart = ''
137 mkdir -m 0700 -p ${cfg.dataDir}
138 if [ "$(id -u)" = 0 ]; then chown -R elasticsearch ${cfg.dataDir}; fi
139
140 # Install plugins
141 rm ${cfg.dataDir}/plugins || true
142 ln -s ${esPlugins}/plugins ${cfg.dataDir}/plugins
143 '';
144 postStart = mkBefore ''
145 until ${pkgs.curl}/bin/curl -s -o /dev/null ${cfg.host}:${toString cfg.port}; do
146 sleep 1
147 done
148 '';
149 };
150
151 environment.systemPackages = [ cfg.package ];
152
153 users.extraUsers = singleton {
154 name = "elasticsearch";
155 uid = config.ids.uids.elasticsearch;
156 description = "Elasticsearch daemon user";
157 home = cfg.dataDir;
158 };
159 };
160}