grafana-alloy: don't build the frontend twice
[NixPkgs.git] / nixos / modules / services / search / opensearch.nix
blobf98ca90068df8a79c26cec573344434d35245d8e
1 { config, lib, pkgs, ... }:
3 with lib;
5 let
6   cfg = config.services.opensearch;
8   settingsFormat = pkgs.formats.yaml {};
10   configDir = cfg.dataDir + "/config";
12   usingDefaultDataDir = cfg.dataDir == "/var/lib/opensearch";
13   usingDefaultUserAndGroup = cfg.user == "opensearch" && cfg.group == "opensearch";
15   opensearchYml = settingsFormat.generate "opensearch.yml" cfg.settings;
17   loggingConfigFilename = "log4j2.properties";
18   loggingConfigFile = pkgs.writeTextFile {
19     name = loggingConfigFilename;
20     text = cfg.logging;
21   };
25   options.services.opensearch = {
26     enable = mkEnableOption "OpenSearch";
28     package = lib.mkPackageOption pkgs "OpenSearch" {
29       default = [ "opensearch" ];
30     };
32     settings = lib.mkOption {
33       type = lib.types.submodule {
34         freeformType = settingsFormat.type;
36         options."network.host" = lib.mkOption {
37           type = lib.types.str;
38           default = "127.0.0.1";
39           description = ''
40             Which port this service should listen on.
41           '';
42         };
44         options."cluster.name" = lib.mkOption {
45           type = lib.types.str;
46           default = "opensearch";
47           description = ''
48             The name of the cluster.
49           '';
50         };
52         options."discovery.type" = lib.mkOption {
53           type = lib.types.str;
54           default = "single-node";
55           description = ''
56             The type of discovery to use.
57           '';
58         };
60         options."http.port" = lib.mkOption {
61           type = lib.types.port;
62           default = 9200;
63           description = ''
64             The port to listen on for HTTP traffic.
65           '';
66         };
68         options."transport.port" = lib.mkOption {
69           type = lib.types.port;
70           default = 9300;
71           description = ''
72             The port to listen on for transport traffic.
73           '';
74         };
76         options."plugins.security.disabled" = lib.mkOption {
77           type = lib.types.bool;
78           default = true;
79           description = ''
80             Whether to enable the security plugin,
81             `plugins.security.ssl.transport.keystore_filepath` or
82             `plugins.security.ssl.transport.server.pemcert_filepath` and
83             `plugins.security.ssl.transport.client.pemcert_filepath`
84             must be set for this plugin to be enabled.
85           '';
86         };
87       };
89       default = {};
91       description = ''
92         OpenSearch configuration.
93       '';
94     };
96     logging = lib.mkOption {
97       description = "opensearch logging configuration.";
99       default = ''
100         logger.action.name = org.opensearch.action
101         logger.action.level = info
103         appender.console.type = Console
104         appender.console.name = console
105         appender.console.layout.type = PatternLayout
106         appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c{1.}] %marker%m%n
108         rootLogger.level = info
109         rootLogger.appenderRef.console.ref = console
110       '';
111       type = types.str;
112     };
114     dataDir = lib.mkOption {
115       type = lib.types.path;
116       default = "/var/lib/opensearch";
117       apply = converge (removeSuffix "/");
118       description = ''
119         Data directory for OpenSearch. If you change this, you need to
120         manually create the directory. You also need to create the
121         `opensearch` user and group, or change
122         [](#opt-services.opensearch.user) and
123         [](#opt-services.opensearch.group) to existing ones with
124         access to the directory.
125       '';
126     };
128     user = lib.mkOption {
129       type = lib.types.str;
130       default = "opensearch";
131       description = ''
132         The user OpenSearch runs as. Should be left at default unless
133         you have very specific needs.
134       '';
135     };
137     group = lib.mkOption {
138       type = lib.types.str;
139       default = "opensearch";
140       description = ''
141         The group OpenSearch runs as. Should be left at default unless
142         you have very specific needs.
143       '';
144     };
146     extraCmdLineOptions = lib.mkOption {
147       description = "Extra command line options for the OpenSearch launcher.";
148       default = [ ];
149       type = lib.types.listOf lib.types.str;
150     };
152     extraJavaOptions = lib.mkOption {
153       description = "Extra command line options for Java.";
154       default = [ ];
155       type = lib.types.listOf lib.types.str;
156       example = [ "-Djava.net.preferIPv4Stack=true" ];
157     };
159     restartIfChanged = lib.mkOption {
160       type = lib.types.bool;
161       description = ''
162         Automatically restart the service on config change.
163         This can be set to false to defer restarts on a server or cluster.
164         Please consider the security implications of inadvertently running an older version,
165         and the possibility of unexpected behavior caused by inconsistent versions across a cluster when disabling this option.
166       '';
167       default = true;
168     };
169   };
171   config = mkIf cfg.enable {
172     systemd.services.opensearch = {
173       description = "OpenSearch Daemon";
174       wantedBy = [ "multi-user.target" ];
175       after = [ "network.target" ];
176       path = [ pkgs.inetutils ];
177       inherit (cfg) restartIfChanged;
178       environment = {
179         OPENSEARCH_HOME = cfg.dataDir;
180         OPENSEARCH_JAVA_OPTS = toString cfg.extraJavaOptions;
181         OPENSEARCH_PATH_CONF = configDir;
182       };
183       serviceConfig = {
184         ExecStartPre =
185           let
186             startPreFullPrivileges = ''
187               set -o errexit -o pipefail -o nounset -o errtrace
188               shopt -s inherit_errexit
189             '' + (optionalString (!config.boot.isContainer) ''
190               # Only set vm.max_map_count if lower than ES required minimum
191               # This avoids conflict if configured via boot.kernel.sysctl
192               if [ $(${pkgs.procps}/bin/sysctl -n vm.max_map_count) -lt 262144 ]; then
193                 ${pkgs.procps}/bin/sysctl -w vm.max_map_count=262144
194               fi
195             '');
196             startPreUnprivileged = ''
197               set -o errexit -o pipefail -o nounset -o errtrace
198               shopt -s inherit_errexit
200               # Install plugins
202               # remove plugins directory if it is empty.
203               if [[ -d ${cfg.dataDir}/plugins && -z "$(ls -A ${cfg.dataDir}/plugins)" ]]; then
204                 rm -r "${cfg.dataDir}/plugins"
205               fi
207               ln -sfT "${cfg.package}/plugins" "${cfg.dataDir}/plugins"
208               ln -sfT ${cfg.package}/lib ${cfg.dataDir}/lib
209               ln -sfT ${cfg.package}/modules ${cfg.dataDir}/modules
211               # opensearch needs to create the opensearch.keystore in the config directory
212               # so this directory needs to be writable.
213               mkdir -p ${configDir}
214               chmod 0700 ${configDir}
216               # Note that we copy config files from the nix store instead of symbolically linking them
217               # because otherwise X-Pack Security will raise the following exception:
218               # java.security.AccessControlException:
219               # access denied ("java.io.FilePermission" "/var/lib/opensearch/config/opensearch.yml" "read")
221               rm -f ${configDir}/opensearch.yml
222               cp ${opensearchYml} ${configDir}/opensearch.yml
224               # Make sure the logging configuration for old OpenSearch versions is removed:
225               rm -f "${configDir}/logging.yml"
226               rm -f ${configDir}/${loggingConfigFilename}
227               cp ${loggingConfigFile} ${configDir}/${loggingConfigFilename}
228               mkdir -p ${configDir}/scripts
230               rm -f ${configDir}/jvm.options
231               cp ${cfg.package}/config/jvm.options ${configDir}/jvm.options
233               # redirect jvm logs to the data directory
234               mkdir -p ${cfg.dataDir}/logs
235               chmod 0700 ${cfg.dataDir}/logs
236               sed -e '#logs/gc.log#${cfg.dataDir}/logs/gc.log#' -i ${configDir}/jvm.options
237             '';
238           in [
239             "+${pkgs.writeShellScript "opensearch-start-pre-full-privileges" startPreFullPrivileges}"
240             "${pkgs.writeShellScript "opensearch-start-pre-unprivileged" startPreUnprivileged}"
241           ];
242         ExecStartPost = pkgs.writeShellScript "opensearch-start-post" ''
243           set -o errexit -o pipefail -o nounset -o errtrace
244           shopt -s inherit_errexit
246           # Make sure opensearch is up and running before dependents
247           # are started
248           while ! ${pkgs.curl}/bin/curl -sS -f http://${cfg.settings."network.host"}:${toString cfg.settings."http.port"} 2>/dev/null; do
249             sleep 1
250           done
251         '';
252         ExecStart = "${cfg.package}/bin/opensearch ${toString cfg.extraCmdLineOptions}";
253         User = cfg.user;
254         Group = cfg.group;
255         LimitNOFILE = "1024000";
256         Restart = "always";
257         TimeoutStartSec = "infinity";
258         DynamicUser = usingDefaultUserAndGroup && usingDefaultDataDir;
259       } // (optionalAttrs (usingDefaultDataDir) {
260         StateDirectory = "opensearch";
261         StateDirectoryMode = "0700";
262       });
263     };
265     environment.systemPackages = [ cfg.package ];
266   };