elasticsearch-transport 7.5.0 → 7.13.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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +28 -11
  3. data/README.md +158 -58
  4. data/Rakefile +16 -3
  5. data/elasticsearch-transport.gemspec +57 -63
  6. data/lib/elasticsearch/transport/client.rb +150 -56
  7. data/lib/elasticsearch/transport/meta_header.rb +135 -0
  8. data/lib/elasticsearch/transport/redacted.rb +16 -3
  9. data/lib/elasticsearch/transport/transport/base.rb +32 -12
  10. data/lib/elasticsearch/transport/transport/connections/collection.rb +18 -8
  11. data/lib/elasticsearch/transport/transport/connections/connection.rb +23 -8
  12. data/lib/elasticsearch/transport/transport/connections/selector.rb +16 -3
  13. data/lib/elasticsearch/transport/transport/errors.rb +16 -3
  14. data/lib/elasticsearch/transport/transport/http/curb.rb +16 -3
  15. data/lib/elasticsearch/transport/transport/http/faraday.rb +27 -6
  16. data/lib/elasticsearch/transport/transport/http/manticore.rb +16 -3
  17. data/lib/elasticsearch/transport/transport/loggable.rb +16 -3
  18. data/lib/elasticsearch/transport/transport/response.rb +16 -4
  19. data/lib/elasticsearch/transport/transport/serializer/multi_json.rb +16 -3
  20. data/lib/elasticsearch/transport/transport/sniffer.rb +35 -15
  21. data/lib/elasticsearch/transport/version.rb +17 -4
  22. data/lib/elasticsearch/transport.rb +16 -3
  23. data/lib/elasticsearch-transport.rb +16 -3
  24. data/spec/elasticsearch/connections/collection_spec.rb +28 -3
  25. data/spec/elasticsearch/connections/selector_spec.rb +16 -3
  26. data/spec/elasticsearch/transport/base_spec.rb +60 -38
  27. data/spec/elasticsearch/transport/client_spec.rb +628 -132
  28. data/spec/elasticsearch/transport/meta_header_spec.rb +265 -0
  29. data/spec/elasticsearch/transport/sniffer_spec.rb +16 -16
  30. data/spec/spec_helper.rb +19 -1
  31. data/test/integration/transport_test.rb +30 -4
  32. data/test/profile/client_benchmark_test.rb +16 -3
  33. data/test/test_helper.rb +16 -3
  34. data/test/unit/connection_test.rb +23 -5
  35. data/test/unit/response_test.rb +17 -4
  36. data/test/unit/serializer_test.rb +16 -3
  37. data/test/unit/transport_base_test.rb +17 -4
  38. data/test/unit/transport_curb_test.rb +16 -3
  39. data/test/unit/transport_faraday_test.rb +18 -5
  40. data/test/unit/transport_manticore_test.rb +29 -16
  41. metadata +70 -69
@@ -1,8 +1,22 @@
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
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
4
17
 
5
18
  require 'base64'
19
+ require 'elasticsearch/transport/meta_header'
6
20
 
7
21
  module Elasticsearch
8
22
  module Transport
@@ -12,6 +26,7 @@ module Elasticsearch
12
26
  # See {file:README.md README} for usage and code examples.
13
27
  #
14
28
  class Client
29
+ include MetaHeader
15
30
  DEFAULT_TRANSPORT_CLASS = Transport::HTTP::Faraday
16
31
 
17
32
  DEFAULT_LOGGER = lambda do
@@ -36,9 +51,15 @@ module Elasticsearch
36
51
  DEFAULT_HOST = 'localhost:9200'.freeze
37
52
 
38
53
  # The default port to use if connecting using a Cloud ID.
54
+ # Updated from 9243 to 443 in client version 7.10.1
39
55
  #
40
56
  # @since 7.2.0
41
- DEFAULT_CLOUD_PORT = 9243
57
+ DEFAULT_CLOUD_PORT = 443
58
+
59
+ # The default port to use if not otherwise specified.
60
+ #
61
+ # @since 7.2.0
62
+ DEFAULT_PORT = 9200
42
63
 
43
64
  # Returns the transport object.
44
65
  #
@@ -99,6 +120,14 @@ module Elasticsearch
99
120
  # The default is false. Responses will automatically be inflated if they are compressed.
