elasticsearch-transport 6.1.0 → 6.2.0

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
- SHA1:
3
- metadata.gz: e353dc91e242f5da6770f9bb54d045e73d891406
4
- data.tar.gz: d68e53725c17871ca4dd102b3d0862bc760416d7
2
+ SHA256:
3
+ metadata.gz: a8e4aede9b2a47e14f9913330cb6278300282e8817474f51cee80a35f2f95c29
4
+ data.tar.gz: 1be5538c84ddd5f6b293787ec3b4c779e001c8d19750b83fdff248e67e4cdcd3
5
5
  SHA512:
6
- metadata.gz: 7ff356b55062d3fad230f9849c7416f1450c29e0a5772e7a013351f2fdbdc978adeba64c1ade75d998988f1d81e1dac7a72d5ba017fb6d56eec7639f2d3cea77
7
- data.tar.gz: 56cbe39365f0aa8ad13a6ff4bc2be0e7fe5b90d77033f16d9772d7794178ebd50d197b05ab325d05259907d68dc9c2b010c1ccce88c057e3ef460ec80cf5c6b2
6
+ metadata.gz: af707cc9d8e3675a41bf0e3daa4624c1370047a1ef8f2d10437887744a78329875eb7115d67d05285c51e3301c1f043524b0d8e113eedb6346bd534e9bbcaadf
7
+ data.tar.gz: 451c56226dce076295231890873aac3d10cc27e5de816183b7bdf87c0891f2f40f34f35ea3e51b6609429994d243e3caae265b036464c31131882ac1378d5de4
data/Gemfile CHANGED
@@ -14,3 +14,8 @@ end
14
14
  if File.exist? File.expand_path("../../elasticsearch/elasticsearch.gemspec", __FILE__)
15
15
  gem 'elasticsearch', :path => File.expand_path("../../elasticsearch", __FILE__), :require => false
16
16
  end
17
+
18
+ group :development do
19
+ gem 'rspec'
20
+ gem 'pry-nav'
21
+ end
data/Rakefile CHANGED
@@ -7,7 +7,17 @@ task :test => 'test:unit'
7
7
  # ----- Test tasks ------------------------------------------------------------
8
8
 
9
9
  require 'rake/testtask'
10
+ require 'rspec/core/rake_task'
11
+
10
12
  namespace :test do
13
+
14
+ RSpec::Core::RakeTask.new(:spec)
15
+
16
+ desc "Wait for Elasticsearch to be in a green state"
17
+ task :wait_for_green do
18
+ sh '../scripts/wait-cluster.sh'
19
+ end
20
+
11
21
  Rake::TestTask.new(:unit) do |test|
12
22
  test.libs << 'lib' << 'test'
13
23
  test.test_files = FileList["test/unit/**/*_test.rb"]
@@ -18,13 +28,13 @@ namespace :test do
18
28
  Rake::TestTask.new(:integration) do |test|
19
29
  test.libs << 'lib' << 'test'
20
30
  test.test_files = FileList["test/integration/**/*_test.rb"]
31
+ test.deps = [ :wait_for_green, :spec ]
21
32
  test.verbose = false
22
33
  test.warning = false
23
34
  end
24
35
 
25
36
  Rake::TestTask.new(:all) do |test|
26
- test.libs << 'lib' << 'test'
27
- test.test_files = FileList["test/unit/**/*_test.rb", "test/integration/**/*_test.rb"]
37
+ test.deps = [ :unit, :integration ]
28
38
  end
29
39
 
30
40
  Rake::TestTask.new(:profile) do |test|
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
10
10
  s.email = ["karel.minarik@elasticsearch.org"]
11
11
  s.summary = "Ruby client for Elasticsearch."
12
12
  s.homepage = "https://github.com/elasticsearch/elasticsearch-ruby/tree/master/elasticsearch-transport"
