elasticsearch-transport 6.3.0 → 6.8.3

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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +86 -32
  3. data/elasticsearch-transport.gemspec +45 -64
  4. data/lib/elasticsearch-transport.rb +4 -0
  5. data/lib/elasticsearch/transport.rb +4 -0
  6. data/lib/elasticsearch/transport/client.rb +141 -20
  7. data/lib/elasticsearch/transport/redacted.rb +4 -0
  8. data/lib/elasticsearch/transport/transport/base.rb +17 -7
  9. data/lib/elasticsearch/transport/transport/connections/collection.rb +4 -0
  10. data/lib/elasticsearch/transport/transport/connections/connection.rb +4 -0
  11. data/lib/elasticsearch/transport/transport/connections/selector.rb +4 -0
  12. data/lib/elasticsearch/transport/transport/errors.rb +4 -0
  13. data/lib/elasticsearch/transport/transport/http/curb.rb +6 -2
  14. data/lib/elasticsearch/transport/transport/http/faraday.rb +6 -2
  15. data/lib/elasticsearch/transport/transport/http/manticore.rb +5 -1
  16. data/lib/elasticsearch/transport/transport/response.rb +4 -0
  17. data/lib/elasticsearch/transport/transport/serializer/multi_json.rb +4 -0
  18. data/lib/elasticsearch/transport/transport/sniffer.rb +31 -3
  19. data/lib/elasticsearch/transport/version.rb +5 -1
  20. data/spec/elasticsearch/transport/base_spec.rb +187 -8
  21. data/spec/elasticsearch/transport/client_spec.rb +157 -23
  22. data/spec/elasticsearch/transport/meta_header_spec.rb +214 -0
  23. data/spec/elasticsearch/transport/sniffer_spec.rb +269 -0
  24. data/spec/spec_helper.rb +11 -0
  25. data/test/integration/transport_test.rb +4 -0
  26. data/test/profile/client_benchmark_test.rb +4 -0
  27. data/test/test_helper.rb +4 -0
  28. data/test/unit/connection_collection_test.rb +4 -0
  29. data/test/unit/connection_selector_test.rb +4 -0
  30. data/test/unit/connection_test.rb +4 -0
  31. data/test/unit/response_test.rb +5 -1
  32. data/test/unit/serializer_test.rb +4 -0
  33. data/test/unit/transport_base_test.rb +4 -0
  34. data/test/unit/transport_curb_test.rb +4 -0
  35. data/test/unit/transport_faraday_test.rb +4 -0
  36. data/test/unit/transport_manticore_test.rb +4 -0
  37. metadata +80 -54
  38. data/test/unit/sniffer_test.rb +0 -179
@@ -1,3 +1,7 @@
1
+ # Licensed to Elasticsearch B.V under one or more agreements.
2
+ # Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3
+ # See the LICENSE file in the project root for more information
4
+
1
5
  # Licensed to Elasticsearch B.V. under one or more contributor
2
6
  # license agreements. See the NOTICE file distributed with
3
7
  # this work for additional information regarding copyright
@@ -1,3 +1,7 @@
1
+ # Licensed to Elasticsearch B.V under one or more agreements.
2
+ # Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3
+ # See the LICENSE file in the project root for more information
4
+
1
5
  module Elasticsearch
2
6
  module Transport
3
7
  module Transport
@@ -16,7 +20,7 @@ module Elasticsearch
16
20
  attr_reader :hosts, :options, :connections, :counter, :last_request_at, :protocol
17
21
  attr_accessor :serializer, :sniffer, :logger, :tracer,
18
22
  :reload_connections, :reload_after,
19
- :resurrect_after, :max_retries
23
+ :resurrect_after
20
24
 
21
25
  # Creates a new transport object
22
26
  #
@@ -52,7 +56,6 @@ module Elasticsearch
52
56
  @reload_connections = options[:reload_connections]
53
57
  @reload_after = options[:reload_connections].is_a?(Integer) ? options[:reload_connections] : DEFAULT_RELOAD_AFTER
54
58
  @resurrect_after = options[:resurrect_after] || DEFAULT_RESURRECT_AFTER
55
- @max_retries = options[:retry_on_failure].is_a?(Integer) ? options[:retry_on_failure] : DEFAULT_MAX_RETRIES
56
59
  @retry_on_status = Array(options[:retry_on_status]).map { |d| d.to_i }
57
60
  end
58
61
 
