logstash-output-elasticsearch 9.2.4-java → 9.3.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +3 -0
  3. data/docs/index.asciidoc +104 -2
  4. data/lib/logstash/outputs/elasticsearch.rb +4 -0
  5. data/lib/logstash/outputs/elasticsearch/common.rb +8 -5
  6. data/lib/logstash/outputs/elasticsearch/common_configs.rb +23 -1
  7. data/lib/logstash/outputs/elasticsearch/default-ilm-policy.json +14 -0
  8. data/lib/logstash/outputs/elasticsearch/http_client.rb +47 -2
  9. data/lib/logstash/outputs/elasticsearch/http_client/manticore_adapter.rb +3 -3
  10. data/lib/logstash/outputs/elasticsearch/ilm.rb +84 -0
  11. data/lib/logstash/outputs/elasticsearch/template_manager.rb +21 -1
  12. data/logstash-output-elasticsearch.gemspec +1 -1
  13. data/spec/es_spec_helper.rb +70 -0
  14. data/spec/fixtures/template-with-policy-es6x.json +48 -0
  15. data/spec/fixtures/template-with-policy-es7x.json +46 -0
  16. data/spec/integration/outputs/create_spec.rb +1 -1
  17. data/spec/integration/outputs/ilm_spec.rb +542 -0
  18. data/spec/integration/outputs/ingest_pipeline_spec.rb +2 -2
  19. data/spec/integration/outputs/no_es_on_startup_spec.rb +2 -2
  20. data/spec/integration/outputs/retry_spec.rb +3 -3
  21. data/spec/integration/outputs/templates_5x_spec.rb +7 -7
  22. data/spec/integration/outputs/templates_spec.rb +7 -7
  23. data/spec/support/elasticsearch/api/actions/delete_ilm_policy.rb +19 -0
  24. data/spec/support/elasticsearch/api/actions/get_alias.rb +18 -0
  25. data/spec/support/elasticsearch/api/actions/get_ilm_policy.rb +18 -0
  26. data/spec/support/elasticsearch/api/actions/put_alias.rb +24 -0
  27. data/spec/support/elasticsearch/api/actions/put_ilm_policy.rb +25 -0
  28. metadata +20 -2
@@ -5,8 +5,9 @@ module LogStash; module Outputs; class ElasticSearch
5
5
  return unless plugin.manage_template
6
6
  plugin.logger.info("Using mapping template from", :path => plugin.template)
7
7
  template = get_template(plugin.template, plugin.maximum_seen_major_version)
8
+ add_ilm_settings_to_template(plugin, template) if plugin.ilm_enabled?
8
9
  plugin.logger.info("Attempting to install template", :manage_template => template)
9
- install(plugin.client, plugin.template_name, template, plugin.template_overwrite)
10
+ install(plugin.client, template_name(plugin), template, plugin.template_overwrite)
10
11
  rescue => e
11
12
  plugin.logger.error("Failed to install template.", :message => e.message, :class => e.class.name, :backtrace => e.backtrace)
12
13
  end
@@ -21,6 +22,25 @@ module LogStash; module Outputs; class ElasticSearch
21
22
  client.template_install(template_name, template, template_overwrite)
22
23
  end
23
24
 
25
+ def self.add_ilm_settings_to_template(plugin, template)
26
+ plugin.logger.info("Overwriting index patterns, as ILM is enabled.")
27
+ # Overwrite any index patterns, and use the rollover alias. Use 'index_patterns' rather than 'template' for pattern
28
+ # definition - remove any existing definition of 'template'
29
+ template.delete('template') if template.include?('template')
30
+ template['index_patterns'] = "#{plugin.ilm_rollover_alias}-*"
31
+ if template['settings'] && (template['settings']['index.lifecycle.name'] || template['settings']['index.lifecycle.rollover_alias'])
32
+ plugin.logger.info("Overwriting index lifecycle name and rollover alias as ILM is enabled.")
33
+ end
34
+ template['settings'].update({ 'index.lifecycle.name' => plugin.ilm_policy, 'index.lifecycle.rollover_alias' => plugin.ilm_rollover_alias})
35
+ end
36
+
37
+ # Template name - if template_name set, use it
38
+ # if not and ILM is enabled, use the rollover alias
39
+ # else use the default value of template_name
40
+ def self.template_name(plugin)
41
+ plugin.ilm_enabled? && !plugin.original_params.key?('template_name') ? plugin.ilm_rollover_alias : plugin.template_name
42
+ end
43
+
24
44
  def self.default_template_path(es_major_version)