13
- s.license = "Apache 2"
13
+ s.license = "Apache-2.0"
14
14
 
15
15
  s.files = `git ls-files`.split($/)
16
16
  s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
@@ -29,7 +29,7 @@ Gem::Specification.new do |s|
29
29
  s.add_dependency "system_timer"
30
30
  end
31
31
 
32
- s.add_development_dependency "bundler", "> 1"
32
+ s.add_development_dependency "bundler"
33
33
 
34
34
  if defined?(RUBY_VERSION) && RUBY_VERSION > '1.9'
35
35
  s.add_development_dependency "rake", "~> 11.1"
@@ -14,6 +14,7 @@ require "elasticsearch/transport/transport/connections/connection"
14
14
  require "elasticsearch/transport/transport/connections/collection"
15
15
  require "elasticsearch/transport/transport/http/faraday"
16
16
  require "elasticsearch/transport/client"
17
+ require "elasticsearch/transport/redacted"
17
18
 
18
19
  require "elasticsearch/transport/version"
19
20
 
@@ -24,6 +24,11 @@ module Elasticsearch
24
24
  logger
25
25
  end
26
26
 
27
+ # The default host and port to use if not otherwise specified.
28
+ #
29
+ # @since 7.0.0
30
+ DEFAULT_HOST = 'localhost:9200'.freeze
31
+
27
32
  # Returns the transport object.
28
33
  #
29
34
  # @see Elasticsearch::Transport::Transport::Base
@@ -83,14 +88,8 @@ module Elasticsearch
83
88
  # @yield [faraday] Access and configure the `Faraday::Connection` instance directly with a block
84
89
  #
85
90
  def initialize(arguments={}, &block)
91
+ @options = arguments
86
92
  @arguments = arguments
87
-
88
- hosts = @arguments[:hosts] || \
89
- @arguments[:host] || \
90
- @arguments[:url] || \
91
- @arguments[:urls] || \
92
- ENV.fetch('ELASTICSEARCH_URL', 'localhost:9200')
93
-
94
93
  @arguments[:logger] ||= @arguments[:log] ? DEFAULT_LOGGER.call() : nil
95
94
  @arguments[:tracer] ||= @arguments[:trace] ? DEFAULT_TRACER.call() : nil
96
95
  @arguments[:reload_connections] ||= false
@@ -99,26 +98,40 @@ module Elasticsearch
99
98
  @arguments[:randomize_hosts] ||= false
100
99
  @arguments[:transport_options] ||= {}
101
100
  @arguments[:http] ||= {}
101
+ @options[:http] ||= {}
102
102
 
103
- @arguments[:transport_options].update(:request => { :timeout => @arguments[:request_timeout] } ) if @arguments[:request_timeout]
104
-
105
- @arguments[:transport_options][:headers] ||= {}
106
- @arguments[:transport_options][:headers].update 'Content-Type' => 'application/json' unless @arguments[:transport_options][:headers].keys.any? {|k| k.to_s.downcase =~ /content\-?\_?type/}
103
+ @seeds = __extract_hosts(@arguments[:hosts] ||
104
+ @arguments[:host] ||
105
+ @arguments[:url] ||
106
+ @arguments[:urls] ||
107
+ ENV['ELASTICSEARCH_URL'] ||
108
+ DEFAULT_HOST)
107
109
 
108
110
  @send_get_body_as = @arguments[:send_get_body_as] || 'GET'
109
111
 
110
- transport_class = @arguments[:transport_class] || DEFAULT_TRANSPORT_CLASS
112
+ if @arguments[:request_timeout]
113
+ @arguments[:transport_options][:request] = { :timeout => @arguments[:request_timeout] }
114
+ end
115
+
116
+ @arguments[:transport_options][:headers] ||= {}
117
+
118
+ unless @arguments[:transport_options][:headers].keys.any? {|k| k.to_s.downcase =~ /content\-?\_?type/}
119
+ @arguments[:transport_options][:headers]['Content-Type'] = 'application/json'
120
+ end
111
121
 
