at 24.11-pre 7.2 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 cfg = config.services.elasticsearch; 7 8 es7 = builtins.compareVersions cfg.package.version "7" >= 0; 9 10 esConfig = '' 11 network.host: ${cfg.listenAddress} 12 cluster.name: ${cfg.cluster_name} 13 ${lib.optionalString cfg.single_node "discovery.type: single-node"} 14 ${lib.optionalString (cfg.single_node && es7) "gateway.auto_import_dangling_indices: true"} 15 16 http.port: ${toString cfg.port} 17 transport.port: ${toString cfg.tcp_port} 18 19 ${cfg.extraConf} 20 ''; 21 22 configDir = cfg.dataDir + "/config"; 23 24 elasticsearchYml = pkgs.writeTextFile { 25 name = "elasticsearch.yml"; 26 text = esConfig; 27 }; 28 29 loggingConfigFilename = "log4j2.properties"; 30 loggingConfigFile = pkgs.writeTextFile { 31 name = loggingConfigFilename; 32 text = cfg.logging; 33 }; 34 35 esPlugins = pkgs.buildEnv { 36 name = "elasticsearch-plugins"; 37 paths = cfg.plugins; 38 postBuild = "${pkgs.coreutils}/bin/mkdir -p $out/plugins"; 39 }; 40 41in 42{ 43 44 ###### interface 45 46 options.services.elasticsearch = { 47 enable = mkOption { 48 description = "Whether to enable elasticsearch."; 49 default = false; 50 type = types.bool; 51 }; 52 53 package = mkPackageOption pkgs "elasticsearch" { }; 54 55 listenAddress = mkOption { 56 description = "Elasticsearch listen address."; 57 default = "127.0.0.1"; 58 type = types.str; 59 }; 60 61 port = mkOption { 62 description = "Elasticsearch port to listen for HTTP traffic."; 63 default = 9200; 64 type = types.port; 65 }; 66 67 tcp_port = mkOption { 68 description = "Elasticsearch port for the node to node communication."; 69 default = 9300; 70 type = types.int; 71 }; 72 73 cluster_name = mkOption { 74 description = "Elasticsearch name that identifies your cluster for auto-discovery."; 75 default = "elasticsearch"; 76 type = types.str; 77 }; 78 79 single_node = mkOption { 80 description = "Start a single-node cluster"; 81 default = true; 82 type = types.bool; 83 }; 84 85 extraConf = mkOption { 86 description = "Extra configuration for elasticsearch."; 87 default = ""; 88 type = types.str; 89 example = '' 90 node.name: "elasticsearch" 91 node.master: true 92 node.data: false 93 ''; 94 }; 95 96 logging = mkOption { 97 description = "Elasticsearch logging configuration."; 98 default = '' 99 logger.action.name = org.elasticsearch.action 100 logger.action.level = info 101 102 appender.console.type = Console 103 appender.console.name = console 104 appender.console.layout.type = PatternLayout 105 appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c{1.}] %marker%m%n 106 107 rootLogger.level = info 108 rootLogger.appenderRef.console.ref = console 109 ''; 110 type = types.str; 111 }; 112 113 dataDir = mkOption { 114 type = types.path; 115 default = "/var/lib/elasticsearch"; 116 description = '' 117 Data directory for elasticsearch. 118 ''; 119 }; 120 121 extraCmdLineOptions = mkOption { 122 description = "Extra command line options for the elasticsearch launcher."; 123 default = [ ]; 124 type = types.listOf types.str; 125 }; 126 127 extraJavaOptions = mkOption { 128 description = "Extra command line options for Java."; 129 default = [ ]; 130 type = types.listOf types.str; 131 example = [ "-Djava.net.preferIPv4Stack=true" ]; 132 }; 133 134 plugins = mkOption { 135 description = "Extra elasticsearch plugins"; 136 default = [ ]; 137 type = types.listOf types.package; 138 example = lib.literalExpression "[ pkgs.elasticsearchPlugins.discovery-ec2 ]"; 139 }; 140 141 restartIfChanged = mkOption { 142 type = types.bool; 143 description = '' 144 Automatically restart the service on config change. 145 This can be set to false to defer restarts on a server or cluster. 146 Please consider the security implications of inadvertently running an older version, 147 and the possibility of unexpected behavior caused by inconsistent versions across a cluster when disabling this option. 148 ''; 149 default = true; 150 }; 151 152 }; 153 154 ###### implementation 155 156 config = mkIf cfg.enable { 157 systemd.services.elasticsearch = { 158 description = "Elasticsearch Daemon"; 159 wantedBy = [ "multi-user.target" ]; 160 after = [ "network.target" ]; 161 path = [ pkgs.inetutils ]; 162 inherit (cfg) restartIfChanged; 163 environment = { 164 ES_HOME = cfg.dataDir; 165 ES_JAVA_OPTS = toString cfg.extraJavaOptions; 166 ES_PATH_CONF = configDir; 167 }; 168 serviceConfig = { 169 ExecStart = "${cfg.package}/bin/elasticsearch ${toString cfg.extraCmdLineOptions}"; 170 User = "elasticsearch"; 171 PermissionsStartOnly = true; 172 LimitNOFILE = "1024000"; 173 Restart = "always"; 174 TimeoutStartSec = "infinity"; 175 }; 176 preStart = '' 177 ${optionalString (!config.boot.isContainer) '' 178 # Only set vm.max_map_count if lower than ES required minimum 179 # This avoids conflict if configured via boot.kernel.sysctl 180 if [ `${pkgs.procps}/bin/sysctl -n vm.max_map_count` -lt 262144 ]; then 181 ${pkgs.procps}/bin/sysctl -w vm.max_map_count=262144 182 fi 183 ''} 184 185 mkdir -m 0700 -p ${cfg.dataDir} 186 187 # Install plugins 188 ln -sfT ${esPlugins}/plugins ${cfg.dataDir}/plugins 189 ln -sfT ${cfg.package}/lib ${cfg.dataDir}/lib 190 ln -sfT ${cfg.package}/modules ${cfg.dataDir}/modules 191 192 # elasticsearch needs to create the elasticsearch.keystore in the config directory 193 # so this directory needs to be writable. 194 mkdir -m 0700 -p ${configDir} 195 196 # Note that we copy config files from the nix store instead of symbolically linking them 197 # because otherwise X-Pack Security will raise the following exception: 198 # java.security.AccessControlException: 199 # access denied ("java.io.FilePermission" "/var/lib/elasticsearch/config/elasticsearch.yml" "read") 200 201 cp ${elasticsearchYml} ${configDir}/elasticsearch.yml 202 # Make sure the logging configuration for old elasticsearch versions is removed: 203 rm -f "${configDir}/logging.yml" 204 cp ${loggingConfigFile} ${configDir}/${loggingConfigFilename} 205 mkdir -p ${configDir}/scripts 206 cp ${cfg.package}/config/jvm.options ${configDir}/jvm.options 207 # redirect jvm logs to the data directory 208 mkdir -m 0700 -p ${cfg.dataDir}/logs 209 ${pkgs.sd}/bin/sd 'logs/gc.log' '${cfg.dataDir}/logs/gc.log' ${configDir}/jvm.options \ 210 211 if [ "$(id -u)" = 0 ]; then chown -R elasticsearch:elasticsearch ${cfg.dataDir}; fi 212 ''; 213 postStart = '' 214 # Make sure elasticsearch is up and running before dependents 215 # are started 216 while ! ${pkgs.curl}/bin/curl -sS -f http://${cfg.listenAddress}:${toString cfg.port} 2>/dev/null; do 217 sleep 1 218 done 219 ''; 220 }; 221 222 environment.systemPackages = [ cfg.package ]; 223 224 users = { 225 groups.elasticsearch.gid = config.ids.gids.elasticsearch; 226 users.elasticsearch = { 227 uid = config.ids.uids.elasticsearch; 228 description = "Elasticsearch daemon user"; 229 home = cfg.dataDir; 230 group = "elasticsearch"; 231 }; 232 }; 233 }; 234}