logstash-output-elasticsearch-test 11.16.0-x86_64-linux

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +649 -0
  3. data/CONTRIBUTORS +34 -0
  4. data/Gemfile +16 -0
  5. data/LICENSE +202 -0
  6. data/NOTICE.TXT +5 -0
  7. data/README.md +106 -0
  8. data/docs/index.asciidoc +1369 -0
  9. data/lib/logstash/outputs/elasticsearch/data_stream_support.rb +282 -0
  10. data/lib/logstash/outputs/elasticsearch/default-ilm-policy.json +14 -0
  11. data/lib/logstash/outputs/elasticsearch/http_client/manticore_adapter.rb +155 -0
  12. data/lib/logstash/outputs/elasticsearch/http_client/pool.rb +534 -0
  13. data/lib/logstash/outputs/elasticsearch/http_client.rb +497 -0
  14. data/lib/logstash/outputs/elasticsearch/http_client_builder.rb +201 -0
  15. data/lib/logstash/outputs/elasticsearch/ilm.rb +92 -0
  16. data/lib/logstash/outputs/elasticsearch/license_checker.rb +52 -0
  17. data/lib/logstash/outputs/elasticsearch/template_manager.rb +131 -0
  18. data/lib/logstash/outputs/elasticsearch/templates/ecs-disabled/elasticsearch-6x.json +45 -0
  19. data/lib/logstash/outputs/elasticsearch/templates/ecs-disabled/elasticsearch-7x.json +44 -0
  20. data/lib/logstash/outputs/elasticsearch/templates/ecs-disabled/elasticsearch-8x.json +50 -0
  21. data/lib/logstash/outputs/elasticsearch.rb +699 -0
  22. data/lib/logstash/plugin_mixins/elasticsearch/api_configs.rb +237 -0
  23. data/lib/logstash/plugin_mixins/elasticsearch/common.rb +409 -0
  24. data/lib/logstash/plugin_mixins/elasticsearch/noop_license_checker.rb +9 -0
  25. data/logstash-output-elasticsearch.gemspec +40 -0
  26. data/spec/es_spec_helper.rb +225 -0
  27. data/spec/fixtures/_nodes/6x.json +81 -0
  28. data/spec/fixtures/_nodes/7x.json +92 -0
  29. data/spec/fixtures/htpasswd +2 -0
  30. data/spec/fixtures/license_check/active.json +16 -0
  31. data/spec/fixtures/license_check/inactive.json +5 -0
  32. data/spec/fixtures/nginx_reverse_proxy.conf +22 -0
  33. data/spec/fixtures/scripts/painless/scripted_update.painless +2 -0
  34. data/spec/fixtures/scripts/painless/scripted_update_nested.painless +1 -0
  35. data/spec/fixtures/scripts/painless/scripted_upsert.painless +1 -0
  36. data/spec/fixtures/template-with-policy-es6x.json +48 -0
  37. data/spec/fixtures/template-with-policy-es7x.json +45 -0
  38. data/spec/fixtures/template-with-policy-es8x.json +50 -0
  39. data/spec/fixtures/test_certs/ca.crt +29 -0
  40. data/spec/fixtures/test_certs/ca.der.sha256 +1 -0
  41. data/spec/fixtures/test_certs/ca.key +51 -0
  42. data/spec/fixtures/test_certs/renew.sh +13 -0
  43. data/spec/fixtures/test_certs/test.crt +30 -0
  44. data/spec/fixtures/test_certs/test.der.sha256 +1 -0
  45. data/spec/fixtures/test_certs/test.key +51 -0
  46. data/spec/fixtures/test_certs/test.p12 +0 -0
  47. data/spec/fixtures/test_certs/test_invalid.crt +36 -0
  48. data/spec/fixtures/test_certs/test_invalid.key +51 -0
  49. data/spec/fixtures/test_certs/test_invalid.p12 +0 -0
  50. data/spec/fixtures/test_certs/test_self_signed.crt +32 -0
  51. data/spec/fixtures/test_certs/test_self_signed.key +54 -0
  52. data/spec/fixtures/test_certs/test_self_signed.p12 +0 -0
  53. data/spec/integration/outputs/compressed_indexing_spec.rb +70 -0
  54. data/spec/integration/outputs/create_spec.rb +67 -0
  55. data/spec/integration/outputs/data_stream_spec.rb +68 -0
  56. data/spec/integration/outputs/delete_spec.rb +63 -0
  57. data/spec/integration/outputs/ilm_spec.rb +534 -0
  58. data/spec/integration/outputs/index_spec.rb +421 -0
  59. data/spec/integration/outputs/index_version_spec.rb +98 -0
  60. data/spec/integration/outputs/ingest_pipeline_spec.rb +75 -0
  61. data/spec/integration/outputs/metrics_spec.rb +66 -0
  62. data/spec/integration/outputs/no_es_on_startup_spec.rb +78 -0
  63. data/spec/integration/outputs/painless_update_spec.rb +99 -0
  64. data/spec/integration/outputs/parent_spec.rb +94 -0
  65. data/spec/integration/outputs/retry_spec.rb +182 -0
  66. data/spec/integration/outputs/routing_spec.rb +61 -0
  67. data/spec/integration/outputs/sniffer_spec.rb +94 -0
  68. data/spec/integration/outputs/templates_spec.rb +133 -0
  69. data/spec/integration/outputs/unsupported_actions_spec.rb +75 -0
  70. data/spec/integration/outputs/update_spec.rb +114 -0
  71. data/spec/spec_helper.rb +10 -0
  72. data/spec/support/elasticsearch/api/actions/delete_ilm_policy.rb +19 -0
  73. data/spec/support/elasticsearch/api/actions/get_alias.rb +18 -0
  74. data/spec/support/elasticsearch/api/actions/get_ilm_policy.rb +18 -0
  75. data/spec/support/elasticsearch/api/actions/put_alias.rb +24 -0
  76. data/spec/support/elasticsearch/api/actions/put_ilm_policy.rb +25 -0
  77. data/spec/unit/http_client_builder_spec.rb +185 -0
  78. data/spec/unit/outputs/elasticsearch/data_stream_support_spec.rb +612 -0
  79. data/spec/unit/outputs/elasticsearch/http_client/manticore_adapter_spec.rb +151 -0
  80. data/spec/unit/outputs/elasticsearch/http_client/pool_spec.rb +501 -0
  81. data/spec/unit/outputs/elasticsearch/http_client_spec.rb +339 -0
  82. data/spec/unit/outputs/elasticsearch/template_manager_spec.rb +189 -0
  83. data/spec/unit/outputs/elasticsearch_proxy_spec.rb +103 -0
  84. data/spec/unit/outputs/elasticsearch_spec.rb +1573 -0
  85. data/spec/unit/outputs/elasticsearch_ssl_spec.rb +197 -0
  86. data/spec/unit/outputs/error_whitelist_spec.rb +56 -0
  87. data/spec/unit/outputs/license_check_spec.rb +57 -0
  88. metadata +423 -0