112
- @transport = @arguments[:transport] || begin
122
+ if @arguments[:transport]
123
+ @transport = @arguments[:transport]
124
+ else
125
+ transport_class = @arguments[:transport_class] || DEFAULT_TRANSPORT_CLASS
113
126
  if transport_class == Transport::HTTP::Faraday
114
- transport_class.new(:hosts => __extract_hosts(hosts, @arguments), :options => @arguments) do |faraday|
127
+ @transport = transport_class.new(:hosts => @seeds, :options => @arguments) do |faraday|
115
128
  block.call faraday if block
116
129
  unless (h = faraday.builder.handlers.last) && h.name.start_with?("Faraday::Adapter")
117
130
  faraday.adapter(@arguments[:adapter] || __auto_detect_adapter)
118
131
  end
119
132
  end
120
133
  else
121
- transport_class.new(:hosts => __extract_hosts(hosts, @arguments), :options => @arguments)
134
+ @transport = transport_class.new(:hosts => @seeds, :options => @arguments)
122
135
  end
123
136
  end
124
137
  end
@@ -127,10 +140,11 @@ module Elasticsearch
127
140
  #
128
141
  def perform_request(method, path, params={}, body=nil, headers=nil)
129
142
  method = @send_get_body_as if 'GET' == method && body
130
-
131
- transport.perform_request method, path, params, body, headers
143
+ transport.perform_request(method, path, params, body, headers)
132
144
  end
133
145
 
146
+ private
147
+
134
148
  # Normalizes and returns hosts configuration.
135
149
  #
136
150
  # Arrayifies the `hosts_config` argument and extracts `host` and `port` info from strings.
@@ -143,52 +157,57 @@ module Elasticsearch
143
157
  #
144
158
  # @api private
145
159
  #
146
- def __extract_hosts(hosts_config, options={})
147
- if hosts_config.is_a?(Hash)
148
- hosts = [ hosts_config ]
149
- else
150
- if hosts_config.is_a?(String) && hosts_config.include?(',')
151
- hosts = hosts_config.split(/\s*,\s*/)
152
- else
153
- hosts = Array(hosts_config)
154
- end
155
- end
156
-
157
- result = hosts.map do |host|
158
- host_parts = case host
159
- when String
160
- if host =~ /^[a-z]+\:\/\//
161
- uri = URI.parse(host)
162
- { :scheme => uri.scheme, :user => uri.user, :password => uri.password, :host => uri.host, :path => uri.path, :port => uri.port }
163
- else
164
- host, port = host.split(':')
165
- { :host => host, :port => port }
166
- end
167
- when URI
168
- { :scheme => host.scheme, :user => host.user, :password => host.password, :host => host.host, :path => host.path, :port => host.port }
169
- when Hash
170
- host
171
- else
172
- raise ArgumentError, "Please pass host as a String, URI or Hash -- #{host.class} given."
173
- end
174
-
175
- host_parts[:port] = host_parts[:port].to_i unless host_parts[:port].nil?
176
-
177
- # Transfer the selected host parts such as authentication credentials to `options`,
178
- # so we can re-use them when reloading connections
179
- #
180
- host_parts.select { |k,v| [:scheme, :port, :user, :password].include?(k) }.each do |k,v|
181
- @arguments[:http][k] ||= v
182
- end
183
-
184
- # Remove the trailing slash
185
- host_parts[:path].chomp!('/') if host_parts[:path]
186
-
187
- host_parts
188
- end
160
+ def __extract_hosts(hosts_config)
161
+ hosts = case hosts_config
162
+ when String
163
+ hosts_config.split(',').map { |h| h.strip! || h }
164
+ when Array
165
+ hosts_config
166
+ when Hash, URI
167
+ [ hosts_config ]
168
+ else
169
+ Array(hosts_config)
170
+ end
171
+
172
+ host_list = hosts.map { |host| __parse_host(host) }
173
+ @options[:randomize_hosts] ? host_list.shuffle! : host_list
174
+ end
189
175
 
