logstash-filter-elasticsearch 3.9.3 → 3.11.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 886cfa121f2af1a9efdcfff9f3f2e97be3456be2aecbb668b89d3517d8087ffc
4
- data.tar.gz: 0f0a568d1bf012cd0845a6d9cb5782a6460a32332a493790b84f010e68c06fcd
3
+ metadata.gz: 2fb1bc80bd95bd0e99591f07f0d2b0c76942d9a06618457e275679caeae9c0ec
4
+ data.tar.gz: 763fbbf17d77630c097bbbfa834842e8316830687a40a216704ee8902eb61e2a
5
5
  SHA512:
6
- metadata.gz: 3e15a05bd9d013a2145ce983b2699f94c619276d93a675d49695ef8b8cf1d48ef88e6dfb4edac975d11a85bc57c0e769566b35ec44b8b2776fca8e35300af65d
7
- data.tar.gz: 667279291114a2a93cbbd211e6ec7ff7533eada83dbfc73377d0a67b759ae773e7787f9b1a11518e9101302653cf5b8b356936a211521f9f635cc58646826730
6
+ metadata.gz: 764940be26047fae75ffc160a5a75831599073c10a2f2712620984ea6fec3e04107efb6fa8c1b7e302e55387ab6629f88e3a82a460543f7a9a90c46ebf3c3ac2
7
+ data.tar.gz: 6a68318f5028c52265c42c3f939f43619427306964bb70453a1ca60444113601b662c45c6eb19fc65912c63b652707463879b2caba9a67f2aa9686736cd42d13
data/CHANGELOG.md CHANGED
@@ -1,3 +1,19 @@
1
+ ## 3.11.0
2
+ - Feat: update Elasticsearch client to 7.14.0 [#150](https://github.com/logstash-plugins/logstash-filter-elasticsearch/pull/150)
3
+
4
+ ## 3.10.0
5
+ - Feat: add user-agent header passed to the Elasticsearch HTTP connection [#152](https://github.com/logstash-plugins/logstash-filter-elasticsearch/pull/152)
6
+
7
+ ## 3.9.5
8
+ - Fixed SSL handshake hang indefinitely with proxy setup [#151](https://github.com/logstash-plugins/logstash-filter-elasticsearch/pull/151)
9
+
10
+ ## 3.9.4
11
+ - Fix: a regression (in LS 7.14.0) where due the elasticsearch client update (from 5.0.5 to 7.5.0) the `Authorization`
12
+ header isn't passed, this leads to the plugin not being able to leverage `user`/`password` credentials set by the user.
13
+ [#148](https://github.com/logstash-plugins/logstash-filter-elasticsearch/pull/148)
14
+ - Fix: default setting for `hosts` not working (since 3.7.0) GH-147
15
+ - Fix: mutating @hosts variable which leads to issues with multiple worker threads GH-129
16
+
1
17
  ## 3.9.3
2
18
  - [DOC] Update links to use shared attributes [#144](https://github.com/logstash-plugins/logstash-filter-elasticsearch/pull/144)
3
19
 
@@ -16,15 +16,17 @@ module LogStash
16
16
  password = options.fetch(:password, nil)
17
17
  api_key = options.fetch(:api_key, nil)
18
18
  proxy = options.fetch(:proxy, nil)
19
+ user_agent = options[:user_agent]
19
20
 
20
21
  transport_options = {:headers => {}}
21
22
  transport_options[:headers].merge!(setup_basic_auth(user, password))
22
23
  transport_options[:headers].merge!(setup_api_key(api_key))
24
+ transport_options[:headers].merge!({ 'user-agent' => "#{user_agent}" })
23
25
 
24
26
  logger.warn "Supplied proxy setting (proxy => '') has no effect" if @proxy.eql?('')
25
27
  transport_options[:proxy] = proxy.to_s if proxy && !proxy.eql?('')
26
28
 
27
- hosts.map! {|h| { host: h, scheme: 'https' } } if ssl
29
+ hosts = hosts.map { |host| { host: host, scheme: 'https' } } if ssl
28
30
  # set ca_file even if ssl isn't on, since the host can be an https url
29
31
  ssl_options = { ssl: true, ca_file: options[:ca_file] } if options[:ca_file]
30
32
  ssl_options ||= {}
@@ -43,14 +45,14 @@ module LogStash
43
45
  return {} unless user && password && password.value
44
46
 
45
47
  token = ::Base64.strict_encode64("#{user}:#{password.value}")
46
- { Authorization: "Basic #{token}" }
48
+ { 'Authorization' => "Basic #{token}" }
47
49
  end
48
50
 
49
51
  def setup_api_key(api_key)
50
52
  return {} unless (api_key && api_key.value)
51
53
 
52
54
  token = ::Base64.strict_encode64(api_key.value)
53
- { Authorization: "ApiKey #{token}" }
55
+ { 'Authorization' => "ApiKey #{token}" }
54
56
  end
55
57
  end
56
58
  end
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+ require "elasticsearch"
3
+ require "elasticsearch/transport/transport/http/manticore"
4
+
5
+ es_client_version = Gem.loaded_specs['elasticsearch-transport'].version
6
+ if es_client_version >= Gem::Version.new('7.2') && es_client_version < Gem::Version.new('7.16')
7
+ # elasticsearch-transport 7.2.0 - 7.14.0 had a bug where setting http headers
8
+ # ES::Client.new ..., transport_options: { headers: { 'Authorization' => ... } }
9
+ # would be lost https://github.com/elastic/elasticsearch-ruby/issues/1428
10
+ #
11
+ # NOTE: needs to be idempotent as input ES plugin might apply the same patch!
12
+ #
13
+ # @private
14
+ module Elasticsearch
15
+ module Transport
16
+ module Transport
17
+ module HTTP
18
+ class Manticore
19
+
20
+ def apply_headers(request_options, options)
21
+ headers = (options && options[:headers]) || {}
22
+ headers[CONTENT_TYPE_STR] = find_value(headers, CONTENT_TYPE_REGEX) || DEFAULT_CONTENT_TYPE
23
+
24
+ # this code is necessary to grab the correct user-agent header
25
+ # when this method is invoked with apply_headers(@request_options, options)
26
+ # from https://github.com/elastic/elasticsearch-ruby/blob/v7.14.0/elasticsearch-transport/lib/elasticsearch/transport/transport/http/manticore.rb#L113-L114
27
+ transport_user_agent = nil
28
+ if (options && options[:transport_options] && options[:transport_options][:headers])
29
+ transport_headers = {}
30
+ transport_headers = options[:transport_options][:headers]
31
+ transport_user_agent = find_value(transport_headers, USER_AGENT_REGEX)
32
+ end
33
+
34
+ headers[USER_AGENT_STR] = transport_user_agent || find_value(headers, USER_AGENT_REGEX) || user_agent_header
35
+ headers[ACCEPT_ENCODING] = GZIP if use_compression?
36
+ (request_options[:headers] ||= {}).merge!(headers) # this line was changed
37
+ end
38
+
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -1,19 +1,15 @@
1
1
  # encoding: utf-8
2
2
  require "logstash/filters/base"
3
3
  require "logstash/namespace"
4
- require_relative "elasticsearch/client"
5
4
  require "logstash/json"
6
- require "logstash/util/safe_uri"
7
- java_import "java.util.concurrent.ConcurrentHashMap"
8
-
5
+ require_relative "elasticsearch/client"
6
+ require_relative "elasticsearch/patches/_elasticsearch_transport_http_manticore"
9
7
 
10
8
  class LogStash::Filters::Elasticsearch < LogStash::Filters::Base
11
9
  config_name "elasticsearch"
12
10
 
13
- DEFAULT_HOST = ::LogStash::Util::SafeURI.new("//localhost:9200")
14
-
15
11
  # List of elasticsearch hosts to use for querying.
16
- config :hosts, :validate => :array, :default => [ DEFAULT_HOST ]
12
+ config :hosts, :validate => :array, :default => [ 'localhost:9200' ]
17
13
 
18
14
  # Comma-delimited list of index names to search; use `_all` or empty string to perform the operation on all indices.
19
15
  # Field substitution (e.g. `index-name-%{date_field}`) is available
@@ -112,7 +108,7 @@ class LogStash::Filters::Elasticsearch < LogStash::Filters::Base
112
108
  fill_user_password_from_cloud_auth
113
109
  fill_hosts_from_cloud_id
114
110
 
115
- @hosts = Array(@hosts).map { |host| host.to_s } # for ES client URI#to_s
111
+ @hosts = Array(@hosts).map { |host| host.to_s } # potential SafeURI#to_s
116
112
 
117
113
  test_connection!
118
114
  end # def register
@@ -120,7 +116,7 @@ class LogStash::Filters::Elasticsearch < LogStash::Filters::Base
120
116
  def filter(event)
121
117
  matched = false
122
118
  begin
123
- params = {:index => event.sprintf(@index) }
119
+ params = { :index => event.sprintf(@index) }
124
120
 
125
121
  if @query_dsl
126
122
  query = LogStash::Json.load(event.sprintf(@query_dsl))
@@ -180,6 +176,19 @@ class LogStash::Filters::Elasticsearch < LogStash::Filters::Base
180
176
  end
181
177
  end # def filter
182
178
 
179
+ # public only to be reuse in testing
180
+ def prepare_user_agent
181
+ os_name = java.lang.System.getProperty('os.name')
182
+ os_version = java.lang.System.getProperty('os.version')
183
+ os_arch = java.lang.System.getProperty('os.arch')
184
+ jvm_vendor = java.lang.System.getProperty('java.vendor')
185
+ jvm_version = java.lang.System.getProperty('java.version')
186
+
187
+ plugin_version = Gem.loaded_specs['logstash-filter-elasticsearch'].version
188
+ # example: logstash/7.14.1 (OS=Linux-5.4.0-84-generic-amd64; JVM=AdoptOpenJDK-11.0.11) logstash-output-elasticsearch/11.0.1
189
+ "logstash/#{LOGSTASH_VERSION} (OS=#{os_name}-#{os_version}-#{os_arch}; JVM=#{jvm_vendor}-#{jvm_version}) logstash-#{@plugin_type}-#{config_name}/#{plugin_version}"
190
+ end
191
+
183
192
  private
184
193
 
185
194
  def client_options
@@ -196,7 +205,11 @@ class LogStash::Filters::Elasticsearch < LogStash::Filters::Base
196
205
  def new_client
197
206
  # NOTE: could pass cloud-id/cloud-auth to client but than we would need to be stricter on ES version requirement
198
207
  # and also LS parsing might differ from ES client's parsing so for consistency we do not pass cloud options ...
199
- LogStash::Filters::ElasticsearchClient.new(@logger, @hosts, client_options)
208
+ opts = client_options
209
+
210
+ opts[:user_agent] = prepare_user_agent
211
+
212
+ LogStash::Filters::ElasticsearchClient.new(@logger, @hosts, opts)
200
213
  end
201
214
 
202
215
  def get_client
@@ -237,8 +250,7 @@ class LogStash::Filters::Elasticsearch < LogStash::Filters::Base
237
250
  end
238
251
 
239
252
  def hosts_default?(hosts)
240
- # NOTE: would be nice if pipeline allowed us a clean way to detect a config default :
241
- hosts.is_a?(Array) && hosts.size == 1 && hosts.first.equal?(DEFAULT_HOST)
253
+ hosts.is_a?(Array) && hosts.size == 1 && !original_params.key?('hosts')
242
254
  end
243
255
 
244
256
  def validate_authentication
@@ -273,6 +285,7 @@ class LogStash::Filters::Elasticsearch < LogStash::Filters::Base
273
285
  end
274
286
 
275
287
  def parse_host_uri_from_cloud_id(cloud_id)
288
+ require 'logstash/util/safe_uri'
276
289
  begin # might not be available on older LS
277
290
  require 'logstash/util/cloud_setting_id'
278
291
  rescue LoadError
@@ -307,6 +320,10 @@ class LogStash::Filters::Elasticsearch < LogStash::Filters::Base
307
320
  end
308
321
 
309
322
  def test_connection!
310
- get_client.client.ping
323
+ begin
324
+ get_client.client.ping
325
+ rescue Elasticsearch::UnsupportedProductError
326
+ raise LogStash::ConfigurationError, "Could not connect to a compatible version of Elasticsearch"
327
+ end
311
328
  end
312
329
  end #class LogStash::Filters::Elasticsearch
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
 
3
3
  s.name = 'logstash-filter-elasticsearch'
4
- s.version = '3.9.3'
4
+ s.version = '3.11.0'
5
5
  s.licenses = ['Apache License (2.0)']
6
6
  s.summary = "Copies fields from previous log events in Elasticsearch to current events "
7
7
  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"
@@ -21,8 +21,10 @@ Gem::Specification.new do |s|
21
21
 
22
22
  # Gem dependencies
23
23
  s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
24
- s.add_runtime_dependency 'elasticsearch', ">= 5.0.3"
25
- s.add_runtime_dependency 'manticore', "~> 0.6"
24
+ s.add_runtime_dependency 'elasticsearch', ">= 7.14.0" # LS >= 6.7 and < 7.14 all used version 5.0.5
25
+ s.add_runtime_dependency 'manticore', ">= 0.7.1"
26
+ s.add_development_dependency 'cabin', ['~> 0.6']
27
+ s.add_development_dependency 'webrick'
26
28
 
27
29
  s.add_development_dependency 'logstash-devutils'
28
30
  end
data/spec/es_helper.rb CHANGED
@@ -7,8 +7,12 @@ module ESHelper
7
7
  end
8
8
  end
9
9
 
10
- def self.get_client
11
- Elasticsearch::Client.new(:hosts => [get_host_port])
10
+ def self.get_client(credentials)
11
+ require 'elasticsearch/transport/transport/http/faraday' # supports user/password options
12
+ host, port = get_host_port.split(':')
13
+ host_opts = credentials.inject({}) { |h, (k, v)| h[k.to_sym] = v; h } # user: _, password: _
14
+ host_opts.merge! host: host, port: port, scheme: 'http'
15
+ Elasticsearch::Client.new(hosts: [host_opts], transport_class: Elasticsearch::Transport::Transport::HTTP::Faraday)
12
16
  end
13
17
 
14
18
  def self.doc_type
@@ -3,18 +3,43 @@ require "logstash/devutils/rspec/spec_helper"
3
3
  require "logstash/plugin"
4
4
  require "logstash/filters/elasticsearch"
5
5
  require "logstash/json"
6
+ require "cabin"
7
+ require "webrick"
8
+ require "uri"
6
9
 
7
10
  describe LogStash::Filters::Elasticsearch do
8
11
 
9
12
  context "registration" do
10
13
 
11
14
  let(:plugin) { LogStash::Plugin.lookup("filter", "elasticsearch").new({}) }
12
- before do
13
- allow(plugin).to receive(:test_connection!)
15
+
16
+ context "against authentic Elasticsearch" do
17
+ before do
18
+ allow(plugin).to receive(:test_connection!)
19
+ end
20
+
21
+ it "should not raise an exception" do
22
+ expect {plugin.register}.to_not raise_error
23
+ end
14
24
  end
15
25
 
16
- it "should not raise an exception" do
17
- expect {plugin.register}.to_not raise_error
26
+ context "against not authentic Elasticsearch" do
27
+ let(:failing_client) do
28
+ client = double("client")
29
+ allow(client).to receive(:ping).and_raise Elasticsearch::UnsupportedProductError
30
+
31
+ client_wrapper = double("filter_client")
32
+ allow(client_wrapper).to receive(:client).and_return client
33
+ client_wrapper
34
+ end
35
+
36
+ before do
37
+ allow(plugin).to receive(:get_client).and_return(failing_client)
38
+ end
39
+
40
+ it "should raise ConfigurationError" do
41
+ expect {plugin.register}.to raise_error(LogStash::ConfigurationError)
42
+ end
18
43
  end
19
44
  end
20
45
 
@@ -291,6 +316,112 @@ describe LogStash::Filters::Elasticsearch do
291
316
  end
292
317
  end
293
318
 
319
+ class StoppableServer
320
+
321
+ attr_reader :port
322
+
323
+ def initialize()
324
+ queue = Queue.new
325
+ @first_req_waiter = java.util.concurrent.CountDownLatch.new(1)
326
+ @first_request = nil
327
+
328
+ @t = java.lang.Thread.new(
329
+ proc do
330
+ begin
331
+ @server = WEBrick::HTTPServer.new :Port => 0, :DocumentRoot => ".",
332
+ :Logger => Cabin::Channel.get, # silence WEBrick logging
333
+ :StartCallback => Proc.new {
334
+ queue.push("started")
335
+ }
336
+ @port = @server.config[:Port]
337
+ @server.mount_proc '/' do |req, res|
338
+ res.body = '''
339
+ {
340
+ "name": "ce7ccfb438e8",
341
+ "cluster_name": "docker-cluster",
342
+ "cluster_uuid": "DyR1hN03QvuCWXRy3jtb0g",
343
+ "version": {
344
+ "number": "7.13.1",
345
+ "build_flavor": "default",
346
+ "build_type": "docker",
347
+ "build_hash": "9a7758028e4ea59bcab41c12004603c5a7dd84a9",
348
+ "build_date": "2021-05-28T17:40:59.346932922Z",
349
+ "build_snapshot": false,
350
+ "lucene_version": "8.8.2",
351
+ "minimum_wire_compatibility_version": "6.8.0",
352
+ "minimum_index_compatibility_version": "6.0.0-beta1"
353
+ },
354
+ "tagline": "You Know, for Search"
355
+ }
356
+ '''
357
+ res.status = 200
358
+ res['Content-Type'] = 'application/json'
359
+ @first_request = req
360
+ @first_req_waiter.countDown()
361
+ end
362
+
363
+ @server.start
364
+ rescue => e
365
+ puts "Error in webserver thread #{e}"
366
+ # ignore
367
+ end
368
+ end
369
+ )
370
+ @t.daemon = true
371
+ @t.start
372
+ queue.pop # blocks until the server is up
373
+ end
374
+
375
+ def stop
376
+ @server.shutdown
377
+ end
378
+
379
+ def wait_receive_request
380
+ @first_req_waiter.await(2, java.util.concurrent.TimeUnit::SECONDS)
381
+ @first_request
382
+ end
383
+ end
384
+
385
+ describe "user-agent header" do
386
+ let!(:webserver) { StoppableServer.new } # webserver must be started before the call, so no lazy "let"
387
+
388
+ after :each do
389
+ webserver.stop
390
+ end
391
+
392
+ it "server should be started" do
393
+ require 'net/http'
394
+ response = nil
395
+ Net::HTTP.start('localhost', webserver.port) {|http|
396
+ response = http.request_get('/')
397
+ }
398
+ expect(response.code.to_i).to eq(200)
399
+ end
400
+
401
+ context "used by plugin" do
402
+ let(:config) do
403
+ {
404
+ "hosts" => ["localhost:#{webserver.port}"],
405
+ "query" => "response: 404",
406
+ "fields" => { "response" => "code" },
407
+ "docinfo_fields" => { "_index" => "es_index" },
408
+ "aggregation_fields" => { "bytes_avg" => "bytes_avg_ls_field" }
409
+ }
410
+ end
411
+ let(:plugin) { described_class.new(config) }
412
+ let(:event) { LogStash::Event.new({}) }
413
+
414
+ it "client should sent the expect user-agent" do
415
+ plugin.register
416
+
417
+ request = webserver.wait_receive_request
418
+
419
+ expect(request.header['user-agent'].size).to eq(1)
420
+ expect(request.header['user-agent'][0]).to match(/logstash\/\d*\.\d*\.\d* \(OS=.*; JVM=.*\) logstash-filter-elasticsearch\/\d*\.\d*\.\d*/)
421
+ end
422
+ end
423
+ end
424
+
294
425
  describe "client" do
295
426
  let(:config) do
296
427
  {
@@ -313,12 +444,12 @@ describe LogStash::Filters::Elasticsearch do
313
444
  'sample:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvJGFjMzFlYmI5MDI0MTc3MzE1NzA0M2MzNGZkMjZmZDQ2OjkyNDMkYTRjMDYyMzBlNDhjOGZjZTdiZTg4YTA3NGEzYmIzZTA6OTI0NA=='
314
445
  end
315
446
 
316
- let(:config) { super.merge({ 'cloud_id' => valid_cloud_id }) }
447
+ let(:config) { super().merge({ 'cloud_id' => valid_cloud_id }) }
317
448
 
318
449
  it "should set host(s)" do
319
450
  plugin.register
320
451
  client = plugin.send(:get_client).client
321
- expect( client.transport.hosts ).to eql [{
452
+ expect( extract_transport(client).hosts ).to eql [{
322
453
  :scheme => "https",
323
454
  :host => "ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io",
324
455
  :port => 9243,
@@ -328,7 +459,7 @@ describe LogStash::Filters::Elasticsearch do
328
459
  end
329
460
 
330
461
  context 'invalid' do
331
- let(:config) { super.merge({ 'cloud_id' => 'invalid:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlv' }) }
462
+ let(:config) { super().merge({ 'cloud_id' => 'invalid:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlv' }) }
332
463
 
333
464
  it "should fail" do
334
465
  expect { plugin.register }.to raise_error LogStash::ConfigurationError, /cloud_id.*? is invalid/
@@ -336,7 +467,7 @@ describe LogStash::Filters::Elasticsearch do
336
467
  end
337
468
 
338
469
  context 'hosts also set' do
339
- let(:config) { super.merge({ 'cloud_id' => valid_cloud_id, 'hosts' => [ 'localhost:9200' ] }) }
470
+ let(:config) { super().merge({ 'cloud_id' => valid_cloud_id, 'hosts' => [ 'localhost:9200' ] }) }
340
471
 
341
472
  it "should fail" do
342
473
  expect { plugin.register }.to raise_error LogStash::ConfigurationError, /cloud_id and hosts/
@@ -345,18 +476,18 @@ describe LogStash::Filters::Elasticsearch do
345
476
  end if LOGSTASH_VERSION > '6.0'
346
477
 
347
478
  describe "cloud.auth" do
348
- let(:config) { super.merge({ 'cloud_auth' => LogStash::Util::Password.new('elastic:my-passwd-00') }) }
479
+ let(:config) { super().merge({ 'cloud_auth' => LogStash::Util::Password.new('elastic:my-passwd-00') }) }
349
480
 
350
481
  it "should set authorization" do
351
482
  plugin.register
352
483
  client = plugin.send(:get_client).client
353
- auth_header = client.transport.options[:transport_options][:headers][:Authorization]
484
+ auth_header = extract_transport(client).options[:transport_options][:headers]['Authorization']
354
485
 
355
486
  expect( auth_header ).to eql "Basic #{Base64.encode64('elastic:my-passwd-00').rstrip}"
356
487
  end
357
488
 
358
489
  context 'invalid' do
359
- let(:config) { super.merge({ 'cloud_auth' => 'invalid-format' }) }
490
+ let(:config) { super().merge({ 'cloud_auth' => 'invalid-format' }) }
360
491
 
361
492
  it "should fail" do
362
493
  expect { plugin.register }.to raise_error LogStash::ConfigurationError, /cloud_auth.*? format/
@@ -364,7 +495,7 @@ describe LogStash::Filters::Elasticsearch do
364
495
  end
365
496
 
366
497
  context 'user also set' do
367
- let(:config) { super.merge({ 'cloud_auth' => 'elastic:my-passwd-00', 'user' => 'another' }) }
498
+ let(:config) { super().merge({ 'cloud_auth' => 'elastic:my-passwd-00', 'user' => 'another' }) }
368
499
 
369
500
  it "should fail" do
370
501
  expect { plugin.register }.to raise_error LogStash::ConfigurationError, /Multiple authentication options are specified/
@@ -374,7 +505,7 @@ describe LogStash::Filters::Elasticsearch do
374
505
 
375
506
  describe "api_key" do
376
507
  context "without ssl" do
377
- let(:config) { super.merge({ 'api_key' => LogStash::Util::Password.new('foo:bar') }) }
508
+ let(:config) { super().merge({ 'api_key' => LogStash::Util::Password.new('foo:bar') }) }
378
509
 
379
510
  it "should fail" do
380
511
  expect { plugin.register }.to raise_error LogStash::ConfigurationError, /api_key authentication requires SSL\/TLS/
@@ -382,18 +513,18 @@ describe LogStash::Filters::Elasticsearch do
382
513
  end
383
514
 
384
515
  context "with ssl" do
385
- let(:config) { super.merge({ 'api_key' => LogStash::Util::Password.new('foo:bar'), "ssl" => true }) }
516
+ let(:config) { super().merge({ 'api_key' => LogStash::Util::Password.new('foo:bar'), "ssl" => true }) }
386
517
 
387
518
  it "should set authorization" do
388
519
  plugin.register
389
520
  client = plugin.send(:get_client).client
390
- auth_header = client.transport.options[:transport_options][:headers][:Authorization]
521
+ auth_header = extract_transport(client).options[:transport_options][:headers]['Authorization']
391
522
 
392
523
  expect( auth_header ).to eql "ApiKey #{Base64.strict_encode64('foo:bar')}"
393
524
  end
394
525
 
395
526
  context 'user also set' do
396
- let(:config) { super.merge({ 'api_key' => 'foo:bar', 'user' => 'another' }) }
527
+ let(:config) { super().merge({ 'api_key' => 'foo:bar', 'user' => 'another' }) }
397
528
 
398
529
  it "should fail" do
399
530
  expect { plugin.register }.to raise_error LogStash::ConfigurationError, /Multiple authentication options are specified/
@@ -404,30 +535,44 @@ describe LogStash::Filters::Elasticsearch do
404
535
 
405
536
  describe "proxy" do
406
537
  context 'valid' do
407
- let(:config) { super.merge({ 'proxy' => 'http://localhost:1234' }) }
538
+ let(:config) { super().merge({ 'proxy' => 'http://localhost:1234' }) }
408
539
 
409
540
  it "should set proxy" do
410
541
  plugin.register
411
542
  client = plugin.send(:get_client).client
412
- proxy = client.transport.options[:transport_options][:proxy]
543
+ proxy = extract_transport(client).options[:transport_options][:proxy]
413
544
 
414
545
  expect( proxy ).to eql "http://localhost:1234"
415
546
  end
416
547
  end
417
548
 
418
549
  context 'invalid' do
419
- let(:config) { super.merge({ 'proxy' => '${A_MISSING_ENV_VAR:}' }) }
550
+ let(:config) { super().merge({ 'proxy' => '${A_MISSING_ENV_VAR:}' }) }
420
551
 
421
552
  it "should not set proxy" do
422
553
  plugin.register
423
554
  client = plugin.send(:get_client).client
424
555
 
425
- expect( client.transport.options[:transport_options] ).to_not include(:proxy)
556
+ expect( extract_transport(client).options[:transport_options] ).to_not include(:proxy)
426
557
  end
427
558
  end
428
559
  end
429
560
  end
430
561
 
562
+ describe "defaults" do
563
+
564
+ let(:config) { Hash.new }
565
+ let(:plugin) { described_class.new(config) }
566
+
567
+ before { allow(plugin).to receive(:test_connection!) }
568
+
569
+ it "should set localhost:9200 as hosts" do
570
+ plugin.register
571
+ client = plugin.send(:get_client).client
572
+ expect( extract_transport(client).hosts ).to eql [{ :host => "localhost", :port => 9200, :protocol => "http"}]
573
+ end
574
+ end
575
+
431
576
  describe "query template" do
432
577
  let(:config) do
433
578
  {
@@ -453,4 +598,10 @@ describe LogStash::Filters::Elasticsearch do
453
598
  plugin.filter(LogStash::Event.new)
454
599
  end
455
600
  end
601
+
602
+ # @note can be removed once gem depends on elasticsearch >= 6.x
603
+ def extract_transport(client) # on 7.x client.transport is a ES::Transport::Client
604
+ client.transport.respond_to?(:transport) ? client.transport.transport : client.transport
605
+ end
606
+
456
607
  end
@@ -6,21 +6,31 @@ require_relative "../../../spec/es_helper"
6
6
 
7
7
  describe LogStash::Filters::Elasticsearch, :integration => true do
8
8
 
9
+ ELASTIC_SECURITY_ENABLED = ENV['ELASTIC_SECURITY_ENABLED'].eql? 'true'
9
10
 
10
- let(:config) do
11
+ let(:base_config) do
11
12
  {
12
- "index" => 'logs',
13
- "hosts" => [ESHelper.get_host_port],
14
- "query" => "response: 404",
15
- "sort" => "response",
16
- "fields" => [ ["response", "code"] ],
13
+ "index" => 'logs',
14
+ "hosts" => [ESHelper.get_host_port],
15
+ "query" => "response: 404",
16
+ "sort" => "response",
17
+ "fields" => [ ["response", "code"] ],
17
18
  }
18
19
  end
20
+
21
+ let(:credentials) do
22
+ { 'user' => 'elastic', 'password' => ENV['ELASTIC_PASSWORD'] }
23
+ end
24
+
25
+ let(:config) do
26
+ ELASTIC_SECURITY_ENABLED ? base_config.merge(credentials) : base_config
27
+ end
28
+
19
29
  let(:plugin) { described_class.new(config) }
20
30
  let(:event) { LogStash::Event.new({}) }
21
31
 
22
32
  before(:each) do
23
- @es = ESHelper.get_client
33
+ @es = ESHelper.get_client(ELASTIC_SECURITY_ENABLED ? credentials : {})
24
34
  # Delete all templates first.
25
35
  # Clean ES of data before we start.
26
36
  @es.indices.delete_template(:name => "*")
@@ -30,11 +40,10 @@ describe LogStash::Filters::Elasticsearch, :integration => true do
30
40
  ESHelper.index_doc(@es, :index => 'logs', :body => { :response => 404, :this => 'that'})
31
41
  end
32
42
  @es.indices.refresh
33
-
34
- plugin.register
35
43
  end
36
44
 
37
45
  it "should enhance the current event with new data" do
46
+ plugin.register
38
47
  plugin.filter(event)
39
48
  expect(event.get('code')).to eq(404)
40
49
  end
@@ -42,20 +51,28 @@ describe LogStash::Filters::Elasticsearch, :integration => true do
42
51
  context "when retrieving a list of elements" do
43
52
 
44
53
  let(:config) do
45
- {
46
- "index" => 'logs',
47
- "hosts" => [ESHelper.get_host_port],
48
- "query" => "response: 404",
49
- "fields" => [ ["response", "code"] ],
50
- "sort" => "response",
51
- "result_size" => 10
52
- }
54
+ super().merge("fields" => [ ["response", "code"] ], "result_size" => 10)
53
55
  end
54
56
 
57
+ before { plugin.register }
58
+
55
59
  it "should enhance the current event with new data" do
56
60
  plugin.filter(event)
57
61
  expect(event.get("code")).to eq([404]*10)
58
62
  end
59
63
 
60
64
  end
65
+
66
+ context "incorrect auth credentials" do
67
+
68
+ let(:config) do
69
+ super().reject { |key, _| key == 'password' }
70
+ end
71
+
72
+ it "should enhance the current event with new data" do
73
+ expect { plugin.register }.to raise_error Elasticsearch::Transport::Transport::Errors::Unauthorized
74
+ end
75
+
76
+ end if ELASTIC_SECURITY_ENABLED
77
+
61
78
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-filter-elasticsearch
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.9.3
4
+ version: 3.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-26 00:00:00.000000000 Z
11
+ date: 2021-10-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -35,7 +35,7 @@ dependencies:
35
35
  requirements:
36
36
  - - ">="
37
37
  - !ruby/object:Gem::Version
38
- version: 5.0.3
38
+ version: 7.14.0
39
39
  name: elasticsearch
40
40
  prerelease: false
41
41
  type: :runtime
@@ -43,21 +43,49 @@ dependencies:
43
43
  requirements:
44
44
  - - ">="
45
45
  - !ruby/object:Gem::Version
46
- version: 5.0.3
46
+ version: 7.14.0
47
47
  - !ruby/object:Gem::Dependency
48
48
  requirement: !ruby/object:Gem::Requirement
49
49
  requirements:
50
- - - "~>"
50
+ - - ">="
51
51
  - !ruby/object:Gem::Version
52
- version: '0.6'
52
+ version: 0.7.1
53
53
  name: manticore
54
54
  prerelease: false
55
55
  type: :runtime
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 0.7.1
61
+ - !ruby/object:Gem::Dependency
62
+ requirement: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: '0.6'
67
+ name: cabin
68
+ prerelease: false
69
+ type: :development
56
70
  version_requirements: !ruby/object:Gem::Requirement
57
71
  requirements:
58
72
  - - "~>"
59
73
  - !ruby/object:Gem::Version
60
74
  version: '0.6'
75
+ - !ruby/object:Gem::Dependency
76
+ requirement: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ name: webrick
82
+ prerelease: false
83
+ type: :development
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
61
89
  - !ruby/object:Gem::Dependency
62
90
  requirement: !ruby/object:Gem::Requirement
63
91
  requirements:
@@ -89,6 +117,7 @@ files:
89
117
  - docs/index.asciidoc
90
118
  - lib/logstash/filters/elasticsearch.rb
91
119
  - lib/logstash/filters/elasticsearch/client.rb
120
+ - lib/logstash/filters/elasticsearch/patches/_elasticsearch_transport_http_manticore.rb
92
121
  - logstash-filter-elasticsearch.gemspec
93
122
  - spec/es_helper.rb
94
123
  - spec/filters/elasticsearch_spec.rb
@@ -121,8 +150,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
121
150
  - !ruby/object:Gem::Version
122
151
  version: '0'
123
152
  requirements: []
124
- rubyforge_project:
125
- rubygems_version: 2.6.13
153
+ rubygems_version: 3.1.6
126
154
  signing_key:
127
155
  specification_version: 4
128
156
  summary: Copies fields from previous log events in Elasticsearch to current events