@@ -0,0 +1,92 @@
1
+ module LogStash; module Outputs; class ElasticSearch
2
+ module Ilm
3
+
4
+ ILM_POLICY_PATH = "default-ilm-policy.json"
5
+
6
+ def setup_ilm
7
+ logger.warn("Overwriting supplied index #{@index} with rollover alias #{@ilm_rollover_alias}") unless default_index?(@index)
8
+ @index = @ilm_rollover_alias
9
+ maybe_create_rollover_alias
10
+ maybe_create_ilm_policy
11
+ end
12
+
13
+ def ilm_in_use?
14
+ return @ilm_actually_enabled if defined?(@ilm_actually_enabled)
15
+ @ilm_actually_enabled =
16
+ begin
17
+ if serverless?
18
+ raise LogStash::ConfigurationError, "Invalid ILM configuration `ilm_enabled => true`. " +
19
+ "Serverless Elasticsearch cluster does not support Index Lifecycle Management." if @ilm_enabled.to_s == 'true'
20
+ @logger.info("ILM auto configuration (`ilm_enabled => auto` or unset) resolved to `false`. "\
21
+ "Serverless Elasticsearch cluster does not support Index Lifecycle Management.") if @ilm_enabled == 'auto'
22
+ false
23
+ elsif @ilm_enabled == 'auto'
24
+ if ilm_on_by_default?
25
+ ilm_alias_set?
26
+ else
27
+ @logger.info("ILM auto configuration (`ilm_enabled => auto` or unset) resolved to `false`."\
28
+ " Elasticsearch cluster is before 7.0.0, which is the minimum version required to automatically run Index Lifecycle Management")
29
+ false
30
+ end
31
+ elsif @ilm_enabled.to_s == 'true'
32
+ ilm_alias_set?
33
+ else
34
+ false
35
+ end
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def ilm_alias_set?
42
+ default_index?(@index) || !default_rollover_alias?(@ilm_rollover_alias)
43
+ end
44
+
45
+ def ilm_on_by_default?
46
+ maximum_seen_major_version >= 7
47
+ end
48
+
49
+ def default_index?(index)
50
+ index == @default_index
51
+ end
52
+
53
+ def default_rollover_alias?(rollover_alias)
54
+ rollover_alias == default_ilm_rollover_alias
55
+ end
56
+
57
+ def ilm_policy_default?
58
+ ilm_policy == LogStash::Outputs::ElasticSearch::DEFAULT_POLICY
59
+ end
60
+
61
+ def maybe_create_ilm_policy
62
+ if ilm_policy_default?
63
+ client.ilm_policy_put(ilm_policy, policy_payload) unless client.ilm_policy_exists?(ilm_policy)
64
+ else
65
+ raise LogStash::ConfigurationError, "The specified ILM policy #{ilm_policy} does not exist on your Elasticsearch instance" unless client.ilm_policy_exists?(ilm_policy)
66
+ end
67
+ end
68
+
69
+ def maybe_create_rollover_alias
70
+ client.rollover_alias_put(rollover_alias_target, rollover_alias_payload) unless client.rollover_alias_exists?(ilm_rollover_alias)
71
+ end
72
+
73
+ def rollover_alias_target
74
+ "<#{ilm_rollover_alias}-#{ilm_pattern}>"
75
+ end
76
+
77
+ def rollover_alias_payload
78
+ {
79
+ 'aliases' => {
80
+ ilm_rollover_alias =>{
81
+ 'is_write_index' => true
82
+ }
83
+ }
84
+ }
85
+ end
86
+
87
+ def policy_payload
88
+ policy_path = ::File.expand_path(ILM_POLICY_PATH, ::File.dirname(__FILE__))
89
+ LogStash::Json.load(::IO.read(policy_path))
90
+ end
91
+ end
92
+ end; end; end
@@ -0,0 +1,52 @@
1
+ module LogStash; module Outputs; class ElasticSearch
2
+ class LicenseChecker
3
+
4
+ def initialize(logger)
5
+ @logger = logger
6
+ end
7
+
8
+ # Figure out if the provided license is appropriate or not
9
+ # The appropriate_license? methods is the method called from LogStash::Outputs::ElasticSearch::HttpClient::Pool#healthcheck!
10
+ # @param pool
11
+ # @param url [LogStash::Util::SafeURI] ES node URL
12
+ # @return [Boolean] true if provided license is deemed appropriate
13
+ def appropriate_license?(pool, url)
14
+ return true if pool.serverless?
15
+
16
+ license = extract_license(pool.get_license(url))
17
+ case license_status(license)
18
+ when 'active'
19
+ true
20
+ when nil
21
+ warn_no_license(url)
22
+ false
23
+ else # 'invalid', 'expired'
24
+ warn_invalid_license(url, license)
25
+ true
26
+ end
27
+ end
28
+
29
+ NO_LICENSE = {}.freeze
30
+ private_constant :NO_LICENSE
31
+
32
+ def extract_license(license)
33
+ license.fetch("license", NO_LICENSE)
34
+ end
35
+
36
+ def license_status(license)
37
+ license.fetch("status", nil)
38
+ end
39
+
40
+ private
41
+
42
+ def warn_no_license(url)
43
+ @logger.error("Could not connect to a compatible version of Elasticsearch", url: url.sanitized.to_s)
44
+ end
45
+
46
+ def warn_invalid_license(url, license)
47
+ @logger.warn("Elasticsearch license is not active, please check Elasticsearch’s licensing information",
48
+ url: url.sanitized.to_s, license: license)
49
+ end
50
+
51
+ end
52
+ end; end; end
@@ -0,0 +1,131 @@
1
+ module LogStash; module Outputs; class ElasticSearch
2
+ class TemplateManager
3
+ LEGACY_TEMPLATE_ENDPOINT = '_template'.freeze
4
+ INDEX_TEMPLATE_ENDPOINT = '_index_template'.freeze
5
+
6
+ # To be mixed into the elasticsearch plugin base
7
+ def self.install_template(plugin)
8
+ return unless plugin.manage_template
9
+
10
+ if plugin.maximum_seen_major_version < 8 && plugin.template_api == 'auto'
11
+ plugin.logger.warn("`template_api => auto` resolved to `legacy` since we are connected to " + "Elasticsearch #{plugin.maximum_seen_major_version}, " +
12
+ "but will resolve to `composable` the first time it connects to Elasticsearch 8+. " +
13
+ "We recommend either setting `template_api => legacy` to continue providing legacy-style templates, " +
14
+ "or migrating your template to the composable style and setting `template_api => composable`. " +
15
+ "The legacy template API is slated for removal in Elasticsearch 9.")
16
+ elsif plugin.template_api == 'legacy' && plugin.serverless?
17
+ raise LogStash::ConfigurationError, "Invalid template configuration `template_api => legacy`. Serverless Elasticsearch does not support legacy template API."
18
+ end
19
+
20
+
21
+ if plugin.template
22
+ plugin.logger.info("Using mapping template from", :path => plugin.template)
23
+ template = read_template_file(plugin.template)
24
+ else
25
+ plugin.logger.info("Using a default mapping template", :es_version => plugin.maximum_seen_major_version,
26
+ :ecs_compatibility => plugin.ecs_compatibility)
27
+ template = load_default_template(plugin.maximum_seen_major_version, plugin.ecs_compatibility)
28
+ end
29
+
30
+ add_ilm_settings_to_template(plugin, template) if plugin.ilm_in_use?
31
+ plugin.logger.debug("Attempting to install template", template: template)
32
+ install(plugin.client, template_endpoint(plugin), template_name(plugin), template, plugin.template_overwrite)
33
+ end
34
+
35
+ private
36
+ def self.load_default_template(es_major_version, ecs_compatibility)
37
+ template_path = default_template_path(es_major_version, ecs_compatibility)
38
+ read_template_file(template_path)
39
+ rescue => e
40
+ fail "Failed to load default template for Elasticsearch v#{es_major_version} with ECS #{ecs_compatibility}; caused by: #{e.inspect}"
41
+ end
42
+
43
+ def self.install(client, template_endpoint, template_name, template, template_overwrite)
44
+ client.template_install(template_endpoint, template_name, template, template_overwrite)
45
+ end
46
+
47
+ def self.add_ilm_settings_to_template(plugin, template)
48
+ # Overwrite any index patterns, and use the rollover alias. Use 'index_patterns' rather than 'template' for pattern
49
+ # definition - remove any existing definition of 'template'
50
+ template.delete('template') if template.include?('template') if plugin.maximum_seen_major_version < 8
51
+ template['index_patterns'] = "#{plugin.ilm_rollover_alias}-*"
52
+ settings = resolve_template_settings(plugin, template)
53
+ if settings && (settings['index.lifecycle.name'] || settings['index.lifecycle.rollover_alias'])
54
+ plugin.logger.info("Overwriting index lifecycle name and rollover alias as ILM is enabled")
55
+ end
56
+ settings.update({ 'index.lifecycle.name' => plugin.ilm_policy, 'index.lifecycle.rollover_alias' => plugin.ilm_rollover_alias})
57
+ end
58
+
59
+ def self.resolve_template_settings(plugin, template)
60
+ if template.key?('template')
61
+ plugin.logger.trace("Resolving ILM template settings: under 'template' key", :template => template, :template_api => plugin.template_api, :es_version => plugin.maximum_seen_major_version)
62
+ composable_index_template_settings(template)
63
+ elsif template.key?('settings')
64
+ plugin.logger.trace("Resolving ILM template settings: under 'settings' key", :template => template, :template_api => plugin.template_api, :es_version => plugin.maximum_seen_major_version)
65
+ legacy_index_template_settings(template)
66
+ else
67
+ use_index_template_api = index_template_api?(plugin)
68
+ plugin.logger.trace("Resolving ILM template settings: template doesn't have 'settings' or 'template' fields, falling back to auto detection", :template => template, :template_api => plugin.template_api, :es_version => plugin.maximum_seen_major_version, :index_template_api => use_index_template_api)
69
+ if use_index_template_api
70
+ composable_index_template_settings(template)
71
+ else
72
+ legacy_index_template_settings(template)
73
+ end
74
+ end
75
+ end
76
+
77
+ # Sets ['settings'] field to be compatible with _template API structure
78
+ def self.legacy_index_template_settings(template)
79
+ template['settings'] ||= {}
80
+ end
81
+
82
+ # Sets the ['template']['settings'] fields if not exist to be compatible with _index_template API structure
83
+ def self.composable_index_template_settings(template)
84
+ template['template'] ||= {}
85
+ template['template']['settings'] ||= {}
86
+ end
87
+
88
+ # Template name - if template_name set, use it
89
+ # if not and ILM is enabled, use the rollover alias
90
+ # else use the default value of template_name
91
+ def self.template_name(plugin)
92
+ plugin.ilm_in_use? && !plugin.original_params.key?('template_name') ? plugin.ilm_rollover_alias : plugin.template_name
93
+ end
94
+
95
+ def self.default_template_path(es_major_version, ecs_compatibility=:disabled)
96
+ template_version = es_major_version
97
+ default_template_name = "templates/ecs-#{ecs_compatibility}/elasticsearch-#{template_version}x.json"
98
+ ::File.expand_path(default_template_name, ::File.dirname(__FILE__))
99
+ end
100
+
101
+ def self.read_template_file(template_path)
102
+ raise ArgumentError, "Template file '#{template_path}' could not be found" unless ::File.exists?(template_path)
103
+ template_data = ::IO.read(template_path)
104
+ LogStash::Json.load(template_data)
105
+ end
106
+
107
+ def self.template_endpoint(plugin)
108
+ index_template_api?(plugin) ? INDEX_TEMPLATE_ENDPOINT : LEGACY_TEMPLATE_ENDPOINT
109
+ end
110
+
111
+ def self.index_template_api?(plugin)
112
+ case plugin.serverless?
113
+ when true
114
+ true
115
+ else
116
+ case plugin.template_api
117
+ when 'auto'
118
+ plugin.maximum_seen_major_version >= 8
119
+ when 'composable'
120
+ true
121
+ when 'legacy'
122
+ false
123
+ else
124
+ plugin.logger.warn("Invalid template_api value #{plugin.template_api}")
125
+ true
126
+ end
127
+ end
128
+ end
129
+
130
+ end
131
+ end end end
@@ -0,0 +1,45 @@
1
+ {
2
+ "template" : "logstash-*",
3
+ "version" : 60001,
4
+ "settings" : {
5
+ "index.refresh_interval" : "5s"
6
+ },
7
+ "mappings" : {
8
+ "_default_" : {
9
+ "dynamic_templates" : [ {
10
+ "message_field" : {
11
+ "path_match" : "message",
12
+ "match_mapping_type" : "string",
13
+ "mapping" : {
14
+ "type" : "text",
15
+ "norms" : false
16
+ }
17
+ }
18
+ }, {
19
+ "string_fields" : {
20
+ "match" : "*",
21
+ "match_mapping_type" : "string",
22
+ "mapping" : {
23
+ "type" : "text", "norms" : false,
24
+ "fields" : {
25
+ "keyword" : { "type": "keyword", "ignore_above": 256 }
26
+ }
27
+ }
28
+ }
29
+ } ],
30
+ "properties" : {
31
+ "@timestamp": { "type": "date"},
32
+ "@version": { "type": "keyword"},
33
+ "geoip" : {
34
+ "dynamic": true,
35
+ "properties" : {
36
+ "ip": { "type": "ip" },
37
+ "location" : { "type" : "geo_point" },
38
+ "latitude" : { "type" : "half_float" },
39
+ "longitude" : { "type" : "half_float" }
40
+ }
41
+ }
42
+ }
43
+ }
44
+ }
45
+ }
@@ -0,0 +1,44 @@
1
+ {
2
+ "index_patterns" : "logstash-*",
3
+ "version" : 60001,
4
+ "settings" : {
5
+ "index.refresh_interval" : "5s",
6
+ "number_of_shards": 1
7
+ },
8
+ "mappings" : {
9
+ "dynamic_templates" : [ {
10
+ "message_field" : {
11
+ "path_match" : "message",
12
+ "match_mapping_type" : "string",
13
+ "mapping" : {
14
+ "type" : "text",
15
+ "norms" : false
16
+ }
17
+ }
18
+ }, {
19
+ "string_fields" : {
20
+ "match" : "*",
21
+ "match_mapping_type" : "string",
22
+ "mapping" : {
23
+ "type" : "text", "norms" : false,
24
+ "fields" : {
25
+ "keyword" : { "type": "keyword", "ignore_above": 256 }
26
+ }
27
+ }
28
+ }
29
+ } ],
30
+ "properties" : {
31
+ "@timestamp": { "type": "date"},
32
+ "@version": { "type": "keyword"},
33
+ "geoip" : {
34
+ "dynamic": true,
35
+ "properties" : {
36
+ "ip": { "type": "ip" },
37
+ "location" : { "type" : "geo_point" },
38
+ "latitude" : { "type" : "half_float" },
39
+ "longitude" : { "type" : "half_float" }
40
+ }
41
+ }
42
+ }
43
+ }
44
+ }
@@ -0,0 +1,50 @@
1
+ {
2
+ "index_patterns" : "logstash-*",
3
+ "version" : 80001,
4
+ "template" : {
5
+ "settings" : {
6
+ "index.refresh_interval" : "5s",
7
+ "number_of_shards": 1
8
+ },
9
+ "mappings" : {
10
+ "dynamic_templates" : [ {
11
+ "message_field" : {
12
+ "path_match" : "message",
13
+ "match_mapping_type" : "string",
14
+ "mapping" : {
15
+ "type" : "text",
16
+ "norms" : false
17
+ }
18
+ }
19
+ }, {
20
+ "string_fields" : {
21
+ "match" : "*",
22
+ "match_mapping_type" : "string",
23
+ "mapping" : {
24
+ "type" : "text", "norms" : false,
25
+ "fields" : {
26
+ "keyword" : { "type": "keyword", "ignore_above": 256 }
27
+ }
28
+ }
29
+ }
30
+ } ],
31
+ "properties" : {
32
+ "@timestamp": { "type": "date" },
33
+ "@version": { "type": "keyword" },
34
+ "geoip" : {
35
+ "dynamic": true,
36
+ "properties" : {
37
+ "ip": { "type": "ip" },
38
+ "location" : { "type" : "geo_point" },
39
+ "latitude" : { "type" : "half_float" },
40
+ "longitude" : { "type" : "half_float" }
41
+ }
42
+ }
43
+ }
44
+ }
45
+ },
46
+ "priority": 200,
47
+ "_meta" : {
48
+ "description": "index template for logstash-output-elasticsearch"
49
+ }
50
+ }