190
- result.shuffle! if options[:randomize_hosts]
191
- result
176
+ def __parse_host(host)
177
+ host_parts = case host
178
+ when String
179
+ if host =~ /^[a-z]+\:\/\//
180
+ uri = URI.parse(host)
181
+ { :scheme => uri.scheme,
182
+ :user => uri.user,
183
+ :password => uri.password,
184
+ :host => uri.host,
185
+ :path => uri.path,
186
+ :port => uri.port }
187
+ else
188
+ host, port = host.split(':')
189
+ { :host => host,
190
+ :port => port }
191
+ end
192
+ when URI
193
+ { :scheme => host.scheme,
194
+ :user => host.user,
195
+ :password => host.password,
196
+ :host => host.host,
197
+ :path => host.path,
198
+ :port => host.port }
199
+ when Hash
200
+ host
201
+ else
202
+ raise ArgumentError, "Please pass host as a String, URI or Hash -- #{host.class} given."
203
+ end
204
+
205
+ @options[:http][:user] ||= host_parts[:user]
206
+ @options[:http][:password] ||= host_parts[:password]
207
+
208
+ host_parts[:port] = host_parts[:port].to_i if host_parts[:port]
209
+ host_parts[:path].chomp!('/') if host_parts[:path]
210
+ host_parts
192
211
  end
193
212
 
194
213
  # Auto-detect the best adapter (HTTP "driver") available, based on libraries
@@ -0,0 +1,75 @@
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
+ module Elasticsearch
19
+ module Transport
20
+
21
+ # Class for wrapping a hash that could have sensitive data.
22
+ # When printed, the sensitive values will be redacted.
23
+ #
24
+ # @since 6.2.0
25
+ class Redacted < ::Hash
26
+
27
+ def initialize(elements = nil)
28
+ super()
29
+ (elements || {}).each_pair{ |key, value| self[key] = value }
30
+ end
31
+
32
+ # The keys whose values will be redacted.
33
+ #
34
+ # @since 6.2.0
35
+ SENSITIVE_KEYS = [ :password,
36
+ :pwd ].freeze
37
+
38
+ # The replacement string used in place of the value for sensitive keys.
39
+ #
40
+ # @since 6.2.0
41
+ STRING_REPLACEMENT = '<REDACTED>'.freeze
42
+
43
+ # Get a string representation of the hash.
44
+ #
45
+ # @return [ String ] The string representation of the hash.
46
+ #
47
+ # @since 6.2.0
48
+ def inspect
49
+ redacted_string(:inspect)
50
+ end
51
+
52
+ # Get a string representation of the hash.
53
+ #
54
+ # @return [ String ] The string representation of the hash.
55
+ #
56
+ # @since 6.2.0
57
+ def to_s
58
+ redacted_string(:to_s)
59
+ end
60
+
61
+ private
62
+
63
+ def redacted_string(method)
64
+ '{' + reduce([]) do |list, (k, v)|
65
+ list << "#{k.send(method)}=>#{redact(k, v, method)}"
66
+ end.join(', ') + '}'
67
+ end
68
+
69
+ def redact(k, v, method)
70
+ return STRING_REPLACEMENT if SENSITIVE_KEYS.include?(k.to_sym)
71
+ v.send(method)
72
+ end
73
+ end
74
+ end
75
+ end
@@ -32,7 +32,7 @@ module Elasticsearch
32
32
  @state_mutex = Mutex.new
33
33
 
34
34
  @hosts = arguments[:hosts] || []
35
- @options = arguments[:options] || {}
35
+ @options = arguments[:options] ? arguments[:options].dup : {}
36
36
  @options[:http] ||= {}