25
45
  template_version = es_major_version == 1 ? 2 : es_major_version
26
46
  default_template_name = "elasticsearch-template-es#{template_version}x.json"
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'logstash-output-elasticsearch'
3
- s.version = '9.2.4'
3
+ s.version = '9.3.0'
4
4
  s.licenses = ['apache-2.0']
5
5
  s.summary = "Stores logs in Elasticsearch"
6
6
  s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"
@@ -1,6 +1,13 @@
1
1
  require "logstash/devutils/rspec/spec_helper"
2
2
  require 'manticore'
3
3
  require 'elasticsearch'
4
+ require_relative "support/elasticsearch/api/actions/delete_ilm_policy"
5
+ require_relative "support/elasticsearch/api/actions/get_alias"
6
+ require_relative "support/elasticsearch/api/actions/put_alias"
7
+ require_relative "support/elasticsearch/api/actions/get_ilm_policy"
8
+ require_relative "support/elasticsearch/api/actions/put_ilm_policy"
9
+
10
+ require 'json'
4
11
 
5
12
  module ESHelper
6
13
  def get_host_port
@@ -19,6 +26,10 @@ module ESHelper
19
26
  end
20
27
  end
21
28
 
29
+ def todays_date
30
+ Time.now.strftime("%Y.%m.%d")
31
+ end
32
+
22
33
  def mapping_name
23
34
  if ESHelper.es_version_satisfies?(">=7")
24
35
  "_doc"
@@ -40,6 +51,17 @@ module ESHelper
40
51
  RSpec.configuration.filter[:es_version] || ENV['ES_VERSION']
41
52
  end
42
53
 
54
+ RSpec::Matchers.define :have_hits do |expected|
55
+ match do |actual|
56
+ if ESHelper.es_version_satisfies?(">=7")
57
+ expected == actual['hits']['total']['value']
58
+ else
59
+ expected == actual['hits']['total']
60
+ end
61
+ end
62
+ end
63
+
64
+
43
65
  def self.es_version_satisfies?(*requirement)
44
66
  es_version = RSpec.configuration.filter[:es_version] || ENV['ES_VERSION']
45
67
  if es_version.nil?
@@ -49,6 +71,54 @@ module ESHelper
49
71
  es_release_version = Gem::Version.new(es_version).release
50
72
  Gem::Requirement.new(requirement).satisfied_by?(es_release_version)
51
73
  end
74
+
75
+ def clean(client)
76
+ client.indices.delete_template(:name => "*")
77
+ # This can fail if there are no indexes, ignore failure.
78
+ client.indices.delete(:index => "*") rescue nil
79
+ clean_ilm(client) if supports_ilm?(client)
80
+ end
81
+
82
+ def set_cluster_settings(client, cluster_settings)
83
+ client.cluster.put_settings(body: cluster_settings)
84
+ get_cluster_settings(client)
85
+ end
86
+
87
+ def get_cluster_settings(client)
88
+ client.cluster.get_settings
89
+ end
90
+
91
+ def get_policy(client, policy_name)
92
+ client.get_ilm_policy(name: policy_name)
93
+ end
94
+
95
+ def put_policy(client, policy_name, policy)
96
+ client.put_ilm_policy({:name => policy_name, :body=> policy})
97
+ end
98
+
99
+ def put_alias(client, the_alias, index)
100
+ body = {
101
+ "aliases" => {
102
+ index => {
103
+ "is_write_index"=> true
104
+ }
105
+ }
106
+ }
107
+ client.put_alias({name: the_alias, body: body})
108
+ end
109
+
110
+ def clean_ilm(client)
111
+ client.get_ilm_policy.each_key {|key| client.delete_ilm_policy(name: key)}
112
+ end
113
+
114
+ def supports_ilm?(client)
115
+ begin
116
+ client.get_ilm_policy
117
+ true
118
+ rescue
119
+ false
120
+ end
121
+ end
52
122
  end
