fluent-plugin-elasticsearch 5.0.0 → 5.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +6 -0
- data/.github/workflows/linux.yml +5 -2
- data/.github/workflows/macos.yml +5 -2
- data/.github/workflows/windows.yml +5 -2
- data/Gemfile +1 -1
- data/History.md +65 -1
- data/README.Troubleshooting.md +91 -0
- data/README.md +129 -4
- data/fluent-plugin-elasticsearch.gemspec +2 -1
- data/lib/fluent/plugin/elasticsearch_compat.rb +30 -0
- data/lib/fluent/plugin/elasticsearch_error_handler.rb +19 -4
- data/lib/fluent/plugin/elasticsearch_fallback_selector.rb +2 -2
- data/lib/fluent/plugin/elasticsearch_index_lifecycle_management.rb +18 -4
- data/lib/fluent/plugin/elasticsearch_index_template.rb +20 -4
- data/lib/fluent/plugin/elasticsearch_simple_sniffer.rb +2 -1
- data/lib/fluent/plugin/filter_elasticsearch_genid.rb +1 -1
- data/lib/fluent/plugin/in_elasticsearch.rb +2 -1
- data/lib/fluent/plugin/oj_serializer.rb +2 -1
- data/lib/fluent/plugin/out_elasticsearch.rb +80 -19
- data/lib/fluent/plugin/out_elasticsearch_data_stream.rb +132 -62
- data/lib/fluent/plugin/out_elasticsearch_dynamic.rb +3 -1
- data/test/plugin/mock_chunk.dat +0 -0
- data/test/plugin/test_elasticsearch_error_handler.rb +130 -23
- data/test/plugin/test_elasticsearch_fallback_selector.rb +16 -8
- data/test/plugin/test_elasticsearch_index_lifecycle_management.rb +55 -15
- data/test/plugin/test_filter_elasticsearch_genid.rb +16 -16
- data/test/plugin/test_in_elasticsearch.rb +20 -0
- data/test/plugin/test_out_elasticsearch.rb +795 -134
- data/test/plugin/test_out_elasticsearch_data_stream.rb +717 -117
- data/test/plugin/test_out_elasticsearch_dynamic.rb +150 -18
- metadata +21 -5
- data/.travis.yml +0 -40
- data/appveyor.yml +0 -20
@@ -28,6 +28,8 @@ module Fluent::Plugin
|
|
28
28
|
@dynamic_config[key] = value.to_s
|
29
29
|
}
|
30
30
|
# end eval all configs
|
31
|
+
|
32
|
+
log.warn "Elasticsearch dynamic plugin will be deprecated and removed in the future. Please consider to use normal Elasticsearch plugin"
|
31
33
|
end
|
32
34
|
|
33
35
|
def create_meta_config_map
|
@@ -53,7 +55,7 @@ module Fluent::Plugin
|
|
53
55
|
end
|
54
56
|
headers = { 'Content-Type' => @content_type.to_s, }.merge(gzip_headers)
|
55
57
|
ssl_options = { verify: @ssl_verify, ca_file: @ca_file}.merge(@ssl_version_options)
|
56
|
-
transport =
|
58
|
+
transport = TRANSPORT_CLASS::Transport::HTTP::Faraday.new(connection_options.merge(
|
57
59
|
options: {
|
58
60
|
reload_connections: @reload_connections,
|
59
61
|
reload_on_failure: @reload_on_failure,
|
Binary file
|
@@ -2,6 +2,7 @@ require_relative '../helper'
|
|
2
2
|
require 'fluent/plugin/out_elasticsearch'
|
3
3
|
require 'fluent/plugin/elasticsearch_error_handler'
|
4
4
|
require 'json'
|
5
|
+
require 'msgpack'
|
5
6
|
|
6
7
|
class TestElasticsearchErrorHandler < Test::Unit::TestCase
|
7
8
|
|
@@ -27,13 +28,18 @@ class TestElasticsearchErrorHandler < Test::Unit::TestCase
|
|
27
28
|
@error_events << {:tag => tag, :time=>time, :record=>record, :error=>e}
|
28
29
|
end
|
29
30
|
|
30
|
-
def process_message(tag, meta, header, time, record, extracted_values)
|
31
|
+
def process_message(tag, meta, header, time, record, affinity_target_indices, extracted_values)
|
31
32
|
return [meta, header, record]
|
32
33
|
end
|
33
34
|
|
35
|
+
def get_affinity_target_indices(chunk)
|
36
|
+
indices = Hash.new
|
37
|
+
indices
|
38
|
+
end
|
39
|
+
|
34
40
|
def append_record_to_messages(op, meta, header, record, msgs)
|
35
41
|
if record.has_key?('raise') && record['raise']
|
36
|
-
raise
|
42
|
+
raise 'process_message'
|
37
43
|
end
|
38
44
|
return true
|
39
45
|
end
|
@@ -49,6 +55,27 @@ class TestElasticsearchErrorHandler < Test::Unit::TestCase
|
|
49
55
|
end
|
50
56
|
end
|
51
57
|
|
58
|
+
class MockMsgpackChunk
|
59
|
+
def initialize(chunk)
|
60
|
+
@chunk = chunk
|
61
|
+
@factory = MessagePack::Factory.new
|
62
|
+
@factory.register_type(Fluent::EventTime::TYPE, Fluent::EventTime)
|
63
|
+
end
|
64
|
+
|
65
|
+
def msgpack_each
|
66
|
+
@factory.unpacker(@chunk).each { |time, record| yield(time, record) }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class MockUnpackedMsg
|
71
|
+
def initialize(records)
|
72
|
+
@records = records
|
73
|
+
end
|
74
|
+
def each
|
75
|
+
@records.each { |item| yield({:time => item[:time], :record => item[:record]}) }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
52
79
|
def setup
|
53
80
|
Fluent::Test.setup
|
54
81
|
@log_device = Fluent::Test::DummyLogDevice.new
|
@@ -93,8 +120,9 @@ class TestElasticsearchErrorHandler < Test::Unit::TestCase
|
|
93
120
|
]
|
94
121
|
}))
|
95
122
|
chunk = MockChunk.new(records)
|
123
|
+
unpacked_msg_arr = MockUnpackedMsg.new(records)
|
96
124
|
dummy_extracted_values = []
|
97
|
-
@handler.handle_error(response, 'atag', chunk, records.length, dummy_extracted_values)
|
125
|
+
@handler.handle_error(response, 'atag', chunk, records.length, dummy_extracted_values, unpacked_msg_arr)
|
98
126
|
assert_equal(1, @plugin.error_events.size)
|
99
127
|
expected_log = "failed to parse"
|
100
128
|
exception_message = @plugin.error_events.first[:error].message
|
@@ -135,8 +163,9 @@ class TestElasticsearchErrorHandler < Test::Unit::TestCase
|
|
135
163
|
]
|
136
164
|
}))
|
137
165
|
chunk = MockChunk.new(records)
|
166
|
+
unpacked_msg_arr = MockUnpackedMsg.new(records)
|
138
167
|
dummy_extracted_values = []
|
139
|
-
@handler.handle_error(response, 'atag', chunk, records.length, dummy_extracted_values)
|
168
|
+
@handler.handle_error(response, 'atag', chunk, records.length, dummy_extracted_values, unpacked_msg_arr)
|
140
169
|
assert_equal(1, @plugin.error_events.size)
|
141
170
|
expected_log = "failed to parse"
|
142
171
|
exception_message = @plugin.error_events.first[:error].message
|
@@ -154,8 +183,9 @@ class TestElasticsearchErrorHandler < Test::Unit::TestCase
|
|
154
183
|
"items" : [{}]
|
155
184
|
}))
|
156
185
|
chunk = MockChunk.new(records)
|
186
|
+
unpacked_msg_arr = MockUnpackedMsg.new(records)
|
157
187
|
dummy_extracted_values = []
|
158
|
-
@handler.handle_error(response, 'atag', chunk, records.length, dummy_extracted_values)
|
188
|
+
@handler.handle_error(response, 'atag', chunk, records.length, dummy_extracted_values, unpacked_msg_arr)
|
159
189
|
assert_equal(0, @plugin.error_events.size)
|
160
190
|
assert_nil(@plugin.error_events[0])
|
161
191
|
end
|
@@ -176,8 +206,9 @@ class TestElasticsearchErrorHandler < Test::Unit::TestCase
|
|
176
206
|
]
|
177
207
|
}))
|
178
208
|
chunk = MockChunk.new(records)
|
209
|
+
unpacked_msg_arr = MockUnpackedMsg.new(records)
|
179
210
|
dummy_extracted_values = []
|
180
|
-
@handler.handle_error(response, 'atag', chunk, records.length, dummy_extracted_values)
|
211
|
+
@handler.handle_error(response, 'atag', chunk, records.length, dummy_extracted_values, unpacked_msg_arr)
|
181
212
|
assert_equal(1, @plugin.error_events.size)
|
182
213
|
assert_true(@plugin.error_events[0][:error].respond_to?(:backtrace))
|
183
214
|
end
|
@@ -199,8 +230,9 @@ class TestElasticsearchErrorHandler < Test::Unit::TestCase
|
|
199
230
|
]
|
200
231
|
}))
|
201
232
|
chunk = MockChunk.new(records)
|
233
|
+
unpacked_msg_arr = MockUnpackedMsg.new(records)
|
202
234
|
dummy_extracted_values = []
|
203
|
-
@handler.handle_error(response, 'atag', chunk, records.length, dummy_extracted_values)
|
235
|
+
@handler.handle_error(response, 'atag', chunk, records.length, dummy_extracted_values, unpacked_msg_arr)
|
204
236
|
assert_equal(1, @plugin.error_events.size)
|
205
237
|
assert_true(@plugin.error_events[0][:error].respond_to?(:backtrace))
|
206
238
|
end
|
@@ -225,10 +257,11 @@ class TestElasticsearchErrorHandler < Test::Unit::TestCase
|
|
225
257
|
]
|
226
258
|
}))
|
227
259
|
|
228
|
-
|
229
|
-
|
260
|
+
chunk = MockChunk.new(records)
|
261
|
+
unpacked_msg_arr = MockUnpackedMsg.new(records)
|
262
|
+
dummy_extracted_values = []
|
230
263
|
assert_raise(Fluent::Plugin::ElasticsearchErrorHandler::ElasticsearchRequestAbortError) do
|
231
|
-
@handler.handle_error(response, 'atag', chunk, records.length, dummy_extracted_values)
|
264
|
+
@handler.handle_error(response, 'atag', chunk, records.length, dummy_extracted_values, unpacked_msg_arr)
|
232
265
|
end
|
233
266
|
end
|
234
267
|
|
@@ -252,10 +285,11 @@ class TestElasticsearchErrorHandler < Test::Unit::TestCase
|
|
252
285
|
]
|
253
286
|
}))
|
254
287
|
|
255
|
-
|
256
|
-
|
288
|
+
chunk = MockChunk.new(records)
|
289
|
+
unpacked_msg_arr = MockUnpackedMsg.new(records)
|
290
|
+
dummy_extracted_values = []
|
257
291
|
assert_raise(Fluent::Plugin::ElasticsearchErrorHandler::ElasticsearchRequestAbortError) do
|
258
|
-
@handler.handle_error(response, 'atag', chunk, records.length, dummy_extracted_values)
|
292
|
+
@handler.handle_error(response, 'atag', chunk, records.length, dummy_extracted_values, unpacked_msg_arr)
|
259
293
|
end
|
260
294
|
end
|
261
295
|
|
@@ -285,8 +319,9 @@ class TestElasticsearchErrorHandler < Test::Unit::TestCase
|
|
285
319
|
begin
|
286
320
|
failed = false
|
287
321
|
chunk = MockChunk.new(records)
|
322
|
+
unpacked_msg_arr = MockUnpackedMsg.new(records)
|
288
323
|
dummy_extracted_values = []
|
289
|
-
handler.handle_error(response, 'atag', chunk, response['items'].length, dummy_extracted_values)
|
324
|
+
handler.handle_error(response, 'atag', chunk, response['items'].length, dummy_extracted_values, unpacked_msg_arr)
|
290
325
|
rescue Fluent::Plugin::ElasticsearchErrorHandler::ElasticsearchRequestAbortError, Fluent::Plugin::ElasticsearchOutput::RetryStreamError=>e
|
291
326
|
failed = true
|
292
327
|
records = [].tap do |records|
|
@@ -302,11 +337,12 @@ class TestElasticsearchErrorHandler < Test::Unit::TestCase
|
|
302
337
|
def test_retry_error
|
303
338
|
records = []
|
304
339
|
error_records = Hash.new(false)
|
305
|
-
error_records.merge!({0=>true, 4=>true
|
340
|
+
error_records.merge!({0=>true, 4=>true})
|
306
341
|
10.times do |i|
|
307
342
|
records << {time: 12345, record: {"message"=>"record #{i}","_id"=>i,"raise"=>error_records[i]}}
|
308
343
|
end
|
309
344
|
chunk = MockChunk.new(records)
|
345
|
+
unpacked_msg_arr = MockUnpackedMsg.new(records)
|
310
346
|
|
311
347
|
response = parse_response(%({
|
312
348
|
"took" : 1,
|
@@ -386,6 +422,18 @@ class TestElasticsearchErrorHandler < Test::Unit::TestCase
|
|
386
422
|
"reason":"unrecognized error"
|
387
423
|
}
|
388
424
|
}
|
425
|
+
},
|
426
|
+
{
|
427
|
+
"create" : {
|
428
|
+
"_index" : "foo",
|
429
|
+
"_type" : "bar",
|
430
|
+
"_id" : "9",
|
431
|
+
"status" : 500,
|
432
|
+
"error" : {
|
433
|
+
"type" : "json_parse_exception",
|
434
|
+
"reason":"Invalid UTF-8 start byte 0x92\\n at [Source: org.elasticsearch.transport.netty4.ByteBufStreamInput@204fe9c9; line: 1, column: 81]"
|
435
|
+
}
|
436
|
+
}
|
389
437
|
}
|
390
438
|
]
|
391
439
|
}))
|
@@ -393,19 +441,19 @@ class TestElasticsearchErrorHandler < Test::Unit::TestCase
|
|
393
441
|
begin
|
394
442
|
failed = false
|
395
443
|
dummy_extracted_values = []
|
396
|
-
@handler.handle_error(response, 'atag', chunk, response['items'].length, dummy_extracted_values)
|
444
|
+
@handler.handle_error(response, 'atag', chunk, response['items'].length, dummy_extracted_values, unpacked_msg_arr)
|
397
445
|
rescue Fluent::Plugin::ElasticsearchErrorHandler::ElasticsearchRequestAbortError, Fluent::Plugin::ElasticsearchOutput::RetryStreamError=>e
|
398
446
|
failed = true
|
399
447
|
records = [].tap do |records|
|
400
448
|
next unless e.respond_to?(:retry_stream)
|
401
449
|
e.retry_stream.each {|time, record| records << record}
|
402
450
|
end
|
403
|
-
assert_equal 2, records.length
|
404
|
-
assert_equal 2, records[0]['_id']
|
405
|
-
assert_equal 8, records[1]['_id']
|
451
|
+
assert_equal 2, records.length, "Exp. retry_stream to contain records"
|
452
|
+
assert_equal 2, records[0]['_id'], "Exp record with given ID to in retry_stream"
|
453
|
+
assert_equal 8, records[1]['_id'], "Exp record with given ID to in retry_stream"
|
406
454
|
error_ids = @plugin.error_events.collect {|h| h[:record]['_id']}
|
407
|
-
assert_equal
|
408
|
-
assert_equal [5, 6, 7], error_ids
|
455
|
+
assert_equal 4, error_ids.length, "Exp. a certain number of records to be dropped from retry_stream"
|
456
|
+
assert_equal [5, 6, 7, 9], error_ids, "Exp. specific records to be dropped from retry_stream"
|
409
457
|
@plugin.error_events.collect {|h| h[:error]}.each do |e|
|
410
458
|
assert_true e.respond_to?(:backtrace)
|
411
459
|
end
|
@@ -422,6 +470,7 @@ class TestElasticsearchErrorHandler < Test::Unit::TestCase
|
|
422
470
|
records << {time: 12345, record: {"message"=>"record #{i}","_id"=>i,"raise"=>error_records[i]}}
|
423
471
|
end
|
424
472
|
chunk = MockChunk.new(records)
|
473
|
+
unpacked_msg_arr = MockUnpackedMsg.new(records)
|
425
474
|
|
426
475
|
response = parse_response(%({
|
427
476
|
"took" : 1,
|
@@ -509,7 +558,7 @@ class TestElasticsearchErrorHandler < Test::Unit::TestCase
|
|
509
558
|
begin
|
510
559
|
failed = false
|
511
560
|
dummy_extracted_values = []
|
512
|
-
@handler.handle_error(response, 'atag', chunk, response['items'].length, dummy_extracted_values)
|
561
|
+
@handler.handle_error(response, 'atag', chunk, response['items'].length, dummy_extracted_values, unpacked_msg_arr)
|
513
562
|
rescue Fluent::Plugin::ElasticsearchErrorHandler::ElasticsearchRequestAbortError, Fluent::Plugin::ElasticsearchOutput::RetryStreamError=>e
|
514
563
|
failed = true
|
515
564
|
records = [].tap do |records|
|
@@ -532,6 +581,7 @@ class TestElasticsearchErrorHandler < Test::Unit::TestCase
|
|
532
581
|
records << {time: 12345, record: {"message"=>"record #{i}","_id"=>i,"raise"=>error_records[i]}}
|
533
582
|
end
|
534
583
|
chunk = MockChunk.new(records)
|
584
|
+
unpacked_msg_arr = MockUnpackedMsg.new(records)
|
535
585
|
|
536
586
|
response = parse_response(%({
|
537
587
|
"took" : 1,
|
@@ -622,7 +672,7 @@ class TestElasticsearchErrorHandler < Test::Unit::TestCase
|
|
622
672
|
begin
|
623
673
|
failed = false
|
624
674
|
dummy_extracted_values = []
|
625
|
-
@handler.handle_error(response, 'atag', chunk, response['items'].length, dummy_extracted_values)
|
675
|
+
@handler.handle_error(response, 'atag', chunk, response['items'].length, dummy_extracted_values, unpacked_msg_arr)
|
626
676
|
rescue Fluent::Plugin::ElasticsearchErrorHandler::ElasticsearchRequestAbortError, Fluent::Plugin::ElasticsearchOutput::RetryStreamError=>e
|
627
677
|
failed = true
|
628
678
|
records = [].tap do |records|
|
@@ -643,4 +693,61 @@ class TestElasticsearchErrorHandler < Test::Unit::TestCase
|
|
643
693
|
end
|
644
694
|
assert_true failed
|
645
695
|
end
|
696
|
+
|
697
|
+
def test_nested_msgpack_each
|
698
|
+
cwd = File.dirname(__FILE__)
|
699
|
+
chunk_path = File.join(cwd, 'mock_chunk.dat')
|
700
|
+
chunk_file = File.open(chunk_path, 'rb', 0644)
|
701
|
+
chunk_file.seek(0, IO::SEEK_SET)
|
702
|
+
|
703
|
+
chunk = MockMsgpackChunk.new(chunk_file)
|
704
|
+
|
705
|
+
unpacked_msg_arr = []
|
706
|
+
msg_count = 0
|
707
|
+
count_to_trigger_error_handle = 0
|
708
|
+
chunk.msgpack_each do |time, record|
|
709
|
+
next unless record.is_a? Hash
|
710
|
+
|
711
|
+
unpacked_msg_arr << {:time => time, :record => record}
|
712
|
+
msg_count += 1
|
713
|
+
|
714
|
+
record.each_key do |k|
|
715
|
+
if k != 'aaa' && k != 'bbb' && k != 'ccc' && k != 'log_path'
|
716
|
+
assert_equal(:impossible, k)
|
717
|
+
end
|
718
|
+
end
|
719
|
+
|
720
|
+
if msg_count % 55 == 0
|
721
|
+
if count_to_trigger_error_handle == 1
|
722
|
+
begin
|
723
|
+
response = {}
|
724
|
+
response['errors'] = true
|
725
|
+
response['items'] = []
|
726
|
+
item = {}
|
727
|
+
item['index'] = {}
|
728
|
+
item['index']['status'] = 429
|
729
|
+
item['index']['error'] = {}
|
730
|
+
item['index']['error']['type'] = "es_rejected_execution_exception"
|
731
|
+
abc = 0
|
732
|
+
while abc < unpacked_msg_arr.length
|
733
|
+
abc += 1
|
734
|
+
response['items'] << item
|
735
|
+
end
|
736
|
+
|
737
|
+
dummy_extracted_values = []
|
738
|
+
@handler.handle_error(response, 'atag', chunk, unpacked_msg_arr.length, dummy_extracted_values, unpacked_msg_arr)
|
739
|
+
assert_equal(0, @plugin.error_events.size)
|
740
|
+
assert_nil(@plugin.error_events[0])
|
741
|
+
rescue => e
|
742
|
+
# capture ElasticsearchRequestAbortError, beacuse es_rejected_execution_exception is unrecoverable.
|
743
|
+
end
|
744
|
+
end
|
745
|
+
|
746
|
+
count_to_trigger_error_handle += 1
|
747
|
+
unpacked_msg_arr.clear
|
748
|
+
end # end if
|
749
|
+
end # end chunk.msgpack_each
|
750
|
+
|
751
|
+
chunk_file.close
|
752
|
+
end
|
646
753
|
end
|
@@ -18,17 +18,25 @@ class ElasticsearchFallbackSelectorTest < Test::Unit::TestCase
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
def
|
22
|
-
|
23
|
-
|
21
|
+
def elasticsearch_version
|
22
|
+
if Gem::Version.new(TRANSPORT_CLASS::VERSION) >= Gem::Version.new("7.14.0")
|
23
|
+
TRANSPORT_CLASS::VERSION
|
24
|
+
else
|
25
|
+
'6.4.2'.freeze
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def stub_elastic_info(url="http://localhost:9200/", version=elasticsearch_version)
|
30
|
+
body ="{\"version\":{\"number\":\"#{version}\", \"build_flavor\":\"default\"},\"tagline\" : \"You Know, for Search\"}"
|
31
|
+
stub_request(:get, url).to_return({:status => 200, :body => body, :headers => { 'Content-Type' => 'json', 'x-elastic-product' => 'Elasticsearch' } })
|
24
32
|
end
|
25
33
|
|
26
|
-
def stub_elastic_info_not_found(url="http://localhost:9200/", version=
|
27
|
-
stub_request(:get, url).to_return(:status => [404, "Not Found"])
|
34
|
+
def stub_elastic_info_not_found(url="http://localhost:9200/", version=elasticsearch_version)
|
35
|
+
stub_request(:get, url).to_return(:status => [404, "Not Found"], headers: {'x-elastic-product' => 'Elasticsearch' })
|
28
36
|
end
|
29
37
|
|
30
|
-
def stub_elastic_info_unavailable(url="http://localhost:9200/", version=
|
31
|
-
stub_request(:get, url).to_return(:status => [503, "Service Unavailable"])
|
38
|
+
def stub_elastic_info_unavailable(url="http://localhost:9200/", version=elasticsearch_version)
|
39
|
+
stub_request(:get, url).to_return(:status => [503, "Service Unavailable"], headers: {'x-elastic-product' => 'Elasticsearch' })
|
32
40
|
end
|
33
41
|
|
34
42
|
def sample_record(content={})
|
@@ -60,7 +68,7 @@ class ElasticsearchFallbackSelectorTest < Test::Unit::TestCase
|
|
60
68
|
reload_after 10
|
61
69
|
catch_transport_exception_on_retry false # For fallback testing
|
62
70
|
]
|
63
|
-
assert_raise(
|
71
|
+
assert_raise(TRANSPORT_CLASS::Transport::Errors::NotFound) do
|
64
72
|
driver(config)
|
65
73
|
end
|
66
74
|
driver.run(default_tag: 'test') do
|
@@ -6,12 +6,14 @@ class TestElasticsearchIndexLifecycleManagement < Test::Unit::TestCase
|
|
6
6
|
include Fluent::Plugin::ElasticsearchIndexLifecycleManagement
|
7
7
|
|
8
8
|
def setup
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
if Gem::Version.new(Elasticsearch::VERSION) < Gem::Version.new("7.14.0")
|
10
|
+
begin
|
11
|
+
require "elasticsearch/xpack"
|
12
|
+
rescue LoadError
|
13
|
+
omit "ILM testcase needs elasticsearch-xpack gem."
|
14
|
+
end
|
13
15
|
end
|
14
|
-
if Gem::Version.create(::
|
16
|
+
if Gem::Version.create(::TRANSPORT_CLASS::VERSION) < Gem::Version.create("7.4.0")
|
15
17
|
omit "elastisearch-ruby v7.4.0 or later is needed for ILM."
|
16
18
|
end
|
17
19
|
Fluent::Plugin::ElasticsearchIndexLifecycleManagement.module_eval(<<-CODE)
|
@@ -27,40 +29,78 @@ class TestElasticsearchIndexLifecycleManagement < Test::Unit::TestCase
|
|
27
29
|
CODE
|
28
30
|
end
|
29
31
|
|
32
|
+
def elasticsearch_version
|
33
|
+
if Gem::Version.new(TRANSPORT_CLASS::VERSION) >= Gem::Version.new("8.0.0")
|
34
|
+
TRANSPORT_CLASS::VERSION
|
35
|
+
else
|
36
|
+
'6.4.2'.freeze
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def ilm_existence_endpoint(policy_id)
|
41
|
+
if Gem::Version.new(TRANSPORT_CLASS::VERSION) >= Gem::Version.new("8.0.0")
|
42
|
+
"_enrich/policy/#{policy_id}"
|
43
|
+
else
|
44
|
+
"_ilm/policy/%7B:policy_id=%3E%22#{policy_id}%22%7D"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def ilm_creation_endpoint(policy_id)
|
49
|
+
if Gem::Version.new(TRANSPORT_CLASS::VERSION) >= Gem::Version.new("8.0.0")
|
50
|
+
"_enrich/policy/#{policy_id}"
|
51
|
+
else
|
52
|
+
"_ilm/policy/#{policy_id}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def stub_elastic_info(url="http://localhost:9200/", version=elasticsearch_version)
|
57
|
+
body ="{\"version\":{\"number\":\"#{version}\", \"build_flavor\":\"default\"},\"tagline\" : \"You Know, for Search\"}"
|
58
|
+
stub_request(:get, url).to_return({:status => 200, :body => body, :headers => { 'Content-Type' => 'json', 'x-elastic-product' => 'Elasticsearch' } })
|
59
|
+
end
|
60
|
+
|
30
61
|
def test_xpack_info
|
31
62
|
stub_request(:get, "http://localhost:9200/_xpack").
|
32
|
-
to_return(:status => 200, :body => '{"features":{"ilm":{"available":true,"enabled":true}}}', :headers => {"Content-Type"=> "application/json"})
|
63
|
+
to_return(:status => 200, :body => '{"features":{"ilm":{"available":true,"enabled":true}}}', :headers => {"Content-Type"=> "application/json" })
|
64
|
+
stub_elastic_info
|
33
65
|
expected = {"features"=>{"ilm"=>{"available"=>true, "enabled"=>true}}}
|
34
|
-
|
66
|
+
if xpack_info.is_a?(Elasticsearch::API::Response)
|
67
|
+
assert_equal(expected, xpack_info.body)
|
68
|
+
else
|
69
|
+
assert_equal(expected, xpack_info)
|
70
|
+
end
|
35
71
|
end
|
36
72
|
|
37
73
|
def test_verify_ilm_working
|
38
74
|
stub_request(:get, "http://localhost:9200/_xpack").
|
39
|
-
to_return(:status => 200, :body => '{"features":{"ilm":{"available":true,"enabled":true}}}', :headers => {"Content-Type"=> "application/json"})
|
75
|
+
to_return(:status => 200, :body => '{"features":{"ilm":{"available":true,"enabled":true}}}', :headers => {"Content-Type"=> "application/json" })
|
76
|
+
stub_elastic_info
|
40
77
|
assert_nothing_raised { verify_ilm_working }
|
41
78
|
end
|
42
79
|
|
43
80
|
def test_ilm_policy_doesnt_exists
|
44
|
-
stub_request(:get, "http://localhost:9200
|
81
|
+
stub_request(:get, "http://localhost:9200/#{ilm_existence_endpoint("fluentd-policy")}").
|
45
82
|
to_return(:status => 404, :body => "", :headers => {})
|
46
|
-
|
83
|
+
stub_elastic_info
|
84
|
+
assert_false(ilm_policy_exists?("fluentd-policy"))
|
47
85
|
end
|
48
86
|
|
49
87
|
def test_ilm_policy_exists
|
50
|
-
stub_request(:get, "http://localhost:9200
|
88
|
+
stub_request(:get, "http://localhost:9200/#{ilm_existence_endpoint("fluent-policy")}").
|
51
89
|
to_return(:status => 200, :body => "", :headers => {})
|
52
|
-
|
90
|
+
stub_elastic_info
|
91
|
+
assert_true(ilm_policy_exists?("fluent-policy"))
|
53
92
|
end
|
54
93
|
|
55
94
|
def test_create_ilm_policy
|
56
|
-
stub_request(:get, "http://localhost:9200
|
95
|
+
stub_request(:get, "http://localhost:9200/#{ilm_creation_endpoint("fluent-policy")}").
|
57
96
|
to_return(:status => 404, :body => "", :headers => {})
|
58
|
-
stub_request(:put, "http://localhost:9200
|
97
|
+
stub_request(:put, "http://localhost:9200/#{ilm_creation_endpoint("fluent-policy")}").
|
59
98
|
with(:body => "{\"policy\":{\"phases\":{\"hot\":{\"actions\":{\"rollover\":{\"max_size\":\"50gb\",\"max_age\":\"30d\"}}}}}}",
|
60
99
|
:headers => {'Content-Type'=>'application/json'}).
|
61
100
|
to_return(:status => 200, :body => "", :headers => {})
|
101
|
+
stub_elastic_info
|
62
102
|
create_ilm_policy("fluent-policy")
|
63
103
|
|
64
|
-
assert_requested(:put, "http://localhost:9200
|
104
|
+
assert_requested(:put, "http://localhost:9200/#{ilm_creation_endpoint("fluent-policy")}", times: 1)
|
65
105
|
end
|
66
106
|
end
|
@@ -132,10 +132,10 @@ class ElasticsearchGenidFilterTest < Test::Unit::TestCase
|
|
132
132
|
end
|
133
133
|
|
134
134
|
class UseEntireRecordAsSeedTest < self
|
135
|
-
data("md5" => ["md5", "
|
136
|
-
"sha1" => ["sha1", "
|
137
|
-
"sha256" => ["sha256", "
|
138
|
-
"sha512" => ["sha512", "
|
135
|
+
data("md5" => ["md5", "OAod7J0DR9s9/rOQnkeSFw=="],
|
136
|
+
"sha1" => ["sha1", "0CT4aMJ4gxMT3TKaYPCYApiVsq8="],
|
137
|
+
"sha256" => ["sha256", "mbAuKF5can0TTj/JBk71AXtOyoVqw5W5gMPUxx6pxLk="],
|
138
|
+
"sha512" => ["sha512", "f7kz5KVuDy+riENePDzqBjGQfbuRNpRBSQMzT2/6hrljXbYtBy3YFmxB86ofIf3zz4ZBao2QM2W7YvcwbRtK1w=="],)
|
139
139
|
def test_record
|
140
140
|
hash_type, expected = data
|
141
141
|
d = create_driver(%[
|
@@ -151,10 +151,10 @@ class ElasticsearchGenidFilterTest < Test::Unit::TestCase
|
|
151
151
|
d.filtered.map {|e| e.last}.first[d.instance.hash_id_key])
|
152
152
|
end
|
153
153
|
|
154
|
-
data("md5" => ["md5", "
|
155
|
-
"sha1" => ["sha1", "
|
156
|
-
"sha256" => ["sha256", "
|
157
|
-
"sha512" => ["sha512", "
|
154
|
+
data("md5" => ["md5", "Hb0jwxofNQP+ufQTKK1U4g=="],
|
155
|
+
"sha1" => ["sha1", "BakTtlotl/u+yOON6YcViTz6nms="],
|
156
|
+
"sha256" => ["sha256", "eLuTCsFqDlk6PfABNyD39r36+yNIBeDTHyNKfJ8fZQw="],
|
157
|
+
"sha512" => ["sha512", "PhPCNGalM4H4xT19DnCBnpwr56lbvCo8wJGyCiH9dWcyhn1nA5l1diYSZlF2fNiq1+wzMqfGvJILIjgQrlAPcg=="],)
|
158
158
|
def test_record_with_tag
|
159
159
|
hash_type, expected = data
|
160
160
|
d = create_driver(%[
|
@@ -171,10 +171,10 @@ class ElasticsearchGenidFilterTest < Test::Unit::TestCase
|
|
171
171
|
d.filtered.map {|e| e.last}.first[d.instance.hash_id_key])
|
172
172
|
end
|
173
173
|
|
174
|
-
data("md5" => ["md5", "
|
175
|
-
"sha1" => ["sha1", "
|
176
|
-
"sha256" => ["sha256", "
|
177
|
-
"sha512" => ["sha512", "
|
174
|
+
data("md5" => ["md5", "C8vfhC4kecNCNutFCuC6MA=="],
|
175
|
+
"sha1" => ["sha1", "+YWVqUEL90wpKJRrionUJwNgXHg="],
|
176
|
+
"sha256" => ["sha256", "eSqGZqjnO6Uum/4CNfJaolX49+2XKogiGMHGNHiO91Q="],
|
177
|
+
"sha512" => ["sha512", "iVmuD0D+i/WtBwNza09ZXSIW8Xg8/yrUwK/M/EZaCMjz/x5FyyCiVkb1VVKsgNnJy0SYt4w21dhHewu1aXM6HA=="],)
|
178
178
|
def test_record_with_time
|
179
179
|
hash_type, expected = data
|
180
180
|
d = create_driver(%[
|
@@ -191,10 +191,10 @@ class ElasticsearchGenidFilterTest < Test::Unit::TestCase
|
|
191
191
|
d.filtered.map {|e| e.last}.first[d.instance.hash_id_key])
|
192
192
|
end
|
193
193
|
|
194
|
-
data("md5" => ["md5", "
|
195
|
-
"sha1" => ["sha1", "
|
196
|
-
"sha256" => ["sha256", "
|
197
|
-
"sha512" => ["sha512", "
|
194
|
+
data("md5" => ["md5", "lU7d4EiF+2M1zxWcsmBbjg=="],
|
195
|
+
"sha1" => ["sha1", "nghmz1y3KTEFxalfS2/Oe4n4yfQ="],
|
196
|
+
"sha256" => ["sha256", "d0le9UOnUeuGPF/2yEBRM1YzOYeHtxYOE1UU6JgJrvU="],
|
197
|
+
"sha512" => ["sha512", "n7rhisGHUBne6c4Cs9DRMbPror8O5Y/vYajDqAtOaiUTys/Z1EKBMnZQA0iVNFw7joX33cenBW3Yyccct3xSew=="],)
|
198
198
|
def test_record_with_tag_and_time
|
199
199
|
hash_type, expected = data
|
200
200
|
d = create_driver(%[
|
@@ -31,6 +31,19 @@ class ElasticsearchInputTest < Test::Unit::TestCase
|
|
31
31
|
@driver ||= Fluent::Test::Driver::Input.new(Fluent::Plugin::ElasticsearchInput).configure(conf)
|
32
32
|
end
|
33
33
|
|
34
|
+
def elasticsearch_version
|
35
|
+
if Gem::Version.new(TRANSPORT_CLASS::VERSION) >= Gem::Version.new("7.14.0")
|
36
|
+
TRANSPORT_CLASS::VERSION
|
37
|
+
else
|
38
|
+
'7.9.0'.freeze
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def stub_elastic_info(url="http://localhost:9200/", version=elasticsearch_version)
|
43
|
+
body ="{\"version\":{\"number\":\"#{version}\", \"build_flavor\":\"default\"},\"tagline\" : \"You Know, for Search\"}"
|
44
|
+
stub_request(:get, url).to_return({:status => 200, :body => body, :headers => { 'Content-Type' => 'json', 'x-elastic-product' => 'Elasticsearch' } })
|
45
|
+
end
|
46
|
+
|
34
47
|
def sample_response(index_name="fluentd")
|
35
48
|
{
|
36
49
|
"took"=>4,
|
@@ -322,6 +335,7 @@ class ElasticsearchInputTest < Test::Unit::TestCase
|
|
322
335
|
with(body: "{\"sort\":[\"_doc\"]}").
|
323
336
|
to_return(status: 200, body: sample_response.to_s,
|
324
337
|
headers: {'Content-Type' => 'application/json'})
|
338
|
+
stub_elastic_info
|
325
339
|
|
326
340
|
driver(CONFIG)
|
327
341
|
driver.run(expect_emits: 1, timeout: 10)
|
@@ -337,6 +351,7 @@ class ElasticsearchInputTest < Test::Unit::TestCase
|
|
337
351
|
with(body: "{\"sort\":[\"_doc\"]}").
|
338
352
|
to_return(status: 200, body: sample_response(index_name).to_s,
|
339
353
|
headers: {'Content-Type' => 'application/json'})
|
354
|
+
stub_elastic_info
|
340
355
|
|
341
356
|
driver(CONFIG + %[index_name #{index_name}])
|
342
357
|
driver.run(expect_emits: 1, timeout: 10)
|
@@ -352,6 +367,7 @@ class ElasticsearchInputTest < Test::Unit::TestCase
|
|
352
367
|
with(body: "{\"sort\":[\"_doc\"]}").
|
353
368
|
to_return(status: 200, body: sample_response(index_name).to_s,
|
354
369
|
headers: {'Content-Type' => 'application/json'})
|
370
|
+
stub_elastic_info
|
355
371
|
|
356
372
|
driver(CONFIG + %[parse_timestamp])
|
357
373
|
driver.run(expect_emits: 1, timeout: 10)
|
@@ -370,6 +386,7 @@ class ElasticsearchInputTest < Test::Unit::TestCase
|
|
370
386
|
with(body: "{\"sort\":[\"_doc\"]}").
|
371
387
|
to_return(status: 200, body: sample_response(index_name).to_s,
|
372
388
|
headers: {'Content-Type' => 'application/json'})
|
389
|
+
stub_elastic_info
|
373
390
|
|
374
391
|
driver(CONFIG + %[parse_timestamp true
|
375
392
|
timestamp_key_format %Y-%m-%dT%H:%M:%S.%N%z
|
@@ -389,6 +406,7 @@ class ElasticsearchInputTest < Test::Unit::TestCase
|
|
389
406
|
with(body: "{\"sort\":[\"_doc\"]}").
|
390
407
|
to_return(status: 200, body: sample_response.to_s,
|
391
408
|
headers: {'Content-Type' => 'application/json'})
|
409
|
+
stub_elastic_info
|
392
410
|
|
393
411
|
driver(CONFIG + %[docinfo true])
|
394
412
|
driver.run(expect_emits: 1, timeout: 10)
|
@@ -412,6 +430,7 @@ class ElasticsearchInputTest < Test::Unit::TestCase
|
|
412
430
|
with(body: "{\"sort\":[\"_doc\"],\"slice\":{\"id\":1,\"max\":2}}").
|
413
431
|
to_return(status: 200, body: sample_response.to_s,
|
414
432
|
headers: {'Content-Type' => 'application/json'})
|
433
|
+
stub_elastic_info
|
415
434
|
|
416
435
|
driver(CONFIG + %[num_slices 2])
|
417
436
|
driver.run(expect_emits: 1, timeout: 10)
|
@@ -434,6 +453,7 @@ class ElasticsearchInputTest < Test::Unit::TestCase
|
|
434
453
|
body: "{\"scroll_id\":\"WomkoUKG0QPB679Ulo6TqQgh3pIGRUmrl9qXXGK3EeiQh9rbYNasTkspZQcJ01uz\"}") do
|
435
454
|
connection += 1
|
436
455
|
end
|
456
|
+
stub_elastic_info
|
437
457
|
scroll_request.to_return(lambda do |req|
|
438
458
|
if connection <= 1
|
439
459
|
{status: 200, body: sample_scroll_response_2.to_s,
|