100
121
  # If a custom transport object is used, it must handle the request compression and response inflation.
101
122
  #
123
+ # @option api_key [String, Hash] :api_key Use API Key Authentication, either the base64 encoding of `id` and `api_key`
124
+ # joined by a colon as a String, or a hash with the `id` and `api_key` values.
125
+ # @option opaque_id_prefix [String] :opaque_id_prefix set a prefix for X-Opaque-Id when initializing the client.
126
+ # This will be prepended to the id you set before each request
127
+ # if you're using X-Opaque-Id
128
+ # @option enable_meta_header [Boolean] :enable_meta_header Enable sending the meta data header to Cloud.
129
+ # (Default: true)
130
+ #
102
131
  # @yield [faraday] Access and configure the `Faraday::Connection` instance directly with a block
103
132
  #
104
133
  def initialize(arguments={}, &block)
@@ -112,57 +141,107 @@ module Elasticsearch
112
141
  @arguments[:randomize_hosts] ||= false
113
142
  @arguments[:transport_options] ||= {}
114
143
  @arguments[:http] ||= {}
144
+ @arguments[:enable_meta_header] = arguments.fetch(:enable_meta_header) { true }
115
145
  @options[:http] ||= {}
116
146
 
147
+ set_api_key if (@api_key = @arguments[:api_key])
148
+ set_compatibility_header if ENV['ELASTIC_CLIENT_APIVERSIONING']
149
+
117
150
  @seeds = extract_cloud_creds(@arguments)
118
151
  @seeds ||= __extract_hosts(@arguments[:hosts] ||
119
- @arguments[:host] ||
120
- @arguments[:url] ||
121
- @arguments[:urls] ||
122
- ENV['ELASTICSEARCH_URL'] ||
123
- DEFAULT_HOST)
152
+ @arguments[:host] ||
153
+ @arguments[:url] ||
154
+ @arguments[:urls] ||
155
+ ENV['ELASTICSEARCH_URL'] ||
156
+ DEFAULT_HOST)
124
157
 
125
158
  @send_get_body_as = @arguments[:send_get_body_as] || 'GET'
159
+ @opaque_id_prefix = @arguments[:opaque_id_prefix] || nil
126
160
 
127
161
  if @arguments[:request_timeout]
128
- @arguments[:transport_options][:request] = { :timeout => @arguments[:request_timeout] }
162
+ @arguments[:transport_options][:request] = { timeout: @arguments[:request_timeout] }
129
163
  end
130
164
 
131
165
  if @arguments[:transport]
132
166
  @transport = @arguments[:transport]
133
167
  else
134
- transport_class = @arguments[:transport_class] || DEFAULT_TRANSPORT_CLASS
135
- if transport_class == Transport::HTTP::Faraday
136
- @transport = transport_class.new(:hosts => @seeds, :options => @arguments) do |faraday|
137
- block.call faraday if block
138
- unless (h = faraday.builder.handlers.last) && h.name.start_with?("Faraday::Adapter")
139
- faraday.adapter(@arguments[:adapter] || __auto_detect_adapter)
140
- end
141
- end
142
- else
143
- @transport = transport_class.new(:hosts => @seeds, :options => @arguments)
144
- end
168
+ @transport_class = @arguments[:transport_class] || DEFAULT_TRANSPORT_CLASS
169
+ @transport = if @transport_class == Transport::HTTP::Faraday
170
+ @arguments[:adapter] ||= __auto_detect_adapter
171
+ set_meta_header # from include MetaHeader
172
+ @transport_class.new(hosts: @seeds, options: @arguments) do |faraday|
173
+ faraday.adapter(@arguments[:adapter])
174
+ block&.call faraday
175
+ end
176
+ else
177
+ set_meta_header # from include MetaHeader
178
+ @transport_class.new(hosts: @seeds, options: @arguments)
179
+ end
145
180
  end
146
181
  end
147
182
 
148
183
  # Performs a request through delegation to {#transport}.
149
184
  #
150
- def perform_request(method, path, params={}, body=nil, headers=nil)
185
+ def perform_request(method, path, params = {}, body = nil, headers = nil)
151
186
  method = @send_get_body_as if 'GET' == method && body
