210 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
			
		
		
	
	
			210 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
| { system ? builtins.currentSystem,
 | |
|   config ? {},
 | |
|   pkgs ? import ../.. { inherit system config; },
 | |
|   enableUnfree ? false
 | |
|   # To run the test on the unfree ELK use the folllowing command:
 | |
|   # NIXPKGS_ALLOW_UNFREE=1 nix-build nixos/tests/elk.nix -A ELK-6 --arg enableUnfree true
 | |
| }:
 | |
| 
 | |
| with import ../lib/testing.nix { inherit system pkgs; };
 | |
| with pkgs.lib;
 | |
| 
 | |
| let
 | |
|   esUrl = "http://localhost:9200";
 | |
| 
 | |
|   totalHits = message :
 | |
|     "curl --silent --show-error '${esUrl}/_search' -H 'Content-Type: application/json' " +
 | |
|     ''-d '{\"query\" : { \"match\" : { \"message\" : \"${message}\"}}}' '' +
 | |
|     "| jq .hits.total";
 | |
| 
 | |
|   mkElkTest = name : elk :
 | |
|    let elasticsearchGe7 = builtins.compareVersions elk.elasticsearch.version "7" >= 0;
 | |
|    in makeTest {
 | |
|     inherit name;
 | |
|     meta = with pkgs.stdenv.lib.maintainers; {
 | |
|       maintainers = [ eelco offline basvandijk ];
 | |
|     };
 | |
|     nodes = {
 | |
|       one =
 | |
|         { pkgs, lib, ... }: {
 | |
|             # Not giving the machine at least 2060MB results in elasticsearch failing with the following error:
 | |
|             #
 | |
|             #   OpenJDK 64-Bit Server VM warning:
 | |
|             #     INFO: os::commit_memory(0x0000000085330000, 2060255232, 0)
 | |
|             #     failed; error='Cannot allocate memory' (errno=12)
 | |
|             #
 | |
|             #   There is insufficient memory for the Java Runtime Environment to continue.
 | |
|             #   Native memory allocation (mmap) failed to map 2060255232 bytes for committing reserved memory.
 | |
|             #
 | |
|             # When setting this to 2500 I got "Kernel panic - not syncing: Out of
 | |
|             # memory: compulsory panic_on_oom is enabled" so lets give it even a
 | |
|             # bit more room:
 | |
|             virtualisation.memorySize = 3000;
 | |
| 
 | |
|             # For querying JSON objects returned from elasticsearch and kibana.
 | |
|             environment.systemPackages = [ pkgs.jq ];
 | |
| 
 | |
|             services = {
 | |
| 
 | |
|               journalbeat = let lt6 = builtins.compareVersions
 | |
|                                         elk.journalbeat.version "6" < 0; in {
 | |
|                 enable = true;
 | |
|                 package = elk.journalbeat;
 | |
|                 extraConfig = mkOptionDefault (''
 | |
|                   logging:
 | |
|                     to_syslog: true
 | |
|                     level: warning
 | |
|                     metrics.enabled: false
 | |
|                   output.elasticsearch:
 | |
|                     hosts: [ "127.0.0.1:9200" ]
 | |
|                     ${optionalString lt6 "template.enabled: false"}
 | |
|                 '' + optionalString (!lt6) ''
 | |
|                   journalbeat.inputs:
 | |
|                   - paths: []
 | |
|                     seek: cursor
 | |
|                 '');
 | |
|               };
 | |
| 
 | |
|               logstash = {
 | |
|                 enable = true;
 | |
|                 package = elk.logstash;
 | |
|                 inputConfig = ''
 | |
|                   exec { command => "echo -n flowers" interval => 1 type => "test" }
 | |
|                   exec { command => "echo -n dragons" interval => 1 type => "test" }
 | |
|                 '';
 | |
|                 filterConfig = ''
 | |
|                   if [message] =~ /dragons/ {
 | |
|                     drop {}
 | |
|                   }
 | |
|                 '';
 | |
|                 outputConfig = ''
 | |
|                   file {
 | |
|                     path => "/tmp/logstash.out"
 | |
|                     codec => line { format => "%{message}" }
 | |
|                   }
 | |
|                   elasticsearch {
 | |
|                     hosts => [ "${esUrl}" ]
 | |
|                   }
 | |
|                 '';
 | |
|               };
 | |
| 
 | |
|               elasticsearch = {
 | |
|                 enable = true;
 | |
|                 package = elk.elasticsearch;
 | |
|               };
 | |
| 
 | |
|               kibana = {
 | |
|                 enable = true;
 | |
|                 package = elk.kibana;
 | |
|               };
 | |
| 
 | |
|               elasticsearch-curator = {
 | |
|                 # The current version of curator (5.6) doesn't support elasticsearch >= 7.0.0.
 | |
|                 enable = !elasticsearchGe7;
 | |
|                 actionYAML = ''
 | |
|                 ---
 | |
|                 actions:
 | |
|                   1:
 | |
|                     action: delete_indices
 | |
|                     description: >-
 | |
|                       Delete indices older than 1 second (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: seconds
 | |
|                       unit_count: 1
 | |
|                 '';
 | |
|               };
 | |
|             };
 | |
|           };
 | |
|       };
 | |
| 
 | |
|     testScript = ''
 | |
|       startAll;
 | |
| 
 | |
|       # Wait until elasticsearch is listening for connections.
 | |
|       $one->waitForUnit("elasticsearch.service");
 | |
|       $one->waitForOpenPort(9200);
 | |
| 
 | |
|       # Continue as long as the status is not "red". The status is probably
 | |
|       # "yellow" instead of "green" because we are using a single elasticsearch
 | |
|       # node which elasticsearch considers risky.
 | |
|       #
 | |
|       # TODO: extend this test with multiple elasticsearch nodes
 | |
|       #       and see if the status turns "green".
 | |
|       $one->waitUntilSucceeds(
 | |
|         "curl --silent --show-error '${esUrl}/_cluster/health' " .
 | |
|         "| jq .status | grep -v red");
 | |
| 
 | |
|       # Perform some simple logstash tests.
 | |
|       $one->waitForUnit("logstash.service");
 | |
|       $one->waitUntilSucceeds("cat /tmp/logstash.out | grep flowers");
 | |
|       $one->waitUntilSucceeds("cat /tmp/logstash.out | grep -v dragons");
 | |
| 
 | |
|       # See if kibana is healthy.
 | |
|       $one->waitForUnit("kibana.service");
 | |
|       $one->waitUntilSucceeds(
 | |
|         "curl --silent --show-error 'http://localhost:5601/api/status' " .
 | |
|         "| jq .status.overall.state | grep green");
 | |
| 
 | |
|       # See if logstash messages arive in elasticsearch.
 | |
|       $one->waitUntilSucceeds("${totalHits "flowers"} | grep -v 0");
 | |
|       $one->waitUntilSucceeds("${totalHits "dragons"} | grep 0");
 | |
| 
 | |
|       # Test if a message logged to the journal
 | |
|       # is ingested by elasticsearch via journalbeat.
 | |
|       $one->waitForUnit("journalbeat.service");
 | |
|       $one->execute("echo 'Supercalifragilisticexpialidocious' | systemd-cat");
 | |
|       $one->waitUntilSucceeds(
 | |
|         "${totalHits "Supercalifragilisticexpialidocious"} | grep -v 0");
 | |
| 
 | |
|     '' + optionalString (!elasticsearchGe7) ''
 | |
|       # Test elasticsearch-curator.
 | |
|       $one->systemctl("stop logstash");
 | |
|       $one->systemctl("start elasticsearch-curator");
 | |
|       $one->waitUntilSucceeds(
 | |
|         "! curl --silent --show-error '${esUrl}/_cat/indices' " .
 | |
|         "| grep logstash | grep -q ^$1");
 | |
|     '';
 | |
|   };
 | |
| in mapAttrs mkElkTest {
 | |
|   ELK-6 =
 | |
|     if enableUnfree
 | |
|     then {
 | |
|       elasticsearch = pkgs.elasticsearch6;
 | |
|       logstash      = pkgs.logstash6;
 | |
|       kibana        = pkgs.kibana6;
 | |
|       journalbeat   = pkgs.journalbeat6;
 | |
|     }
 | |
|     else {
 | |
|       elasticsearch = pkgs.elasticsearch6-oss;
 | |
|       logstash      = pkgs.logstash6-oss;
 | |
|       kibana        = pkgs.kibana6-oss;
 | |
|       journalbeat   = pkgs.journalbeat6;
 | |
|     };
 | |
|   ELK-7 =
 | |
|     if enableUnfree
 | |
|     then {
 | |
|       elasticsearch = pkgs.elasticsearch7;
 | |
|       logstash      = pkgs.logstash7;
 | |
|       kibana        = pkgs.kibana7;
 | |
|       journalbeat   = pkgs.journalbeat7;
 | |
|     }
 | |
|     else {
 | |
|       elasticsearch = pkgs.elasticsearch7-oss;
 | |
|       logstash      = pkgs.logstash7-oss;
 | |
|       kibana        = pkgs.kibana7-oss;
 | |
|       journalbeat   = pkgs.journalbeat7;
 | |
|     };
 | |
| }
 | 
