at 21.11-pre 7.7 kB view raw
1{ system ? builtins.currentSystem, 2 config ? {}, 3 pkgs ? import ../.. { inherit system config; }, 4 enableUnfree ? false 5 # To run the test on the unfree ELK use the folllowing command: 6 # NIXPKGS_ALLOW_UNFREE=1 nix-build nixos/tests/elk.nix -A ELK-6 --arg enableUnfree true 7}: 8 9let 10 esUrl = "http://localhost:9200"; 11 12 mkElkTest = name : elk : 13 import ./make-test-python.nix ({ 14 inherit name; 15 meta = with pkgs.lib.maintainers; { 16 maintainers = [ eelco offline basvandijk ]; 17 }; 18 nodes = { 19 one = 20 { pkgs, lib, ... }: { 21 # Not giving the machine at least 2060MB results in elasticsearch failing with the following error: 22 # 23 # OpenJDK 64-Bit Server VM warning: 24 # INFO: os::commit_memory(0x0000000085330000, 2060255232, 0) 25 # failed; error='Cannot allocate memory' (errno=12) 26 # 27 # There is insufficient memory for the Java Runtime Environment to continue. 28 # Native memory allocation (mmap) failed to map 2060255232 bytes for committing reserved memory. 29 # 30 # When setting this to 2500 I got "Kernel panic - not syncing: Out of 31 # memory: compulsory panic_on_oom is enabled" so lets give it even a 32 # bit more room: 33 virtualisation.memorySize = 3000; 34 35 # For querying JSON objects returned from elasticsearch and kibana. 36 environment.systemPackages = [ pkgs.jq ]; 37 38 services = { 39 40 journalbeat = let lt6 = builtins.compareVersions 41 elk.journalbeat.version "6" < 0; in { 42 enable = true; 43 package = elk.journalbeat; 44 extraConfig = pkgs.lib.mkOptionDefault ('' 45 logging: 46 to_syslog: true 47 level: warning 48 metrics.enabled: false 49 output.elasticsearch: 50 hosts: [ "127.0.0.1:9200" ] 51 ${pkgs.lib.optionalString lt6 "template.enabled: false"} 52 '' + pkgs.lib.optionalString (!lt6) '' 53 journalbeat.inputs: 54 - paths: [] 55 seek: cursor 56 ''); 57 }; 58 59 logstash = { 60 enable = true; 61 package = elk.logstash; 62 inputConfig = '' 63 exec { command => "echo -n flowers" interval => 1 type => "test" } 64 exec { command => "echo -n dragons" interval => 1 type => "test" } 65 ''; 66 filterConfig = '' 67 if [message] =~ /dragons/ { 68 drop {} 69 } 70 ''; 71 outputConfig = '' 72 file { 73 path => "/tmp/logstash.out" 74 codec => line { format => "%{message}" } 75 } 76 elasticsearch { 77 hosts => [ "${esUrl}" ] 78 } 79 ''; 80 }; 81 82 elasticsearch = { 83 enable = true; 84 package = elk.elasticsearch; 85 }; 86 87 kibana = { 88 enable = true; 89 package = elk.kibana; 90 }; 91 92 elasticsearch-curator = { 93 enable = true; 94 actionYAML = '' 95 --- 96 actions: 97 1: 98 action: delete_indices 99 description: >- 100 Delete indices older than 1 second (based on index name), for logstash- 101 prefixed indices. Ignore the error if the filter does not result in an 102 actionable list of indices (ignore_empty_list) and exit cleanly. 103 options: 104 allow_ilm_indices: true 105 ignore_empty_list: True 106 disable_action: False 107 filters: 108 - filtertype: pattern 109 kind: prefix 110 value: logstash- 111 - filtertype: age 112 source: name 113 direction: older 114 timestring: '%Y.%m.%d' 115 unit: seconds 116 unit_count: 1 117 ''; 118 }; 119 }; 120 }; 121 }; 122 123 passthru.elkPackages = elk; 124 testScript = '' 125 import json 126 127 128 def total_hits(message): 129 dictionary = {"query": {"match": {"message": message}}} 130 return ( 131 "curl --silent --show-error '${esUrl}/_search' " 132 + "-H 'Content-Type: application/json' " 133 + "-d '{}' ".format(json.dumps(dictionary)) 134 + "| jq .hits.total" 135 ) 136 137 138 start_all() 139 140 one.wait_for_unit("elasticsearch.service") 141 one.wait_for_open_port(9200) 142 143 # Continue as long as the status is not "red". The status is probably 144 # "yellow" instead of "green" because we are using a single elasticsearch 145 # node which elasticsearch considers risky. 146 # 147 # TODO: extend this test with multiple elasticsearch nodes 148 # and see if the status turns "green". 149 one.wait_until_succeeds( 150 "curl --silent --show-error '${esUrl}/_cluster/health' | jq .status | grep -v red" 151 ) 152 153 with subtest("Perform some simple logstash tests"): 154 one.wait_for_unit("logstash.service") 155 one.wait_until_succeeds("cat /tmp/logstash.out | grep flowers") 156 one.wait_until_succeeds("cat /tmp/logstash.out | grep -v dragons") 157 158 with subtest("Kibana is healthy"): 159 one.wait_for_unit("kibana.service") 160 one.wait_until_succeeds( 161 "curl --silent --show-error 'http://localhost:5601/api/status' | jq .status.overall.state | grep green" 162 ) 163 164 with subtest("Logstash messages arive in elasticsearch"): 165 one.wait_until_succeeds(total_hits("flowers") + " | grep -v 0") 166 one.wait_until_succeeds(total_hits("dragons") + " | grep 0") 167 168 with subtest( 169 "A message logged to the journal is ingested by elasticsearch via journalbeat" 170 ): 171 one.wait_for_unit("journalbeat.service") 172 one.execute("echo 'Supercalifragilisticexpialidocious' | systemd-cat") 173 one.wait_until_succeeds( 174 total_hits("Supercalifragilisticexpialidocious") + " | grep -v 0" 175 ) 176 177 with subtest("Elasticsearch-curator works"): 178 one.systemctl("stop logstash") 179 one.systemctl("start elasticsearch-curator") 180 one.wait_until_succeeds( 181 '! curl --silent --show-error "${esUrl}/_cat/indices" | grep logstash | grep -q ^' 182 ) 183 ''; 184 }) {}; 185in pkgs.lib.mapAttrs mkElkTest { 186 ELK-6 = 187 if enableUnfree 188 then { 189 elasticsearch = pkgs.elasticsearch6; 190 logstash = pkgs.logstash6; 191 kibana = pkgs.kibana6; 192 journalbeat = pkgs.journalbeat6; 193 } 194 else { 195 elasticsearch = pkgs.elasticsearch6-oss; 196 logstash = pkgs.logstash6-oss; 197 kibana = pkgs.kibana6-oss; 198 journalbeat = pkgs.journalbeat6; 199 }; 200 ELK-7 = 201 if enableUnfree 202 then { 203 elasticsearch = pkgs.elasticsearch7; 204 logstash = pkgs.logstash7; 205 kibana = pkgs.kibana7; 206 journalbeat = pkgs.journalbeat7; 207 } 208 else { 209 elasticsearch = pkgs.elasticsearch7-oss; 210 logstash = pkgs.logstash7-oss; 211 kibana = pkgs.kibana7-oss; 212 journalbeat = pkgs.journalbeat7; 213 }; 214}