187
+ if (opaque_id = params.delete(:opaque_id))
188
+ headers = {} if headers.nil?
189
+ opaque_id = @opaque_id_prefix ? "#{@opaque_id_prefix}#{opaque_id}" : opaque_id
190
+ headers.merge!('X-Opaque-Id' => opaque_id)
191
+ end
152
192
  transport.perform_request(method, path, params, body, headers)
153
193
  end
154
194
 
155
195
  private
156
196
 
197
+ def set_api_key
198
+ @api_key = __encode(@api_key) if @api_key.is_a? Hash
199
+ add_header('Authorization' => "ApiKey #{@api_key}")
200
+ @arguments.delete(:user)
201
+ @arguments.delete(:password)
202
+ end
203
+
204
+ def set_compatibility_header
205
+ return unless ['1', 'true'].include?(ENV['ELASTIC_CLIENT_APIVERSIONING'])
206
+
207
+ add_header(
208
+ {
209
+ 'Accept' => 'application/vnd.elasticsearch+json;compatible-with=7',
210
+ 'Content-Type' => 'application/vnd.elasticsearch+json; compatible-with=7'
211
+ }
212
+ )
213
+ end
214
+
215
+ def add_header(header)
216
+ headers = @arguments[:transport_options]&.[](:headers) || {}
217
+ headers.merge!(header)
218
+ @arguments[:transport_options].merge!(
219
+ headers: headers
220
+ )
221
+ end
222
+
157
223
  def extract_cloud_creds(arguments)
158
- return unless arguments[:cloud_id]
224
+ return unless arguments[:cloud_id] && !arguments[:cloud_id].empty?
225
+
159
226
  name = arguments[:cloud_id].split(':')[0]
160
227
  cloud_url, elasticsearch_instance = Base64.decode64(arguments[:cloud_id].gsub("#{name}:", '')).split('$')
161
- [ { scheme: 'https',
228
+
229
+ if cloud_url.include?(':')
230
+ url, port = cloud_url.split(':')
231
+ host = "#{elasticsearch_instance}.#{url}"
232
+ else
233
+ host = "#{elasticsearch_instance}.#{cloud_url}"
234
+ port = arguments[:port] || DEFAULT_CLOUD_PORT
235
+ end
236
+ [
237
+ {
238
+ scheme: 'https',
162
239
  user: arguments[:user],
163
240
  password: arguments[:password],
164
- host: "#{elasticsearch_instance}.#{cloud_url}",
165
- port: arguments[:port] || DEFAULT_CLOUD_PORT } ]
241
+ host: host,
242
+ port: port.to_i
243
+ }
244
+ ]
166
245
  end
167
246
 
168
247
  # Normalizes and returns hosts configuration.
@@ -195,39 +274,47 @@ module Elasticsearch
195
274
 
196
275
  def __parse_host(host)
197
276
  host_parts = case host
198
- when String
199
- if host =~ /^[a-z]+\:\/\//
200
- # Construct a new `URI::Generic` directly from the array returned by URI::split.
201
- # This avoids `URI::HTTP` and `URI::HTTPS`, which supply default ports.
202
- uri = URI::Generic.new(*URI.split(host))
203
-
204
- { :scheme => uri.scheme,
205
- :user => uri.user,
206
- :password => uri.password,
207
- :host => uri.host,
208
- :path => uri.path,
209
- :port => uri.port }
210
- else
211
- host, port = host.split(':')
212
- { :host => host,
213
- :port => port }
214
- end
215
- when URI
216
- { :scheme => host.scheme,
217
- :user => host.user,
218
- :password => host.password,
219
- :host => host.host,
220
- :path => host.path,
221
- :port => host.port }
222
- when Hash
223
- host
277
+ when String
278
+ if host =~ /^[a-z]+\:\/\//
279
+ # Construct a new `URI::Generic` directly from the array returned by URI::split.
280
+ # This avoids `URI::HTTP` and `URI::HTTPS`, which supply default ports.
281
+ uri = URI::Generic.new(*URI.split(host))
282
+ default_port = uri.scheme == 'https' ? 443 : DEFAULT_PORT
283
+ {
284
+ scheme: uri.scheme,
285
+ user: uri.user,
286
+ password: uri.password,
287
+ host: uri.host,
288
+ path: uri.path,
289
+ port: uri.port || default_port
290
+ }
291
+ else
292
+ host, port = host.split(':')
293
+ { host: host, port: port }
294
+ end
295
+ when URI
296
+ {
297
+ scheme: host.scheme,
298
+ user: host.user,
299
+ password: host.password,
300
+ host: host.host,
301
+ path: host.path,
302
+ port: host.port
303
+ }
304
+ when Hash
305
+ host
306
+ else
307
+ raise ArgumentError, "Please pass host as a String, URI or Hash -- #{host.class} given."
308
+ end
309
+ if @api_key
310
+ # Remove Basic Auth if using API KEY
311
+ host_parts.delete(:user)
312
+ host_parts.delete(:password)
224
313
  else