@@ -244,10 +247,17 @@ module Elasticsearch
244
247
  # @raise [ServerError] If request failed on server
245
248
  # @raise [Error] If no connection is available
246
249
  #
247
- def perform_request(method, path, params={}, body=nil, headers=nil, &block)
250
+ def perform_request(method, path, params={}, body=nil, headers=nil, opts={}, &block)
248
251
  raise NoMethodError, "Implement this method in your transport class" unless block_given?
249
252
  start = Time.now if logger || tracer
250
253
  tries = 0
254
+ reload_on_failure = opts.fetch(:reload_on_failure, @options[:reload_on_failure])
255
+
256
+ max_retries = if opts.key?(:retry_on_failure)
257
+ opts[:retry_on_failure] === true ? DEFAULT_MAX_RETRIES : opts[:retry_on_failure]
258
+ elsif options.key?(:retry_on_failure)
259
+ options[:retry_on_failure] === true ? DEFAULT_MAX_RETRIES : options[:retry_on_failure]
260
+ end
251
261
 
252
262
  params = params.clone
253
263
 
@@ -271,9 +281,9 @@ module Elasticsearch
271
281
  __raise_transport_error(response) if response.status.to_i >= 300 && @retry_on_status.include?(response.status.to_i)
272
282
 
273
283
  rescue Elasticsearch::Transport::Transport::ServerError => e
274
- if @retry_on_status.include?(response.status)
284
+ if response && @retry_on_status.include?(response.status)
275
285
  logger.warn "[#{e.class}] Attempt #{tries} to get response from #{url}" if logger
276
- if tries <= max_retries
286
+ if tries <= (max_retries || DEFAULT_MAX_RETRIES)
277
287
  retry
278
288
  else
279
289
  logger.fatal "[#{e.class}] Cannot get response from #{url} after #{tries} tries" if logger
@@ -288,12 +298,12 @@ module Elasticsearch
288
298
 
289
299
  connection.dead!
290
300
 
291
- if @options[:reload_on_failure] and tries < connections.all.size
301
+ if reload_on_failure and tries < connections.all.size
292
302
  logger.warn "[#{e.class}] Reloading connections (attempt #{tries} of #{connections.all.size})" if logger
293
303
  reload_connections! and retry
294
304
  end
295
305
 
296
- if @options[:retry_on_failure]
306
+ if max_retries
297
307
  logger.warn "[#{e.class}] Attempt #{tries} connecting to #{connection.host.inspect}" if logger
298
308
  if tries <= max_retries
299
309
  retry
@@ -1,3 +1,7 @@
1
+ # Licensed to Elasticsearch B.V under one or more agreements.
2
+ # Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3
+ # See the LICENSE file in the project root for more information
4
+
1
5
  module Elasticsearch
2
6
  module Transport
3
7
  module Transport
@@ -1,3 +1,7 @@
1
+ # Licensed to Elasticsearch B.V under one or more agreements.
2
+ # Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3
+ # See the LICENSE file in the project root for more information
4
+
1
5
  module Elasticsearch
2
6
  module Transport
3
7
  module Transport
@@ -1,3 +1,7 @@
1
+ # Licensed to Elasticsearch B.V under one or more agreements.
2
+ # Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3
+ # See the LICENSE file in the project root for more information
4
+
1
5
  module Elasticsearch
2
6
  module Transport
3
7
  module Transport
@@ -1,3 +1,7 @@
1
+ # Licensed to Elasticsearch B.V under one or more agreements.
2
+ # Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3
+ # See the LICENSE file in the project root for more information
4
+
1
5
  module Elasticsearch
2
6
  module Transport
3
7
  module Transport
@@ -1,3 +1,7 @@
1
+ # Licensed to Elasticsearch B.V under one or more agreements.
2
+ # Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3
+ # See the LICENSE file in the project root for more information
4
+
1
5
  module Elasticsearch
2
6
  module Transport
3
7
  module Transport
@@ -15,8 +19,8 @@ module Elasticsearch
15
19
  # @return [Response]
16
20
  # @see Transport::Base#perform_request
17
21
  #
18
- def perform_request(method, path, params={}, body=nil, headers=nil)
19
- super do |connection,url|
22
+ def perform_request(method, path, params={}, body=nil, headers=nil, opts={})
23
+ super do |connection, url|
20
24
  connection.connection.url = url
21
25
 
22
26
  case method
@@ -1,3 +1,7 @@
1
+ # Licensed to Elasticsearch B.V under one or more agreements.
2
+ # Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3
+ # See the LICENSE file in the project root for more information
4
+
1
5
  module Elasticsearch
