logstash-output-elasticsearch 5.4.1-java → 6.0.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 +7 -0
- data/lib/logstash/outputs/elasticsearch.rb +6 -5
- data/lib/logstash/outputs/elasticsearch/common.rb +3 -4
- data/lib/logstash/outputs/elasticsearch/common_configs.rb +3 -1
- data/lib/logstash/outputs/elasticsearch/http_client.rb +151 -110
- data/lib/logstash/outputs/elasticsearch/http_client/manticore_adapter.rb +43 -12
- data/lib/logstash/outputs/elasticsearch/http_client/pool.rb +26 -47
- data/lib/logstash/outputs/elasticsearch/http_client_builder.rb +4 -20
- data/lib/logstash/outputs/elasticsearch/template_manager.rb +1 -1
- data/logstash-output-elasticsearch.gemspec +1 -1
- data/spec/integration/outputs/sniffer_spec.rb +5 -1
- data/spec/unit/outputs/elasticsearch/http_client/manticore_adapter_spec.rb +25 -2
- data/spec/unit/outputs/elasticsearch/http_client/pool_spec.rb +24 -23
- data/spec/unit/outputs/elasticsearch/http_client_spec.rb +111 -44
- data/spec/unit/outputs/elasticsearch_proxy_spec.rb +33 -33
- data/spec/unit/outputs/elasticsearch_spec.rb +74 -16
- data/spec/unit/outputs/elasticsearch_ssl_spec.rb +23 -4
- metadata +2 -5
- data/lib/logstash/outputs/elasticsearch/safe_url.rb +0 -16
- data/spec/unit/safe_url_spec.rb +0 -46
@@ -6,7 +6,7 @@ module LogStash; module Outputs; class ElasticSearch; class HttpClient;
|
|
6
6
|
|
7
7
|
def initialize(response_code, url, body)
|
8
8
|
@response_code = response_code
|
9
|
-
@url =
|
9
|
+
@url = url
|
10
10
|
@body = body
|
11
11
|
end
|
12
12
|
|
@@ -19,7 +19,7 @@ module LogStash; module Outputs; class ElasticSearch; class HttpClient;
|
|
19
19
|
|
20
20
|
def initialize(original_error, url)
|
21
21
|
@original_error = original_error
|
22
|
-
@url =
|
22
|
+
@url = url
|
23
23
|
end
|
24
24
|
|
25
25
|
def message
|
@@ -27,13 +27,12 @@ module LogStash; module Outputs; class ElasticSearch; class HttpClient;
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
-
attr_reader :logger, :adapter, :sniffing, :sniffer_delay, :resurrect_delay, :
|
30
|
+
attr_reader :logger, :adapter, :sniffing, :sniffer_delay, :resurrect_delay, :healthcheck_path
|
31
31
|
|
32
32
|
DEFAULT_OPTIONS = {
|
33
33
|
:healthcheck_path => '/'.freeze,
|
34
34
|
:scheme => 'http',
|
35
35
|
:resurrect_delay => 5,
|
36
|
-
:auth => nil, # Can be set to {:user => 'user', :password => 'pass'}
|
37
36
|
:sniffing => false,
|
38
37
|
:sniffer_delay => 10,
|
39
38
|
}.freeze
|
@@ -41,30 +40,27 @@ module LogStash; module Outputs; class ElasticSearch; class HttpClient;
|
|
41
40
|
def initialize(logger, adapter, initial_urls=[], options={})
|
42
41
|
@logger = logger
|
43
42
|
@adapter = adapter
|
44
|
-
|
43
|
+
@initial_urls = initial_urls
|
44
|
+
|
45
|
+
raise ArgumentError, "No URL Normalizer specified!" unless options[:url_normalizer]
|
46
|
+
@url_normalizer = options[:url_normalizer]
|
45
47
|
DEFAULT_OPTIONS.merge(options).tap do |merged|
|
46
48
|
@healthcheck_path = merged[:healthcheck_path]
|
47
|
-
@scheme = merged[:scheme]
|
48
49
|
@resurrect_delay = merged[:resurrect_delay]
|
49
|
-
@auth = merged[:auth]
|
50
50
|
@sniffing = merged[:sniffing]
|
51
51
|
@sniffer_delay = merged[:sniffer_delay]
|
52
52
|
end
|
53
53
|
|
54
|
-
# Override the scheme if one is explicitly set in urls
|
55
|
-
if initial_urls.any? {|u| u.scheme == 'https'} && @scheme == 'http'
|
56
|
-
raise ArgumentError, "HTTP was set as scheme, but an HTTPS URL was passed in!"
|
57
|
-
end
|
58
|
-
|
59
54
|
# Used for all concurrent operations in this class
|
60
55
|
@state_mutex = Mutex.new
|
61
56
|
|
62
57
|
# Holds metadata about all URLs
|
63
58
|
@url_info = {}
|
64
59
|
@stopping = false
|
65
|
-
|
66
|
-
|
67
|
-
|
60
|
+
end
|
61
|
+
|
62
|
+
def start
|
63
|
+
update_urls(@initial_urls)
|
68
64
|
start_resurrectionist
|
69
65
|
start_sniffer if @sniffing
|
70
66
|
end
|
@@ -204,7 +200,7 @@ module LogStash; module Outputs; class ElasticSearch; class HttpClient;
|
|
204
200
|
if matches
|
205
201
|
host = matches[1].empty? ? matches[2] : matches[1]
|
206
202
|
port = matches[3]
|
207
|
-
LogStash::Util::SafeURI.new("#{host}:#{port}")
|
203
|
+
::LogStash::Util::SafeURI.new("#{host}:#{port}")
|
208
204
|
end
|
209
205
|
end.compact
|
210
206
|
end
|
@@ -228,26 +224,25 @@ module LogStash; module Outputs; class ElasticSearch; class HttpClient;
|
|
228
224
|
def healthcheck!
|
229
225
|
# Try to keep locking granularity low such that we don't affect IO...
|
230
226
|
@state_mutex.synchronize { @url_info.select {|url,meta| meta[:state] != :alive } }.each do |url,meta|
|
231
|
-
safe_url = ::LogStash::Outputs::ElasticSearch::SafeURL.without_credentials(url)
|
232
227
|
begin
|
233
228
|
logger.info("Running health check to see if an Elasticsearch connection is working",
|
234
|
-
url:
|
235
|
-
response = perform_request_to_url(url,
|
229
|
+
url: url, healthcheck_path: healthcheck_path)
|
230
|
+
response = perform_request_to_url(url, :head, healthcheck_path)
|
236
231
|
# If no exception was raised it must have succeeded!
|
237
|
-
logger.warn("Restored connection to ES instance", :url =>
|
232
|
+
logger.warn("Restored connection to ES instance", :url => url.sanitized)
|
238
233
|
@state_mutex.synchronize { meta[:state] = :alive }
|
239
234
|
rescue HostUnreachableError, BadResponseCodeError => e
|
240
|
-
logger.warn("Attempted to resurrect connection to dead ES instance, but got an error.", url:
|
235
|
+
logger.warn("Attempted to resurrect connection to dead ES instance, but got an error.", url: url.sanitized, error_type: e.class, error: e.message)
|
241
236
|
end
|
242
237
|
end
|
243
238
|
end
|
244
239
|
|
245
240
|
def stop_resurrectionist
|
246
|
-
@resurrectionist.join
|
241
|
+
@resurrectionist.join if @resurrectionist
|
247
242
|
end
|
248
243
|
|
249
244
|
def resurrectionist_alive?
|
250
|
-
@resurrectionist.alive?
|
245
|
+
@resurrectionist ? @resurrectionist.alive? : nil
|
251
246
|
end
|
252
247
|
|
253
248
|
def perform_request(method, path, params={}, body=nil)
|
@@ -270,18 +265,11 @@ module LogStash; module Outputs; class ElasticSearch; class HttpClient;
|
|
270
265
|
end
|
271
266
|
|
272
267
|
def normalize_url(uri)
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
# Set credentials if need be
|
277
|
-
if @auth && !uri.user
|
278
|
-
uri.user ||= @auth[:user]
|
279
|
-
uri.password ||= @auth[:password]
|
268
|
+
u = @url_normalizer.call(uri)
|
269
|
+
if !u.is_a?(::LogStash::Util::SafeURI)
|
270
|
+
raise "URL Normalizer returned a '#{u.class}' rather than a SafeURI! This shouldn't happen!"
|
280
271
|
end
|
281
|
-
|
282
|
-
uri.scheme = @scheme
|
283
|
-
|
284
|
-
uri
|
272
|
+
u
|
285
273
|
end
|
286
274
|
|
287
275
|
def update_urls(new_urls)
|
@@ -313,7 +301,7 @@ module LogStash; module Outputs; class ElasticSearch; class HttpClient;
|
|
313
301
|
|
314
302
|
if state_changes[:removed].size > 0 || state_changes[:added].size > 0
|
315
303
|
if logger.info?
|
316
|
-
logger.info("Elasticsearch pool URLs updated", :changes =>
|
304
|
+
logger.info("Elasticsearch pool URLs updated", :changes => state_changes)
|
317
305
|
end
|
318
306
|
end
|
319
307
|
|
@@ -324,14 +312,6 @@ module LogStash; module Outputs; class ElasticSearch; class HttpClient;
|
|
324
312
|
healthcheck!
|
325
313
|
end
|
326
314
|
|
327
|
-
def safe_state_changes(state_changes)
|
328
|
-
state_changes.reduce({}) do |acc, kv|
|
329
|
-
k,v = kv
|
330
|
-
acc[k] = v.map(&LogStash::Outputs::ElasticSearch::SafeURL.method(:without_credentials)).map(&:to_s)
|
331
|
-
acc
|
332
|
-
end
|
333
|
-
end
|
334
|
-
|
335
315
|
def size
|
336
316
|
@state_mutex.synchronize { @url_info.size }
|
337
317
|
end
|
@@ -378,10 +358,9 @@ module LogStash; module Outputs; class ElasticSearch; class HttpClient;
|
|
378
358
|
meta = @url_info[url]
|
379
359
|
# In case a sniff happened removing the metadata just before there's nothing to mark
|
380
360
|
# This is an extreme edge case, but it can happen!
|
381
|
-
return unless meta
|
382
|
-
|
383
|
-
|
384
|
-
:error_message => error.message, :error_class => error.class.name)
|
361
|
+
return unless meta
|
362
|
+
logger.warn("Marking url as dead. Last error: [#{error.class}] #{error.message}",
|
363
|
+
:url => url, :error_message => error.message, :error_class => error.class.name)
|
385
364
|
meta[:state] = :dead
|
386
365
|
meta[:last_error] = error
|
387
366
|
meta[:last_errored_at] = Time.now
|
@@ -6,7 +6,9 @@ module LogStash; module Outputs; class ElasticSearch;
|
|
6
6
|
:pool_max_per_route => params["pool_max_per_route"],
|
7
7
|
:check_connection_timeout => params["validate_after_inactivity"]
|
8
8
|
}
|
9
|
-
|
9
|
+
|
10
|
+
client_settings[:proxy] = params["proxy"] if params["proxy"]
|
11
|
+
|
10
12
|
common_options = {
|
11
13
|
:client_settings => client_settings,
|
12
14
|
:resurrect_delay => params["resurrect_delay"],
|
@@ -31,7 +33,6 @@ module LogStash; module Outputs; class ElasticSearch;
|
|
31
33
|
logger.debug? && logger.debug("Normalizing http path", :path => params["path"], :normalized => client_settings[:path])
|
32
34
|
|
33
35
|
client_settings.merge! setup_ssl(logger, params)
|
34
|
-
client_settings.merge! setup_proxy(logger, params)
|
35
36
|
common_options.merge! setup_basic_auth(logger, params)
|
36
37
|
|
37
38
|
# Update API setup
|
@@ -59,25 +60,8 @@ module LogStash; module Outputs; class ElasticSearch;
|
|
59
60
|
)
|
60
61
|
end
|
61
62
|
|
62
|
-
def self.setup_proxy(logger, params)
|
63
|
-
proxy = params["proxy"]
|
64
|
-
return {} unless proxy
|
65
|
-
|
66
|
-
# Symbolize keys
|
67
|
-
proxy = if proxy.is_a?(Hash)
|
68
|
-
Hash[proxy.map {|k,v| [k.to_sym, v]}]
|
69
|
-
elsif proxy.is_a?(String)
|
70
|
-
proxy
|
71
|
-
else
|
72
|
-
raise LogStash::ConfigurationError, "Expected 'proxy' to be a string or hash, not '#{proxy}''!"
|
73
|
-
end
|
74
|
-
|
75
|
-
return {:proxy => proxy}
|
76
|
-
end
|
77
|
-
|
78
63
|
def self.setup_ssl(logger, params)
|
79
|
-
|
80
|
-
params["ssl"] = true if params["hosts"].any? {|h| h.start_with?("https://")}
|
64
|
+
params["ssl"] = true if params["hosts"].any? {|h| h.scheme == "https" }
|
81
65
|
return {} if params["ssl"].nil?
|
82
66
|
|
83
67
|
return {:ssl => {:enabled => false}} if params["ssl"] == false
|
@@ -8,7 +8,7 @@ module LogStash; module Outputs; class ElasticSearch
|
|
8
8
|
plugin.logger.info("Attempting to install template", :manage_template => template)
|
9
9
|
install(plugin.client, plugin.template_name, template, plugin.template_overwrite)
|
10
10
|
rescue => e
|
11
|
-
plugin.logger.error("Failed to install template.", :message => e.message, :class => e.class.name)
|
11
|
+
plugin.logger.error("Failed to install template.", :message => e.message, :class => e.class.name, :backtrace => e.backtrace)
|
12
12
|
end
|
13
13
|
|
14
14
|
private
|
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
|
3
3
|
s.name = 'logstash-output-elasticsearch'
|
4
|
-
s.version = '
|
4
|
+
s.version = '6.0.0'
|
5
5
|
s.licenses = ['apache-2.0']
|
6
6
|
s.summary = "Logstash Output to Elasticsearch"
|
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"
|
@@ -7,10 +7,14 @@ describe "pool sniffer", :integration => true do
|
|
7
7
|
let(:logger) { Cabin::Channel.get }
|
8
8
|
let(:adapter) { LogStash::Outputs::ElasticSearch::HttpClient::ManticoreAdapter.new(logger) }
|
9
9
|
let(:initial_urls) { [::LogStash::Util::SafeURI.new("http://#{get_host_port}")] }
|
10
|
-
let(:options) { {:resurrect_delay => 2} } # Shorten the delay a bit to speed up tests
|
10
|
+
let(:options) { {:resurrect_delay => 2, :url_normalizer => proc {|u| u}} } # Shorten the delay a bit to speed up tests
|
11
11
|
|
12
12
|
subject { LogStash::Outputs::ElasticSearch::HttpClient::Pool.new(logger, adapter, initial_urls, options) }
|
13
13
|
|
14
|
+
before do
|
15
|
+
subject.start
|
16
|
+
end
|
17
|
+
|
14
18
|
shared_examples("sniff parsing") do |check_exact|
|
15
19
|
it "should execute a sniff without error" do
|
16
20
|
expect { subject.check_sniff }.not_to raise_error
|
@@ -9,16 +9,39 @@ describe LogStash::Outputs::ElasticSearch::HttpClient::ManticoreAdapter do
|
|
9
9
|
|
10
10
|
it "should raise an exception if requests are issued after close" do
|
11
11
|
subject.close
|
12
|
-
expect { subject.perform_request("http://localhost:9200", :get, '/') }.to raise_error(::Manticore::ClientStoppedException)
|
12
|
+
expect { subject.perform_request(::LogStash::Util::SafeURI.new("http://localhost:9200"), :get, '/') }.to raise_error(::Manticore::ClientStoppedException)
|
13
13
|
end
|
14
14
|
|
15
15
|
it "should implement host unreachable exceptions" do
|
16
16
|
expect(subject.host_unreachable_exceptions).to be_a(Array)
|
17
17
|
end
|
18
|
+
|
19
|
+
describe "auth" do
|
20
|
+
let(:user) { "myuser" }
|
21
|
+
let(:password) { "mypassword" }
|
22
|
+
let(:noauth_uri) { clone = uri.uri.clone;clone.user=nil; clone.password=nil; clone.to_s }
|
23
|
+
let(:uri) { ::LogStash::Util::SafeURI.new("http://#{user}:#{password}@localhost:9200") }
|
24
|
+
|
25
|
+
it "should convert the auth to params" do
|
26
|
+
resp = double("response")
|
27
|
+
allow(resp).to receive(:call)
|
28
|
+
allow(resp).to receive(:code).and_return(200)
|
29
|
+
expect(subject.manticore).to receive(:get).
|
30
|
+
with(noauth_uri, {
|
31
|
+
:auth => {
|
32
|
+
:user => user,
|
33
|
+
:password => password,
|
34
|
+
:eager => true
|
35
|
+
}
|
36
|
+
}).and_return resp
|
37
|
+
|
38
|
+
subject.perform_request(uri, :get, "/")
|
39
|
+
end
|
40
|
+
end
|
18
41
|
|
19
42
|
describe "integration specs", :integration => true do
|
20
43
|
it "should perform correct tests without error" do
|
21
|
-
resp = subject.perform_request("http://localhost:9200", :get, "/")
|
44
|
+
resp = subject.perform_request(::LogStash::Util::SafeURI.new("http://localhost:9200"), :get, "/")
|
22
45
|
expect(resp.code).to eql(200)
|
23
46
|
end
|
24
47
|
end
|
@@ -5,15 +5,30 @@ require "json"
|
|
5
5
|
describe LogStash::Outputs::ElasticSearch::HttpClient::Pool do
|
6
6
|
let(:logger) { Cabin::Channel.get }
|
7
7
|
let(:adapter) { LogStash::Outputs::ElasticSearch::HttpClient::ManticoreAdapter.new(logger) }
|
8
|
-
let(:initial_urls) { [
|
9
|
-
let(:options) { {:resurrect_delay => 2} } # Shorten the delay a bit to speed up tests
|
8
|
+
let(:initial_urls) { [::LogStash::Util::SafeURI.new("http://localhost:9200")] }
|
9
|
+
let(:options) { {:resurrect_delay => 2, :url_normalizer => proc {|u| u}} } # Shorten the delay a bit to speed up tests
|
10
10
|
|
11
11
|
subject { described_class.new(logger, adapter, initial_urls, options) }
|
12
12
|
|
13
|
+
let(:manticore_double) { double("manticore a") }
|
13
14
|
before do
|
14
|
-
allow(adapter).to receive(:perform_request).with(anything,
|
15
|
-
|
15
|
+
allow(adapter).to receive(:perform_request).with(anything, :head, subject.healthcheck_path, {}, nil)
|
16
|
+
|
17
|
+
|
18
|
+
response_double = double("manticore response").as_null_object
|
19
|
+
# Allow healtchecks
|
20
|
+
allow(manticore_double).to receive(:head).with(any_args).and_return(response_double)
|
21
|
+
allow(manticore_double).to receive(:get).with(any_args).and_return(response_double)
|
22
|
+
|
23
|
+
allow(::Manticore::Client).to receive(:new).and_return(manticore_double)
|
16
24
|
|
25
|
+
subject.start
|
26
|
+
end
|
27
|
+
|
28
|
+
after do
|
29
|
+
subject.close
|
30
|
+
end
|
31
|
+
|
17
32
|
describe "initialization" do
|
18
33
|
it "should be successful" do
|
19
34
|
expect { subject }.not_to raise_error
|
@@ -51,6 +66,7 @@ describe LogStash::Outputs::ElasticSearch::HttpClient::Pool do
|
|
51
66
|
allow(adapter).to receive(:close).and_call_original
|
52
67
|
allow(subject).to receive(:wait_for_in_use_connections).and_call_original
|
53
68
|
allow(subject).to receive(:in_use_connections).and_return([subject.empty_url_meta()],[])
|
69
|
+
allow(subject).to receive(:start)
|
54
70
|
subject.close
|
55
71
|
end
|
56
72
|
|
@@ -73,33 +89,18 @@ describe LogStash::Outputs::ElasticSearch::HttpClient::Pool do
|
|
73
89
|
end
|
74
90
|
end
|
75
91
|
|
76
|
-
describe "safe_state_changes" do
|
77
|
-
let(:state_changes) do
|
78
|
-
{
|
79
|
-
:added => [URI.parse("http://sekretu:sekretp@foo1")],
|
80
|
-
:removed => [URI.parse("http://sekretu:sekretp@foo2")]
|
81
|
-
}
|
82
|
-
end
|
83
|
-
let(:processed) { subject.safe_state_changes(state_changes)}
|
84
|
-
|
85
|
-
it "should hide passwords" do
|
86
|
-
expect(processed[:added].any? {|p| p =~ /sekretp/ }).to be false
|
87
|
-
expect(processed[:removed].any? {|p| p =~ /sekretp/ }).to be false
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
92
|
describe "connection management" do
|
92
93
|
context "with only one URL in the list" do
|
93
94
|
it "should use the only URL in 'with_connection'" do
|
94
95
|
subject.with_connection do |c|
|
95
|
-
expect(c).to
|
96
|
+
expect(c).to eq(initial_urls.first)
|
96
97
|
end
|
97
98
|
end
|
98
99
|
end
|
99
100
|
|
100
101
|
context "with multiple URLs in the list" do
|
101
|
-
let(:initial_urls) { [
|
102
|
-
|
102
|
+
let(:initial_urls) { [ ::LogStash::Util::SafeURI.new("http://localhost:9200"), ::LogStash::Util::SafeURI.new("http://localhost:9201"), ::LogStash::Util::SafeURI.new("http://localhost:9202") ] }
|
103
|
+
|
103
104
|
it "should minimize the number of connections to a single URL" do
|
104
105
|
connected_urls = []
|
105
106
|
|
@@ -122,7 +123,7 @@ describe LogStash::Outputs::ElasticSearch::HttpClient::Pool do
|
|
122
123
|
|
123
124
|
# The resurrectionist will call this to check on the backend
|
124
125
|
response = double("response")
|
125
|
-
expect(adapter).to receive(:perform_request).with(u,
|
126
|
+
expect(adapter).to receive(:perform_request).with(u, :head, subject.healthcheck_path, {}, nil).and_return(response)
|
126
127
|
|
127
128
|
subject.return_connection(u)
|
128
129
|
subject.mark_dead(u, Exception.new)
|
@@ -3,7 +3,19 @@ require "logstash/outputs/elasticsearch/http_client"
|
|
3
3
|
require "java"
|
4
4
|
|
5
5
|
describe LogStash::Outputs::ElasticSearch::HttpClient do
|
6
|
-
let(:
|
6
|
+
let(:ssl) { nil }
|
7
|
+
let(:base_options) do
|
8
|
+
opts = {
|
9
|
+
:hosts => [::LogStash::Util::SafeURI.new("127.0.0.1")],
|
10
|
+
:logger => Cabin::Channel.get
|
11
|
+
}
|
12
|
+
|
13
|
+
if !ssl.nil? # Shortcut to set this
|
14
|
+
opts[:client_settings] = {:ssl => {:enabled => ssl}}
|
15
|
+
end
|
16
|
+
|
17
|
+
opts
|
18
|
+
end
|
7
19
|
|
8
20
|
describe "Host/URL Parsing" do
|
9
21
|
subject { described_class.new(base_options) }
|
@@ -12,71 +24,83 @@ describe LogStash::Outputs::ElasticSearch::HttpClient do
|
|
12
24
|
let(:ipv6_hostname) { "[::1]" }
|
13
25
|
let(:ipv4_hostname) { "127.0.0.1" }
|
14
26
|
let(:port) { 9202 }
|
15
|
-
let(:hostname_port) { "#{hostname}:#{port}"}
|
16
|
-
let(:
|
17
|
-
let(:
|
18
|
-
let(:
|
19
|
-
|
27
|
+
let(:hostname_port) { "#{hostname}:#{port}" }
|
28
|
+
let(:hostname_port_uri) { ::LogStash::Util::SafeURI.new("//#{hostname_port}") }
|
29
|
+
let(:http_hostname_port) { ::LogStash::Util::SafeURI.new("http://#{hostname_port}") }
|
30
|
+
let(:https_hostname_port) { ::LogStash::Util::SafeURI.new("https://#{hostname_port}") }
|
31
|
+
let(:http_hostname_port_path) { ::LogStash::Util::SafeURI.new("http://#{hostname_port}/path") }
|
32
|
+
|
20
33
|
shared_examples("proper host handling") do
|
21
34
|
it "should properly transform a host:port string to a URL" do
|
22
|
-
expect(subject.
|
23
|
-
end
|
24
|
-
|
25
|
-
it "should raise an error when a partial URL is an invalid format" do
|
26
|
-
expect {
|
27
|
-
subject.send(:host_to_url, "#{hostname_port}/")
|
28
|
-
}.to raise_error(LogStash::ConfigurationError)
|
35
|
+
expect(subject.host_to_url(hostname_port_uri)).to eq(http_hostname_port)
|
29
36
|
end
|
30
37
|
|
31
38
|
it "should not raise an error with a / for a path" do
|
32
|
-
expect(subject.
|
39
|
+
expect(subject.host_to_url(::LogStash::Util::SafeURI.new("#{http_hostname_port}/"))).to eq(LogStash::Util::SafeURI.new("#{http_hostname_port}/"))
|
33
40
|
end
|
34
41
|
|
35
42
|
it "should parse full URLs correctly" do
|
36
|
-
expect(subject.
|
37
|
-
end
|
38
|
-
|
39
|
-
it "should reject full URLs with usernames and passwords" do
|
40
|
-
expect {
|
41
|
-
subject.send(:host_to_url, "http://user:password@host.domain")
|
42
|
-
}.to raise_error(LogStash::ConfigurationError)
|
43
|
+
expect(subject.host_to_url(http_hostname_port)).to eq(http_hostname_port)
|
43
44
|
end
|
44
45
|
|
45
46
|
describe "ssl" do
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
47
|
+
context "when SSL is true" do
|
48
|
+
let(:ssl) { true }
|
49
|
+
let(:base_options) { super.merge(:hosts => [http_hostname_port]) }
|
50
|
+
|
51
|
+
it "should refuse to handle an http url" do
|
52
|
+
expect {
|
53
|
+
subject.host_to_url(http_hostname_port)
|
54
|
+
}.to raise_error(LogStash::ConfigurationError)
|
55
|
+
end
|
50
56
|
end
|
51
57
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
58
|
+
context "when SSL is false" do
|
59
|
+
let(:ssl) { false }
|
60
|
+
let(:base_options) { super.merge(:hosts => [https_hostname_port]) }
|
61
|
+
|
62
|
+
it "should refuse to handle an https url" do
|
63
|
+
expect {
|
64
|
+
subject.host_to_url(https_hostname_port)
|
65
|
+
}.to raise_error(LogStash::ConfigurationError)
|
66
|
+
end
|
56
67
|
end
|
57
68
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
end
|
69
|
+
describe "ssl is nil" do
|
70
|
+
let(:base_options) { super.merge(:hosts => [https_hostname_port]) }
|
71
|
+
it "should handle an ssl url correctly when SSL is nil" do
|
72
|
+
subject
|
73
|
+
expect(subject.host_to_url(https_hostname_port)).to eq(https_hostname_port)
|
74
|
+
end
|
75
|
+
end
|
65
76
|
end
|
66
77
|
|
67
78
|
describe "path" do
|
79
|
+
let(:url) { http_hostname_port_path }
|
80
|
+
let(:base_options) { super.merge(:hosts => [url]) }
|
81
|
+
|
68
82
|
it "should allow paths in a url" do
|
69
|
-
expect(subject.
|
83
|
+
expect(subject.host_to_url(url)).to eq(url)
|
70
84
|
end
|
71
85
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
86
|
+
context "with the path option set" do
|
87
|
+
let(:base_options) { super.merge(:client_settings => {:path => "/otherpath"}) }
|
88
|
+
|
89
|
+
it "should not allow paths in two places" do
|
90
|
+
expect {
|
91
|
+
subject.host_to_url(url)
|
92
|
+
}.to raise_error(LogStash::ConfigurationError)
|
93
|
+
end
|
76
94
|
end
|
77
|
-
|
78
|
-
|
79
|
-
|
95
|
+
|
96
|
+
context "with a path missing a leading /" do
|
97
|
+
let(:url) { http_hostname_port }
|
98
|
+
let(:base_options) { super.merge(:client_settings => {:path => "otherpath"}) }
|
99
|
+
|
100
|
+
|
101
|
+
it "should automatically insert a / in front of path overlays" do
|
102
|
+
expect(subject.host_to_url(url)).to eq(LogStash::Util::SafeURI.new(url + "/otherpath"))
|
103
|
+
end
|
80
104
|
end
|
81
105
|
end
|
82
106
|
end
|
@@ -97,6 +121,49 @@ describe LogStash::Outputs::ElasticSearch::HttpClient do
|
|
97
121
|
end
|
98
122
|
end
|
99
123
|
|
124
|
+
describe "join_bulk_responses" do
|
125
|
+
subject { described_class.new(base_options) }
|
126
|
+
|
127
|
+
context "when items key is available" do
|
128
|
+
require "json"
|
129
|
+
let(:bulk_response) {
|
130
|
+
LogStash::Json.load ('[{
|
131
|
+
"items": [{
|
132
|
+
"delete": {
|
133
|
+
"_index": "website",
|
134
|
+
"_type": "blog",
|
135
|
+
"_id": "123",
|
136
|
+
"_version": 2,
|
137
|
+
"status": 200,
|
138
|
+
"found": true
|
139
|
+
}
|
140
|
+
}],
|
141
|
+
"errors": false
|
142
|
+
}]')
|
143
|
+
}
|
144
|
+
it "should be handled properly" do
|
145
|
+
s = subject.send(:join_bulk_responses, bulk_response)
|
146
|
+
expect(s["errors"]).to be false
|
147
|
+
expect(s["items"].size).to be 1
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
context "when items key is not available" do
|
152
|
+
require "json"
|
153
|
+
let(:bulk_response) {
|
154
|
+
JSON.parse ('[{
|
155
|
+
"took": 4,
|
156
|
+
"errors": false
|
157
|
+
}]')
|
158
|
+
}
|
159
|
+
it "should be handled properly" do
|
160
|
+
s = subject.send(:join_bulk_responses, bulk_response)
|
161
|
+
expect(s["errors"]).to be false
|
162
|
+
expect(s["items"].size).to be 0
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
100
167
|
describe "sniffing" do
|
101
168
|
let(:client) { LogStash::Outputs::ElasticSearch::HttpClient.new(base_options.merge(client_opts)) }
|
102
169
|
|