Skip to content

Commit a075f7a

Browse files
committed
[GEM] Updates product validation
This update refactors the product validation in a few ways: - Just check header, does not check the version of the server - Warns only once when there's a general server error - Removes the call to '/' (client.info) when doing the first request, checking on the first actual request from the client
1 parent 0939ebf commit a075f7a

File tree

2 files changed

+56
-220
lines changed

2 files changed

+56
-220
lines changed

elasticsearch/lib/elasticsearch.rb

Lines changed: 21 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class Client
4343
# if you're using X-Opaque-Id
4444
def initialize(arguments = {}, &block)
4545
@verified = false
46+
@warned = false
4647
@opaque_id_prefix = arguments[:opaque_id_prefix] || nil
4748
api_key(arguments) if arguments[:api_key]
4849
if arguments[:cloud_id]
@@ -67,8 +68,11 @@ def method_missing(name, *args, &block)
6768
opaque_id = @opaque_id_prefix ? "#{@opaque_id_prefix}#{opaque_id}" : opaque_id
6869
args[4] = headers.merge('X-Opaque-Id' => opaque_id)
6970
end
70-
verify_elasticsearch unless @verified
71-
@transport.perform_request(*args, &block)
71+
unless @verified
72+
verify_elasticsearch(*args, &block)
73+
else
74+
@transport.perform_request(*args, &block)
75+
end
7276
else
7377
@transport.send(name, *args, &block)
7478
end
@@ -80,42 +84,28 @@ def respond_to_missing?(method_name, *args)
8084

8185
private
8286

83-
def verify_elasticsearch
87+
def verify_elasticsearch(*args, &block)
8488
begin
85-
response = elasticsearch_validation_request
89+
response = @transport.perform_request(*args, &block)
8690
rescue Elastic::Transport::Transport::Errors::Unauthorized,
8791
Elastic::Transport::Transport::Errors::Forbidden,
88-
Elastic::Transport::Transport::Errors::RequestEntityTooLarge
89-
@verified = true
92+
Elastic::Transport::Transport::Errors::RequestEntityTooLarge => e
9093
warn(SECURITY_PRIVILEGES_VALIDATION_WARNING)
91-
return
92-
rescue Elastic::Transport::Transport::Error
94+
@verified = true
95+
raise e
96+
rescue Elastic::Transport::Transport::Error => e
97+
unless @warned
98+
warn(VALIDATION_WARNING)
99+
@warned = true
100+
end
101+
raise e
102+
rescue StandardError => e
93103
warn(VALIDATION_WARNING)
94-
return
95-
end
96-
97-
body = if response.headers['content-type'] == 'application/yaml'
98-
require 'yaml'
99-
YAML.safe_load(response.body)
100-
else
101-
response.body
102-
end
103-
version = body.dig('version', 'number')
104-
verify_with_version_or_header(version, response.headers)
105-
rescue StandardError => e
106-
warn(VALIDATION_WARNING)
107-
raise e
108-
end
109-
110-
def verify_with_version_or_header(version, headers)
111-
if version.nil? ||
112-
Gem::Version.new(version) < Gem::Version.new('8.0.0.pre') && version != '8.0.0-SNAPSHOT' ||
113-
headers['x-elastic-product'] != 'Elasticsearch'
114-
115-
raise Elasticsearch::UnsupportedProductError
104+
raise e
116105
end
117-
106+
raise Elasticsearch::UnsupportedProductError unless response.headers['x-elastic-product'] == 'Elasticsearch'
118107
@verified = true
108+
response
119109
end
120110

121111
def setup_cloud_host(cloud_id, user, password, port)

elasticsearch/spec/unit/elasticsearch_product_validation_spec.rb

Lines changed: 35 additions & 189 deletions
Original file line numberDiff line numberDiff line change
@@ -20,52 +20,28 @@
2020

2121
describe 'Elasticsearch: Validation' do
2222
let(:host) { 'http://localhost:9200' }
23-
let(:verify_request_stub) do
24-
stub_request(:get, host)
25-
.to_return(status: status, body: body, headers: headers)
26-
end
2723
let(:count_request_stub) do
2824
stub_request(:get, "#{host}/_count")
29-
.to_return(status: 200, body: nil, headers: {})
25+
.to_return(status: status, body: nil, headers: headers)
3026
end
3127
let(:status) { 200 }
32-
let(:body) { {}.to_json }
28+
let(:body) { nil }
29+
let(:headers) { {} }
3330
let(:client) { Elasticsearch::Client.new }
34-
let(:headers) do
35-
{ 'content-type' => 'application/json' }
36-
end
37-
38-
def error_requests_and_expectations(message = Elasticsearch::NOT_ELASTICSEARCH_WARNING)
39-
expect { client.count }.to raise_error Elasticsearch::UnsupportedProductError, message
40-
assert_requested :get, host
41-
assert_not_requested :post, "#{host}/_count"
42-
expect { client.cluster.health }.to raise_error Elasticsearch::UnsupportedProductError, message
43-
expect(client.instance_variable_get('@verified')).to be false
44-
expect { client.cluster.health }.to raise_error Elasticsearch::UnsupportedProductError, message
45-
end
46-
47-
def valid_requests_and_expectations
48-
expect(client.instance_variable_get('@verified')).to be false
49-
assert_not_requested :get, host
50-
51-
client.count
52-
expect(client.instance_variable_get('@verified'))
53-
assert_requested :get, host
54-
assert_requested :get, "#{host}/_count"
55-
end
5631

