diff options
Diffstat (limited to 'nixpkgs/nixos/modules/services/search')
-rw-r--r-- | nixpkgs/nixos/modules/services/search/elasticsearch-curator.nix | 94 | ||||
-rw-r--r-- | nixpkgs/nixos/modules/services/search/elasticsearch.nix | 208 | ||||
-rw-r--r-- | nixpkgs/nixos/modules/services/search/hound.nix | 125 | ||||
-rw-r--r-- | nixpkgs/nixos/modules/services/search/kibana.nix | 208 | ||||
-rw-r--r-- | nixpkgs/nixos/modules/services/search/solr.nix | 118 |
5 files changed, 753 insertions, 0 deletions
diff --git a/nixpkgs/nixos/modules/services/search/elasticsearch-curator.nix b/nixpkgs/nixos/modules/services/search/elasticsearch-curator.nix new file mode 100644 index 000000000000..9620c3e0b6d4 --- /dev/null +++ b/nixpkgs/nixos/modules/services/search/elasticsearch-curator.nix @@ -0,0 +1,94 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.elasticsearch-curator; + curatorConfig = pkgs.writeTextFile { + name = "config.yaml"; + text = '' + --- + # Remember, leave a key empty if there is no value. None will be a string, + # not a Python "NoneType" + client: + hosts: ${builtins.toJSON cfg.hosts} + port: ${toString cfg.port} + url_prefix: + use_ssl: False + certificate: + client_cert: + client_key: + ssl_no_validate: False + http_auth: + timeout: 30 + master_only: False + logging: + loglevel: INFO + logfile: + logformat: default + blacklist: ['elasticsearch', 'urllib3'] + ''; + }; + curatorAction = pkgs.writeTextFile { + name = "action.yaml"; + text = cfg.actionYAML; + }; +in { + + options.services.elasticsearch-curator = { + + enable = mkEnableOption "elasticsearch curator"; + interval = mkOption { + description = "The frequency to run curator, a systemd.time such as 'hourly'"; + default = "hourly"; + type = types.str; + }; + hosts = mkOption { + description = "a list of elasticsearch hosts to connect to"; + type = types.listOf types.str; + default = ["localhost"]; + }; + port = mkOption { + description = "the port that elasticsearch is listening on"; + type = types.int; + default = 9200; + }; + actionYAML = mkOption { + description = "curator action.yaml file contents, alternatively use curator-cli which takes a simple action command"; + example = '' + --- + actions: + 1: + action: delete_indices + description: >- + Delete indices older than 45 days (based on index name), for logstash- + prefixed indices. Ignore the error if the filter does not result in an + actionable list of indices (ignore_empty_list) and exit cleanly. + options: + ignore_empty_list: True + disable_action: False + filters: + - filtertype: pattern + kind: prefix + value: logstash- + - filtertype: age + source: name + direction: older + timestring: '%Y.%m.%d' + unit: days + unit_count: 45 + ''; + }; + }; + + config = mkIf cfg.enable { + systemd.services.elasticsearch-curator = { + startAt = cfg.interval; + serviceConfig = { + ExecStart = + "${pkgs.elasticsearch-curator}/bin/curator" + + " --config ${curatorConfig} ${curatorAction}"; + }; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/search/elasticsearch.nix b/nixpkgs/nixos/modules/services/search/elasticsearch.nix new file mode 100644 index 000000000000..91d8f544e16b --- /dev/null +++ b/nixpkgs/nixos/modules/services/search/elasticsearch.nix @@ -0,0 +1,208 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.elasticsearch; + + es6 = builtins.compareVersions cfg.package.version "6" >= 0; + + esConfig = '' + network.host: ${cfg.listenAddress} + cluster.name: ${cfg.cluster_name} + + http.port: ${toString cfg.port} + transport.tcp.port: ${toString cfg.tcp_port} + + ${cfg.extraConf} + ''; + + configDir = cfg.dataDir + "/config"; + + elasticsearchYml = pkgs.writeTextFile { + name = "elasticsearch.yml"; + text = esConfig; + }; + + loggingConfigFilename = "log4j2.properties"; + loggingConfigFile = pkgs.writeTextFile { + name = loggingConfigFilename; + text = cfg.logging; + }; + + esPlugins = pkgs.buildEnv { + name = "elasticsearch-plugins"; + paths = cfg.plugins; + postBuild = "${pkgs.coreutils}/bin/mkdir -p $out/plugins"; + }; + +in { + + ###### interface + + options.services.elasticsearch = { + enable = mkOption { + description = "Whether to enable elasticsearch."; + default = false; + type = types.bool; + }; + + package = mkOption { + description = "Elasticsearch package to use."; + default = pkgs.elasticsearch; + defaultText = "pkgs.elasticsearch"; + type = types.package; + }; + + listenAddress = mkOption { + description = "Elasticsearch listen address."; + default = "127.0.0.1"; + type = types.str; + }; + + port = mkOption { + description = "Elasticsearch port to listen for HTTP traffic."; + default = 9200; + type = types.int; + }; + + tcp_port = mkOption { + description = "Elasticsearch port for the node to node communication."; + default = 9300; + type = types.int; + }; + + cluster_name = mkOption { + description = "Elasticsearch name that identifies your cluster for auto-discovery."; + default = "elasticsearch"; + type = types.str; + }; + + extraConf = mkOption { + description = "Extra configuration for elasticsearch."; + default = ""; + type = types.str; + example = '' + node.name: "elasticsearch" + node.master: true + node.data: false + ''; + }; + + logging = mkOption { + description = "Elasticsearch logging configuration."; + default = '' + logger.action.name = org.elasticsearch.action + logger.action.level = info + + appender.console.type = Console + appender.console.name = console + appender.console.layout.type = PatternLayout + appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c{1.}] %marker%m%n + + rootLogger.level = info + rootLogger.appenderRef.console.ref = console + ''; + type = types.str; + }; + + dataDir = mkOption { + type = types.path; + default = "/var/lib/elasticsearch"; + description = '' + Data directory for elasticsearch. + ''; + }; + + extraCmdLineOptions = mkOption { + description = "Extra command line options for the elasticsearch launcher."; + default = []; + type = types.listOf types.str; + }; + + extraJavaOptions = mkOption { + description = "Extra command line options for Java."; + default = []; + type = types.listOf types.str; + example = [ "-Djava.net.preferIPv4Stack=true" ]; + }; + + plugins = mkOption { + description = "Extra elasticsearch plugins"; + default = []; + type = types.listOf types.package; + example = lib.literalExample "[ pkgs.elasticsearchPlugins.discovery-ec2 ]"; + }; + + }; + + ###### implementation + + config = mkIf cfg.enable { + systemd.services.elasticsearch = { + description = "Elasticsearch Daemon"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + path = [ pkgs.inetutils ]; + environment = { + ES_HOME = cfg.dataDir; + ES_JAVA_OPTS = toString ( optional (!es6) [ "-Des.path.conf=${configDir}" ] + ++ cfg.extraJavaOptions); + } // optionalAttrs es6 { + ES_PATH_CONF = configDir; + }; + serviceConfig = { + ExecStart = "${cfg.package}/bin/elasticsearch ${toString cfg.extraCmdLineOptions}"; + User = "elasticsearch"; + PermissionsStartOnly = true; + LimitNOFILE = "1024000"; + }; + preStart = '' + ${optionalString (!config.boot.isContainer) '' + # Only set vm.max_map_count if lower than ES required minimum + # This avoids conflict if configured via boot.kernel.sysctl + if [ `${pkgs.procps}/bin/sysctl -n vm.max_map_count` -lt 262144 ]; then + ${pkgs.procps}/bin/sysctl -w vm.max_map_count=262144 + fi + ''} + + mkdir -m 0700 -p ${cfg.dataDir} + + # Install plugins + ln -sfT ${esPlugins}/plugins ${cfg.dataDir}/plugins + ln -sfT ${cfg.package}/lib ${cfg.dataDir}/lib + ln -sfT ${cfg.package}/modules ${cfg.dataDir}/modules + + # elasticsearch needs to create the elasticsearch.keystore in the config directory + # so this directory needs to be writable. + mkdir -m 0700 -p ${configDir} + + # Note that we copy config files from the nix store instead of symbolically linking them + # because otherwise X-Pack Security will raise the following exception: + # java.security.AccessControlException: + # access denied ("java.io.FilePermission" "/var/lib/elasticsearch/config/elasticsearch.yml" "read") + + cp ${elasticsearchYml} ${configDir}/elasticsearch.yml + # Make sure the logging configuration for old elasticsearch versions is removed: + rm -f "${configDir}/logging.yml" + cp ${loggingConfigFile} ${configDir}/${loggingConfigFilename} + mkdir -p ${configDir}/scripts + ${optionalString es6 "cp ${cfg.package}/config/jvm.options ${configDir}/jvm.options"} + + if [ "$(id -u)" = 0 ]; then chown -R elasticsearch:elasticsearch ${cfg.dataDir}; fi + ''; + }; + + environment.systemPackages = [ cfg.package ]; + + users = { + groups.elasticsearch.gid = config.ids.gids.elasticsearch; + users.elasticsearch = { + uid = config.ids.uids.elasticsearch; + description = "Elasticsearch daemon user"; + home = cfg.dataDir; + group = "elasticsearch"; + }; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/search/hound.nix b/nixpkgs/nixos/modules/services/search/hound.nix new file mode 100644 index 000000000000..7a44489efe61 --- /dev/null +++ b/nixpkgs/nixos/modules/services/search/hound.nix @@ -0,0 +1,125 @@ +{ config, lib, pkgs, ... }: +with lib; +let + cfg = config.services.hound; +in { + options = { + services.hound = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable the hound code search daemon. + ''; + }; + + user = mkOption { + default = "hound"; + type = types.str; + description = '' + User the hound daemon should execute under. + ''; + }; + + group = mkOption { + default = "hound"; + type = types.str; + description = '' + Group the hound daemon should execute under. + ''; + }; + + extraGroups = mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ "dialout" ]; + description = '' + List of extra groups that the "hound" user should be a part of. + ''; + }; + + home = mkOption { + default = "/var/lib/hound"; + type = types.path; + description = '' + The path to use as hound's $HOME. If the default user + "hound" is configured then this is the home of the "hound" + user. + ''; + }; + + package = mkOption { + default = pkgs.hound; + defaultText = "pkgs.hound"; + type = types.package; + description = '' + Package for running hound. + ''; + }; + + config = mkOption { + type = types.str; + description = '' + The full configuration of the Hound daemon. Note the dbpath + should be an absolute path to a writable location on disk. + ''; + example = '' + { + "max-concurrent-indexers" : 2, + "dbpath" : "''${services.hound.home}/data", + "repos" : { + "nixpkgs": { + "url" : "https://www.github.com/NixOS/nixpkgs.git" + } + } + } + ''; + }; + + listen = mkOption { + type = types.str; + default = "0.0.0.0:6080"; + example = "127.0.0.1:6080 or just :6080"; + description = '' + Listen on this IP:port / :port + ''; + }; + }; + }; + + config = mkIf cfg.enable { + users.groups = optionalAttrs (cfg.group == "hound") { + hound.gid = config.ids.gids.hound; + }; + + users.users = optionalAttrs (cfg.user == "hound") { + hound = { + description = "hound code search"; + createHome = true; + home = cfg.home; + group = cfg.group; + extraGroups = cfg.extraGroups; + uid = config.ids.uids.hound; + }; + }; + + systemd.services.hound = { + description = "Hound Code Search"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + + serviceConfig = { + User = cfg.user; + Group = cfg.group; + WorkingDirectory = cfg.home; + ExecStartPre = "${pkgs.git}/bin/git config --global --replace-all http.sslCAinfo /etc/ssl/certs/ca-certificates.crt"; + ExecStart = "${cfg.package}/bin/houndd" + + " -addr ${cfg.listen}" + + " -conf ${pkgs.writeText "hound.json" cfg.config}"; + + }; + path = [ pkgs.git pkgs.mercurial pkgs.openssh ]; + }; + }; + +} diff --git a/nixpkgs/nixos/modules/services/search/kibana.nix b/nixpkgs/nixos/modules/services/search/kibana.nix new file mode 100644 index 000000000000..2beb265ee5d1 --- /dev/null +++ b/nixpkgs/nixos/modules/services/search/kibana.nix @@ -0,0 +1,208 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.kibana; + + ge7 = builtins.compareVersions cfg.package.version "7" >= 0; + lt6_6 = builtins.compareVersions cfg.package.version "6.6" < 0; + + cfgFile = pkgs.writeText "kibana.json" (builtins.toJSON ( + (filterAttrsRecursive (n: v: v != null && v != []) ({ + server.host = cfg.listenAddress; + server.port = cfg.port; + server.ssl.certificate = cfg.cert; + server.ssl.key = cfg.key; + + kibana.index = cfg.index; + kibana.defaultAppId = cfg.defaultAppId; + + elasticsearch.url = cfg.elasticsearch.url; + elasticsearch.hosts = cfg.elasticsearch.hosts; + elasticsearch.username = cfg.elasticsearch.username; + elasticsearch.password = cfg.elasticsearch.password; + + elasticsearch.ssl.certificate = cfg.elasticsearch.cert; + elasticsearch.ssl.key = cfg.elasticsearch.key; + elasticsearch.ssl.certificateAuthorities = cfg.elasticsearch.certificateAuthorities; + } // cfg.extraConf) + ))); + +in { + options.services.kibana = { + enable = mkEnableOption "kibana service"; + + listenAddress = mkOption { + description = "Kibana listening host"; + default = "127.0.0.1"; + type = types.str; + }; + + port = mkOption { + description = "Kibana listening port"; + default = 5601; + type = types.int; + }; + + cert = mkOption { + description = "Kibana ssl certificate."; + default = null; + type = types.nullOr types.path; + }; + + key = mkOption { + description = "Kibana ssl key."; + default = null; + type = types.nullOr types.path; + }; + + index = mkOption { + description = "Elasticsearch index to use for saving kibana config."; + default = ".kibana"; + type = types.str; + }; + + defaultAppId = mkOption { + description = "Elasticsearch default application id."; + default = "discover"; + type = types.str; + }; + + elasticsearch = { + url = mkOption { + description = '' + Elasticsearch url. + + Defaults to <literal>"http://localhost:9200"</literal>. + + Don't set this when using Kibana >= 7.0.0 because it will result in a + configuration error. Use <option>services.kibana.elasticsearch.hosts</option> + instead. + ''; + default = null; + type = types.nullOr types.str; + }; + + hosts = mkOption { + description = '' + The URLs of the Elasticsearch instances to use for all your queries. + All nodes listed here must be on the same cluster. + + Defaults to <literal>[ "http://localhost:9200" ]</literal>. + + This option is only valid when using kibana >= 6.6. + ''; + default = null; + type = types.nullOr (types.listOf types.str); + }; + + username = mkOption { + description = "Username for elasticsearch basic auth."; + default = null; + type = types.nullOr types.str; + }; + + password = mkOption { + description = "Password for elasticsearch basic auth."; + default = null; + type = types.nullOr types.str; + }; + + ca = mkOption { + description = '' + CA file to auth against elasticsearch. + + It's recommended to use the <option>certificateAuthorities</option> option + when using kibana-5.4 or newer. + ''; + default = null; + type = types.nullOr types.path; + }; + + certificateAuthorities = mkOption { + description = '' + CA files to auth against elasticsearch. + + Please use the <option>ca</option> option when using kibana < 5.4 + because those old versions don't support setting multiple CA's. + + This defaults to the singleton list [ca] when the <option>ca</option> option is defined. + ''; + default = if cfg.elasticsearch.ca == null then [] else [ca]; + type = types.listOf types.path; + }; + + cert = mkOption { + description = "Certificate file to auth against elasticsearch."; + default = null; + type = types.nullOr types.path; + }; + + key = mkOption { + description = "Key file to auth against elasticsearch."; + default = null; + type = types.nullOr types.path; + }; + }; + + package = mkOption { + description = "Kibana package to use"; + default = pkgs.kibana; + defaultText = "pkgs.kibana"; + example = "pkgs.kibana"; + type = types.package; + }; + + dataDir = mkOption { + description = "Kibana data directory"; + default = "/var/lib/kibana"; + type = types.path; + }; + + extraConf = mkOption { + description = "Kibana extra configuration"; + default = {}; + type = types.attrs; + }; + }; + + config = mkIf (cfg.enable) { + assertions = [ + { + assertion = ge7 -> cfg.elasticsearch.url == null; + message = + "The option services.kibana.elasticsearch.url has been removed when using kibana >= 7.0.0. " + + "Please use option services.kibana.elasticsearch.hosts instead."; + } + { + assertion = lt6_6 -> cfg.elasticsearch.hosts == null; + message = + "The option services.kibana.elasticsearch.hosts is only valid for kibana >= 6.6."; + } + ]; + systemd.services.kibana = { + description = "Kibana Service"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" "elasticsearch.service" ]; + environment = { BABEL_CACHE_PATH = "${cfg.dataDir}/.babelcache.json"; }; + serviceConfig = { + ExecStart = + "${cfg.package}/bin/kibana" + + " --config ${cfgFile}" + + " --path.data ${cfg.dataDir}"; + User = "kibana"; + WorkingDirectory = cfg.dataDir; + }; + }; + + environment.systemPackages = [ cfg.package ]; + + users.users.kibana = { + uid = config.ids.uids.kibana; + description = "Kibana service user"; + home = cfg.dataDir; + createHome = true; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/search/solr.nix b/nixpkgs/nixos/modules/services/search/solr.nix new file mode 100644 index 000000000000..b2176225493e --- /dev/null +++ b/nixpkgs/nixos/modules/services/search/solr.nix @@ -0,0 +1,118 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.solr; + +in + +{ + options = { + services.solr = { + enable = mkEnableOption "Solr"; + + # default to the 8.x series not forcing major version upgrade of those on the 7.x series + package = mkOption { + type = types.package; + default = if versionAtLeast config.system.stateVersion "19.09" + then pkgs.solr_8 + else pkgs.solr_7 + ; + defaultText = "pkgs.solr"; + description = '' + Which Solr package to use. This defaults to version 7.x if + <literal>system.stateVersion < 19.09</literal> and version 8.x + otherwise. + ''; + }; + + port = mkOption { + type = types.int; + default = 8983; + description = "Port on which Solr is ran."; + }; + + stateDir = mkOption { + type = types.path; + default = "/var/lib/solr"; + description = "The solr home directory containing config, data, and logging files."; + }; + + extraJavaOptions = mkOption { + type = types.listOf types.str; + default = []; + description = "Extra command line options given to the java process running Solr."; + }; + + user = mkOption { + type = types.str; + default = "solr"; + description = "User under which Solr is ran."; + }; + + group = mkOption { + type = types.str; + default = "solr"; + description = "Group under which Solr is ran."; + }; + }; + }; + + config = mkIf cfg.enable { + + environment.systemPackages = [ cfg.package ]; + + systemd.services.solr = { + after = [ "network.target" "remote-fs.target" "nss-lookup.target" "systemd-journald-dev-log.socket" ]; + wantedBy = [ "multi-user.target" ]; + + environment = { + SOLR_HOME = "${cfg.stateDir}/data"; + LOG4J_PROPS = "${cfg.stateDir}/log4j2.xml"; + SOLR_LOGS_DIR = "${cfg.stateDir}/logs"; + SOLR_PORT = "${toString cfg.port}"; + }; + path = with pkgs; [ + gawk + procps + ]; + preStart = '' + mkdir -p "${cfg.stateDir}/data"; + mkdir -p "${cfg.stateDir}/logs"; + + if ! test -e "${cfg.stateDir}/data/solr.xml"; then + install -D -m0640 ${cfg.package}/server/solr/solr.xml "${cfg.stateDir}/data/solr.xml" + install -D -m0640 ${cfg.package}/server/solr/zoo.cfg "${cfg.stateDir}/data/zoo.cfg" + fi + + if ! test -e "${cfg.stateDir}/log4j2.xml"; then + install -D -m0640 ${cfg.package}/server/resources/log4j2.xml "${cfg.stateDir}/log4j2.xml" + fi + ''; + + serviceConfig = { + User = cfg.user; + Group = cfg.group; + ExecStart="${cfg.package}/bin/solr start -f -a \"${concatStringsSep " " cfg.extraJavaOptions}\""; + ExecStop="${cfg.package}/bin/solr stop"; + }; + }; + + users.users = optionalAttrs (cfg.user == "solr") { + solr = { + group = cfg.group; + home = cfg.stateDir; + createHome = true; + uid = config.ids.uids.solr; + }; + }; + + users.groups = optionalAttrs (cfg.group == "solr") { + solr.gid = config.ids.gids.solr; + }; + + }; + +} |