elasticsearch-transport 7.9.0.pre → 7.11.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8e172f03d64feff3991f8ef723219c1f3f26824d624cfaee35195168c2224361
4
- data.tar.gz: d8039d3a4e5a5f406aae9ff94a56ef0c1068dd985b71c36a4d21d553b3404775
3
+ metadata.gz: 1e364f5d86474b878377249e59488749009a24682da9d35e3eaeb430a0c9d9d4
4
+ data.tar.gz: 9952aede93dd570e563acef81038e9423793f4e0682b9916d5155fa37edb0792
5
5
  SHA512:
6
- metadata.gz: 1ae8684bffd3b1c1badd932702491266d93dafbe63cc7b02de814601bd120c0955914ff6e3f3220e7cfafe0654f87ecca3fea652c6df4783d106b9749b69eaca
7
- data.tar.gz: 8607504cde6a896a5c11d2e7ab753829dddb9c1d7c2ae960e3cdb3a9bfff2f3d46e9bec0790222e7d34f8309ea86d5c096e9646fdadd51cfae6b0891defed73d
6
+ metadata.gz: be3c7ecd096850addb44e502f471ae2e88e43e3ee93dc342eb4b32b36eb994d66131e35f6458cec5026a02e7edd25e71d058efaa5a675fdacfe38c567a478a7f
7
+ data.tar.gz: 9ed532c04edc174e1eb903bb116add80f946f1610360a0294bed09d6d3f3b26444432745c67431e3611d3c478434e5afb18db9271450854c3255ef67e049e506
data/Gemfile CHANGED
@@ -32,7 +32,7 @@ if File.exist? File.expand_path('../../elasticsearch/elasticsearch.gemspec', __F
32
32
  gem 'elasticsearch', path: File.expand_path('../../elasticsearch', __FILE__), require: false
33
33
  end
34
34
 
35
- group :development do
35
+ group :development, :test do
36
36
  gem 'rspec'
37
37
  if defined?(JRUBY_VERSION)
38
38
  gem 'pry-nav'
data/README.md CHANGED
@@ -136,7 +136,7 @@ Please see below for an exception to this when connecting using an Elastic Cloud
136
136
 
137
137
  If you are using [Elastic Cloud](https://www.elastic.co/cloud), you can provide your cloud id to the client.
138
138
  You must supply your username and password separately, and optionally a port. If no port is supplied,
139
- port 9243 will be used.
139
+ port 443 will be used.
140
140
 
141
141
  Note: Do not enable sniffing when using Elastic Cloud. The nodes are behind a load balancer so
142
142
  Elastic Cloud will take care of everything for you.
@@ -187,18 +187,24 @@ Elasticsearch::Client.new(
187
187
 
188
188
  ### Logging
189
189
 
190
- To log requests and responses to standard output with the default logger (an instance of Ruby's {::Logger} class),
191
- set the `log` argument:
190
+ To log requests and responses to standard output with the default logger (an instance of Ruby's {::Logger} class), set the `log` argument to true:
192
191
 
193
192
  ```ruby
194
- Elasticsearch::Client.new log: true
193
+ Elasticsearch::Client.new(log: true)
194
+ ```
195
+
196
+ You can also use [ecs-logging](https://github.com/elastic/ecs-logging-ruby). `ecs-logging` is a set of libraries that allows you to transform your application logs to structured logs that comply with the [Elastic Common Schema (ECS)](https://www.elastic.co/guide/en/ecs/current/ecs-reference.html):
197
+
198
+ ```ruby
199
+ logger = EcsLogging::Logger.new($stdout)
200
+ Elasticsearch::Client.new(logger: logger)
195
201
  ```
196
202
 
197
203
 
198
204
  To trace requests and responses in the _Curl_ format, set the `trace` argument:
199
205
 
200
206
  ```ruby
201
- Elasticsearch::Client.new trace: true
207
+ Elasticsearch::Client.new(trace: true)
202
208
  ```
203
209
 
204
210
  You can customize the default logger or tracer:
@@ -211,7 +217,7 @@ You can customize the default logger or tracer:
211
217
  Or, you can use a custom `::Logger` instance:
212
218
 
213
219
  ```ruby
214
- Elasticsearch::Client.new logger: Logger.new(STDERR)
220
+ Elasticsearch::Client.new(logger: Logger.new(STDERR))
215
221
  ```
216
222
 
217
223
  You can pass the client any conforming logger implementation:
@@ -223,7 +229,7 @@ log = Logging.logger['elasticsearch']
223
229
  log.add_appenders Logging.appenders.stdout
224
230
  log.level = :info
225
231
 
226
- client = Elasticsearch::Client.new logger: log
232
+ client = Elasticsearch::Client.new(logger: log)
227
233
  ```
228
234
 
229
235
  ### Custom HTTP Headers
@@ -293,11 +299,16 @@ on a different host:
293
299
 
294
300
  Elasticsearch::Client.new hosts: ['localhost:9200', 'localhost:9201'], retry_on_failure: true
295
301
 
296
- You can specify how many times should the client retry the request before it raises an exception
297
- (the default is 3 times):
302
+ By default, the client will retry the request 3 times. You can specify how many times to retry before it raises an exception by passing a number to `retry_on_failure`:
298
303
 
299
304
  Elasticsearch::Client.new hosts: ['localhost:9200', 'localhost:9201'], retry_on_failure: 5
300
305
 
306
+ These two parameters can also be used together:
307
+
308
+ ```ruby
309
+ Elasticsearch::Client.new hosts: ['localhost:9200', 'localhost:9201'], retry_on_status: [502, 503], retry_on_failure: 10
310
+ ```
311
+
301
312
  ### Reloading Hosts
302
313
 
303
314
  Elasticsearch by default dynamically discovers new nodes in the cluster. You can leverage this
@@ -49,9 +49,15 @@ module Elasticsearch
49
49
  DEFAULT_HOST = 'localhost:9200'.freeze
50
50
 
51
51
  # The default port to use if connecting using a Cloud ID.
52
+ # Updated from 9243 to 443 in client version 7.10.1
52
53
  #
53
54
  # @since 7.2.0
54
- DEFAULT_CLOUD_PORT = 9243
55
+ DEFAULT_CLOUD_PORT = 443
56
+
57
+ # The default port to use if not otherwise specified.
58
+ #
59
+ # @since 7.2.0
60
+ DEFAULT_PORT = 9200
55
61
 
56
62
  # Returns the transport object.
57
63
  #
@@ -114,8 +120,11 @@ module Elasticsearch
114
120
  #
115
121
  # @option api_key [String, Hash] :api_key Use API Key Authentication, either the base64 encoding of `id` and `api_key`
116
122
  # joined by a colon as a String, or a hash with the `id` and `api_key` values.
117
- # @option opaque_id_prefix [String] :opaque_id_prefix set a prefix for X-Opaque-Id when initializing the client. This
118
- # will be prepended to the id you set before each request if you're using X-Opaque-Id
123
+ # @option opaque_id_prefix [String] :opaque_id_prefix set a prefix for X-Opaque-Id when initializing the client.
124
+ # This will be prepended to the id you set before each request
125
+ # if you're using X-Opaque-Id
126
+ # @option enable_meta_header [Boolean] :enable_meta_header Enable sending the meta data header to Cloud.
127
+ # (Default: true)
119
128
  #
120
129
  # @yield [faraday] Access and configure the `Faraday::Connection` instance directly with a block
121
130
  #
@@ -130,6 +139,7 @@ module Elasticsearch
130
139
  @arguments[:randomize_hosts] ||= false
131
140
  @arguments[:transport_options] ||= {}
132
141
  @arguments[:http] ||= {}
142
+ @arguments[:enable_meta_header] = arguments.fetch(:enable_meta_header) { true }
133
143
  @options[:http] ||= {}
134
144
 
135
145
  set_api_key if (@api_key = @arguments[:api_key])
@@ -152,15 +162,18 @@ module Elasticsearch
152
162
  if @arguments[:transport]
153
163
  @transport = @arguments[:transport]
154
164
  else
155
- transport_class = @arguments[:transport_class] || DEFAULT_TRANSPORT_CLASS
156
- if transport_class == Transport::HTTP::Faraday
157
- @transport = transport_class.new(hosts: @seeds, options: @arguments) do |faraday|
158
- faraday.adapter(@arguments[:adapter] || __auto_detect_adapter)
159
- block&.call faraday
160
- end
161
- else
162
- @transport = transport_class.new(hosts: @seeds, options: @arguments)
163
- end
165
+ @transport_class = @arguments[:transport_class] || DEFAULT_TRANSPORT_CLASS
166
+ @transport = if @transport_class == Transport::HTTP::Faraday
167
+ @arguments[:adapter] ||= __auto_detect_adapter
168
+ set_meta_header
169
+ @transport_class.new(hosts: @seeds, options: @arguments) do |faraday|
170
+ faraday.adapter(@arguments[:adapter])
171
+ block&.call faraday
172
+ end
173
+ else
174
+ set_meta_header
175
+ @transport_class.new(hosts: @seeds, options: @arguments)
176
+ end
164
177
  end
165
178
  end
166
179
 
@@ -180,24 +193,103 @@ module Elasticsearch
180
193
 
181
194
  def set_api_key
182
195
  @api_key = __encode(@api_key) if @api_key.is_a? Hash
196
+ add_header('Authorization' => "ApiKey #{@api_key}")
197
+ @arguments.delete(:user)
198
+ @arguments.delete(:password)
199
+ end
200
+
201
+ def add_header(header)
183
202
  headers = @arguments[:transport_options]&.[](:headers) || {}
184
- headers.merge!('Authorization' => "ApiKey #{@api_key}")
203
+ headers.merge!(header)
185
204
  @arguments[:transport_options].merge!(
186
205
  headers: headers
187
206
  )
188
- @arguments.delete(:user)
189
- @arguments.delete(:password)
207
+ end
208
+
209
+ def set_meta_header
210
+ return if @arguments[:enable_meta_header] == false
211
+
212
+ service, version = meta_header_service_version
213
+
214
+ meta_headers = {
215
+ service.to_sym => version,
216
+ rb: RUBY_VERSION,
217
+ t: Elasticsearch::Transport::VERSION
218
+ }
219
+ meta_headers.merge!(meta_header_engine) if meta_header_engine
220
+ meta_headers.merge!(meta_header_adapter) if meta_header_adapter
221
+
222
+ add_header({ 'x-elastic-client-meta' => meta_headers.map { |k, v| "#{k}=#{v}" }.join(',') })
223
+ end
224
+
225
+ def meta_header_service_version
226
+ if defined?(Elastic::META_HEADER_SERVICE_VERSION)
227
+ Elastic::META_HEADER_SERVICE_VERSION
228
+ elsif defined?(Elasticsearch::VERSION)
229
+ ['es', Elasticsearch::VERSION]
230
+ else
231
+ ['es', Elasticsearch::Transport::VERSION]
232
+ end
233
+ end
234
+
235
+ def meta_header_engine
236
+ case RUBY_ENGINE
237
+ when 'ruby'
238
+ {}
239
+ when 'jruby'
240
+ { jv: ENV_JAVA['java.version'], jr: JRUBY_VERSION }
241
+ when 'rbx'
242
+ { rbx: RUBY_VERSION }
243
+ else
244
+ { RUBY_ENGINE.to_sym => RUBY_VERSION }
245
+ end
246
+ end
247
+
248
+ def meta_header_adapter
249
+ if @transport_class == Transport::HTTP::Faraday
250
+ {fd: Faraday::VERSION}.merge(
251
+ case @arguments[:adapter]
252
+ when :patron
253
+ {pt: Patron::VERSION}
254
+ when :net_http
255
+ {nh: defined?(Net::HTTP::VERSION) ? Net::HTTP::VERSION : Net::HTTP::HTTPVersion}
256
+ when :typhoeus
257
+ {ty: Typhoeus::VERSION}
258
+ when :httpclient
259
+ {hc: HTTPClient::VERSION}
260
+ when :net_http_persistent
261
+ {np: Net::HTTP::Persistent::VERSION}
262
+ end
263
+ )
264
+ elsif defined?(Transport::HTTP::Curb) && @transport_class == Transport::HTTP::Curb
265
+ {cl: Curl::CURB_VERSION}
266
+ elsif defined?(Transport::HTTP::Manticore) && @transport_class == Transport::HTTP::Manticore
267
+ {mc: Manticore::VERSION}
268
+ end
190
269
  end
191
270
 
192
271
  def extract_cloud_creds(arguments)
193
- return unless arguments[:cloud_id]
272
+ return unless arguments[:cloud_id] && !arguments[:cloud_id].empty?
273
+
194
274
  name = arguments[:cloud_id].split(':')[0]
195
275
  cloud_url, elasticsearch_instance = Base64.decode64(arguments[:cloud_id].gsub("#{name}:", '')).split('$')
196
- [ { scheme: 'https',
276
+
277
+ if cloud_url.include?(':')
278
+ url, port = cloud_url.split(':')
279
+ host = "#{elasticsearch_instance}.#{url}"
280
+ else
281
+ host = "#{elasticsearch_instance}.#{cloud_url}"
282
+ port = arguments[:port] || DEFAULT_CLOUD_PORT
283
+ end
284
+ [
285
+ {
286
+ scheme: 'https',
197
287
  user: arguments[:user],
198
288
  password: arguments[:password],
199
- host: "#{elasticsearch_instance}.#{cloud_url}",
200
- port: arguments[:port] || DEFAULT_CLOUD_PORT } ]
289
+ host: host,
290
+ port: port.to_i
291
+ }
292
+ ]
201
293
  end
202
294
 
203
295
  # Normalizes and returns hosts configuration.
@@ -230,36 +322,38 @@ module Elasticsearch
230
322
 
231
323
  def __parse_host(host)
232
324
  host_parts = case host
233
- when String
234
- if host =~ /^[a-z]+\:\/\//
235
- # Construct a new `URI::Generic` directly from the array returned by URI::split.
236
- # This avoids `URI::HTTP` and `URI::HTTPS`, which supply default ports.
237
- uri = URI::Generic.new(*URI.split(host))
238
-
239
- { :scheme => uri.scheme,
240
- :user => uri.user,
241
- :password => uri.password,
242
- :host => uri.host,
243
- :path => uri.path,
244
- :port => uri.port }
245
- else
246
- host, port = host.split(':')
247
- { :host => host,
248
- :port => port }
249
- end
250
- when URI
251
- { :scheme => host.scheme,
252
- :user => host.user,
253
- :password => host.password,
254
- :host => host.host,
255
- :path => host.path,
256
- :port => host.port }
257
- when Hash
258
- host
259
- else
260
- raise ArgumentError, "Please pass host as a String, URI or Hash -- #{host.class} given."
261
- end
262
-
325
+ when String
326
+ if host =~ /^[a-z]+\:\/\//
327
+ # Construct a new `URI::Generic` directly from the array returned by URI::split.
328
+ # This avoids `URI::HTTP` and `URI::HTTPS`, which supply default ports.
329
+ uri = URI::Generic.new(*URI.split(host))
330
+ default_port = uri.scheme == 'https' ? 443 : DEFAULT_PORT
331
+ {
332
+ scheme: uri.scheme,
333
+ user: uri.user,
334
+ password: uri.password,
335
+ host: uri.host,
336
+ path: uri.path,
337
+ port: uri.port || default_port
338
+ }
339
+ else
340
+ host, port = host.split(':')
341
+ { host: host, port: port }
342
+ end
343
+ when URI
344
+ {
345
+ scheme: host.scheme,
346
+ user: host.user,
347
+ password: host.password,
348
+ host: host.host,
349
+ path: host.path,
350
+ port: host.port
351
+ }
352
+ when Hash
353
+ host
354
+ else
355
+ raise ArgumentError, "Please pass host as a String, URI or Hash -- #{host.class} given."
356
+ end
263
357
  if @api_key
264
358
  # Remove Basic Auth if using API KEY
265
359
  host_parts.delete(:user)
@@ -19,7 +19,6 @@ module Elasticsearch
19
19
  module Transport
20
20
  module Transport
21
21
  module Connections
22
-
23
22
  # Wraps the connection information and logic.
24
23
  #
25
24
  # The Connection instance wraps the host information (hostname, port, attributes, etc),
@@ -54,12 +53,14 @@ module Elasticsearch
54
53
  #
55
54
  # @return [String]
56
55
  #
57
- def full_url(path, params={})
56
+ def full_url(path, params = {})
58
57
  url = "#{host[:protocol]}://"
59
58
  url += "#{CGI.escape(host[:user])}:#{CGI.escape(host[:password])}@" if host[:user]
60
59
  url += "#{host[:host]}:#{host[:port]}"
61
60
  url += "#{host[:path]}" if host[:path]
62
- url += "/#{full_path(path, params)}"
61
+ full_path = full_path(path, params)
62
+ url += '/' unless full_path.match?(/^\//)
63
+ url += full_path
63
64
  end
64
65
 
65
66
  # Returns the complete endpoint path with serialized parameters.
@@ -17,6 +17,6 @@
17
17
 
18
18
  module Elasticsearch
19
19
  module Transport
20
- VERSION = "7.9.0.pre"
20
+ VERSION = '7.11.0.pre.1'.freeze
21
21
  end
22
22
  end
@@ -46,10 +46,12 @@ describe Elasticsearch::Transport::Transport::Base do
46
46
 
47
47
  context 'when the user and password are provided as separate arguments' do
48
48
  let(:arguments) do
49
- { hosts: 'fake',
49
+ {
50
+ hosts: 'fake',
50
51
  logger: logger,
51
52
  password: 'secret_password',
52
- user: 'test' }
53
+ user: 'test'
54
+ }
53
55
  end
54
56
 
55
57
  it_behaves_like 'a redacted string'
@@ -57,8 +59,10 @@ describe Elasticsearch::Transport::Transport::Base do
57
59
 
58
60
  context 'when the user and password are provided in the string URI' do
59
61
  let(:arguments) do
60
- { hosts: 'https://test:secret_password@fake_local_elasticsearch',
61
- logger: logger }
62
+ {
63
+ hosts: 'https://test:secret_password@fake_local_elasticsearch',
64
+ logger: logger
65
+ }
62
66
  end
63
67
 
64
68
  it_behaves_like 'a redacted string'
@@ -66,8 +70,10 @@ describe Elasticsearch::Transport::Transport::Base do
66
70
 
67
71
  context 'when the user and password are provided in the URI object' do
68
72
  let(:arguments) do
69
- { hosts: URI.parse('https://test:secret_password@fake_local_elasticsearch'),
70
- logger: logger }
73
+ {
74
+ hosts: URI.parse('https://test:secret_password@fake_local_elasticsearch'),
75
+ logger: logger
76
+ }
71
77
  end
72
78
 
73
79
  it_behaves_like 'a redacted string'
@@ -75,36 +81,32 @@ describe Elasticsearch::Transport::Transport::Base do
75
81
  end
76
82
 
77
83
  context 'when reload_on_failure is true and and hosts are unreachable' do
78
-
79
84
  let(:client) do
80
85
  Elasticsearch::Transport::Client.new(arguments)
81
86
  end
82
87
 
83
88
  let(:arguments) do
84
89
  {
85
- hosts: ['http://unavailable:9200', 'http://unavailable:9201'],
86
- reload_on_failure: true,
87
- sniffer_timeout: 5
90
+ hosts: ['http://unavailable:9200', 'http://unavailable:9201'],
91
+ reload_on_failure: true,
92
+ sniffer_timeout: 5
88
93
  }
89
94
  end
90
95
 
91
96
  it 'raises an exception' do
92
- expect {
93
- client.info
94
- }.to raise_exception(Faraday::ConnectionFailed)
97
+ expect { client.info }.to raise_exception(Faraday::ConnectionFailed)
95
98
  end
96
99
  end
97
100
 
98
101
  context 'when the client has `retry_on_failure` set to an integer' do
99
-
100
102
  let(:client) do
101
103
  Elasticsearch::Transport::Client.new(arguments)
102
104
  end
103
105
 
104
106
  let(:arguments) do
105
107
  {
106
- hosts: ['http://unavailable:9200', 'http://unavailable:9201'],
107
- retry_on_failure: 2
108
+ hosts: ['http://unavailable:9200', 'http://unavailable:9201'],
109
+ retry_on_failure: 2
108
110
  }
109
111
  end
110
112
 
@@ -120,15 +122,34 @@ describe Elasticsearch::Transport::Transport::Base do
120
122
  end
121
123
  end
122
124
 
125
+ context 'when `perform_request` is called with a `retry_on_status` option value' do
126
+ before do
127
+ expect(client.transport).to receive(:__raise_transport_error).exactly(6).times.and_call_original
128
+ end
129
+
130
+ let(:arguments) do
131
+ {
132
+ hosts: ['http://localhost:9250'],
133
+ retry_on_status: ['404']
134
+ }
135
+ end
136
+
137
+ it 'retries on 404 status the specified number of max_retries' do
138
+ expect do
139
+ client.transport.perform_request('GET', 'myindex/mydoc/1?routing=FOOBARBAZ', {}, nil, nil, retry_on_failure: 5)
140
+ end.to raise_exception(Elasticsearch::Transport::Transport::Errors::NotFound)
141
+ end
142
+ end
143
+
123
144
  context 'when `perform_request` is called with a `retry_on_failure` option value' do
124
145
  before do
125
146
  expect(client.transport).to receive(:get_connection).exactly(6).times.and_call_original
126
147
  end
127
148
 
128
149
  it 'uses the option `retry_on_failure` value' do
129
- expect {
150
+ expect do
130
151
  client.transport.perform_request('GET', '/info', {}, nil, nil, retry_on_failure: 5)
131
- }.to raise_exception(Faraday::ConnectionFailed)
152
+ end.to raise_exception(Faraday::ConnectionFailed)
132
153
  end
133
154
  end
134
155
  end
@@ -209,40 +230,35 @@ describe Elasticsearch::Transport::Transport::Base do
209
230
  end
210
231
 
211
232
  context 'when the client has no `retry_on_failure` set' do
212
-
213
233
  let(:client) do
214
234
  Elasticsearch::Transport::Client.new(arguments)
215
235
  end
216
236
 
217
237
  let(:arguments) do
218
- {
219
- hosts: ['http://unavailable:9200', 'http://unavailable:9201'],
220
- }
238
+ { hosts: ['http://unavailable:9200', 'http://unavailable:9201'] }
221
239
  end
222
240
 
223
241
  context 'when `perform_request` is called without a `retry_on_failure` option value' do
224
-
225
242
  before do
226
243
  expect(client.transport).to receive(:get_connection).exactly(1).times.and_call_original
227
244
  end
228
245
 
229
246
  it 'does not retry' do
230
- expect {
247
+ expect do
231
248
  client.transport.perform_request('GET', '/info')
232
- }.to raise_exception(Faraday::ConnectionFailed)
249
+ end.to raise_exception(Faraday::ConnectionFailed)
233
250
  end
234
251
  end
235
252
 
236
253
  context 'when `perform_request` is called with a `retry_on_failure` option value' do
237
-
238
254
  before do
239
255
  expect(client.transport).to receive(:get_connection).exactly(6).times.and_call_original
240
256
  end
241
257
 
242
258
  it 'uses the option `retry_on_failure` value' do
243
- expect {
259
+ expect do
244
260
  client.transport.perform_request('GET', '/info', {}, nil, nil, retry_on_failure: 5)
245
- }.to raise_exception(Faraday::ConnectionFailed)
261
+ end.to raise_exception(Faraday::ConnectionFailed)
246
262
  end
247
263
  end
248
264
  end