53
123
 
54
124
  RSpec.configure do |config|
@@ -0,0 +1,48 @@
1
+ {
2
+ "template" : "overwrite-*",
3
+ "version" : 60001,
4
+ "settings" : {
5
+ "index.refresh_interval" : "1s",
6
+ "number_of_shards": 1,
7
+ "index.lifecycle.name": "overwrite-policy",
8
+ "index.lifecycle.rollover_alias": "overwrite"
9
+ },
10
+ "mappings" : {
11
+ "_default_" : {
12
+ "dynamic_templates" : [ {
13
+ "message_field" : {
14
+ "path_match" : "message",
15
+ "match_mapping_type" : "string",
16
+ "mapping" : {
17
+ "type" : "text",
18
+ "norms" : false
19
+ }
20
+ }
21
+ }, {
22
+ "string_fields" : {
23
+ "match" : "*",
24
+ "match_mapping_type" : "string",
25
+ "mapping" : {
26
+ "type" : "text", "norms" : false,
27
+ "fields" : {
28
+ "keyword" : { "type": "keyword", "ignore_above": 256 }
29
+ }
30
+ }
31
+ }
32
+ } ],
33
+ "properties" : {
34
+ "@timestamp": { "type": "date"},
35
+ "@version": { "type": "keyword"},
36
+ "geoip" : {
37
+ "dynamic": true,
38
+ "properties" : {
39
+ "ip": { "type": "ip" },
40
+ "location" : { "type" : "geo_point" },
41
+ "latitude" : { "type" : "half_float" },
42
+ "longitude" : { "type" : "half_float" }
43
+ }
44
+ }
45
+ }
46
+ }
47
+ }
48
+ }
@@ -0,0 +1,46 @@
1
+ {
2
+ "index_patterns" : "overwrite-*",
3
+ "version" : 60001,
4
+ "settings" : {
5
+ "index.refresh_interval" : "1s",
6
+ "number_of_shards": 1
7
+ },
8
+ "mappings" : {
9
+ "_doc" : {
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
+ }
@@ -35,7 +35,7 @@ describe "client create actions", :integration => true do
35
35
  # Wait or fail until everything's indexed.
36
36
  Stud::try(3.times) do
37
37
  r = @es.search
38
- expect(r["hits"]["total"]).to eq(1)
38
+ expect(r).to have_hits(1)
39
39
  end
40
40
  end
41
41
 
@@ -0,0 +1,542 @@
1
+ require_relative "../../../spec/es_spec_helper"
2
+
3
+ shared_examples_for 'an Elasticsearch instance that does not support index lifecycle management' do
4
+ require "logstash/outputs/elasticsearch"
5
+
6
+ let (:ilm_enabled) { false }
7
+ let (:settings) {
8
+ {
9
+ "ilm_enabled" => ilm_enabled,
10
+ "hosts" => "#{get_host_port()}"
11
+ }
12
+ }
13
+
14
+ before :each do
15
+ require "elasticsearch"
16
+
17
+ # Clean ES of data before we start.
18
+ @es = get_client
19
+ clean(@es)
20
+ end
21
+
22
+ after :each do
23
+ clean(@es)
24
+ end
25
+
26
+ subject { LogStash::Outputs::ElasticSearch.new(settings) }
27
+
28
+ context 'when ilm is enabled in Logstash' do
29
+ let (:ilm_enabled) { true }
30
+
31
+ it 'should raise a configuration error' do
32
+ expect do
33
+ begin
34
+ subject.register
35
+ sleep(1)
36
+ ensure
37
+ subject.stop_template_installer
38
+ end
39
+ end.to raise_error(LogStash::ConfigurationError)
40
+ end
41
+ end
42
+
43
+ context 'when ilm is disabled in Logstash' do
44
+ it 'should index documents normally' do
45
+ subject.register
46
+
47
+ subject.multi_receive([
48
+ LogStash::Event.new("message" => "sample message here"),
49
+ LogStash::Event.new("somemessage" => { "message" => "sample nested message here" }),
50
+ LogStash::Event.new("somevalue" => 100),
51
+ ])
52
+
53
+ sleep(6)
54
+
55
+ subject.multi_receive([
56
+ LogStash::Event.new("country" => "us"),
57
+ LogStash::Event.new("country" => "at"),
58
+ LogStash::Event.new("geoip" => { "location" => [ 0.0, 0.0 ] })
59
+ ])
60
+
61
+ @es.indices.refresh
62
+
63
+ # Wait or fail until everything's indexed.
64
+ Stud::try(20.times) do
65
+ r = @es.search
66
+ expect(r).to have_hits(6)
67
+ end
68
+ indexes_written = @es.search['hits']['hits'].each_with_object(Hash.new(0)) do |x, res|
69
+ index_written = x['_index']
70
+ res[index_written] += 1
71
+ end
72
+ expect(indexes_written.count).to eq(1)
73
+ end
74
+ end
75
+
76
+ end
77
+
78
+ shared_examples_for 'an ILM enabled Logstash' do
79
+
80
+ context 'with a policy with a maximum number of documents' do
81
+ let (:policy) { small_max_doc_policy }
82
+ let (:ilm_policy_name) { "custom-policy"}
83
+ let (:settings) { super.merge("ilm_policy" => ilm_policy_name)}
84
+
85
+ it 'should rollover when the policy max docs is reached' do
86
+ put_policy(@es,ilm_policy_name, policy)
87
+ subject.register
88
+
89
+ subject.multi_receive([
90
+ LogStash::Event.new("message" => "sample message here"),
91
+ LogStash::Event.new("somemessage" => { "message" => "sample nested message here" }),
92
+ LogStash::Event.new("somevalue" => 100),
93
+ ])
94
+
95
+ sleep(6)
96
+
97
+ subject.multi_receive([
98
+ LogStash::Event.new("country" => "us"),
99
+ LogStash::Event.new("country" => "at"),
100
+ LogStash::Event.new("geoip" => { "location" => [ 0.0, 0.0 ] })
101
+ ])
102
+
103
+ sleep(6)
104
+
105
+ subject.multi_receive([
106
+ LogStash::Event.new("country" => "uk"),
107
+ LogStash::Event.new("country" => "fr"),
108
+ LogStash::Event.new("geoip" => { "location" => [ 0.1, 1.0 ] })
109
+ ])
110
+
111
+ @es.indices.refresh
112
+
113
+ # Wait or fail until everything's indexed.
114
+ Stud::try(20.times) do
115
+ r = @es.search
116
+ expect(r).to have_hits(9)
117
+ end
118
+ indexes_written = @es.search['hits']['hits'].each_with_object(Hash.new(0)) do |x, res|
119
+ index_written = x['_index']
120
+ res[index_written] += 1
121
+ end
122
+ expect(indexes_written.count).to eq(3)
123
+ expect(indexes_written["#{expected_index}-#{todays_date}-000001"]).to eq(3)
124
+ expect(indexes_written["#{expected_index}-#{todays_date}-000002"]).to eq(3)
125
+ expect(indexes_written["#{expected_index}-#{todays_date}-000003"]).to eq(3)
126
+ end
127
+ end
128
+
129
+ context 'with a policy where the maximum number of documents is not reached' do
130
+ let (:policy) { large_max_doc_policy }
131
+ let (:ilm_policy_name) { "custom-policy"}
132
+ let (:settings) { super.merge("ilm_policy" => ilm_policy_name)}
133
+
134
+ it 'should ingest into a single index when max docs is not reached' do
135
+ put_policy(@es,ilm_policy_name, policy)
136
+ subject.register
137
+
138
+ subject.multi_receive([
139
+ LogStash::Event.new("message" => "sample message here"),
140
+ LogStash::Event.new("somemessage" => { "message" => "sample nested message here" }),
141
+ LogStash::Event.new("somevalue" => 100),
142
+ ])
143
+
144
+ sleep(6)
145
+
146
+ subject.multi_receive([
147
+ LogStash::Event.new("country" => "us"),
148
+ LogStash::Event.new("country" => "at"),
149
+ LogStash::Event.new("geoip" => { "location" => [ 0.0, 0.0 ] })
150
+ ])
151
+
152
+ @es.indices.refresh
153
+
154
+ # Wait or fail until everything's indexed.
155
+ Stud::try(20.times) do
156
+ r = @es.search
157
+ expect(r).to have_hits(6)
158
+ end
159
+ indexes_written = @es.search['hits']['hits'].each_with_object(Hash.new(0)) do |x, res|
160
+ index_written = x['_index']
161
+ res[index_written] += 1
162
+ end
163
+ expect(indexes_written.count).to eq(1)
164
+ expect(indexes_written["#{expected_index}-#{todays_date}-000001"]).to eq(6)
165
+ end
166
+ end
167
+ end
168
+
169
+
170
+ if ESHelper.es_version_satisfies?("<= 6.5")
171
+ describe 'Pre-ILM versions of Elasticsearch', :integration => true do
172
+ it_behaves_like 'an Elasticsearch instance that does not support index lifecycle management'
173
+ end
174
+ end
175
+
176
+ if ESHelper.es_version_satisfies?(">= 6.6")
177
+ describe 'OSS Elasticsearch', :distribution => 'oss', :integration => true do
178
+ it_behaves_like 'an Elasticsearch instance that does not support index lifecycle management'
179
+ end
180
+
181
+ describe 'Elasticsearch has index lifecycle management enabled', :distribution => 'xpack', :integration => true do
182
+ DEFAULT_INTERVAL = '600s'
183
+
184
+ require "logstash/outputs/elasticsearch"
185
+ let (:ilm_enabled) { true }
186
+
187
+ let (:settings) {
188
+ {
189
+ "ilm_enabled" => ilm_enabled,
190
+ "hosts" => "#{get_host_port()}"
191
+ }
192
+ }
193
+ let (:policy) { small_max_doc_policy }
194
+
195
+
196
+ let (:small_max_doc_policy) {
197
+ {"policy" => {
198
+ "phases"=> {
199
+ "hot" => {
200
+ "actions" => {
201
+ "rollover" => {
202
+ "max_docs" => "3"
203
+ }
204
+ }
205
+ }
206
+ }
207
+ }}
208
+ }
209
+
210
+ let (:large_max_doc_policy) {
211
+ {"policy" => {
212
+ "phases"=> {
213
+ "hot" => {
214
+ "actions" => {
215
+ "rollover" => {
216
+ "max_docs" => "1000000"
217
+ }
218
+ }
219
+ }
220
+ }
221
+ }}
222
+ }
223
+
224
+
225
+
226
+ subject { LogStash::Outputs::ElasticSearch.new(settings) }
227
+
228
+ before :each do
229
+ # Delete all templates first.
230
+ require "elasticsearch"
231
+
232
+ # Clean ES of data before we start.
233
+ @es = get_client
234
+ clean(@es)
235
+ # Set the poll interval for lifecycle management to be short so changes get picked up in time.
236
+ set_cluster_settings(@es, {
237
+ "persistent" => {
238
+ "indices.lifecycle.poll_interval" => "1s"
239
+ }
240
+ })
241
+ end
242
+
243
+ after :each do
244
+ # Set poll interval back to default
245
+ set_cluster_settings(@es, {
246
+ "persistent" => {
247
+ "indices.lifecycle.poll_interval" => DEFAULT_INTERVAL
248
+ }
249
+ })
250
+ clean(@es)
251
+ end
252
+
253
+
254
+ context 'with ilm enabled' do
255
+ let (:ilm_enabled) { true }
256
+
257
+
258
+ context 'when using the default policy' do
259
+ context 'with a custom pattern' do
260
+ let (:settings) { super.merge("ilm_pattern" => "000001")}
261
+ it 'should create a rollover alias' do
262
+ expect(@es.indices.exists_alias(index: "logstash")).to be_falsey
263
+ subject.register
264
+ sleep(1)
265
+ expect(@es.indices.exists_alias(index: "logstash")).to be_truthy
266
+ expect(@es.get_alias(name: "logstash")).to include("logstash-000001")
267
+ end
268
+ end
269
+
270
+
271
+ it 'should install it if it is not present' do
272
+ expect{get_policy(@es, LogStash::Outputs::ElasticSearch::DEFAULT_POLICY)}.to raise_error(Elasticsearch::Transport::Transport::Errors::NotFound)
273
+ subject.register
274
+ sleep(1)
275
+ expect{get_policy(@es, LogStash::Outputs::ElasticSearch::DEFAULT_POLICY)}.not_to raise_error
276
+ end
277
+
278
+ it 'should create the default rollover alias' do
279
+ expect(@es.indices.exists_alias(index: "logstash")).to be_falsey
280
+ subject.register
281
+ sleep(1)
282
+ expect(@es.indices.exists_alias(index: "logstash")).to be_truthy
283
+ expect(@es.get_alias(name: "logstash")).to include("logstash-#{todays_date}-000001")
284
+ end
285
+
286
+
287
+ it 'should ingest into a single index' do
288
+ subject.register
289
+
290
+ subject.multi_receive([
291
+ LogStash::Event.new("message" => "sample message here"),
292
+ LogStash::Event.new("somemessage" => { "message" => "sample nested message here" }),
293
+ LogStash::Event.new("somevalue" => 100),
294
+ ])
295
+
296
+ sleep(6)
297
+
298
+ subject.multi_receive([
299
+ LogStash::Event.new("country" => "us"),
300
+ LogStash::Event.new("country" => "at"),
301
+ LogStash::Event.new("geoip" => { "location" => [ 0.0, 0.0 ] })
302
+ ])
303
+
304
+ @es.indices.refresh
305
+
306
+ # Wait or fail until everything's indexed.
307
+ Stud::try(20.times) do
308
+ r = @es.search
309
+ expect(r).to have_hits(6)
310
+ end
311
+ indexes_written = @es.search['hits']['hits'].each_with_object(Hash.new(0)) do |x, res|
312
+ index_written = x['_index']
313
+ res[index_written] += 1
314
+ end
315
+
316
+ expect(indexes_written.count).to eq(1)
317
+ expect(indexes_written["logstash-#{todays_date}-000001"]).to eq(6)
318
+ end
319
+ end
320
+
321
+ context 'when not using the default policy' do
322
+ let (:ilm_policy_name) {"new_one"}
323
+ let (:settings) { super.merge("ilm_policy" => ilm_policy_name)}
324
+ let (:policy) {{
325
+ "policy" => {
326
+ "phases"=> {
327
+ "hot" => {
328
+ "actions" => {
329
+ "rollover" => {
330
+ "max_docs" => "3"
331
+ }
332
+ }
333
+ }
334
+ }
335
+ }}}
336
+
337
+ before do
338
+ expect{get_policy(@es, LogStash::Outputs::ElasticSearch::DEFAULT_POLICY)}.to raise_error(Elasticsearch::Transport::Transport::Errors::NotFound)
339
+ put_policy(@es,ilm_policy_name, policy)
340
+ end
341
+
342
+ it 'should not install the default policy if it is not used' do
343
+ subject.register
344
+ sleep(1)
345
+ expect{get_policy(@es, LogStash::Outputs::ElasticSearch::DEFAULT_POLICY)}.to raise_error(Elasticsearch::Transport::Transport::Errors::NotFound)
346
+ end
347
+ end
348
+
349
+ context 'when using a time based policy' do
350
+ let (:ilm_policy_name) {"new_one"}
351
+ let (:settings) { super.merge("ilm_policy" => ilm_policy_name)}
352
+ let (:policy) {{
353
+ "policy" => {
354
+ "phases"=> {
355
+ "hot" => {
356
+ "actions" => {
357
+ "rollover" => {
358
+ "max_age" => "1d"
359
+ }
360
+ }
361
+ }
362
+ }
363
+ }}}
364
+
365
+ before do
366
+ expect{get_policy(@es, LogStash::Outputs::ElasticSearch::DEFAULT_POLICY)}.to raise_error(Elasticsearch::Transport::Transport::Errors::NotFound)
367
+ put_policy(@es,ilm_policy_name, policy)
368
+ end
369
+
370
+ it 'should not install the default policy if it is not used' do
371
+ subject.register
372
+ sleep(1)
373
+ expect{get_policy(@es, LogStash::Outputs::ElasticSearch::DEFAULT_POLICY)}.to raise_error(Elasticsearch::Transport::Transport::Errors::NotFound)
374
+ end
375
+ end
376
+ context 'with the default template' do
377
+ let(:expected_index) { "logstash" }
378
+
379
+ it 'should create the rollover alias' do
380
+ expect(@es.indices.exists_alias(index: expected_index)).to be_falsey
381
+ subject.register
382
+ sleep(1)
383
+ expect(@es.indices.exists_alias(index: expected_index)).to be_truthy
384
+ expect(@es.get_alias(name: expected_index)).to include("#{expected_index}-#{todays_date}-000001")
385
+ end
386
+
387
+ it 'should write the ILM settings into the template' do
388
+ subject.register
389
+ sleep(1)
390
+ expect(@es.indices.get_template(name: "logstash")["logstash"]["index_patterns"]).to eq(["logstash-*"])
391
+ expect(@es.indices.get_template(name: "logstash")["logstash"]["settings"]['index']['lifecycle']['name']).to eq("logstash-policy")
392
+ expect(@es.indices.get_template(name: "logstash")["logstash"]["settings"]['index']['lifecycle']['rollover_alias']).to eq("logstash")
393
+ end
394
+
395
+ it_behaves_like 'an ILM enabled Logstash'
396
+ end
397
+
398
+ context 'with a custom template' do
399
+ let (:ilm_rollover_alias) { "the_cat_in_the_hat" }
400
+ let (:index) { ilm_rollover_alias }
401
+ let(:expected_index) { index }
402
+ let (:settings) { super.merge("ilm_policy" => ilm_policy_name,
403
+ "template" => template,
404
+ "ilm_rollover_alias" => ilm_rollover_alias)}
405
+
406
+
407
+ if ESHelper.es_version_satisfies?(">= 7.0")
408
+ let (:template) { "spec/fixtures/template-with-policy-es7x.json" }
409
+ else
410
+ let (:template) { "spec/fixtures/template-with-policy-es6x.json" }
411
+ end
412
+ let (:ilm_enabled) { true }
413
+ let (:ilm_policy_name) { "custom-policy" }
414
+
415
+
416
+ before :each do
417
+ put_policy(@es,ilm_policy_name, policy)
418
+ end
419
+
420
+ it_behaves_like 'an ILM enabled Logstash'
421
+
422
+ it 'should create the rollover alias' do
423
+ expect(@es.indices.exists_alias(index: ilm_rollover_alias)).to be_falsey
424
+ subject.register
425
+ sleep(1)
426
+ expect(@es.indices.exists_alias(index: ilm_rollover_alias)).to be_truthy
427
+ expect(@es.get_alias(name: ilm_rollover_alias)).to include("#{ilm_rollover_alias}-#{todays_date}-000001")
428
+ end
429
+
430
+ context 'when the custom rollover alias already exists' do
431
+ it 'should ignore the already exists error' do
432
+ expect(@es.indices.exists_alias(index: ilm_rollover_alias)).to be_falsey
433
+ put_alias(@es, "#{ilm_rollover_alias}-#{todays_date}-000001", ilm_rollover_alias)
434
+ expect(@es.indices.exists_alias(index: ilm_rollover_alias)).to be_truthy
435
+ subject.register
436
+ sleep(1)
437
+ expect(@es.get_alias(name: ilm_rollover_alias)).to include("#{ilm_rollover_alias}-#{todays_date}-000001")
438
+ end
439
+
440
+ end
441
+
442
+ it 'should write the ILM settings into the template' do
443
+ subject.register
444
+ sleep(1)
445
+ expect(@es.indices.get_template(name: ilm_rollover_alias)[ilm_rollover_alias]["index_patterns"]).to eq(["#{ilm_rollover_alias}-*"])
446
+ expect(@es.indices.get_template(name: ilm_rollover_alias)[ilm_rollover_alias]["settings"]['index']['lifecycle']['name']).to eq(ilm_policy_name)
447
+ expect(@es.indices.get_template(name: ilm_rollover_alias)[ilm_rollover_alias]["settings"]['index']['lifecycle']['rollover_alias']).to eq(ilm_rollover_alias)
448
+ end
449
+
450
+ context 'with a different template_name' do
451
+ let (:template_name) { "custom_template_name" }
452
+ let (:settings) { super.merge('template_name' => template_name)}
453
+
454
+ it_behaves_like 'an ILM enabled Logstash'
455
+
456
+ it 'should write the ILM settings into the template' do
457
+ subject.register
458
+ sleep(1)
459
+ expect(@es.indices.get_template(name: template_name)[template_name]["index_patterns"]).to eq(["#{ilm_rollover_alias}-*"])
460
+ expect(@es.indices.get_template(name: template_name)[template_name]["settings"]['index']['lifecycle']['name']).to eq(ilm_policy_name)
461
+ expect(@es.indices.get_template(name: template_name)[template_name]["settings"]['index']['lifecycle']['rollover_alias']).to eq(ilm_rollover_alias)
462
+ end
463
+ end
464
+
465
+ end
466
+ end
467
+
468
+ context 'with ilm disabled' do
469
+ let (:ilm_enabled) { false }
470
+
471
+ it 'should not create a rollover alias' do
472
+ expect(@es.get_alias).to be_empty
473
+ subject.register
474
+ sleep(1)
475
+ expect(@es.get_alias).to be_empty
476
+ end
477
+
478
+ it 'should not install the default policy' do
479
+ subject.register
480
+ sleep(1)
481
+ expect{get_policy(@es, LogStash::Outputs::ElasticSearch::DEFAULT_POLICY)}.to raise_error(Elasticsearch::Transport::Transport::Errors::NotFound)
482
+ end
483
+
484
+ it 'should not write the ILM settings into the template' do
485
+ subject.register
486
+ sleep(1)
487
+ expect(@es.indices.get_template(name: "logstash")["logstash"]["index_patterns"]).to eq(["logstash-*"])
488
+ expect(@es.indices.get_template(name: "logstash")["logstash"]["settings"]['index']['lifecycle']).to be_nil
489
+ end
490
+
491
+ context 'with an existing policy that will roll over' do
492
+ let (:policy) { small_max_doc_policy }
493
+ let (:ilm_policy_name) { "3_docs"}
494
+ let (:settings) { super.merge("ilm_policy" => ilm_policy_name)}
495
+
496
+ it 'should not roll over indices' do
497
+ subject.register
498
+ subject.multi_receive([
499
+ LogStash::Event.new("message" => "sample message here"),
500
+ LogStash::Event.new("somemessage" => { "message" => "sample nested message here" }),
501
+ LogStash::Event.new("somevalue" => 100),
502
+ ])
503
+
504
+ sleep(6)
505
+
506
+ subject.multi_receive([
507
+ LogStash::Event.new("country" => "us"),
508
+ LogStash::Event.new("country" => "at"),
509
+ LogStash::Event.new("geoip" => { "location" => [ 0.0, 0.0 ] })
510
+ ])
511
+
512
+ @es.indices.refresh
513
+
514
+ # Wait or fail until everything's indexed.
515
+ Stud::try(20.times) do
516
+ r = @es.search
517
+ expect(r).to have_hits(6)
518
+ end
519
+ indexes_written = @es.search['hits']['hits'].each_with_object(Hash.new(0)) do |x, res|
520
+ index_written = x['_index']
521
+ res[index_written] += 1
522
+ end
523
+ expect(indexes_written.count).to eq(1)
524
+ expect(indexes_written.values.first).to eq(6)
525
+ end
526
+ end
527
+
528
+ context 'with a custom template name' do
529
+ let (:template_name) { "custom_template_name" }
530
+ let (:settings) { super.merge('template_name' => template_name)}
531
+
532
+ it 'should not write the ILM settings into the template' do
533
+ subject.register
534
+ sleep(1)
535
+ expect(@es.indices.get_template(name: template_name)[template_name]["index_patterns"]).to eq(["logstash-*"])
536
+ expect(@es.indices.get_template(name: template_name)[template_name]["settings"]['index']['lifecycle']).to be_nil
537
+ end
538
+ end
539
+
540
+ end
541
+ end
542
+ end