elasticsearch-transport 7.8.1 → 7.10.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +8 -3
- data/lib/elasticsearch/transport/client.rb +56 -35
- data/lib/elasticsearch/transport/transport/base.rb +9 -8
- data/lib/elasticsearch/transport/transport/connections/connection.rb +7 -5
- data/lib/elasticsearch/transport/transport/sniffer.rb +19 -12
- data/lib/elasticsearch/transport/version.rb +1 -1
- data/spec/elasticsearch/transport/base_spec.rb +44 -28
- data/spec/elasticsearch/transport/client_spec.rb +369 -99
- data/spec/elasticsearch/transport/sniffer_spec.rb +0 -13
- data/test/unit/connection_test.rb +5 -0
- data/test/unit/transport_manticore_test.rb +11 -11
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 420122a402e799e70ce7a879b1cabe62cd4750fc356438c0f980a2b78d852fc4
|
4
|
+
data.tar.gz: 420a016f766aa19fd8c6400ae8dd78c95d76090c8de38cc1658bbd06348c3136
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ed848e2746878f56203c6c3a9d73a0f995f65cf5854ef262d3504f98f6a889ee74e4c5e7c67bbe0d0a89b1a03c55ddd74e56c2d6efc65adbaabcd0f557653656
|
7
|
+
data.tar.gz: c7ba8b088fad4ecb5fd55870f8c50e7fb68b66ca1c157993e69cee0db4205b6371f4b69f83431196e825f22ed08affc35be5c94f5d42b4558d22feb9e0236555
|
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
|
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.
|
@@ -293,11 +293,16 @@ on a different host:
|
|
293
293
|
|
294
294
|
Elasticsearch::Client.new hosts: ['localhost:9200', 'localhost:9201'], retry_on_failure: true
|
295
295
|
|
296
|
-
You can specify how many times
|
297
|
-
(the default is 3 times):
|
296
|
+
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
297
|
|
299
298
|
Elasticsearch::Client.new hosts: ['localhost:9200', 'localhost:9201'], retry_on_failure: 5
|
300
299
|
|
300
|
+
These two parameters can also be used together:
|
301
|
+
|
302
|
+
```ruby
|
303
|
+
Elasticsearch::Client.new hosts: ['localhost:9200', 'localhost:9201'], retry_on_status: [502, 503], retry_on_failure: 10
|
304
|
+
```
|
305
|
+
|
301
306
|
### Reloading Hosts
|
302
307
|
|
303
308
|
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 =
|
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
|
#
|
@@ -190,14 +196,27 @@ module Elasticsearch
|
|
190
196
|
end
|
191
197
|
|
192
198
|
def extract_cloud_creds(arguments)
|
193
|
-
return unless arguments[:cloud_id]
|
199
|
+
return unless arguments[:cloud_id] && !arguments[:cloud_id].empty?
|
200
|
+
|
194
201
|
name = arguments[:cloud_id].split(':')[0]
|
195
202
|
cloud_url, elasticsearch_instance = Base64.decode64(arguments[:cloud_id].gsub("#{name}:", '')).split('$')
|
196
|
-
|
203
|
+
|
204
|
+
if cloud_url.include?(':')
|
205
|
+
url, port = cloud_url.split(':')
|
206
|
+
host = "#{elasticsearch_instance}.#{url}"
|
207
|
+
else
|
208
|
+
host = "#{elasticsearch_instance}.#{cloud_url}"
|
209
|
+
port = arguments[:port] || DEFAULT_CLOUD_PORT
|
210
|
+
end
|
211
|
+
[
|
212
|
+
{
|
213
|
+
scheme: 'https',
|
197
214
|
user: arguments[:user],
|
198
215
|
password: arguments[:password],
|
199
|
-
host:
|
200
|
-
port:
|
216
|
+
host: host,
|
217
|
+
port: port.to_i
|
218
|
+
}
|
219
|
+
]
|
201
220
|
end
|
202
221
|
|
203
222
|
# Normalizes and returns hosts configuration.
|
@@ -230,36 +249,38 @@ module Elasticsearch
|
|
230
249
|
|
231
250
|
def __parse_host(host)
|
232
251
|
host_parts = case host
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
252
|
+
when String
|
253
|
+
if host =~ /^[a-z]+\:\/\//
|
254
|
+
# Construct a new `URI::Generic` directly from the array returned by URI::split.
|
255
|
+
# This avoids `URI::HTTP` and `URI::HTTPS`, which supply default ports.
|
256
|
+
uri = URI::Generic.new(*URI.split(host))
|
257
|
+
default_port = uri.scheme == 'https' ? 443 : DEFAULT_PORT
|
258
|
+
{
|
259
|
+
scheme: uri.scheme,
|
260
|
+
user: uri.user,
|
261
|
+
password: uri.password,
|
262
|
+
host: uri.host,
|
263
|
+
path: uri.path,
|
264
|
+
port: uri.port || default_port
|
265
|
+
}
|
266
|
+
else
|
267
|
+
host, port = host.split(':')
|
268
|
+
{ host: host, port: port }
|
269
|
+
end
|
270
|
+
when URI
|
271
|
+
{
|
272
|
+
scheme: host.scheme,
|
273
|
+
user: host.user,
|
274
|
+
password: host.password,
|
275
|
+
host: host.host,
|
276
|
+
path: host.path,
|
277
|
+
port: host.port
|
278
|
+
}
|
279
|
+
when Hash
|
280
|
+
host
|
281
|
+
else
|
282
|
+
raise ArgumentError, "Please pass host as a String, URI or Hash -- #{host.class} given."
|
283
|
+
end
|
263
284
|
if @api_key
|
264
285
|
# Remove Basic Auth if using API KEY
|
265
286
|
host_parts.delete(:user)
|
@@ -47,7 +47,7 @@ module Elasticsearch
|
|
47
47
|
#
|
48
48
|
# @see Client#initialize
|
49
49
|
#
|
50
|
-
def initialize(arguments={}, &block)
|
50
|
+
def initialize(arguments = {}, &block)
|
51
51
|
@state_mutex = Mutex.new
|
52
52
|
|
53
53
|
@hosts = arguments[:hosts] || []
|
@@ -234,9 +234,9 @@ module Elasticsearch
|
|
234
234
|
def __full_url(host)
|
235
235
|
url = "#{host[:protocol]}://"
|
236
236
|
url += "#{CGI.escape(host[:user])}:#{CGI.escape(host[:password])}@" if host[:user]
|
237
|
-
url +=
|
237
|
+
url += host[:host]
|
238
238
|
url += ":#{host[:port]}" if host[:port]
|
239
|
-
url +=
|
239
|
+
url += host[:path] if host[:path]
|
240
240
|
url
|
241
241
|
end
|
242
242
|
|
@@ -258,8 +258,9 @@ module Elasticsearch
|
|
258
258
|
# @raise [ServerError] If request failed on server
|
259
259
|
# @raise [Error] If no connection is available
|
260
260
|
#
|
261
|
-
def perform_request(method, path, params={}, body=nil, headers=nil, opts={}, &block)
|
262
|
-
raise NoMethodError,
|
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
|
+
|
263
264
|
start = Time.now
|
264
265
|
tries = 0
|
265
266
|
reload_on_failure = opts.fetch(:reload_on_failure, @options[:reload_on_failure])
|
@@ -276,15 +277,15 @@ module Elasticsearch
|
|
276
277
|
|
277
278
|
begin
|
278
279
|
tries += 1
|
279
|
-
connection = get_connection or raise Error.new(
|
280
|
+
connection = get_connection or raise Error.new('Cannot get new connection from pool.')
|
280
281
|
|
281
282
|
if connection.connection.respond_to?(:params) && connection.connection.params.respond_to?(:to_hash)
|
282
283
|
params = connection.connection.params.merge(params.to_hash)
|
283
284
|
end
|
284
285
|
|
285
|
-
url
|
286
|
+
url = connection.full_url(path, params)
|
286
287
|
|
287
|
-
response
|
288
|
+
response = block.call(connection, url)
|
288
289
|
|
289
290
|
connection.healthy! if connection.failures > 0
|
290
291
|
|
@@ -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
|
-
|
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.
|
@@ -135,14 +136,15 @@ module Elasticsearch
|
|
135
136
|
}
|
136
137
|
end
|
137
138
|
|
138
|
-
# Equality operator based on connection protocol, host and
|
139
|
+
# Equality operator based on connection protocol, host, port and attributes
|
139
140
|
#
|
140
141
|
# @return [Boolean]
|
141
142
|
#
|
142
143
|
def ==(other)
|
143
144
|
self.host[:protocol] == other.host[:protocol] && \
|
144
145
|
self.host[:host] == other.host[:host] && \
|
145
|
-
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]
|
146
148
|
end
|
147
149
|
|
148
150
|
# @return [String]
|
@@ -45,21 +45,21 @@ module Elasticsearch
|
|
45
45
|
#
|
46
46
|
def hosts
|
47
47
|
Timeout::timeout(timeout, SnifferTimeoutError) do
|
48
|
-
nodes =
|
49
|
-
reload_on_failure: false).body
|
48
|
+
nodes = perform_sniff_request.body
|
50
49
|
|
51
50
|
hosts = nodes['nodes'].map do |id, info|
|
52
|
-
|
53
|
-
|
51
|
+
next unless info[PROTOCOL]
|
52
|
+
host, port = parse_publish_address(info[PROTOCOL]['publish_address'])
|
54
53
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
54
|
+
{
|
55
|
+
id: id,
|
56
|
+
name: info['name'],
|
57
|
+
version: info['version'],
|
58
|
+
host: host,
|
59
|
+
port: port,
|
60
|
+
roles: info['roles'],
|
61
|
+
attributes: info['attributes']
|
62
|
+
}
|
63
63
|
end.compact
|
64
64
|
|
65
65
|
hosts.shuffle! if transport.options[:randomize_hosts]
|
@@ -69,6 +69,13 @@ module Elasticsearch
|
|
69
69
|
|
70
70
|
private
|
71
71
|
|
72
|
+
def perform_sniff_request
|
73
|
+
transport.perform_request(
|
74
|
+
'GET', '_nodes/http', {}, nil, nil,
|
75
|
+
reload_on_failure: false
|
76
|
+
)
|
77
|
+
end
|
78
|
+
|
72
79
|
def parse_publish_address(publish_address)
|
73
80
|
# publish_address is in the format hostname/ip:port
|
74
81
|
if publish_address =~ /\//
|
@@ -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
|
-
{
|
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
|
-
{
|
61
|
-
|
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
|
-
{
|
70
|
-
|
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
|
-
|
86
|
-
|
87
|
-
|
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
|
-
|
107
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
261
|
+
end.to raise_exception(Faraday::ConnectionFailed)
|
246
262
|
end
|
247
263
|
end
|
248
264
|
end
|