2
6
  module Transport
3
7
  module Transport
@@ -16,7 +20,7 @@ module Elasticsearch
16
20
  # @return [Response]
17
21
  # @see Transport::Base#perform_request
18
22
  #
19
- def perform_request(method, path, params={}, body=nil, headers=nil)
23
+ def perform_request(method, path, params={}, body=nil, headers=nil, opts={})
20
24
  super do |connection, url|
21
25
  headers = headers || connection.connection.headers
22
26
 
@@ -43,7 +47,7 @@ module Elasticsearch
43
47
  # @return [Array]
44
48
  #
45
49
  def host_unreachable_exceptions
46
- [::Faraday::Error::ConnectionFailed, ::Faraday::Error::TimeoutError]
50
+ [::Faraday::ConnectionFailed, ::Faraday::TimeoutError]
47
51
  end
48
52
  end
49
53
  end
@@ -1,3 +1,7 @@
1
+ # Licensed to Elasticsearch B.V under one or more agreements.
2
+ # Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3
+ # See the LICENSE file in the project root for more information
4
+
1
5
  require 'manticore'
2
6
 
3
7
  module Elasticsearch
@@ -63,7 +67,7 @@ module Elasticsearch
63
67
  # @return [Response]
64
68
  # @see Transport::Base#perform_request
65
69
  #
66
- def perform_request(method, path, params={}, body=nil, headers=nil)
70
+ def perform_request(method, path, params={}, body=nil, headers=nil, opts={})
67
71
  super do |connection, url|
68
72
  params[:body] = __convert_to_json(body) if body
69
73
  params[:headers] = headers if headers
@@ -1,3 +1,7 @@
1
+ # Licensed to Elasticsearch B.V under one or more agreements.
2
+ # Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3
+ # See the LICENSE file in the project root for more information
4
+
1
5
  module Elasticsearch
2
6
  module Transport
3
7
  module Transport
@@ -1,3 +1,7 @@
1
+ # Licensed to Elasticsearch B.V under one or more agreements.
2
+ # Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3
+ # See the LICENSE file in the project root for more information
4
+
1
5
  module Elasticsearch
2
6
  module Transport
3
7
  module Transport
@@ -1,3 +1,7 @@
1
+ # Licensed to Elasticsearch B.V under one or more agreements.
2
+ # Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3
+ # See the LICENSE file in the project root for more information
4
+
1
5
  module Elasticsearch
2
6
  module Transport
3
7
  module Transport
@@ -28,11 +32,12 @@ module Elasticsearch
28
32
  #
29
33
  def hosts
30
34
  Timeout::timeout(timeout, SnifferTimeoutError) do
31
- nodes = transport.perform_request('GET', '_nodes/http').body
35
+ nodes = transport.perform_request('GET', '_nodes/http', {}, nil, nil,
36
+ reload_on_failure: false).body
32
37
 
33
- hosts = nodes['nodes'].map do |id,info|
38
+ hosts = nodes['nodes'].map do |id, info|
34
39
  if info[PROTOCOL]
35
- host, port = info[PROTOCOL]['publish_address'].split(':')
40
+ host, port = parse_publish_address(info[PROTOCOL]['publish_address'])
36
41
 
