diff --git a/lib/attrsets.nix b/lib/attrsets.nix index 2300ee9c000..5aad76e75e4 100644 --- a/lib/attrsets.nix +++ b/lib/attrsets.nix @@ -78,6 +78,26 @@ rec { listToAttrs (concatMap (name: let v = set.${name}; in if pred name v then [(nameValuePair name v)] else []) (attrNames set)); + /* Filter an attribute set recursivelly by removing all attributes for + which the given predicate return false. + + Example: + filterAttrsRecursive (n: v: v != null) { foo = { bar = null; }; } + => { foo = {}; } + */ + filterAttrsRecursive = pred: set: + listToAttrs ( + concatMap (name: + let v = set.${name}; in + if pred name v then [ + (nameValuePair name ( + if isAttrs v then filterAttrsRecursive pred v + else v + )) + ] else [] + ) (attrNames set) + ); + /* foldAttrs: apply fold functions to values grouped by key. Eg accumulate values as list: foldAttrs (n: a: [n] ++ a) [] [{ a = 2; } { a = 3; }] => { a = [ 2 3 ]; } diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index 195d22f455c..b0e9ceea10b 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -232,6 +232,7 @@ namecoin = 208; dnschain = 209; #lxd = 210; # unused + kibana = 211; # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399! @@ -442,6 +443,7 @@ namecoin = 208; #dnschain = 209; #unused lxd = 210; # unused + #kibana = 211; # When adding a gid, make sure it doesn't match an existing # uid. Users and groups with the same name should have equal diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 82e0cdc6926..76547a61454 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -365,6 +365,7 @@ ./services/scheduling/fcron.nix ./services/scheduling/marathon.nix ./services/search/elasticsearch.nix + ./services/search/kibana.nix ./services/search/solr.nix ./services/security/clamav.nix ./services/security/fail2ban.nix diff --git a/nixos/modules/services/search/kibana.nix b/nixos/modules/services/search/kibana.nix new file mode 100644 index 00000000000..f47ab8f5586 --- /dev/null +++ b/nixos/modules/services/search/kibana.nix @@ -0,0 +1,168 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.kibana; + + cfgFile = pkgs.writeText "kibana.json" (builtins.toJSON ( + (filterAttrsRecursive (n: v: v != null) ({ + server = { + host = cfg.host; + port = cfg.port; + ssl = { + cert = cfg.cert; + key = cfg.key; + }; + }; + + kibana = { + index = cfg.index; + defaultAppId = cfg.defaultAppId; + }; + + elasticsearch = { + url = cfg.elasticsearch.url; + username = cfg.elasticsearch.username; + password = cfg.elasticsearch.password; + ssl = { + cert = cfg.elasticsearch.cert; + key = cfg.elasticsearch.key; + ca = cfg.elasticsearch.ca; + }; + }; + + logging = { + verbose = cfg.logLevel == "verbose"; + quiet = cfg.logLevel == "quiet"; + silent = cfg.logLevel == "silent"; + dest = "stdout"; + }; + } // cfg.extraConf) + ))); +in { + options.services.kibana = { + enable = mkEnableOption "enable kibana service"; + + host = 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"; + default = "http://localhost:9200"; + type = 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."; + default = null; + type = types.nullOr 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; + }; + }; + + logLevel = mkOption { + description = "Kibana log level"; + default = "normal"; + type = types.enum ["verbose" "normal" "silent" "quiet"]; + }; + + package = mkOption { + description = "Kibana package to use"; + default = 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) { + systemd.services.kibana = { + description = "Kibana Service"; + wantedBy = [ "multi-user.target" ]; + after = [ "network-interfaces.target" "elasticsearch.service" ]; + serviceConfig = { + ExecStart = "${cfg.package}/bin/kibana --config ${cfgFile}"; + User = "kibana"; + WorkingDirectory = cfg.dataDir; + }; + }; + + environment.systemPackages = [ cfg.package ]; + + users.extraUsers = singleton { + name = "kibana"; + uid = config.ids.uids.kibana; + description = "Kibana service user"; + home = cfg.dataDir; + createHome = true; + }; + }; +} diff --git a/pkgs/development/tools/misc/kibana/default.nix b/pkgs/development/tools/misc/kibana/default.nix index dab04861d9f..e1479819c2f 100644 --- a/pkgs/development/tools/misc/kibana/default.nix +++ b/pkgs/development/tools/misc/kibana/default.nix @@ -1,22 +1,24 @@ -{ stdenv, fetchurl, conf ? null }: +{ stdenv, makeWrapper, fetchurl, nodejs, coreutils, which }: with stdenv.lib; stdenv.mkDerivation rec { name = "kibana-${version}"; - version = "3.1.1"; + version = "4.2.0"; src = fetchurl { - url = "https://download.elasticsearch.org/kibana/kibana/${name}.tar.gz"; - sha256 = "195x6zq9x16nlh2akvn6z0kp8qnba4vq90yrysiafgv8dmw34p5b"; + url = "http://download.elastic.co/kibana/kibana-snapshot/kibana-4.2.0-snapshot-linux-x86.tar.gz"; + sha256 = "01v35iwy8y6gpbl0v9gikvbx3zdxkrm60sxann76mkaq2al3pv0i"; }; - phases = ["unpackPhase" "installPhase"]; + buildInputs = [ makeWrapper ]; installPhase = '' - mkdir -p $out - mv * $out/ - ${optionalString (conf != null) "cp ${conf} $out/config.js"} + mkdir -p $out/libexec/kibana $out/bin + mv * $out/libexec/kibana/ + rm -r $out/libexec/kibana/node + makeWrapper $out/libexec/kibana/bin/kibana $out/bin/kibana \ + --prefix PATH : "${nodejs}/bin:${coreutils}/bin:${which}/bin" ''; meta = {