225
- raise ArgumentError, "Please pass host as a String, URI or Hash -- #{host.class} given."
314
+ @options[:http][:user] ||= host_parts[:user]
315
+ @options[:http][:password] ||= host_parts[:password]
226
316
  end
227
317
 
228
- @options[:http][:user] ||= host_parts[:user]
229
- @options[:http][:password] ||= host_parts[:password]
230
-
231
318
  host_parts[:port] = host_parts[:port].to_i if host_parts[:port]
232
319
  host_parts[:path].chomp!('/') if host_parts[:path]
233
320
  host_parts
@@ -255,6 +342,13 @@ module Elasticsearch
255
342
  ::Faraday.default_adapter
256
343
  end
257
344
  end
345
+
346
+ # Encode credentials for the Authorization Header
347
+ # Credentials is the base64 encoding of id and api_key joined by a colon
348
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html
349
+ def __encode(api_key)
350
+ Base64.strict_encode64([api_key[:id], api_key[:api_key]].join(':'))
351
+ end
258
352
  end
259
353
  end
260
354
  end
@@ -0,0 +1,135 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ require 'base64'
19
+
20
+ module Elasticsearch
21
+ module Transport
22
+ # Methods for the Elastic meta header used by Cloud.
23
+ # X-Elastic-Client-Meta HTTP header which is used by Elastic Cloud and can be disabled when
24
+ # instantiating the Client with the :enable_meta_header parameter set to `false`.
25
+ #
26
+ module MetaHeader
27
+ def set_meta_header
28
+ return if @arguments[:enable_meta_header] == false
29
+
30
+ service, version = meta_header_service_version
31
+
32
+ meta_headers = {
33
+ service.to_sym => version,
34
+ rb: RUBY_VERSION,
35
+ t: Elasticsearch::Transport::VERSION
36
+ }
37
+ meta_headers.merge!(meta_header_engine) if meta_header_engine
38
+ meta_headers.merge!(meta_header_adapter) if meta_header_adapter
39
+
40
+ add_header({ 'x-elastic-client-meta' => meta_headers.map { |k, v| "#{k}=#{v}" }.join(',') })
41
+ end
42
+
43
+ def meta_header_service_version
44
+ if enterprise_search?
45
+ Elastic::ENTERPRISE_SERVICE_VERSION
46
+ elsif elasticsearch?
47
+ Elastic::ELASTICSEARCH_SERVICE_VERSION
48
+ elsif defined?(Elasticsearch::VERSION)
49
+ [:es, client_meta_version(Elasticsearch::VERSION)]
50
+ else
51
+ [:es, client_meta_version(Elasticsearch::Transport::VERSION)]
52
+ end
53
+ end
54
+
55
+ def enterprise_search?
56
+ defined?(Elastic::ENTERPRISE_SERVICE_VERSION) &&
57
+ called_from?('enterprise-search-ruby')
58
+ end
59
+
60
+ def elasticsearch?
61
+ defined?(Elastic::ELASTICSEARCH_SERVICE_VERSION) &&
62
+ called_from?('elasticsearch')
63
+ end
64
+
65
+ def called_from?(service)
66
+ !caller.select { |c| c.match?(service) }.empty?
67
+ end
68
+
69
+ # We return the current version if it's a release, but if it's a pre/alpha/beta release we
70
+ # return <VERSION_NUMBER>p
71
+ #
72
+ def client_meta_version(version)
73
+ regexp = /^([0-9]+\.[0-9]+\.[0-9]+)(\.?[a-z0-9.-]+)?$/
74
+ match = version.match(regexp)
75
+ return "#{match[1]}p" if (match[2])
76
+
77
+ version
78
+ end
79
+
80
+ def meta_header_engine
81
+ case RUBY_ENGINE
82
+ when 'ruby'
83
+ {}
84
+ when 'jruby'
85
+ { jv: ENV_JAVA['java.version'], jr: JRUBY_VERSION }
86
+ when 'rbx'
87
+ { rbx: RUBY_VERSION }
88
+ else
89
+ { RUBY_ENGINE.to_sym => RUBY_VERSION }
90
+ end
91
+ end
92
+
93
+ # This function tries to define the version for the Faraday adapter. If it hasn't been loaded
94
+ # by the time we're calling this method, it's going to report the adapter (if we know it) but
95
+ # return 0 as the version. It won't report anything when using a custom adapter we don't
96
+ # identify.
97
+ #
98
+ # Returns a Hash<adapter_alias, version>
99
+ #
100
+ def meta_header_adapter
101
+ if @transport_class == Transport::HTTP::Faraday
102
+ version = '0'
103
+ adapter_version = case @arguments[:adapter]
104
+ when :patron
105
+ version = Patron::VERSION if defined?(::Patron::VERSION)
106
+ {pt: version}
107
+ when :net_http
108
+ version = if defined?(Net::HTTP::VERSION)
109
+ Net::HTTP::VERSION
110
+ elsif defined?(Net::HTTP::HTTPVersion)
111
+ Net::HTTP::HTTPVersion
112
+ end
113
+ {nh: version}
114
+ when :typhoeus
115
+ version = Typhoeus::VERSION if defined?(::Typhoeus::VERSION)
116
+ {ty: version}
117
+ when :httpclient
118
+ version = HTTPClient::VERSION if defined?(HTTPClient::VERSION)
119
+ {hc: version}
120
+ when :net_http_persistent
121
+ version = Net::HTTP::Persistent::VERSION if defined?(Net::HTTP::Persistent::VERSION)
122
+ {np: version}
123
+ else
124
+ {}
125
+ end
126
+ {fd: Faraday::VERSION}.merge(adapter_version)
127
+ elsif defined?(Transport::HTTP::Curb) && @transport_class == Transport::HTTP::Curb
128
+ {cl: Curl::CURB_VERSION}
129
+ elsif defined?(Transport::HTTP::Manticore) && @transport_class == Transport::HTTP::Manticore
130
+ {mc: Manticore::VERSION}
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
@@ -1,6 +1,19 @@
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
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
4
17
 
