summary refs log blame commit diff
path: root/nixos/tests/elk.nix
blob: 95371ef44436afc89cfa78af28d73148feb6af6a (plain) (tree)
1
2
3
4
5
6
7
8
9



                                                 

                                                                                         


                                                        
              
 

                                  
 




                                                                                          


                                                                                      

                                              
                                                 


             
                             












                                                                                                               
 

                                                                               
 
                        



















                                                                             





















                                                                                    
 



                                            
 


                                     
                

                                       

                                                                                              





                                          
                                                                                             












                                                                                            
                                   


                                   

              
        
 

                   
 
                                                              
                                                 
                                  
 



                                                                               




                                                                  
 



                                                                         
 

                                          


                                                                          
 
                                                        









                                                                               
                                              
                                   

                                                     


                                                                 






                                        
                                      
    





                                          
                                        




                                              
                                        
      





                                          
                                        




                                              
                                        
      
 
{ 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-5" = {
    elasticsearch = pkgs.elasticsearch5;
    logstash      = pkgs.logstash5;
    kibana        = pkgs.kibana5;
    journalbeat   = pkgs.journalbeat5;
  };
  "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;
    };
}