logstash-output-elasticsearch 11.0.4-java → 11.2.1-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/lib/logstash/outputs/elasticsearch/http_client/pool.rb +48 -2
- data/lib/logstash/outputs/elasticsearch/http_client.rb +19 -0
- data/lib/logstash/plugin_mixins/elasticsearch/common.rb +5 -1
- data/logstash-output-elasticsearch.gemspec +3 -1
- data/spec/es_spec_helper.rb +10 -1
- data/spec/integration/outputs/no_es_on_startup_spec.rb +14 -0
- data/spec/unit/outputs/elasticsearch/http_client/pool_spec.rb +158 -9
- data/spec/unit/outputs/elasticsearch/http_client_spec.rb +69 -0
- data/spec/unit/outputs/elasticsearch_spec.rb +2 -1
- data/spec/unit/outputs/error_whitelist_spec.rb +1 -0
- metadata +30 -3
- data/lib/logstash/outputs/elasticsearch/templates/ecs-v1/elasticsearch-8x.json +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 55d5bf15c3c83c50fc630b6de9b6e150b84bc82ef981b18b62043294323be07a
|
4
|
+
data.tar.gz: ed957435bcf63f85835d7eabf5f5a5c249f8dfe28183d204574bc8553e960907
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 664ba0d3d5e26089b8a9b29a87cec5fb17da3ae7ead430b10572ca540236da0918f24a4df874d499074060683b8f57937fb5d7239c7c32778a51728d1378b431
|
7
|
+
data.tar.gz: d513fa0801d91b80b3434c7f7576e7c9874c7f36a699d35408981013a64a0762309371f2aeaecac5720e82225a44301c435f1328d63b1d056b6beccf0b5163db
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
## 11.2.1
|
2
|
+
- Fix referencing Gem classes from global lexical scope [#1044](https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/1044)
|
3
|
+
|
4
|
+
## 11.2.0
|
5
|
+
- Added preflight checks on Elasticsearch [#1026](https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/1026)
|
6
|
+
|
7
|
+
## 11.1.0
|
8
|
+
- Feat: add `user-agent` header passed to the Elasticsearch HTTP connection [#1038](https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/1038)
|
9
|
+
|
10
|
+
## 11.0.5
|
11
|
+
- Fixed running post-register action when Elasticsearch status change from unhealthy to healthy [#1035](https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/1035)
|
12
|
+
|
1
13
|
## 11.0.4
|
2
14
|
- [DOC] Clarify that `http_compression` applies to _requests_, and remove noise about _response_ decompression [#1000](https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/1000)
|
3
15
|
|
@@ -37,6 +37,9 @@ module LogStash; module Outputs; class ElasticSearch; class HttpClient;
|
|
37
37
|
ROOT_URI_PATH = '/'.freeze
|
38
38
|
LICENSE_PATH = '/_license'.freeze
|
39
39
|
|
40
|
+
VERSION_6_TO_7 = ::Gem::Requirement.new([">= 6.0.0", "< 7.0.0"])
|
41
|
+
VERSION_7_TO_7_14 = ::Gem::Requirement.new([">= 7.0.0", "< 7.14.0"])
|
42
|
+
|
40
43
|
DEFAULT_OPTIONS = {
|
41
44
|
:healthcheck_path => ROOT_URI_PATH,
|
42
45
|
:sniffing_path => "/_nodes/http",
|
@@ -211,7 +214,7 @@ module LogStash; module Outputs; class ElasticSearch; class HttpClient;
|
|
211
214
|
def start_resurrectionist
|
212
215
|
@resurrectionist = Thread.new do
|
213
216
|
until_stopped("resurrection", @resurrect_delay) do
|
214
|
-
healthcheck!
|
217
|
+
healthcheck!(false)
|
215
218
|
end
|
216
219
|
end
|
217
220
|
end
|
@@ -232,11 +235,18 @@ module LogStash; module Outputs; class ElasticSearch; class HttpClient;
|
|
232
235
|
perform_request_to_url(url, :head, @healthcheck_path)
|
233
236
|
end
|
234
237
|
|
235
|
-
def healthcheck!
|
238
|
+
def healthcheck!(register_phase = true)
|
236
239
|
# Try to keep locking granularity low such that we don't affect IO...
|
237
240
|
@state_mutex.synchronize { @url_info.select {|url,meta| meta[:state] != :alive } }.each do |url,meta|
|
238
241
|
begin
|
239
242
|
health_check_request(url)
|
243
|
+
|
244
|
+
# when called from resurrectionist skip the product check done during register phase
|
245
|
+
if register_phase
|
246
|
+
if !elasticsearch?(url)
|
247
|
+
raise LogStash::ConfigurationError, "Could not connect to a compatible version of Elasticsearch"
|
248
|
+
end
|
249
|
+
end
|
240
250
|
# If no exception was raised it must have succeeded!
|
241
251
|
logger.warn("Restored connection to ES instance", url: url.sanitized.to_s)
|
242
252
|
# We reconnected to this node, check its ES version
|
@@ -254,6 +264,42 @@ module LogStash; module Outputs; class ElasticSearch; class HttpClient;
|
|
254
264
|
end
|
255
265
|
end
|
256
266
|
|
267
|
+
def elasticsearch?(url)
|
268
|
+
begin
|
269
|
+
response = perform_request_to_url(url, :get, ROOT_URI_PATH)
|
270
|
+
rescue ::LogStash::Outputs::ElasticSearch::HttpClient::Pool::BadResponseCodeError => e
|
271
|
+
return false if response.code == 401 || response.code == 403
|
272
|
+
raise e
|
273
|
+
end
|
274
|
+
|
275
|
+
version_info = LogStash::Json.load(response.body)
|
276
|
+
return false if version_info['version'].nil?
|
277
|
+
|
278
|
+
version = ::Gem::Version.new(version_info["version"]['number'])
|
279
|
+
return false if version < ::Gem::Version.new('6.0.0')
|
280
|
+
|
281
|
+
if VERSION_6_TO_7.satisfied_by?(version)
|
282
|
+
return valid_tagline?(version_info)
|
283
|
+
elsif VERSION_7_TO_7_14.satisfied_by?(version)
|
284
|
+
build_flavor = version_info["version"]['build_flavor']
|
285
|
+
return false if build_flavor.nil? || build_flavor != 'default' || !valid_tagline?(version_info)
|
286
|
+
else
|
287
|
+
# case >= 7.14
|
288
|
+
lower_headers = response.headers.transform_keys {|key| key.to_s.downcase }
|
289
|
+
product_header = lower_headers['x-elastic-product']
|
290
|
+
return false if product_header != 'Elasticsearch'
|
291
|
+
end
|
292
|
+
return true
|
293
|
+
rescue => e
|
294
|
+
logger.error("Unable to retrieve Elasticsearch version", url: url.sanitized.to_s, exception: e.class, message: e.message)
|
295
|
+
false
|
296
|
+
end
|
297
|
+
|
298
|
+
def valid_tagline?(version_info)
|
299
|
+
tagline = version_info['tagline']
|
300
|
+
tagline == "You Know, for Search"
|
301
|
+
end
|
302
|
+
|
257
303
|
def stop_resurrectionist
|
258
304
|
@resurrectionist.join if @resurrectionist
|
259
305
|
end
|
@@ -4,6 +4,7 @@ require 'logstash/outputs/elasticsearch/http_client/manticore_adapter'
|
|
4
4
|
require 'cgi'
|
5
5
|
require 'zlib'
|
6
6
|
require 'stringio'
|
7
|
+
require 'java'
|
7
8
|
|
8
9
|
module LogStash; module Outputs; class ElasticSearch;
|
9
10
|
# This is a constant instead of a config option because
|
@@ -92,6 +93,10 @@ module LogStash; module Outputs; class ElasticSearch;
|
|
92
93
|
@pool.maximum_seen_major_version
|
93
94
|
end
|
94
95
|
|
96
|
+
def alive_urls_count
|
97
|
+
@pool.alive_urls_count
|
98
|
+
end
|
99
|
+
|
95
100
|
def bulk(actions)
|
96
101
|
@action_count ||= 0
|
97
102
|
@action_count += actions.size
|
@@ -297,6 +302,8 @@ module LogStash; module Outputs; class ElasticSearch;
|
|
297
302
|
:request_timeout => timeout,
|
298
303
|
}
|
299
304
|
|
305
|
+
adapter_options[:user_agent] = prepare_user_agent
|
306
|
+
|
300
307
|
adapter_options[:proxy] = client_settings[:proxy] if client_settings[:proxy]
|
301
308
|
|
302
309
|
adapter_options[:check_connection_timeout] = client_settings[:check_connection_timeout] if client_settings[:check_connection_timeout]
|
@@ -318,6 +325,18 @@ module LogStash; module Outputs; class ElasticSearch;
|
|
318
325
|
adapter_class = ::LogStash::Outputs::ElasticSearch::HttpClient::ManticoreAdapter
|
319
326
|
adapter = adapter_class.new(@logger, adapter_options)
|
320
327
|
end
|
328
|
+
|
329
|
+
def prepare_user_agent
|
330
|
+
os_name = java.lang.System.getProperty('os.name')
|
331
|
+
os_version = java.lang.System.getProperty('os.version')
|
332
|
+
os_arch = java.lang.System.getProperty('os.arch')
|
333
|
+
jvm_vendor = java.lang.System.getProperty('java.vendor')
|
334
|
+
jvm_version = java.lang.System.getProperty('java.version')
|
335
|
+
|
336
|
+
plugin_version = Gem.loaded_specs['logstash-output-elasticsearch'].version
|
337
|
+
# example: Logstash/7.14.1 (OS=Linux-5.4.0-84-generic-amd64; JVM=AdoptOpenJDK-11.0.11) logstash-output-elasticsearch/11.0.1
|
338
|
+
"Logstash/#{LOGSTASH_VERSION} (OS=#{os_name}-#{os_version}-#{os_arch}; JVM=#{jvm_vendor}-#{jvm_version}) logstash-output-elasticsearch/#{plugin_version}"
|
339
|
+
end
|
321
340
|
|
322
341
|
def build_pool(options)
|
323
342
|
adapter = build_adapter(options)
|
@@ -128,8 +128,12 @@ module LogStash; module PluginMixins; module ElasticSearch
|
|
128
128
|
client.maximum_seen_major_version
|
129
129
|
end
|
130
130
|
|
131
|
+
def alive_urls_count
|
132
|
+
client.alive_urls_count
|
133
|
+
end
|
134
|
+
|
131
135
|
def successful_connection?
|
132
|
-
!!maximum_seen_major_version
|
136
|
+
!!maximum_seen_major_version && alive_urls_count > 0
|
133
137
|
end
|
134
138
|
|
135
139
|
# launch a thread that waits for an initial successful connection to the ES cluster to call the given block
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'logstash-output-elasticsearch'
|
3
|
-
s.version = '11.
|
3
|
+
s.version = '11.2.1'
|
4
4
|
|
5
5
|
s.licenses = ['apache-2.0']
|
6
6
|
s.summary = "Stores logs in Elasticsearch"
|
@@ -30,6 +30,8 @@ Gem::Specification.new do |s|
|
|
30
30
|
s.add_development_dependency 'logstash-devutils'
|
31
31
|
s.add_development_dependency 'flores'
|
32
32
|
s.add_development_dependency 'cabin', ['~> 0.6']
|
33
|
+
s.add_development_dependency 'webrick'
|
34
|
+
s.add_development_dependency 'webmock'
|
33
35
|
# Still used in some specs, we should remove this ASAP
|
34
36
|
s.add_development_dependency 'elasticsearch'
|
35
37
|
end
|
data/spec/es_spec_helper.rb
CHANGED
@@ -80,7 +80,7 @@ module ESHelper
|
|
80
80
|
end
|
81
81
|
|
82
82
|
def self.es_version_satisfies?(*requirement)
|
83
|
-
es_version = RSpec.configuration.filter[:es_version] || ENV['ES_VERSION'] || ENV['ELASTIC_STACK_VERSION']
|
83
|
+
es_version = nilify(RSpec.configuration.filter[:es_version]) || nilify(ENV['ES_VERSION']) || nilify(ENV['ELASTIC_STACK_VERSION'])
|
84
84
|
if es_version.nil?
|
85
85
|
puts "Info: ES_VERSION, ELASTIC_STACK_VERSION or 'es_version' tag wasn't set. Returning false to all `es_version_satisfies?` call."
|
86
86
|
return false
|
@@ -89,6 +89,15 @@ module ESHelper
|
|
89
89
|
Gem::Requirement.new(requirement).satisfied_by?(es_release_version)
|
90
90
|
end
|
91
91
|
|
92
|
+
private
|
93
|
+
def self.nilify(str)
|
94
|
+
if str.nil?
|
95
|
+
return str
|
96
|
+
end
|
97
|
+
str.empty? ? nil : str
|
98
|
+
end
|
99
|
+
|
100
|
+
public
|
92
101
|
def clean(client)
|
93
102
|
client.indices.delete_template(:name => "*")
|
94
103
|
client.indices.delete_index_template(:name => "logstash*") rescue nil
|
@@ -55,4 +55,18 @@ describe "elasticsearch is down on startup", :integration => true do
|
|
55
55
|
expect(r).to have_hits(2)
|
56
56
|
end
|
57
57
|
|
58
|
+
it 'should get cluster_uuid when Elasticsearch recovers from license check failure' do
|
59
|
+
allow_any_instance_of(LogStash::Outputs::ElasticSearch::HttpClient::Pool).to receive(:get_license).with(instance_of(LogStash::Util::SafeURI)).and_raise(::LogStash::Outputs::ElasticSearch::HttpClient::Pool::HostUnreachableError.new(StandardError.new, "big fail"))
|
60
|
+
subject.register
|
61
|
+
Thread.new do
|
62
|
+
sleep 4
|
63
|
+
allow_any_instance_of(LogStash::Outputs::ElasticSearch::HttpClient::Pool).to receive(:get_license).with(instance_of(LogStash::Util::SafeURI)).and_call_original
|
64
|
+
end
|
65
|
+
subject.multi_receive([event1, event2])
|
66
|
+
@es.indices.refresh
|
67
|
+
r = @es.search(index: 'logstash-*')
|
68
|
+
expect(r).to have_hits(2)
|
69
|
+
expect(subject.plugin_metadata.get(:cluster_uuid)).not_to be_empty
|
70
|
+
expect(subject.plugin_metadata.get(:cluster_uuid)).not_to eq("_na_")
|
71
|
+
end if ESHelper.es_version_satisfies?(">=7")
|
58
72
|
end
|
@@ -50,15 +50,18 @@ describe LogStash::Outputs::ElasticSearch::HttpClient::Pool do
|
|
50
50
|
|
51
51
|
describe "healthcheck url handling" do
|
52
52
|
let(:initial_urls) { [::LogStash::Util::SafeURI.new("http://localhost:9200")] }
|
53
|
+
before(:example) do
|
54
|
+
expect(adapter).to receive(:perform_request).with(anything, :get, "/", anything, anything) do |url, _, _, _, _|
|
55
|
+
expect(url.path).to be_empty
|
56
|
+
end
|
57
|
+
end
|
53
58
|
|
54
59
|
context "and not setting healthcheck_path" do
|
55
60
|
it "performs the healthcheck to the root" do
|
56
|
-
expect(adapter).to receive(:perform_request) do |url,
|
57
|
-
expect(method).to eq(:head)
|
61
|
+
expect(adapter).to receive(:perform_request).with(anything, :head, "/", anything, anything) do |url, _, _, _, _|
|
58
62
|
expect(url.path).to be_empty
|
59
|
-
expect(req_path).to eq("/")
|
60
63
|
end
|
61
|
-
subject.healthcheck!
|
64
|
+
expect { subject.healthcheck! }.to raise_error(LogStash::ConfigurationError, "Could not connect to a compatible version of Elasticsearch")
|
62
65
|
end
|
63
66
|
end
|
64
67
|
|
@@ -66,12 +69,10 @@ describe LogStash::Outputs::ElasticSearch::HttpClient::Pool do
|
|
66
69
|
let(:healthcheck_path) { "/my/health" }
|
67
70
|
let(:options) { super().merge(:healthcheck_path => healthcheck_path) }
|
68
71
|
it "performs the healthcheck to the healthcheck_path" do
|
69
|
-
expect(adapter).to receive(:perform_request) do |url,
|
70
|
-
expect(method).to eq(:head)
|
72
|
+
expect(adapter).to receive(:perform_request).with(anything, :head, eq(healthcheck_path), anything, anything) do |url, _, _, _, _|
|
71
73
|
expect(url.path).to be_empty
|
72
|
-
expect(req_path).to eq(healthcheck_path)
|
73
74
|
end
|
74
|
-
subject.healthcheck!
|
75
|
+
expect { subject.healthcheck! }.to raise_error(LogStash::ConfigurationError, "Could not connect to a compatible version of Elasticsearch")
|
75
76
|
end
|
76
77
|
end
|
77
78
|
end
|
@@ -164,6 +165,20 @@ describe LogStash::Outputs::ElasticSearch::HttpClient::Pool do
|
|
164
165
|
end
|
165
166
|
end
|
166
167
|
|
168
|
+
class MockResponse
|
169
|
+
attr_reader :code, :headers
|
170
|
+
|
171
|
+
def initialize(code = 200, body = nil, headers = {})
|
172
|
+
@code = code
|
173
|
+
@body = body
|
174
|
+
@headers = headers
|
175
|
+
end
|
176
|
+
|
177
|
+
def body
|
178
|
+
@body.to_json
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
167
182
|
describe "connection management" do
|
168
183
|
before(:each) { subject.start }
|
169
184
|
context "with only one URL in the list" do
|
@@ -175,8 +190,17 @@ describe LogStash::Outputs::ElasticSearch::HttpClient::Pool do
|
|
175
190
|
end
|
176
191
|
|
177
192
|
context "with multiple URLs in the list" do
|
193
|
+
let(:version_ok) do
|
194
|
+
MockResponse.new(200, {"tagline" => "You Know, for Search",
|
195
|
+
"version" => {
|
196
|
+
"number" => '7.13.0',
|
197
|
+
"build_flavor" => 'default'}
|
198
|
+
})
|
199
|
+
end
|
200
|
+
|
178
201
|
before :each do
|
179
202
|
allow(adapter).to receive(:perform_request).with(anything, :head, subject.healthcheck_path, {}, nil)
|
203
|
+
allow(adapter).to receive(:perform_request).with(anything, :get, subject.healthcheck_path, {}, nil).and_return(version_ok)
|
180
204
|
end
|
181
205
|
let(:initial_urls) { [ ::LogStash::Util::SafeURI.new("http://localhost:9200"), ::LogStash::Util::SafeURI.new("http://localhost:9201"), ::LogStash::Util::SafeURI.new("http://localhost:9202") ] }
|
182
206
|
|
@@ -220,8 +244,14 @@ describe LogStash::Outputs::ElasticSearch::HttpClient::Pool do
|
|
220
244
|
::LogStash::Util::SafeURI.new("http://otherhost:9201")
|
221
245
|
] }
|
222
246
|
|
247
|
+
let(:valid_response) { MockResponse.new(200, {"tagline" => "You Know, for Search",
|
248
|
+
"version" => {
|
249
|
+
"number" => '7.13.0',
|
250
|
+
"build_flavor" => 'default'}
|
251
|
+
}) }
|
252
|
+
|
223
253
|
before(:each) do
|
224
|
-
allow(subject).to receive(:perform_request_to_url).and_return(
|
254
|
+
allow(subject).to receive(:perform_request_to_url).and_return(valid_response)
|
225
255
|
subject.start
|
226
256
|
end
|
227
257
|
|
@@ -240,6 +270,7 @@ describe LogStash::Outputs::ElasticSearch::HttpClient::Pool do
|
|
240
270
|
describe "license checking" do
|
241
271
|
before(:each) do
|
242
272
|
allow(subject).to receive(:health_check_request)
|
273
|
+
allow(subject).to receive(:elasticsearch?).and_return(true)
|
243
274
|
end
|
244
275
|
|
245
276
|
let(:options) do
|
@@ -273,6 +304,7 @@ describe LogStash::Outputs::ElasticSearch::HttpClient::Pool do
|
|
273
304
|
|
274
305
|
before(:each) do
|
275
306
|
allow(subject).to receive(:health_check_request)
|
307
|
+
allow(subject).to receive(:elasticsearch?).and_return(true)
|
276
308
|
end
|
277
309
|
|
278
310
|
context "if ES doesn't return a valid license" do
|
@@ -319,3 +351,120 @@ describe LogStash::Outputs::ElasticSearch::HttpClient::Pool do
|
|
319
351
|
end
|
320
352
|
end
|
321
353
|
end
|
354
|
+
|
355
|
+
describe "#elasticsearch?" do
|
356
|
+
let(:logger) { Cabin::Channel.get }
|
357
|
+
let(:adapter) { double("Manticore Adapter") }
|
358
|
+
let(:initial_urls) { [::LogStash::Util::SafeURI.new("http://localhost:9200")] }
|
359
|
+
let(:options) { {:resurrect_delay => 2, :url_normalizer => proc {|u| u}} } # Shorten the delay a bit to speed up tests
|
360
|
+
let(:es_node_versions) { [ "0.0.0" ] }
|
361
|
+
let(:license_status) { 'active' }
|
362
|
+
|
363
|
+
subject { LogStash::Outputs::ElasticSearch::HttpClient::Pool.new(logger, adapter, initial_urls, options) }
|
364
|
+
|
365
|
+
let(:url) { ::LogStash::Util::SafeURI.new("http://localhost:9200") }
|
366
|
+
|
367
|
+
context "in case HTTP error code" do
|
368
|
+
it "should fail for 401" do
|
369
|
+
allow(adapter).to receive(:perform_request)
|
370
|
+
.with(anything, :get, "/", anything, anything)
|
371
|
+
.and_return(MockResponse.new(401))
|
372
|
+
|
373
|
+
expect(subject.elasticsearch?(url)).to be false
|
374
|
+
end
|
375
|
+
|
376
|
+
it "should fail for 403" do
|
377
|
+
allow(adapter).to receive(:perform_request)
|
378
|
+
.with(anything, :get, "/", anything, anything)
|
379
|
+
.and_return(status: 403)
|
380
|
+
expect(subject.elasticsearch?(url)).to be false
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
context "when connecting to a cluster which reply without 'version' field" do
|
385
|
+
it "should fail" do
|
386
|
+
allow(adapter).to receive(:perform_request)
|
387
|
+
.with(anything, :get, "/", anything, anything)
|
388
|
+
.and_return(body: {"field" => "funky.com"}.to_json)
|
389
|
+
expect(subject.elasticsearch?(url)).to be false
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
context "when connecting to a cluster with version < 6.0.0" do
|
394
|
+
it "should fail" do
|
395
|
+
allow(adapter).to receive(:perform_request)
|
396
|
+
.with(anything, :get, "/", anything, anything)
|
397
|
+
.and_return(200, {"version" => { "number" => "5.0.0"}}.to_json)
|
398
|
+
expect(subject.elasticsearch?(url)).to be false
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
context "when connecting to a cluster with version in [6.0.0..7.0.0)" do
|
403
|
+
it "must be successful with valid 'tagline'" do
|
404
|
+
allow(adapter).to receive(:perform_request)
|
405
|
+
.with(anything, :get, "/", anything, anything)
|
406
|
+
.and_return(MockResponse.new(200, {"version" => {"number" => "6.5.0"}, "tagline" => "You Know, for Search"}))
|
407
|
+
expect(subject.elasticsearch?(url)).to be true
|
408
|
+
end
|
409
|
+
|
410
|
+
it "should fail if invalid 'tagline'" do
|
411
|
+
allow(adapter).to receive(:perform_request)
|
412
|
+
.with(anything, :get, "/", anything, anything)
|
413
|
+
.and_return(MockResponse.new(200, {"version" => {"number" => "6.5.0"}, "tagline" => "You don't know"}))
|
414
|
+
expect(subject.elasticsearch?(url)).to be false
|
415
|
+
end
|
416
|
+
|
417
|
+
it "should fail if 'tagline' is not present" do
|
418
|
+
allow(adapter).to receive(:perform_request)
|
419
|
+
.with(anything, :get, "/", anything, anything)
|
420
|
+
.and_return(MockResponse.new(200, {"version" => {"number" => "6.5.0"}}))
|
421
|
+
expect(subject.elasticsearch?(url)).to be false
|
422
|
+
end
|
423
|
+
end
|
424
|
+
|
425
|
+
context "when connecting to a cluster with version in [7.0.0..7.14.0)" do
|
426
|
+
it "must be successful is 'build_flavor' is 'default' and tagline is correct" do
|
427
|
+
allow(adapter).to receive(:perform_request)
|
428
|
+
.with(anything, :get, "/", anything, anything)
|
429
|
+
.and_return(MockResponse.new(200, {"version": {"number": "7.5.0", "build_flavor": "default"}, "tagline": "You Know, for Search"}))
|
430
|
+
expect(subject.elasticsearch?(url)).to be true
|
431
|
+
end
|
432
|
+
|
433
|
+
it "should fail if 'build_flavor' is not 'default' and tagline is correct" do
|
434
|
+
allow(adapter).to receive(:perform_request)
|
435
|
+
.with(anything, :get, "/", anything, anything)
|
436
|
+
.and_return(MockResponse.new(200, {"version": {"number": "7.5.0", "build_flavor": "oss"}, "tagline": "You Know, for Search"}))
|
437
|
+
expect(subject.elasticsearch?(url)).to be false
|
438
|
+
end
|
439
|
+
|
440
|
+
it "should fail if 'build_flavor' is not present and tagline is correct" do
|
441
|
+
allow(adapter).to receive(:perform_request)
|
442
|
+
.with(anything, :get, "/", anything, anything)
|
443
|
+
.and_return(MockResponse.new(200, {"version": {"number": "7.5.0"}, "tagline": "You Know, for Search"}))
|
444
|
+
expect(subject.elasticsearch?(url)).to be false
|
445
|
+
end
|
446
|
+
end
|
447
|
+
|
448
|
+
context "when connecting to a cluster with version >= 7.14.0" do
|
449
|
+
it "should fail if 'X-elastic-product' header is not present" do
|
450
|
+
allow(adapter).to receive(:perform_request)
|
451
|
+
.with(anything, :get, "/", anything, anything)
|
452
|
+
.and_return(MockResponse.new(200, {"version": {"number": "7.14.0"}}))
|
453
|
+
expect(subject.elasticsearch?(url)).to be false
|
454
|
+
end
|
455
|
+
|
456
|
+
it "should fail if 'X-elastic-product' header is present but with bad value" do
|
457
|
+
allow(adapter).to receive(:perform_request)
|
458
|
+
.with(anything, :get, "/", anything, anything)
|
459
|
+
.and_return(MockResponse.new(200, {"version": {"number": "7.14.0"}}, {'X-elastic-product' => 'not good'}))
|
460
|
+
expect(subject.elasticsearch?(url)).to be false
|
461
|
+
end
|
462
|
+
|
463
|
+
it "must be successful when 'X-elastic-product' header is present with 'Elasticsearch' value" do
|
464
|
+
allow(adapter).to receive(:perform_request)
|
465
|
+
.with(anything, :get, "/", anything, anything)
|
466
|
+
.and_return(MockResponse.new(200, {"version": {"number": "7.14.0"}}, {'X-elastic-product' => 'Elasticsearch'}))
|
467
|
+
expect(subject.elasticsearch?(url)).to be true
|
468
|
+
end
|
469
|
+
end
|
470
|
+
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require_relative "../../../../spec/spec_helper"
|
2
2
|
require "logstash/outputs/elasticsearch/http_client"
|
3
3
|
require "cabin"
|
4
|
+
require "webrick"
|
5
|
+
require "java"
|
4
6
|
|
5
7
|
describe LogStash::Outputs::ElasticSearch::HttpClient do
|
6
8
|
let(:ssl) { nil }
|
@@ -287,4 +289,71 @@ describe LogStash::Outputs::ElasticSearch::HttpClient do
|
|
287
289
|
end
|
288
290
|
end
|
289
291
|
end
|
292
|
+
|
293
|
+
class StoppableServer
|
294
|
+
|
295
|
+
attr_reader :port
|
296
|
+
|
297
|
+
def initialize()
|
298
|
+
queue = Queue.new
|
299
|
+
@first_req_waiter = java.util.concurrent.CountDownLatch.new(1)
|
300
|
+
@first_request = nil
|
301
|
+
|
302
|
+
@t = java.lang.Thread.new(
|
303
|
+
proc do
|
304
|
+
begin
|
305
|
+
@server = WEBrick::HTTPServer.new :Port => 0, :DocumentRoot => ".",
|
306
|
+
:Logger => Cabin::Channel.get, # silence WEBrick logging
|
307
|
+
:StartCallback => Proc.new {
|
308
|
+
queue.push("started")
|
309
|
+
}
|
310
|
+
@port = @server.config[:Port]
|
311
|
+
@server.mount_proc '/headers_check' do |req, res|
|
312
|
+
res.body = 'Hello, world from WEBrick mocking server!'
|
313
|
+
@first_request = req
|
314
|
+
@first_req_waiter.countDown()
|
315
|
+
end
|
316
|
+
|
317
|
+
@server.start
|
318
|
+
rescue => e
|
319
|
+
puts "Error in webserver thread #{e}"
|
320
|
+
# ignore
|
321
|
+
end
|
322
|
+
end
|
323
|
+
)
|
324
|
+
@t.daemon = true
|
325
|
+
@t.start
|
326
|
+
queue.pop # blocks until the server is up
|
327
|
+
end
|
328
|
+
|
329
|
+
def stop
|
330
|
+
@server.shutdown
|
331
|
+
end
|
332
|
+
|
333
|
+
def wait_receive_request
|
334
|
+
@first_req_waiter.await(2, java.util.concurrent.TimeUnit::SECONDS)
|
335
|
+
@first_request
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
describe "#build_adapter" do
|
340
|
+
let(:client) { LogStash::Outputs::ElasticSearch::HttpClient.new(base_options) }
|
341
|
+
let!(:webserver) { StoppableServer.new } # webserver must be started before the call, so no lazy "let"
|
342
|
+
|
343
|
+
after :each do
|
344
|
+
webserver.stop
|
345
|
+
end
|
346
|
+
|
347
|
+
context "the 'user-agent' header" do
|
348
|
+
it "contains the Logstash environment details" do
|
349
|
+
adapter = client.build_adapter(client.options)
|
350
|
+
adapter.perform_request(::LogStash::Util::SafeURI.new("http://localhost:#{webserver.port}"), :get, "/headers_check")
|
351
|
+
|
352
|
+
request = webserver.wait_receive_request
|
353
|
+
|
354
|
+
transmitted_user_agent = request.header['user-agent'][0]
|
355
|
+
expect(transmitted_user_agent).to match(/Logstash\/\d*\.\d*\.\d* \(OS=.*; JVM=.*\) logstash-output-elasticsearch\/\d*\.\d*\.\d*/)
|
356
|
+
end
|
357
|
+
end
|
358
|
+
end
|
290
359
|
end
|
@@ -156,7 +156,7 @@ describe LogStash::Outputs::ElasticSearch do
|
|
156
156
|
include_examples("an authenticated config")
|
157
157
|
end
|
158
158
|
|
159
|
-
context '
|
159
|
+
context 'cloud_auth also set' do
|
160
160
|
let(:do_register) { false } # this is what we want to test, so we disable the before(:each) call
|
161
161
|
let(:options) { { "user" => user, "password" => password, "cloud_auth" => "elastic:my-passwd-00" } }
|
162
162
|
|
@@ -934,6 +934,7 @@ describe LogStash::Outputs::ElasticSearch do
|
|
934
934
|
allow(subject).to receive(:last_es_version).and_return es_version
|
935
935
|
# make successful_connection? return true:
|
936
936
|
allow(subject).to receive(:maximum_seen_major_version).and_return Integer(es_version.split('.').first)
|
937
|
+
allow(subject).to receive(:alive_urls_count).and_return Integer(1)
|
937
938
|
allow(subject).to receive(:stop_after_successful_connection_thread)
|
938
939
|
end
|
939
940
|
|
@@ -12,6 +12,7 @@ describe "whitelisting error types in expected behavior" do
|
|
12
12
|
before :each do
|
13
13
|
allow(subject.logger).to receive(:warn)
|
14
14
|
allow(subject).to receive(:maximum_seen_major_version).and_return(0)
|
15
|
+
allow(subject).to receive(:alive_urls_count).and_return(1)
|
15
16
|
allow(subject).to receive(:finish_register)
|
16
17
|
|
17
18
|
subject.register
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-output-elasticsearch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 11.
|
4
|
+
version: 11.2.1
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Elastic
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-10-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -140,6 +140,34 @@ dependencies:
|
|
140
140
|
- - "~>"
|
141
141
|
- !ruby/object:Gem::Version
|
142
142
|
version: '0.6'
|
143
|
+
- !ruby/object:Gem::Dependency
|
144
|
+
requirement: !ruby/object:Gem::Requirement
|
145
|
+
requirements:
|
146
|
+
- - ">="
|
147
|
+
- !ruby/object:Gem::Version
|
148
|
+
version: '0'
|
149
|
+
name: webrick
|
150
|
+
prerelease: false
|
151
|
+
type: :development
|
152
|
+
version_requirements: !ruby/object:Gem::Requirement
|
153
|
+
requirements:
|
154
|
+
- - ">="
|
155
|
+
- !ruby/object:Gem::Version
|
156
|
+
version: '0'
|
157
|
+
- !ruby/object:Gem::Dependency
|
158
|
+
requirement: !ruby/object:Gem::Requirement
|
159
|
+
requirements:
|
160
|
+
- - ">="
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
version: '0'
|
163
|
+
name: webmock
|
164
|
+
prerelease: false
|
165
|
+
type: :development
|
166
|
+
version_requirements: !ruby/object:Gem::Requirement
|
167
|
+
requirements:
|
168
|
+
- - ">="
|
169
|
+
- !ruby/object:Gem::Version
|
170
|
+
version: '0'
|
143
171
|
- !ruby/object:Gem::Dependency
|
144
172
|
requirement: !ruby/object:Gem::Requirement
|
145
173
|
requirements:
|
@@ -184,7 +212,6 @@ files:
|
|
184
212
|
- lib/logstash/outputs/elasticsearch/templates/ecs-disabled/elasticsearch-8x.json
|
185
213
|
- lib/logstash/outputs/elasticsearch/templates/ecs-v1/elasticsearch-6x.json
|
186
214
|
- lib/logstash/outputs/elasticsearch/templates/ecs-v1/elasticsearch-7x.json
|
187
|
-
- lib/logstash/outputs/elasticsearch/templates/ecs-v1/elasticsearch-8x.json
|
188
215
|
- lib/logstash/plugin_mixins/elasticsearch/api_configs.rb
|
189
216
|
- lib/logstash/plugin_mixins/elasticsearch/common.rb
|
190
217
|
- lib/logstash/plugin_mixins/elasticsearch/noop_license_checker.rb
|
@@ -1 +0,0 @@
|
|
1
|
-
lib/logstash/outputs/elasticsearch/templates/ecs-v1/Users/yaauie/src/elastic/logstash-plugins/logsta
|