37
37
  @options[:retry_on_status] ||= []
38
38
 
@@ -110,7 +110,7 @@ module Elasticsearch
110
110
 
111
111
  new_connections = __build_connections
112
112
  stale_connections = @connections.all.select { |c| ! new_connections.include?(c) }
113
- new_connections = new_connections.reject { |c| @connections.include?(c) }
113
+ new_connections = new_connections.reject { |c| @connections.all.include?(c) }
114
114
 
115
115
  @connections.remove(stale_connections)
116
116
  @connections.add(new_connections)
@@ -23,7 +23,7 @@ module Elasticsearch
23
23
  # @option arguments [Hash] :options Options (usually passed in from transport)
24
24
  #
25
25
  def initialize(arguments={})
26
- @host = arguments[:host]
26
+ @host = arguments[:host].is_a?(Hash) ? Redacted.new(arguments[:host]) : arguments[:host]
27
27
  @connection = arguments[:connection]
28
28
  @options = arguments[:options] || {}
29
29
  @state_mutex = Mutex.new
@@ -20,11 +20,10 @@ module Elasticsearch
20
20
  super do |connection, url|
21
21
  headers = headers || connection.connection.headers
22
22
 
23
- response = connection.connection.run_request \
24
- method.downcase.to_sym,
25
- url,
26
- ( body ? __convert_to_json(body) : nil ),
27
- headers
23
+ response = connection.connection.run_request(method.downcase.to_sym,
24
+ url,
25
+ ( body ? __convert_to_json(body) : nil ),
26
+ headers)
28
27
 
29
28
  Response.new response.status, response.body, response.headers
30
29
  end
@@ -1,5 +1,5 @@
1
1
  module Elasticsearch
2
2
  module Transport
3
- VERSION = "6.1.0"
3
+ VERSION = "6.2.0"
4
4
  end
5
5
  end
@@ -0,0 +1,81 @@
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 'spec_helper'
19
+
20
+ describe Elasticsearch::Transport::Transport::Base do
21
+
22
+ context 'when a host is printed in a logged message' do
23
+
24
+ shared_examples_for 'a redacted string' do
25
+
26
+ let(:client) do
27
+ Elasticsearch::Transport::Client.new(arguments)
28
+ end
29
+
30
+ let(:logger) do
31
+ double('logger', error?: true, error: '')
32
+ end
33
+
34
+ it 'does not include the password in the logged string' do
35
+ expect(logger).not_to receive(:error).with(/secret_password/)
36
+ expect {
37
+ client.cluster.stats
38
+ }.to raise_exception(Faraday::ConnectionFailed)
39
+ end
40
+
41
+ it 'replaces the password with the string \'REDACTED\'' do
42
+ expect(logger).to receive(:error).with(/REDACTED/)
43
+ expect {
44
+ client.cluster.stats
45
+ }.to raise_exception(Faraday::ConnectionFailed)
46
+ end
47
+ end
48
+
49
+ context 'when the user and password are provided as separate arguments' do
50
+
51
+ let(:arguments) do
52
+ { hosts: 'fake',
53
+ logger: logger,
54
+ password: 'secret_password',
55
+ user: 'test' }
56
+ end
57
+
58
+ it_behaves_like 'a redacted string'
59
+ end
60
+
61
+ context 'when the user and password are provided in the string URI' do
62
+
63
+ let(:arguments) do
64
+ { hosts: 'http://test:secret_password@fake.com',
65
+ logger: logger }
66
+ end
67
+
68
+ it_behaves_like 'a redacted string'
69
+ end
70
+
71
+ context 'when the user and password are provided in the URI object' do
72
+
73
+ let(:arguments) do
74
+ { hosts: URI.parse('http://test:secret_password@fake.com'),
75
+ logger: logger }
76
+ end
77
+
78
+ it_behaves_like 'a redacted string'
79
+ end
80
+ end
81
+ end