5732
context 'When Elasticsearch replies with status 401' do
5833
let(:status) { 401 }
59-
let(:body) { {}.to_json }
6034

6135
it 'Verifies the request but shows a warning' do
6236
stderr = $stderr
6337
fake_stderr = StringIO.new
6438
$stderr = fake_stderr
65-
66-
verify_request_stub
39+
expect(client.instance_variable_get('@verified')).to be false
6740
count_request_stub
68-
valid_requests_and_expectations
41+
expect do
42+
client.count
43+
end.to raise_error Elastic::Transport::Transport::Errors::Unauthorized
44+
expect(client.instance_variable_get('@verified')).to be true
6945

7046
fake_stderr.rewind
7147
expect(fake_stderr.string).to eq("#{Elasticsearch::SECURITY_PRIVILEGES_VALIDATION_WARNING}\n")
@@ -76,16 +52,18 @@ def valid_requests_and_expectations
7652

7753
context 'When Elasticsearch replies with status 403' do
7854
let(:status) { 403 }
79-
let(:body) { {}.to_json }
8055

8156
it 'Verifies the request but shows a warning' do
8257
stderr = $stderr
8358
fake_stderr = StringIO.new
8459
$stderr = fake_stderr
8560

86-
verify_request_stub
61+
expect(client.instance_variable_get('@verified')).to be false
8762
count_request_stub
88-
valid_requests_and_expectations
63+
expect do
64+
client.count
65+
end.to raise_error Elastic::Transport::Transport::Errors::Forbidden
66+
expect(client.instance_variable_get('@verified')).to be true
8967

9068
fake_stderr.rewind
9169
expect(fake_stderr.string).to eq("#{Elasticsearch::SECURITY_PRIVILEGES_VALIDATION_WARNING}\n")
@@ -96,17 +74,17 @@ def valid_requests_and_expectations
9674

9775
context 'When Elasticsearch replies with status 413' do
9876
let(:status) { 413 }
99-
let(:body) { {}.to_json }
10077

10178
it 'Verifies the request and shows a warning' do
10279
stderr = $stderr
10380
fake_stderr = StringIO.new
10481
$stderr = fake_stderr
10582

10683
expect(client.instance_variable_get('@verified')).to be false
107-
assert_not_requested :get, host
108-
verify_request_stub
109-
expect { client.info }.to raise_error Elastic::Transport::Transport::Errors::RequestEntityTooLarge
84+
count_request_stub
85+
expect do
86+
client.count
87+
end.to raise_error Elastic::Transport::Transport::Errors::RequestEntityTooLarge
11088
expect(client.instance_variable_get('@verified')).to be true
11189

11290
fake_stderr.rewind
@@ -127,10 +105,10 @@ def valid_requests_and_expectations
127105
$stderr = fake_stderr
128106

129107
expect(client.instance_variable_get('@verified')).to be false
130-
assert_not_requested :get, host
131-
verify_request_stub
132-
expect { client.info }.to raise_error Elastic::Transport::Transport::Errors::ServiceUnavailable
133-
assert_not_requested :post, "#{host}/_count"
108+
count_request_stub
109+
expect do
110+
client.count
111+
end.to raise_error Elastic::Transport::Transport::Errors::ServiceUnavailable
134112
expect(client.instance_variable_get('@verified')).to be false
135113

136114
fake_stderr.rewind
@@ -147,156 +125,24 @@ def valid_requests_and_expectations
147125
end
148126
end
149127

128+
context 'When the header is present' do
129+
let(:headers) { { 'X-Elastic-Product' => 'Elasticsearch' } }
150130

