elasticsearch 7.17.9 → 8.0.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +4 -10
- data/README.md +70 -31
- data/bin/elastic_ruby_console +2 -5
- data/elasticsearch.gemspec +14 -14
- data/lib/elasticsearch/version.rb +1 -1
- data/lib/elasticsearch.rb +97 -33
- data/spec/integration/client_integration_spec.rb +10 -4
- data/spec/spec_helper.rb +8 -3
- data/spec/unit/api_key_spec.rb +101 -0
- data/spec/unit/cloud_credentials_spec.rb +167 -0
- data/spec/unit/custom_transport_implementation_spec.rb +43 -0
- data/spec/unit/elasticsearch_product_validation_spec.rb +17 -233
- data/spec/unit/headers_spec.rb +55 -0
- data/spec/unit/opaque_id_spec.rb +48 -0
- data/spec/unit/wrapper_gem_spec.rb +4 -10
- metadata +31 -25
- data/spec/integration/characters_escaping_spec.rb +0 -94
- data/spec/integration/validation_integration_spec.rb +0 -30
- /data/{LICENSE → LICENSE.txt} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ca479af01bac2b0dd8b654294c63f0f1bc675cd69036f9704ae9fd1b22684546
|
4
|
+
data.tar.gz: c2252be5532689f299dfb3084215beab37a797358d41cc355e74fa820c63cf42
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 27abb64b012188c2dd762c4e1a856dd84a80624a7d2c478b55ed84ab7cde54952c507847ac52a13c5c9170c9bfce5114ca4174c0ac5ae0d05fe234bd7a8a8f8a
|
7
|
+
data.tar.gz: 1f4a3e1ef357eba8709fe91a24c0d677835b40586232427c62372c0ce2a45b707cce51c02618235cdaf44567a408ab30c7da5e4172ef6010cdb6a20f9b57fdf1
|
data/Gemfile
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Licensed to Elasticsearch B.V. under one or more contributor
|
2
4
|
# license agreements. See the NOTICE file distributed with
|
3
5
|
# this work for additional information regarding copyright
|
@@ -20,14 +22,6 @@ source 'https://rubygems.org'
|
|
20
22
|
# Specify your gem's dependencies in elasticsearch.gemspec
|
21
23
|
gemspec
|
22
24
|
|
23
|
-
if File.exist? File.expand_path(
|
24
|
-
gem 'elasticsearch-api', :
|
25
|
-
end
|
26
|
-
|
27
|
-
if File.exist? File.expand_path("../../elasticsearch-transport/elasticsearch-transport.gemspec", __FILE__)
|
28
|
-
gem 'elasticsearch-transport', :path => File.expand_path("../../elasticsearch-transport", __FILE__), :require => false
|
29
|
-
end
|
30
|
-
|
31
|
-
if File.exist? File.expand_path("../../elasticsearch-extensions", __FILE__)
|
32
|
-
gem 'elasticsearch-extensions', :path => File.expand_path("../../elasticsearch-extensions", __FILE__), :require => true
|
25
|
+
if File.exist? File.expand_path('../elasticsearch-api/elasticsearch-api.gemspec', __dir__)
|
26
|
+
gem 'elasticsearch-api', path: File.expand_path('../elasticsearch-api', __dir__), require: false
|
33
27
|
end
|
data/README.md
CHANGED
@@ -2,6 +2,29 @@
|
|
2
2
|
|
3
3
|
The `elasticsearch` library provides a Ruby client and API for [Elasticsearch](http://elasticsearch.com).
|
4
4
|
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
This gem is a wrapper for two separate libraries:
|
8
|
+
|
9
|
+
* [`elasticsearch-transport`](https://github.com/elasticsearch/elasticsearch-ruby/tree/main/elasticsearch-transport), which provides a low-level Ruby client for connecting to [Elastic](http://elasticsearch.com) services.
|
10
|
+
* [`elasticsearch-api`](https://github.com/elasticsearch/elasticsearch-ruby/tree/main/elasticsearch-api), which provides a Ruby API for the Elasticsearch RESTful API.
|
11
|
+
|
12
|
+
Install the `elasticsearch` package and use the API directly:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
require 'elasticsearch'
|
16
|
+
|
17
|
+
client = Elasticsearch::Client.new(log: true)
|
18
|
+
|
19
|
+
client.cluster.health
|
20
|
+
|
21
|
+
client.transport.reload_connections!
|
22
|
+
|
23
|
+
client.search(q: 'test')
|
24
|
+
|
25
|
+
# etc.
|
26
|
+
```
|
27
|
+
|
5
28
|
Features overview:
|
6
29
|
|
7
30
|
* Pluggable logging and tracing
|
@@ -14,25 +37,13 @@ Features overview:
|
|
14
37
|
* Extensive documentation and examples
|
15
38
|
* Emphasis on modularity and extendability of both the client and API libraries
|
16
39
|
|
17
|
-
(For integration with Ruby models and Rails applications,
|
18
|
-
see the <https://github.com/elasticsearch/elasticsearch-rails> project.)
|
40
|
+
(For integration with Ruby models and Rails applications, see the <https://github.com/elasticsearch/elasticsearch-rails> project.)
|
19
41
|
|
20
42
|
## Compatibility
|
21
43
|
|
22
|
-
|
44
|
+
We follow Ruby’s own maintenance policy and officially support all currently maintained versions per [Ruby Maintenance Branches](https://www.ruby-lang.org/en/downloads/branches/).
|
23
45
|
|
24
|
-
|
25
|
-
just use a release matching major version of Elasticsearch.
|
26
|
-
|
27
|
-
| Ruby | | Elasticsearch |
|
28
|
-
|:-------------:|:-:| :-----------: |
|
29
|
-
| 0.90 | → | 0.90 |
|
30
|
-
| 1.x | → | 1.x |
|
31
|
-
| 2.x | → | 2.x |
|
32
|
-
| 5.x | → | 5.x |
|
33
|
-
| 6.x | → | 6.x |
|
34
|
-
| 7.x | → | 7.x |
|
35
|
-
| master | → | master |
|
46
|
+
Language clients are forward compatible; meaning that clients support communicating with greater minor versions of Elasticsearch. Elastic language clients are also backwards compatible with lesser supported minor Elasticsearch versions.
|
36
47
|
|
37
48
|
## Installation
|
38
49
|
|
@@ -51,45 +62,73 @@ or install it from a source code checkout:
|
|
51
62
|
bundle install
|
52
63
|
rake install
|
53
64
|
|
54
|
-
##
|
65
|
+
## Configuration
|
55
66
|
|
56
|
-
|
67
|
+
* [Identifying running tasks with X-Opaque-Id](#identifying-running-tasks-with-x-opaque-id)
|
68
|
+
* [Api Key Authentication](#api-key-authentication)
|
57
69
|
|
58
|
-
|
59
|
-
which provides a low-level Ruby client for connecting to an [Elasticsearch](http://elasticsearch.com) cluster
|
60
|
-
* [`elasticsearch-api`](https://github.com/elasticsearch/elasticsearch-ruby/tree/master/elasticsearch-api),
|
61
|
-
which provides a Ruby API for the Elasticsearch RESTful API
|
70
|
+
### Identifying running tasks with X-Opaque-Id
|
62
71
|
|
63
|
-
|
72
|
+
The X-Opaque-Id header allows to track certain calls, or associate certain tasks with the client that started them ([more on the Elasticsearch docs](https://www.elastic.co/guide/en/elasticsearch/reference/master/tasks.html#_identifying_running_tasks)). To use this feature, you need to set an id for `opaque_id` on the client on each request. Example:
|
64
73
|
|
65
74
|
```ruby
|
66
|
-
|
75
|
+
client = Elasticsearch::Client.new
|
76
|
+
client.search(index: 'myindex', q: 'title:test', opaque_id: '123456')
|
77
|
+
```
|
78
|
+
The search request will include the following HTTP Header:
|
79
|
+
```
|
80
|
+
X-Opaque-Id: 123456
|
81
|
+
```
|
82
|
+
|
83
|
+
You can also set a prefix for X-Opaque-Id when initializing the client. This will be prepended to the id you set before each request if you're using X-Opaque-Id. Example:
|
84
|
+
```ruby
|
85
|
+
client = Elastic::Transport::Client.new(opaque_id_prefix: 'eu-west1_')
|
86
|
+
client.search(index: 'myindex', q: 'title:test', opaque_id: '123456')
|
87
|
+
```
|
88
|
+
The request will include the following HTTP Header:
|
89
|
+
```
|
90
|
+
X-Opaque-Id: eu-west1_123456
|
91
|
+
```
|
67
92
|
|
68
|
-
|
93
|
+
### Api Key Authentication
|
69
94
|
|
70
|
-
|
95
|
+
You can use [**API Key authentication**](https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html):
|
71
96
|
|
72
|
-
|
97
|
+
``` ruby
|
98
|
+
Elasticsearch::Client.new(
|
99
|
+
host: host,
|
100
|
+
transport_options: transport_options,
|
101
|
+
api_key: credentials
|
102
|
+
)
|
103
|
+
```
|
73
104
|
|
74
|
-
|
105
|
+
Where credentials is either the base64 encoding of `id` and `api_key` joined by a colon or a hash with the `id` and `api_key`:
|
75
106
|
|
76
|
-
|
107
|
+
``` ruby
|
108
|
+
Elasticsearch::Client.new(
|
109
|
+
host: host,
|
110
|
+
transport_options: transport_options,
|
111
|
+
api_key: {id: 'my_id', api_key: 'my_api_key'}
|
112
|
+
)
|
77
113
|
```
|
78
114
|
|
115
|
+
## API and Transport
|
116
|
+
|
79
117
|
Please refer to the specific library documentation for details:
|
80
118
|
|
81
119
|
* **Transport**:
|
82
|
-
[[README]](https://github.com/elasticsearch/elasticsearch-ruby/blob/
|
120
|
+
[[README]](https://github.com/elasticsearch/elasticsearch-ruby/blob/main/elasticsearch-transport/README.md)
|
83
121
|
[[Documentation]](http://rubydoc.info/gems/elasticsearch-transport/file/README.markdown)
|
84
122
|
|
85
123
|
* **API**:
|
86
|
-
[[README]](https://github.com/elasticsearch/elasticsearch-ruby/blob/
|
124
|
+
[[README]](https://github.com/elasticsearch/elasticsearch-ruby/blob/main/elasticsearch-api/README.md)
|
87
125
|
[[Documentation]](http://rubydoc.info/gems/elasticsearch-api/file/README.markdown)
|
88
126
|
|
127
|
+
|
89
128
|
## Development
|
90
129
|
|
91
130
|
You can run `rake -T` to check the test tasks. Use `COVERAGE=true` before running a test task to check the coverage with Simplecov.
|
92
131
|
|
93
132
|
## License
|
94
133
|
|
95
|
-
This software is licensed under the [Apache 2 license](./LICENSE).
|
134
|
+
This software is licensed under the [Apache 2 license](./LICENSE).
|
data/bin/elastic_ruby_console
CHANGED
@@ -1,17 +1,14 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
$LOAD_PATH.unshift(File.expand_path('../../elasticsearch/lib', __dir__))
|
4
|
-
$LOAD_PATH.unshift(File.expand_path('../../elasticsearch-transport/lib', __dir__))
|
5
4
|
$LOAD_PATH.unshift(File.expand_path('../../elasticsearch-dsl/lib', __dir__))
|
6
5
|
$LOAD_PATH.unshift(File.expand_path('../../elasticsearch-api/lib', __dir__))
|
7
|
-
$LOAD_PATH.unshift(File.expand_path('../../elasticsearch-xpack/lib', __dir__))
|
8
|
-
$LOAD_PATH.unshift(File.expand_path('../../elasticsearch-extensions/lib', __dir__))
|
9
6
|
|
10
7
|
require 'elasticsearch'
|
11
|
-
require 'elasticsearch-transport'
|
12
8
|
require 'elasticsearch-api'
|
9
|
+
require 'elasticsearch-dsl'
|
13
10
|
|
14
|
-
gems_not_loaded = ['elasticsearch-dsl'
|
11
|
+
gems_not_loaded = ['elasticsearch-dsl'].reject do |gem|
|
15
12
|
begin
|
16
13
|
(require gem) || true
|
17
14
|
rescue LoadError
|
data/elasticsearch.gemspec
CHANGED
@@ -25,33 +25,33 @@ Gem::Specification.new do |s|
|
|
25
25
|
s.authors = ['Karel Minarik']
|
26
26
|
s.email = ['karel.minarik@elasticsearch.org']
|
27
27
|
s.summary = 'Ruby integrations for Elasticsearch'
|
28
|
-
s.homepage = 'https://www.elastic.co/guide/en/elasticsearch/client/ruby-api/
|
28
|
+
s.homepage = 'https://www.elastic.co/guide/en/elasticsearch/client/ruby-api/current/index.html'
|
29
29
|
s.license = 'Apache-2.0'
|
30
30
|
s.metadata = {
|
31
|
-
'homepage_uri' => 'https://www.elastic.co/guide/en/elasticsearch/client/ruby-api/
|
32
|
-
'changelog_uri' => 'https://github.com/elastic/elasticsearch-ruby/blob/
|
33
|
-
'source_code_uri' => 'https://github.com/elastic/elasticsearch-ruby/tree/
|
31
|
+
'homepage_uri' => 'https://www.elastic.co/guide/en/elasticsearch/client/ruby-api/current/index.html',
|
32
|
+
'changelog_uri' => 'https://github.com/elastic/elasticsearch-ruby/blob/main/CHANGELOG.md',
|
33
|
+
'source_code_uri' => 'https://github.com/elastic/elasticsearch-ruby/tree/main',
|
34
34
|
'bug_tracker_uri' => 'https://github.com/elastic/elasticsearch-ruby/issues'
|
35
35
|
}
|
36
|
-
s.files
|
37
|
-
s.executables
|
38
|
-
s.executables
|
39
|
-
s.test_files
|
36
|
+
s.files = `git ls-files`.split($/)
|
37
|
+
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
38
|
+
s.executables << 'elastic_ruby_console'
|
39
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
40
40
|
s.require_paths = ['lib']
|
41
41
|
s.bindir = 'bin'
|
42
42
|
|
43
|
-
s.extra_rdoc_files = [
|
44
|
-
s.rdoc_options = [
|
43
|
+
s.extra_rdoc_files = ['README.md', 'LICENSE.txt']
|
44
|
+
s.rdoc_options = ['--charset=UTF-8']
|
45
45
|
|
46
|
-
s.required_ruby_version = '>= 2.
|
46
|
+
s.required_ruby_version = '>= 2.5'
|
47
47
|
|
48
|
-
s.add_dependency '
|
49
|
-
s.add_dependency 'elasticsearch-api',
|
48
|
+
s.add_dependency 'elastic-transport', '8.0.0.pre2'
|
49
|
+
s.add_dependency 'elasticsearch-api', '8.0.0.pre1'
|
50
50
|
|
51
51
|
s.add_development_dependency 'bundler'
|
52
52
|
s.add_development_dependency 'byebug' unless defined?(JRUBY_VERSION) || defined?(Rubinius)
|
53
53
|
s.add_development_dependency 'pry'
|
54
|
-
s.add_development_dependency 'rake'
|
54
|
+
s.add_development_dependency 'rake'
|
55
55
|
s.add_development_dependency 'require-prof' unless defined?(JRUBY_VERSION) || defined?(Rubinius)
|
56
56
|
s.add_development_dependency 'rspec'
|
57
57
|
s.add_development_dependency 'ruby-prof' unless defined?(JRUBY_VERSION) || defined?(Rubinius)
|
data/lib/elasticsearch.rb
CHANGED
@@ -16,42 +16,76 @@
|
|
16
16
|
# under the License.
|
17
17
|
|
18
18
|
require 'elasticsearch/version'
|
19
|
-
require '
|
19
|
+
require 'elastic/transport'
|
20
20
|
require 'elasticsearch/api'
|
21
21
|
|
22
22
|
module Elasticsearch
|
23
|
-
SECURITY_PRIVILEGES_VALIDATION_WARNING = 'The client is unable to verify that the server is Elasticsearch due to security privileges on the server side. Some functionality may not be compatible if the server is running an unsupported product.'.freeze
|
24
23
|
NOT_ELASTICSEARCH_WARNING = 'The client noticed that the server is not Elasticsearch and we do not support this unknown product.'.freeze
|
25
|
-
|
26
|
-
YOU_KNOW_FOR_SEARCH = 'You Know, for Search'.freeze
|
24
|
+
SECURITY_PRIVILEGES_VALIDATION_WARNING = 'The client is unable to verify that the server is Elasticsearch due to security privileges on the server side. Some functionality may not be compatible if the server is running an unsupported product.'.freeze
|
27
25
|
|
26
|
+
# This is the stateful Elasticsearch::Client, using an instance of elastic-transport.
|
28
27
|
class Client
|
29
28
|
include Elasticsearch::API
|
30
|
-
|
31
|
-
|
32
|
-
#
|
29
|
+
# The default port to use if connecting using a Cloud ID.
|
30
|
+
# Updated from 9243 to 443 in client version 7.10.1
|
31
|
+
#
|
32
|
+
# @since 7.2.0
|
33
|
+
DEFAULT_CLOUD_PORT = 443
|
34
|
+
|
35
|
+
# Create a client connected to an Elasticsearch cluster.
|
36
|
+
#
|
37
|
+
# @option arguments [String] :cloud_id - The Cloud ID to connect to Elastic Cloud
|
38
|
+
# @option api_key [String, Hash] :api_key Use API Key Authentication, either the base64 encoding of `id` and `api_key`
|
39
|
+
# joined by a colon as a String, or a hash with the `id` and `api_key` values.
|
40
|
+
# @option opaque_id_prefix [String] :opaque_id_prefix set a prefix for X-Opaque-Id when initializing the client.
|
41
|
+
# This will be prepended to the id you set before each request
|
42
|
+
# if you're using X-Opaque-Id
|
33
43
|
def initialize(arguments = {}, &block)
|
34
44
|
@verified = false
|
35
|
-
@
|
45
|
+
@opaque_id_prefix = arguments[:opaque_id_prefix] || nil
|
46
|
+
api_key(arguments) if arguments[:api_key]
|
47
|
+
if arguments[:cloud_id]
|
48
|
+
arguments[:hosts] = setup_cloud_host(
|
49
|
+
arguments[:cloud_id],
|
50
|
+
arguments[:user],
|
51
|
+
arguments[:password],
|
52
|
+
arguments[:port]
|
53
|
+
)
|
54
|
+
end
|
55
|
+
@transport = Elastic::Transport::Client.new(arguments, &block)
|
36
56
|
end
|
37
57
|
|
38
58
|
def method_missing(name, *args, &block)
|
39
|
-
if name
|
40
|
-
verify_elasticsearch unless @verified
|
41
|
-
@transport.perform_request(*args, &block)
|
42
|
-
else
|
59
|
+
if methods.include?(name)
|
43
60
|
super
|
61
|
+
elsif name == :perform_request
|
62
|
+
# The signature for perform_request is:
|
63
|
+
# method, path, params, body, headers
|
64
|
+
if (opaque_id = args[2]&.delete(:opaque_id))
|
65
|
+
headers = args[4] || {}
|
66
|
+
opaque_id = @opaque_id_prefix ? "#{@opaque_id_prefix}#{opaque_id}" : opaque_id
|
67
|
+
args[4] = headers.merge('X-Opaque-Id' => opaque_id)
|
68
|
+
end
|
69
|
+
if name == :perform_request
|
70
|
+
verify_elasticsearch unless @verified
|
71
|
+
@transport.perform_request(*args, &block)
|
72
|
+
end
|
73
|
+
else
|
74
|
+
@transport.send(name, *args, &block)
|
44
75
|
end
|
45
76
|
end
|
46
77
|
|
78
|
+
def respond_to_missing?(method_name, *args)
|
79
|
+
@transport.respond_to?(method_name) || super
|
80
|
+
end
|
81
|
+
|
47
82
|
private
|
48
83
|
|
49
84
|
def verify_elasticsearch
|
50
85
|
begin
|
51
86
|
response = elasticsearch_validation_request
|
52
|
-
rescue
|
53
|
-
|
54
|
-
Elasticsearch::Transport::Transport::Errors::RequestEntityTooLarge
|
87
|
+
rescue Elastic::Transport::Transport::Errors::Unauthorized,
|
88
|
+
Elastic::Transport::Transport::Errors::Forbidden
|
55
89
|
@verified = true
|
56
90
|
warn(SECURITY_PRIVILEGES_VALIDATION_WARNING)
|
57
91
|
return
|
@@ -59,41 +93,70 @@ module Elasticsearch
|
|
59
93
|
|
60
94
|
body = if response.headers['content-type'] == 'application/yaml'
|
61
95
|
require 'yaml'
|
62
|
-
YAML.
|
96
|
+
YAML.load(response.body)
|
63
97
|
else
|
64
98
|
response.body
|
65
99
|
end
|
66
100
|
version = body.dig('version', 'number')
|
67
|
-
verify_with_version_or_header(
|
101
|
+
verify_with_version_or_header(version, response.headers)
|
68
102
|
end
|
69
103
|
|
70
|
-
def verify_with_version_or_header(
|
71
|
-
|
104
|
+
def verify_with_version_or_header(version, headers)
|
105
|
+
if version.nil? ||
|
106
|
+
Gem::Version.new(version) < Gem::Version.new('8.0.0.pre') && version != '8.0.0-SNAPSHOT' ||
|
107
|
+
headers['x-elastic-product'] != 'Elasticsearch'
|
72
108
|
|
73
|
-
|
74
|
-
|
109
|
+
raise Elasticsearch::UnsupportedProductError
|
110
|
+
end
|
75
111
|
|
76
|
-
|
77
|
-
|
78
|
-
Gem::Version.new(version) < Gem::Version.new('7.0.0')
|
79
|
-
raise Elasticsearch::UnsupportedProductError unless
|
80
|
-
body['tagline'] == YOU_KNOW_FOR_SEARCH
|
112
|
+
@verified = true
|
113
|
+
end
|
81
114
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
raise Elasticsearch::UnsupportedProductError unless body['tagline'] == YOU_KNOW_FOR_SEARCH
|
86
|
-
raise Elasticsearch::UnsupportedProductError.new(NOT_SUPPORTED_ELASTICSEARCH_WARNING) unless body.dig('version', 'build_flavor') == 'default'
|
115
|
+
def setup_cloud_host(cloud_id, user, password, port)
|
116
|
+
name = cloud_id.split(':')[0]
|
117
|
+
cloud_url, elasticsearch_instance = Base64.decode64(cloud_id.gsub("#{name}:", '')).split('$')
|
87
118
|
|
88
|
-
|
119
|
+
if cloud_url.include?(':')
|
120
|
+
url, port = cloud_url.split(':')
|
121
|
+
host = "#{elasticsearch_instance}.#{url}"
|
122
|
+
else
|
123
|
+
host = "#{elasticsearch_instance}.#{cloud_url}"
|
124
|
+
port ||= DEFAULT_CLOUD_PORT
|
125
|
+
end
|
126
|
+
[{ scheme: 'https', user: user, password: password, host: host, port: port.to_i }]
|
127
|
+
end
|
128
|
+
|
129
|
+
def api_key(arguments)
|
130
|
+
api_key = if arguments[:api_key].is_a? Hash
|
131
|
+
encode(arguments[:api_key])
|
132
|
+
else
|
133
|
+
arguments[:api_key]
|
134
|
+
end
|
135
|
+
arguments.delete(:user)
|
136
|
+
arguments.delete(:password)
|
137
|
+
authorization = { 'Authorization' => "ApiKey #{api_key}" }
|
138
|
+
if (headers = arguments.dig(:transport_options, :headers))
|
139
|
+
headers.merge!(authorization)
|
140
|
+
else
|
141
|
+
arguments[:transport_options] = {
|
142
|
+
headers: authorization
|
143
|
+
}
|
89
144
|
end
|
90
145
|
end
|
91
146
|
|
147
|
+
# Encode credentials for the Authorization Header
|
148
|
+
# Credentials is the base64 encoding of id and api_key joined by a colon
|
149
|
+
# @see https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html
|
150
|
+
def encode(api_key)
|
151
|
+
Base64.strict_encode64([api_key[:id], api_key[:api_key]].join(':'))
|
152
|
+
end
|
153
|
+
|
92
154
|
def elasticsearch_validation_request
|
93
155
|
@transport.perform_request('GET', '/')
|
94
156
|
end
|
95
157
|
end
|
96
158
|
|
159
|
+
# Error class for when we detect an unsupported version of Elasticsearch
|
97
160
|
class UnsupportedProductError < StandardError
|
98
161
|
def initialize(message = NOT_ELASTICSEARCH_WARNING)
|
99
162
|
super(message)
|
@@ -101,6 +164,7 @@ module Elasticsearch
|
|
101
164
|
end
|
102
165
|
end
|
103
166
|
|
167
|
+
# Helper for the meta-header value for Cloud
|
104
168
|
module Elastic
|
105
169
|
# If the version is X.X.X.pre/alpha/beta, use X.X.Xp for the meta-header:
|
106
170
|
def self.client_meta_version
|
@@ -111,6 +175,6 @@ module Elastic
|
|
111
175
|
Elasticsearch::VERSION
|
112
176
|
end
|
113
177
|
|
114
|
-
# Constant for
|
178
|
+
# Constant for elastic-transport meta-header
|
115
179
|
ELASTICSEARCH_SERVICE_VERSION = [:es, client_meta_version].freeze
|
116
180
|
end
|
@@ -14,6 +14,9 @@
|
|
14
14
|
# KIND, either express or implied. See the License for the
|
15
15
|
# specific language governing permissions and limitations
|
16
16
|
# under the License.
|
17
|
+
ELASTICSEARCH_URL = ENV['TEST_ES_SERVER'] || "http://localhost:#{(ENV['PORT'] || 9200)}"
|
18
|
+
raise URI::InvalidURIError unless ELASTICSEARCH_URL =~ /\A#{URI::DEFAULT_PARSER.make_regexp}\z/
|
19
|
+
|
17
20
|
require 'spec_helper'
|
18
21
|
require 'logger'
|
19
22
|
|
@@ -23,7 +26,9 @@ context 'Elasticsearch client' do
|
|
23
26
|
let(:client) do
|
24
27
|
Elasticsearch::Client.new(
|
25
28
|
host: ELASTICSEARCH_URL,
|
26
|
-
logger: logger
|
29
|
+
logger: logger,
|
30
|
+
user: 'elastic',
|
31
|
+
password: 'changeme'
|
27
32
|
)
|
28
33
|
end
|
29
34
|
|
@@ -49,9 +54,10 @@ context 'Elasticsearch client' do
|
|
49
54
|
end
|
50
55
|
|
51
56
|
context 'Reports the right meta header' do
|
52
|
-
it 'Reports es service name and gem
|
53
|
-
headers = client.transport.
|
54
|
-
|
57
|
+
it 'Reports es service name and gem versio' do
|
58
|
+
headers = client.transport.connections.first.connection.headers
|
59
|
+
version = Class.new.extend(Elastic::Transport::MetaHeader).send(:client_meta_version, Elasticsearch::VERSION)
|
60
|
+
expect(headers['x-elastic-client-meta']).to match /^es=#{version}/
|
55
61
|
end
|
56
62
|
end
|
57
63
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -18,9 +18,14 @@
|
|
18
18
|
require 'elasticsearch'
|
19
19
|
require 'rspec'
|
20
20
|
|
21
|
-
ELASTICSEARCH_URL = ENV['TEST_ES_SERVER'] || "http://localhost:#{(ENV['PORT'] || 9200)}"
|
22
|
-
raise URI::InvalidURIError unless ELASTICSEARCH_URL =~ /\A#{URI::DEFAULT_PARSER.make_regexp}\z/
|
23
|
-
|
24
21
|
RSpec.configure do |config|
|
25
22
|
config.formatter = :documentation
|
26
23
|
end
|
24
|
+
|
25
|
+
def meta_version
|
26
|
+
client.send(:client_meta_version, Elasticsearch::VERSION)
|
27
|
+
end
|
28
|
+
|
29
|
+
def jruby?
|
30
|
+
defined?(JRUBY_VERSION)
|
31
|
+
end
|
@@ -0,0 +1,101 @@
|
|
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::Client do
|
21
|
+
context 'when using API Key' do
|
22
|
+
let(:authorization_header) do
|
23
|
+
client.transport.connections.first.connection.headers['Authorization']
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'when an encoded api_key is provided' do
|
27
|
+
let(:client) do
|
28
|
+
described_class.new(api_key: 'an_api_key')
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'Adds the ApiKey header to the connection' do
|
32
|
+
expect(authorization_header).to eq('ApiKey an_api_key')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'when an un-encoded api_key is provided' do
|
37
|
+
let(:client) do
|
38
|
+
described_class.new(api_key: { id: 'my_id', api_key: 'my_api_key' })
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'Adds the ApiKey header to the connection' do
|
42
|
+
expect(authorization_header).to eq("ApiKey #{Base64.strict_encode64('my_id:my_api_key')}")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'when basic auth and api_key are provided' do
|
47
|
+
let(:client) do
|
48
|
+
described_class.new(
|
49
|
+
api_key: { id: 'my_id', api_key: 'my_api_key' },
|
50
|
+
host: 'http://elastic:password@localhost:9200'
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'removes basic auth credentials' do
|
55
|
+
expect(authorization_header).not_to match(/^Basic/)
|
56
|
+
expect(authorization_header).to match(/^ApiKey/)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'when other headers where specified' do
|
61
|
+
let(:client) do
|
62
|
+
described_class.new(
|
63
|
+
api_key: 'elasticsearch_api_key',
|
64
|
+
transport_options: { headers: { 'x-test-header' => 'test' } }
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'Adds the ApiKey header to the connection and keeps the header' do
|
69
|
+
header = client.transport.connections.first.connection.headers
|
70
|
+
expect(header['Authorization']).to eq('ApiKey elasticsearch_api_key')
|
71
|
+
expect(header['X-Test-Header']).to eq('test')
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'Metaheader' do
|
76
|
+
let(:adapter_code) { "nh=#{defined?(Net::HTTP::VERSION) ? Net::HTTP::VERSION : Net::HTTP::HTTPVersion}" }
|
77
|
+
let(:meta_header) do
|
78
|
+
if jruby?
|
79
|
+
"es=#{meta_version},rb=#{RUBY_VERSION},t=#{Elastic::Transport::VERSION},jv=#{ENV_JAVA['java.version']},jr=#{JRUBY_VERSION},fd=#{Faraday::VERSION},#{adapter_code}"
|
80
|
+
else
|
81
|
+
"es=#{meta_version},rb=#{RUBY_VERSION},t=#{Elastic::Transport::VERSION},fd=#{Faraday::VERSION},#{adapter_code}"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'when using API Key' do
|
86
|
+
let(:client) do
|
87
|
+
described_class.new(api_key: 'an_api_key')
|
88
|
+
end
|
89
|
+
|
90
|
+
let(:headers) do
|
91
|
+
client.transport.connections.first.connection.headers
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'adds the ApiKey header to the connection' do
|
95
|
+
expect(authorization_header).to eq('ApiKey an_api_key')
|
96
|
+
expect(headers).to include('x-elastic-client-meta' => meta_header)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|