5
18
  module Elasticsearch
6
19
  module Transport
@@ -1,6 +1,19 @@
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
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
4
17
 
5
18
  module Elasticsearch
6
19
  module Transport
@@ -34,7 +47,7 @@ module Elasticsearch
34
47
  #
35
48
  # @see Client#initialize
36
49
  #
37
- def initialize(arguments={}, &block)
50
+ def initialize(arguments = {}, &block)
38
51
  @state_mutex = Mutex.new
39
52
 
40
53
  @hosts = arguments[:hosts] || []
@@ -221,9 +234,9 @@ module Elasticsearch
221
234
  def __full_url(host)
222
235
  url = "#{host[:protocol]}://"
223
236
  url += "#{CGI.escape(host[:user])}:#{CGI.escape(host[:password])}@" if host[:user]
224
- url += "#{host[:host]}"
237
+ url += host[:host]
225
238
  url += ":#{host[:port]}" if host[:port]
226
- url += "#{host[:path]}" if host[:path]
239
+ url += host[:path] if host[:path]
227
240
  url
228
241
  end
229
242
 
@@ -245,8 +258,9 @@ module Elasticsearch
245
258
  # @raise [ServerError] If request failed on server
246
259
  # @raise [Error] If no connection is available
247
260
  #
248
- def perform_request(method, path, params={}, body=nil, headers=nil, opts={}, &block)
249
- raise NoMethodError, "Implement this method in your transport class" unless block_given?
261
+ def perform_request(method, path, params = {}, body = nil, headers = nil, opts = {}, &block)
262
+ raise NoMethodError, 'Implement this method in your transport class' unless block_given?
263
+
250
264
  start = Time.now
251
265
  tries = 0
252
266
  reload_on_failure = opts.fetch(:reload_on_failure, @options[:reload_on_failure])
@@ -263,15 +277,15 @@ module Elasticsearch
263
277
 
264
278
  begin
