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