logstash-output-elasticsearch 11.0.3-java → 11.2.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/docs/index.asciidoc +11 -11
- 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: 0bd2f7b95f4a121df8712ce601a2c56c228de6e113f90c96058c58f966af31db
|
4
|
+
data.tar.gz: bac417c7d999e1676ed451cf5216b0b6085203b533fd7d5039abf3efbc070578
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '09274b381e8026eb8527b5926318c603ffc776e645538671263f61fec3d00731e7695a13e2f72cdccd4037f1d7298975a6424f03115a38060f4e2e34f7498049'
|
7
|
+
data.tar.gz: 47fddb97c3634cd68588bebaed1d0fac38d4eb33c3cc69083e59a9c13c1f74a87f7835e6fc7982762a2db19009150900ca7ac2bee213d973e56dc0a8fbcc1158
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
## 11.2.0
|
2
|
+
- Added preflight checks on Elasticsearch [#1026](https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/1026)
|
3
|
+
|
4
|
+
## 11.1.0
|
5
|
+
- Feat: add `user-agent` header passed to the Elasticsearch HTTP connection [#1038](https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/1038)
|
6
|
+
|
7
|
+
## 11.0.5
|
8
|
+
- Fixed running post-register action when Elasticsearch status change from unhealthy to healthy [#1035](https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/1035)
|
9
|
+
|
10
|
+
## 11.0.4
|
11
|
+
- [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)
|
12
|
+
|
1
13
|
## 11.0.3
|
2
14
|
- Fixed SSL handshake hang indefinitely with proxy setup [#1032](https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/1032)
|
3
15
|
|
data/docs/index.asciidoc
CHANGED
@@ -278,16 +278,11 @@ not reevaluate its DNS value while the keepalive is in effect.
|
|
278
278
|
|
279
279
|
==== HTTP Compression
|
280
280
|
|
281
|
-
This plugin supports request and
|
282
|
-
|
281
|
+
This plugin supports request compression, and handles compressed responses
|
282
|
+
from Elasticsearch.
|
283
283
|
|
284
|
-
|
285
|
-
|
286
|
-
`http.compression` must be set to `true` {ref}/modules-http.html#modules-http[in
|
287
|
-
Elasticsearch] to take advantage of response compression when using this plugin.
|
288
|
-
|
289
|
-
For requests compression, regardless of the Elasticsearch version, enable the
|
290
|
-
`http_compression` setting in the Logstash config file.
|
284
|
+
To enable request compression, use the <<plugins-{type}s-{plugin}-http_compression>>
|
285
|
+
setting on this plugin.
|
291
286
|
|
292
287
|
==== Authentication
|
293
288
|
|
@@ -640,8 +635,13 @@ Any special characters present in the URLs here MUST be URL escaped! This means
|
|
640
635
|
* Value type is <<boolean,boolean>>
|
641
636
|
* Default value is `false`
|
642
637
|
|
643
|
-
Enable gzip compression on requests.
|
644
|
-
|
638
|
+
Enable gzip compression on requests.
|
639
|
+
|
640
|
+
This setting allows you to reduce this plugin's outbound network traffic by
|
641
|
+
compressing each bulk _request_ to {es}.
|
642
|
+
|
643
|
+
NOTE: This output plugin reads compressed _responses_ from {es} regardless
|
644
|
+
of the value of this setting.
|
645
645
|
|
646
646
|
[id="plugins-{type}s-{plugin}-ilm_enabled"]
|
647
647
|
===== `ilm_enabled`
|
@@ -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.0
|
3
|
+
s.version = '11.2.0'
|
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.0
|
4
|
+
version: 11.2.0
|
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-12 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
|