37
42
  { :id => id,
38
43
  :name => info['name'],
@@ -48,6 +53,29 @@ module Elasticsearch
48
53
  hosts
49
54
  end
50
55
  end
56
+
57
+ private
58
+
59
+ def parse_publish_address(publish_address)
60
+ # publish_address is in the format hostname/ip:port
61
+ if publish_address =~ /\//
62
+ parts = publish_address.partition('/')
63
+ [ parts[0], parse_address_port(parts[2])[1] ]
64
+ else
65
+ parse_address_port(publish_address)
66
+ end
67
+ end
68
+
69
+ def parse_address_port(publish_address)
70
+ # address is ipv6
71
+ if publish_address =~ /[\[\]]/
72
+ if parts = publish_address.match(/\A\[(.+)\](?::(\d+))?\z/)
73
+ [ parts[1], parts[2] ]
74
+ end
75
+ else
76
+ publish_address.split(':')
77
+ end
78
+ end
51
79
  end
52
80
  end
53
81
  end
@@ -1,5 +1,9 @@
1
+ # Licensed to Elasticsearch B.V under one or more agreements.
2
+ # Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3
+ # See the LICENSE file in the project root for more information
4
+
1
5
  module Elasticsearch
2
6
  module Transport
3
- VERSION = "6.3.0"
7
+ VERSION = '6.8.3'
4
8
  end
5
9
  end
@@ -1,3 +1,7 @@
1
+ # Licensed to Elasticsearch B.V under one or more agreements.
2
+ # Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3
+ # See the LICENSE file in the project root for more information
4
+
1
5
  # Licensed to Elasticsearch B.V. under one or more contributor
2
6
  # license agreements. See the NOTICE file distributed with
3
7
  # this work for additional information regarding copyright
@@ -18,11 +22,8 @@
18
22
  require 'spec_helper'
19
23
 
20
24
  describe Elasticsearch::Transport::Transport::Base do
21
-
22
25
  context 'when a host is printed in a logged message' do
23
-
24
26
  shared_examples_for 'a redacted string' do
25
-
26
27
  let(:client) do
27
28
  Elasticsearch::Transport::Client.new(arguments)
28
29
  end
@@ -33,6 +34,7 @@ describe Elasticsearch::Transport::Transport::Base do
33
34
 
34
35
  it 'does not include the password in the logged string' do
35
36
  expect(logger).not_to receive(:error).with(/secret_password/)
37
+
36
38
  expect {
37
39
  client.cluster.stats
38
40
  }.to raise_exception(Faraday::ConnectionFailed)
@@ -47,7 +49,6 @@ describe Elasticsearch::Transport::Transport::Base do
47
49
  end
48
50
 
49
51
  context 'when the user and password are provided as separate arguments' do
50
-
51
52
  let(:arguments) do
52
53
  { hosts: 'fake',
53
54
  logger: logger,
@@ -59,9 +60,8 @@ describe Elasticsearch::Transport::Transport::Base do
59
60
  end
60
61
 
61
62
  context 'when the user and password are provided in the string URI' do
62
-
63
63
  let(:arguments) do
64
- { hosts: 'http://test:secret_password@fake.com',
64
+ { hosts: 'https://test:secret_password@fake_local_elasticsearch',
65
65
  logger: logger }
66
66
  end
67
67
 
@@ -69,13 +69,192 @@ describe Elasticsearch::Transport::Transport::Base do
69
69
  end
70
70
 
71
71
  context 'when the user and password are provided in the URI object' do
72
-
73
72
  let(:arguments) do
74
- { hosts: URI.parse('http://test:secret_password@fake.com'),
73
+ { hosts: URI.parse('https://test:secret_password@fake_local_elasticsearch'),
75
74
  logger: logger }
76
75
  end
77
76
 
78
77
  it_behaves_like 'a redacted string'
79
78
  end
80
79
  end
80
+
81
+ context 'when reload_on_failure is true and and hosts are unreachable' do
82
+
83
+ let(:client) do
84
+ Elasticsearch::Transport::Client.new(arguments)
85
+ end
86
+
87
+ let(:arguments) do
88
+ {
89
+ hosts: ['http://unavailable:9200', 'http://unavailable:9201'],
90
+ reload_on_failure: true,
91
+ sniffer_timeout: 5
92
+ }
93
+ end
94
+
95
+ it 'raises an exception' do
96
+ expect {
97
+ client.info
98
+ }.to raise_exception(Faraday::ConnectionFailed)
99
+ end
100
+ end
101
+
102
+ context 'when the client has `retry_on_failure` set to an integer' do
103
+
104
+ let(:client) do
105
+ Elasticsearch::Transport::Client.new(arguments)
106
+ end
107
+
108
+ let(:arguments) do
109
+ {
110
+ hosts: ['http://unavailable:9200', 'http://unavailable:9201'],
111
+ retry_on_failure: 2
112
+ }
113
+ end
114
+
115
+ context 'when `perform_request` is called without a `retry_on_failure` option value' do
116
+
117
+ before do
118
+ expect(client.transport).to receive(:get_connection).exactly(3).times.and_call_original
119
+ end
120
+
121
+ it 'uses the client `retry_on_failure` value' do
122
+ expect {
123
+ client.transport.perform_request('GET', '/info')
124
+ }.to raise_exception(Faraday::ConnectionFailed)
125
+ end
126
+ end
127
+
128
+ context 'when `perform_request` is called with a `retry_on_failure` option value' do
129
+
130
+ before do
131
+ expect(client.transport).to receive(:get_connection).exactly(6).times.and_call_original
132
+ end
133
+
134
+ it 'uses the option `retry_on_failure` value' do
135
+ expect {
136
+ client.transport.perform_request('GET', '/info', {}, nil, nil, retry_on_failure: 5)
137
+ }.to raise_exception(Faraday::ConnectionFailed)
138
+ end
139
+ end
140
+ end
141
+
142
+ context 'when the client has `retry_on_failure` set to true' do
143
+
144
+ let(:client) do
145
+ Elasticsearch::Transport::Client.new(arguments)
146
+ end
147
+
148
+ let(:arguments) do
149
+ {
150
+ hosts: ['http://unavailable:9200', 'http://unavailable:9201'],
151
+ retry_on_failure: true
152
+ }
153
+ end
154
+
155
+ context 'when `perform_request` is called without a `retry_on_failure` option value' do
156
+
157
+ before do
158
+ expect(client.transport).to receive(:get_connection).exactly(4).times.and_call_original
159
+ end
160
+
161
+ it 'uses the default `MAX_RETRIES` value' do
162
+ expect {
163
+ client.transport.perform_request('GET', '/info')
164
+ }.to raise_exception(Faraday::ConnectionFailed)
165
+ end
166
+ end
167
+
168
+ context 'when `perform_request` is called with a `retry_on_failure` option value' do
169
+
170
+ before do
171
+ expect(client.transport).to receive(:get_connection).exactly(6).times.and_call_original
172
+ end
173
+
174
+ it 'uses the option `retry_on_failure` value' do
175
+ expect {
176
+ client.transport.perform_request('GET', '/info', {}, nil, nil, retry_on_failure: 5)
177
+ }.to raise_exception(Faraday::ConnectionFailed)
178
+ end
179
+ end
180
+ end
181
+
182
+ context 'when the client has `retry_on_failure` set to false' do
183
+
184
+ let(:client) do
185
+ Elasticsearch::Transport::Client.new(arguments)
186
+ end
187
+
188
+ let(:arguments) do
189
+ {
190
+ hosts: ['http://unavailable:9200', 'http://unavailable:9201'],
191
+ retry_on_failure: false
192
+ }
193
+ end
194
+
195
+ context 'when `perform_request` is called without a `retry_on_failure` option value' do
196
+
197
+ before do
198
+ expect(client.transport).to receive(:get_connection).once.and_call_original
199
+ end
200
+
201
+ it 'does not retry' do
202
+ expect {
203
+ client.transport.perform_request('GET', '/info')
204
+ }.to raise_exception(Faraday::ConnectionFailed)
205
+ end
206
+ end
207
+
208
+ context 'when `perform_request` is called with a `retry_on_failure` option value' do
209
+
210
+ before do
211
+ expect(client.transport).to receive(:get_connection).exactly(6).times.and_call_original
212
+ end
213
+
214
+ it 'uses the option `retry_on_failure` value' do
215
+ expect {
216
+ client.transport.perform_request('GET', '/info', {}, nil, nil, retry_on_failure: 5)
217
+ }.to raise_exception(Faraday::ConnectionFailed)
218
+ end
219
+ end
220
+ end
221
+
222
+ context 'when the client has no `retry_on_failure` set' do
223
+
224
+ let(:client) do
225
+ Elasticsearch::Transport::Client.new(arguments)
226
+ end
227
+
228
+ let(:arguments) do
229
+ {
230
+ hosts: ['http://unavailable:9200', 'http://unavailable:9201'],
231
+ }
232
+ end
233
+
234
+ context 'when `perform_request` is called without a `retry_on_failure` option value' do
235
+
236
+ before do
237
+ expect(client.transport).to receive(:get_connection).exactly(1).times.and_call_original
238
+ end
239
+
240
+ it 'does not retry' do
241
+ expect {
242
+ client.transport.perform_request('GET', '/info')
243
+ }.to raise_exception(Faraday::ConnectionFailed)
244
+ end
245
+ end
246
+
247
+ context 'when `perform_request` is called with a `retry_on_failure` option value' do
248
+
249
+ before do
250
+ expect(client.transport).to receive(:get_connection).exactly(6).times.and_call_original
251
+ end
252
+
253
+ it 'uses the option `retry_on_failure` value' do
254
+ expect {
255
+ client.transport.perform_request('GET', '/info', {}, nil, nil, retry_on_failure: 5)
256
+ }.to raise_exception(Faraday::ConnectionFailed)
257
+ end
258
+ end
259
+ end
81
260
  end