151-
context 'When the Elasticsearch version is >= 8.0.0' do
152-
context 'With a valid Elasticsearch response' do
153-
let(:body) { { 'version' => { 'number' => '8.0.0' } }.to_json }
154-
let(:headers) do
155-
{
156-
'X-Elastic-Product' => 'Elasticsearch',
157-
'content-type' => 'json'
158-
}
159-
end
160-
161-
it 'Makes requests and passes validation' do
162-
verify_request_stub
163-
count_request_stub
164-
165-
valid_requests_and_expectations
166-
end
167-
end
168-
169-
context 'When the header is not present' do
170-
it 'Fails validation' do
171-
verify_request_stub
172-
173-
expect(client.instance_variable_get('@verified')).to be false
174-
assert_not_requested :get, host
175-
176-
error_requests_and_expectations
177-
end
178-
end
179-
end
180-
181-
context 'When the Elasticsearch version is >= 8.1.0' do
182-
context 'With a valid Elasticsearch response' do
183-
let(:body) { { 'version' => { 'number' => '8.1.0' } }.to_json }
184-
let(:headers) do
185-
{
186-
'X-Elastic-Product' => 'Elasticsearch',
187-
'content-type' => 'json'
188-
}
189-
end
190-
191-
it 'Makes requests and passes validation' do
192-
verify_request_stub
193-
count_request_stub
194-
195-
valid_requests_and_expectations
196-
end
197-
end
198-
199-
context 'When the header is not present' do
200-
it 'Fails validation' do
201-
verify_request_stub
202-
203-
expect(client.instance_variable_get('@verified')).to be false
204-
assert_not_requested :get, host
205-
206-
error_requests_and_expectations
207-
end
208-
end
209-
end
210-
211-
212-
context 'When the Elasticsearch version is 8.0.0.pre' do
213-
context 'With a valid Elasticsearch response' do
214-
let(:body) { { 'version' => { 'number' => '8.0.0.pre' } }.to_json }
215-
let(:headers) do
216-
{
217-
'X-Elastic-Product' => 'Elasticsearch',
218-
'content-type' => 'json'
219-
}
220-
end
221-
222-
it 'Makes requests and passes validation' do
223-
verify_request_stub
224-
count_request_stub
225-
226-
valid_requests_and_expectations
227-
end
228-
end
229-
230-
context 'When the header is not present' do
231-
it 'Fails validation' do
232-
verify_request_stub
233-
234-
expect(client.instance_variable_get('@verified')).to be false
235-
assert_not_requested :get, host
236-
237-
error_requests_and_expectations
238-
end
239-
end
240-
end
241-
242-
context 'When the version is 8.0.0-SNAPSHOT' do
243-
let(:body) { { 'version' => { 'number' => '8.0.0-SNAPSHOT' } }.to_json }
244-
245-
context 'When the header is not present' do
246-
it 'Fails validation' do
247-
verify_request_stub
248-
count_request_stub
249-
250-
error_requests_and_expectations
251-
end
252-
end
253-
254-
context 'With a valid Elasticsearch response' do
255-
let(:headers) do
256-
{
257-
'X-Elastic-Product' => 'Elasticsearch',
258-
'content-type' => 'json'
259-
}
260-
end
261-
262-
it 'Makes requests and passes validation' do
263-
verify_request_stub
264-
count_request_stub
265-
266-
valid_requests_and_expectations
267-
end
268-
end
269-
end
270-
271-
context 'When Elasticsearch version is < 8.0.0' do
272-
let(:body) { { 'version' => { 'number' => '7.16.0' } }.to_json }
273-
274-
it 'Raises an exception and client doesnae work' do
275-
verify_request_stub
276-
error_requests_and_expectations
277-
end
278-
end
279-
280-
context 'When there is no version data' do
281-
let(:body) { {}.to_json }
282-
it 'Raises an exception and client doesnae work' do
283-
verify_request_stub
284-
error_requests_and_expectations
131+
it 'Makes requests and passes validation' do
132+
expect(client.instance_variable_get('@verified')).to be false
133+
count_request_stub
134+
client.count
135+
expect(client.instance_variable_get('@verified')).to be true
285136
end
286137
end
287138

288-
context 'When doing a yaml content-type request' do
289-
let(:client) do
290-
Elasticsearch::Client.new(transport_options: {headers: { accept: 'application/yaml', content_type: 'application/yaml' }})
291-
end
292-
293-
let(:headers) { { 'content-type' => 'application/yaml', 'X-Elastic-Product' => 'Elasticsearch' } }
294-
let(:body) { "---\nversion:\n number: \"8.0.0-SNAPSHOT\"\n" }
295-
296-
it 'validates' do
297-
verify_request_stub
298-
count_request_stub
299-
valid_requests_and_expectations
139+
context 'When the header is not present' do
140+
it 'Fails validation' do
141+
expect(client.instance_variable_get('@verified')).to be false
142+
stub_request(:get, "#{host}/_cluster/health")
143+
.to_return(status: status, body: nil, headers: {})
144+
expect { client.cluster.health }.to raise_error Elasticsearch::UnsupportedProductError, Elasticsearch::NOT_ELASTICSEARCH_WARNING
145+
expect(client.instance_variable_get('@verified')).to be false
300146
end
301147
end
302148
end

0 commit comments

Comments
 (0)