logstash-input-elasticsearch 4.23.1 → 5.0.0

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.
@@ -21,13 +21,6 @@ describe LogStash::Inputs::Elasticsearch, :ecs_compatibility_support do
21
21
  let(:es_version) { "7.5.0" }
22
22
  let(:cluster_info) { {"version" => {"number" => es_version, "build_flavor" => build_flavor}, "tagline" => "You Know, for Search"} }
23
23
 
24
- def elastic_ruby_v8_client_available?
25
- Elasticsearch::Transport
26
- false
27
- rescue NameError # NameError: uninitialized constant Elasticsearch::Transport if Elastic Ruby client is not available
28
- true
29
- end
30
-
31
24
  before(:each) do
32
25
  Elasticsearch::Client.send(:define_method, :ping) { } # define no-action ping method
33
26
  allow_any_instance_of(Elasticsearch::Client).to receive(:info).and_return(cluster_info)
@@ -65,6 +58,19 @@ describe LogStash::Inputs::Elasticsearch, :ecs_compatibility_support do
65
58
  end
66
59
  end
67
60
 
61
+ describe 'handling obsolete settings' do
62
+ [{:name => 'ssl', :replacement => 'ssl_enabled', :sample_value => true},
63
+ {:name => 'ca_file', :replacement => 'ssl_certificate_authorities', :sample_value => 'spec/fixtures/test_certs/ca.crt'},
64
+ {:name => 'ssl_certificate_verification', :replacement => 'ssl_verification_mode', :sample_value => false }].each do | obsolete_setting|
65
+ context "with obsolete #{obsolete_setting[:name]}" do
66
+ let (:config) { {obsolete_setting[:name] => obsolete_setting[:sample_value]} }
67
+ it "should raise a config error with the appropriate message" do
68
+ expect { plugin.register }.to raise_error LogStash::ConfigurationError, /The setting `#{obsolete_setting[:name]}` in plugin `elasticsearch` is obsolete and is no longer available. Set '#{obsolete_setting[:replacement]}' instead/i
69
+ end
70
+ end
71
+ end
72
+ end
73
+
68
74
  context "against not authentic Elasticsearch" do
69
75
  before(:each) do
70
76
  Elasticsearch::Client.send(:define_method, :ping) { raise Elasticsearch::UnsupportedProductError.new("Fake error") } # define error ping method
@@ -86,11 +92,9 @@ describe LogStash::Inputs::Elasticsearch, :ecs_compatibility_support do
86
92
 
87
93
  before do
88
94
  allow(Elasticsearch::Client).to receive(:new).and_return(es_client)
89
- if elastic_ruby_v8_client_available?
90
- allow(es_client).to receive(:info).and_raise(Elastic::Transport::Transport::Errors::BadRequest.new)
91
- else
92
- allow(es_client).to receive(:info).and_raise(Elasticsearch::Transport::Transport::Errors::BadRequest.new)
93
- end
95
+ allow(es_client).to receive(:info).and_raise(
96
+ Elasticsearch::Transport::Transport::Errors::BadRequest.new
97
+ )
94
98
  end
95
99
 
96
100
  it "raises an exception" do
@@ -662,28 +666,11 @@ describe LogStash::Inputs::Elasticsearch, :ecs_compatibility_support do
662
666
  context 'if the `docinfo_target` exist but is not of type hash' do
663
667
  let(:config) { base_config.merge 'docinfo' => true, "docinfo_target" => 'metadata_with_string' }
664
668
  let(:do_register) { false }
665
- let(:mock_queue) { double('Queue', :<< => nil) }
666
- let(:hit) { response.dig('hits', 'hits').first }
667
-
668
- it 'emits a tagged event with JSON-serialized event in [event][original]' do
669
- allow(plugin).to receive(:logger).and_return(double('Logger').as_null_object)
670
669
 
670
+ it 'raises an exception if the `docinfo_target` exist but is not of type hash' do
671
+ expect(client).not_to receive(:clear_scroll)
671
672
  plugin.register
