fluent-plugin-elasticsearch 5.0.0 → 5.2.3
Sign up to get free protection for your applications and to get access to all the features.
- 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,
|