265
279
  tries += 1
266
- connection = get_connection or raise Error.new("Cannot get new connection from pool.")
280
+ connection = get_connection or raise Error.new('Cannot get new connection from pool.')
267
281
 
268
282
  if connection.connection.respond_to?(:params) && connection.connection.params.respond_to?(:to_hash)
269
283
  params = connection.connection.params.merge(params.to_hash)
270
284
  end
271
285
 
272
- url = connection.full_url(path, params)
286
+ url = connection.full_url(path, params)
273
287
 
274
- response = block.call(connection, url)
288
+ response = block.call(connection, url)
275
289
 
276
290
  connection.healthy! if connection.failures > 0
277
291
 
@@ -342,6 +356,8 @@ module Elasticsearch
342
356
 
343
357
  __trace method, path, params, connection.connection.headers, body, url, response, nil, 'N/A', duration if tracer
344
358
 
359
+ warnings(response.headers['warning']) if response.headers&.[]('warning')
360
+
345
361
  Response.new response.status, json || response.body, response.headers
346
362
  ensure
347
363
  @last_request_at = Time.now
@@ -415,7 +431,11 @@ module Elasticsearch
415
431
  "elasticsearch-ruby/#{VERSION} (#{meta.join('; ')})"
416
432
  end
417
433
  end
434
+
435
+ def warnings(warning)
436
+ warn("warning: #{warning}")
437
+ end
418
438
  end
419
439
  end
420
440
  end
421
- end
441
+ end
@@ -1,6 +1,19 @@
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
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
4
17
 
5
18
  module Elasticsearch
6
19
  module Transport
@@ -65,16 +78,13 @@ module Elasticsearch
65
78
 
66
79
  # Returns a connection.
67
80
  #
68
- # If there are no alive connections, resurrects a connection with least failures.
81
+ # If there are no alive connections, returns a connection with least failures.
69
82
  # Delegates to selector's `#select` method to get the connection.
70
83
  #
71
84
  # @return [Connection]
72
85
  #
73
86
  def get_connection(options={})
74
- if connections.empty? && dead_connection = dead.sort { |a,b| a.failures <=> b.failures }.first
75
- dead_connection.alive!
76
- end
77
- selector.select(options)
87
+ selector.select(options) || @connections.min_by(&:failures)
78
88
  end
79
89
 
80
90
  def each(&block)
@@ -1,12 +1,24 @@
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
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
4
17
 
5
18
  module Elasticsearch
6
19
  module Transport
7
20
  module Transport
8
21
  module Connections
9
-
10
22
  # Wraps the connection information and logic.
11
23
  #
12
24
  # The Connection instance wraps the host information (hostname, port, attributes, etc),
@@ -41,12 +53,14 @@ module Elasticsearch
41
53
  #
42
54
  # @return [String]
43
55
  #
44
- def full_url(path, params={})
56
+ def full_url(path, params = {})
45
57
  url = "#{host[:protocol]}://"
46
58
  url += "#{CGI.escape(host[:user])}:#{CGI.escape(host[:password])}@" if host[:user]
47
59
  url += "#{host[:host]}:#{host[:port]}"
48
60
  url += "#{host[:path]}" if host[:path]
49
- url += "/#{full_path(path, params)}"
61
+ full_path = full_path(path, params)
62
+ url += '/' unless full_path.match?(/^\//)
63
+ url += full_path
50
64
  end
51
65
 
52
66
  # Returns the complete endpoint path with serialized parameters.
@@ -122,14 +136,15 @@ module Elasticsearch
122
136
  }
123
137
  end
124
138
 
125
- # Equality operator based on connection protocol, host and port
139
+ # Equality operator based on connection protocol, host, port and attributes
126
140
  #
127
141
  # @return [Boolean]
128
142
  #
129
143
  def ==(other)
130
144
  self.host[:protocol] == other.host[:protocol] && \
131
145
  self.host[:host] == other.host[:host] && \
132
- self.host[:port].to_i == other.host[:port].to_i
146
+ self.host[:port].to_i == other.host[:port].to_i && \
147
+ self.host[:attributes] == other.host[:attributes]
133
148
  end
134
149
 
135
150
  # @return [String]
@@ -1,6 +1,19 @@
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
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
4
17
 
5
18
  module Elasticsearch
6
19
  module Transport