672
- plugin.run(mock_queue)
673
-
674
- expect(mock_queue).to have_received(:<<) do |event|
675
- expect(event).to be_a_kind_of LogStash::Event
676
-
677
- expect(event.get('tags')).to include("_elasticsearch_input_failure")
678
- expect(event.get('[event][original]')).to be_a_kind_of String
679
- expect(JSON.load(event.get('[event][original]'))).to eq hit
680
- end
681
-
682
- expect(plugin.logger)
683
- .to have_received(:warn).with(
684
- a_string_including("Event creation error, original data now in [event][original] field"),
685
- a_hash_including(:message => a_string_including('unable to merge docinfo fields into docinfo_target=`metadata_with_string`'),
686
- :data => a_string_including('"_id":"C5b2xLQwTZa76jBmHIbwHQ"')))
673
+ expect { plugin.run([]) }.to raise_error(Exception, /incompatible event/)
687
674
  end
688
675
 
689
676
  end
@@ -740,13 +727,8 @@ describe LogStash::Inputs::Elasticsearch, :ecs_compatibility_support do
740
727
  it "should set host(s)" do
741
728
  plugin.register
742
729
  client = plugin.send(:client)
743
- target_field = :@seeds
744
- begin
745
- Elasticsearch::Transport::Client
746
- rescue
747
- target_field = :@hosts
748
- end
749
- expect( client.transport.instance_variable_get(target_field) ).to eql [{
730
+
731
+ expect( client.transport.instance_variable_get(:@seeds) ).to eql [{
750
732
  :scheme => "https",
751
733
  :host => "ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io",
752
734
  :port => 9243,
@@ -810,50 +792,14 @@ describe LogStash::Inputs::Elasticsearch, :ecs_compatibility_support do
810
792
  end
811
793
 
812
794
  context "with ssl" do
813
- let(:api_key_value) { nil }
814
- let(:config) { super().merge("ssl_enabled" => true, 'api_key' => LogStash::Util::Password.new(api_key_value)) }
815
- let(:encoded_api_key) { Base64.strict_encode64('foo:bar') }
816
-
817
- shared_examples "a plugin that sets the ApiKey authorization header" do
818
- it "correctly sets the Authorization header" do
819
- plugin.register
820
- client = plugin.send(:client)
821
- auth_header = extract_transport(client).options[:transport_options][:headers]['Authorization']
822
-
823
- expect(auth_header).to eql("ApiKey #{encoded_api_key}")
824
- end
825
- end
826
-
827
- context "with a non-encoded API key" do
828
- let(:api_key_value) { "foo:bar" }
829
- it_behaves_like "a plugin that sets the ApiKey authorization header"
830
- end
795
+ let(:config) { super().merge({ 'api_key' => LogStash::Util::Password.new('foo:bar'), "ssl_enabled" => true }) }
831
796
 
832
- context "with an encoded API key" do
833
- let(:api_key_value) { encoded_api_key }
834
- it_behaves_like "a plugin that sets the ApiKey authorization header"
835
- end
836
-
837
- context "with an Elastic Cloud API key (essu_ prefix)" do
838
- # The suffix is intentionally not canonical base64: a Cloud key is opaque
839
- # and must be forwarded verbatim regardless of its payload encoding.
840
- let(:api_key_value) { "essu_VFZGblZreFhTekJ4ZDB4M2NHUnZRMEU2YzNWd1pYSnpaV055WlhRPQ==AAAAAAAA" }
841
-
842
- it "sets the Authorization header verbatim without re-encoding" do
843
- plugin.register
844
- client = plugin.send(:client)
845
- auth_header = extract_transport(client).options[:transport_options][:headers]['Authorization']
846
-
847
- expect(auth_header).to eql("ApiKey #{api_key_value}")
848
- end
849
- end
850
-
851
- context "with an unrecognized api_key format" do
852
- let(:api_key_value) { "not-a-valid-key" }
797
+ it "should set authorization" do
798
+ plugin.register
799
+ client = plugin.send(:client)
800
+ auth_header = extract_transport(client).options[:transport_options][:headers]['Authorization']
853
801
 
854
- it "fails registration with a configuration error" do
855
- expect { plugin.register }.to raise_error(LogStash::ConfigurationError, /Invalid api_key format/)
856
- end
802
+ expect( auth_header ).to eql "ApiKey #{Base64.strict_encode64('foo:bar')}"
857
803
  end
858
804
 
859
805
  context 'user also set' do
@@ -1188,7 +1134,7 @@ describe LogStash::Inputs::Elasticsearch, :ecs_compatibility_support do
1188
1134
 
1189
1135
  context "when there's an exception" do
1190
1136
  before(:each) do
1191
- allow(client).to receive(:search).and_raise RuntimeError.new("test exception")
1137
+ allow(client).to receive(:search).and_raise RuntimeError
1192
1138
  end
1193
1139
  it 'produces no events' do
1194
1140
  plugin.run queue
@@ -1302,220 +1248,9 @@ describe LogStash::Inputs::Elasticsearch, :ecs_compatibility_support do
1302
1248
  end
1303
1249
  end
1304
1250
 
1305
- context '#push_hit' do
1306
- let(:config) do
1307
- {
1308
- 'docinfo' => true, # include ids
1309
- 'docinfo_target' => '[@metadata][docinfo]'
1310
- }
1311
- end
1312
-
1313
- let(:hit) do
1314
- JSON.load(<<~EOJSON)
1315
- {
1316
- "_index" : "test_bulk_index_2",
1317
- "_type" : "_doc",
1318
- "_id" : "sHe6A3wBesqF7ydicQvG",
1319
- "_score" : 1.0,
1320
- "_source" : {
1321
- "@timestamp" : "2021-09-20T15:02:02.557Z",
1322
- "message" : "ping",
1323
- "@version" : "17",
1324
- "sequence" : 7,
1325
- "host" : {
1326
- "name" : "maybe.local",
1327
- "ip" : "127.0.0.1"
1328
- }
1329
- }
1330
- }
1331
- EOJSON
1332
- end
1333
-
1334
- let(:mock_queue) { double('queue', :<< => nil) }
1335
-
1336
- before(:each) do
1337
- plugin.send(:setup_cursor_tracker)
1338
- end
1339
-
1340
- it 'pushes a generated event to the queue' do
1341
- plugin.send(:push_hit, hit, mock_queue)
1342
- expect(mock_queue).to have_received(:<<) do |event|
1343
- expect(event).to be_a_kind_of LogStash::Event
1344
-
1345
- # fields overriding defaults
1346
- expect(event.timestamp.to_s).to eq("2021-09-20T15:02:02.557Z")
1347
- expect(event.get('@version')).to eq("17")
1348
-
1349
- # structure from hit's _source
1350
- expect(event.get('message')).to eq("ping")
1351
- expect(event.get('sequence')).to eq(7)
1352
- expect(event.get('[host][name]')).to eq("maybe.local")
1353
- expect(event.get('[host][ip]')).to eq("127.0.0.1")
1354
-
1355
- # docinfo fields
1356
- expect(event.get('[@metadata][docinfo][_index]')).to eq("test_bulk_index_2")
1357
- expect(event.get('[@metadata][docinfo][_type]')).to eq("_doc")
1358
- expect(event.get('[@metadata][docinfo][_id]')).to eq("sHe6A3wBesqF7ydicQvG")
1359
- end
1360
- end
1361
-
1362
- context 'when event creation fails' do
1363
- before(:each) do
1364
- allow(plugin).to receive(:logger).and_return(double('Logger').as_null_object)
1365
-
1366
- allow(plugin.event_factory).to receive(:new_event).and_call_original
1367
- allow(plugin.event_factory).to receive(:new_event).with(a_hash_including hit['_source']).and_raise(RuntimeError, 'intentional')
1368
- end
1369
-
1370
- it 'pushes a tagged event containing a JSON-encoded hit in [event][original]' do
1371
- plugin.send(:push_hit, hit, mock_queue)
1372
-
1373
- expect(mock_queue).to have_received(:<<) do |event|
1374
- expect(event).to be_a_kind_of LogStash::Event
1375
-
1376
- expect(event.get('tags')).to include("_elasticsearch_input_failure")
1377
- expect(event.get('[event][original]')).to be_a_kind_of String
1378
- expect(JSON.load(event.get('[event][original]'))).to eq hit
1379
- end
1380
-
1381
- expect(plugin.logger)
1382
- .to have_received(:warn).with(
1383
- a_string_including("Event creation error, original data now in [event][original] field"),
1384
- a_hash_including(:message => a_string_including('intentional'),
1385
- :data => a_string_including('"_id":"sHe6A3wBesqF7ydicQvG"')))
1386
-
1387
- end
1388
- end
1389
- end
1390
-
1391
1251
  # @note can be removed once we depends on elasticsearch gem >= 6.x
1392
1252
  def extract_transport(client) # on 7.x client.transport is a ES::Transport::Client
1393
1253
  client.transport.respond_to?(:transport) ? client.transport.transport : client.transport
1394
1254
  end
1395
1255
 
1396
- describe "#ESQL" do
1397
- let(:config) do
1398
- {
1399
- "query" => "FROM test-index | STATS count() BY field",
1400
- "query_type" => "esql",
1401
- "retries" => 3
1402
- }
1403
- end
1404
- let(:es_version) { LogStash::Inputs::Elasticsearch::ES_ESQL_SUPPORT_VERSION }
1405
- let(:ls_version) { LogStash::Inputs::Elasticsearch::LS_ESQL_SUPPORT_VERSION }
1406
-
1407
- before(:each) do
1408
- stub_const("LOGSTASH_VERSION", ls_version)
1409
- end
1410
-
1411
- describe "#initialize" do
1412
- it "sets up the ESQL client with correct parameters" do
1413
- expect(plugin.instance_variable_get(:@query_type)).to eq(config["query_type"])
1414
- expect(plugin.instance_variable_get(:@query)).to eq(config["query"])
1415
- expect(plugin.instance_variable_get(:@retries)).to eq(config["retries"])
1416
- end
1417
- end
1418
-
1419
- describe "#register" do
1420
- before(:each) do
1421
- Elasticsearch::Client.send(:define_method, :ping) { }
1422
- allow_any_instance_of(Elasticsearch::Client).to receive(:info).and_return(cluster_info)
1423
- end
1424
- it "creates ES|QL executor" do
1425
- plugin.register
1426
- expect(plugin.instance_variable_get(:@query_executor)).to be_an_instance_of(LogStash::Inputs::Elasticsearch::Esql)
1427
- end
1428
- end
1429
-
1430
- describe "#validation" do
1431
-
1432
- describe "LS version" do
1433
- context "when compatible" do
1434
-
1435
- it "does not raise an error" do
1436
- expect { plugin.send(:validate_ls_version_for_esql_support!) }.not_to raise_error
1437
- end
1438
- end
1439
-
1440
- context "when incompatible" do
1441
- before(:each) do
1442
- stub_const("LOGSTASH_VERSION", "8.10.0")
1443
- end
1444
-
1445
- it "raises a runtime error" do
1446
- expect { plugin.send(:validate_ls_version_for_esql_support!) }
1447
- .to raise_error(RuntimeError, /Current version of Logstash does not include Elasticsearch client which supports ES|QL. Please upgrade Logstash to at least #{ls_version}/)
1448
- end
1449
- end
1450
- end
1451
-
1452
- describe "ES version" do
1453
- before(:each) do
1454
- allow(plugin).to receive(:es_version).and_return("8.10.5")
1455
- end
1456
-
1457
- context "when incompatible" do
1458
- it "raises a runtime error" do
1459
- expect { plugin.send(:validate_es_for_esql_support!) }
1460
- .to raise_error(RuntimeError, /Connected Elasticsearch 8.10.5 version does not supports ES|QL. ES|QL feature requires at least Elasticsearch #{es_version} version./)
1461
- end
1462
- end
1463
- end
1464
-
1465
- context "ES|QL query and DSL params used together" do
1466
- let(:config) {
1467
- super().merge({
1468
- "index" => "my-index",
1469
- "size" => 1,
1470
- "slices" => 1,
1471
- "search_api" => "auto",
1472
- "docinfo" => true,
1473
- "docinfo_target" => "[@metadata][docinfo]",
1474
- "docinfo_fields" => ["_index"],
1475
- "response_type" => "hits",
1476
- "tracking_field" => "[@metadata][tracking]"
1477
- })}
1478
-
1479
- it "raises a config error" do
1480
- mixed_fields = %w[index size slices docinfo_fields response_type tracking_field]
1481
- expect { plugin.register }.to raise_error(LogStash::ConfigurationError, /Configured #{mixed_fields} params are not allowed while using ES|QL query/)
1482
- end
1483
- end
1484
-
1485
- describe "ES|QL query" do
1486
- context "when query is valid" do
1487
- it "does not raise an error" do
1488
- expect { plugin.send(:validate_esql_query!) }.not_to raise_error
1489
- end
1490
- end
1491
-
1492
- context "when query is empty" do
1493
- let(:config) do
1494
- {
1495
- "query" => " "
1496
- }
1497
- end
1498
-
1499
- it "raises a configuration error" do
1500
- expect { plugin.send(:validate_esql_query!) }
1501
- .to raise_error(LogStash::ConfigurationError, /`query` cannot be empty/)
1502
- end
1503
- end
1504
-
1505
- context "when query doesn't align with ES syntax" do
1506
- let(:config) do
1507
- {
1508
- "query" => "RANDOM query"
1509
- }
1510
- end
1511
-
1512
- it "raises a configuration error" do
1513
- source_commands = %w[FROM ROW SHOW]
1514
- expect { plugin.send(:validate_esql_query!) }
1515
- .to raise_error(LogStash::ConfigurationError, "`query` needs to start with any of #{source_commands}")
1516
- end
1517
- end
1518
- end
1519
- end
1520
- end
1521
1256
  end
@@ -4,7 +4,7 @@ require "logstash/plugin"
4
4
  require "logstash/inputs/elasticsearch"
5
5
  require_relative "../../../spec/es_helper"
6
6
 
7
- describe LogStash::Inputs::Elasticsearch do
7
+ describe LogStash::Inputs::Elasticsearch, :integration => true do
8
8
 
9
9
  SECURE_INTEGRATION = ENV['SECURE_INTEGRATION'].eql? 'true'
10
10
 
@@ -76,14 +76,6 @@ describe LogStash::Inputs::Elasticsearch do
76
76
  shared_examples 'secured_elasticsearch' do
77
77
  it_behaves_like 'an elasticsearch index plugin'
78
78
 
79
- let(:unauth_exception_class) do
80
- begin
81
- Elasticsearch::Transport::Transport::Errors::Unauthorized
82
- rescue
83
- Elastic::Transport::Transport::Errors::Unauthorized
84
- end
85
- end
86
-
87
79
  context "incorrect auth credentials" do
88
80
 
89
81
  let(:config) do
@@ -93,7 +85,7 @@ describe LogStash::Inputs::Elasticsearch do
93
85
  let(:queue) { [] }
94
86
 
95
87
  it "fails to run the plugin" do
96
- expect { plugin.register }.to raise_error unauth_exception_class
88
+ expect { plugin.register }.to raise_error Elasticsearch::Transport::Transport::Errors::Unauthorized
97
89
  end
98
90
  end
99
91
  end