Skip to content

Commit 6405034

Browse files
committed
[GEM] Extracts cloud_id from elasticsearch-transport into elasticsearch
1 parent 1a39e8e commit 6405034

File tree

4 files changed

+223
-190
lines changed

4 files changed

+223
-190
lines changed

elasticsearch-transport/lib/elasticsearch/transport/client.rb

Lines changed: 8 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,6 @@ class Client
4949
# @since 7.0.0
5050
DEFAULT_HOST = 'localhost:9200'.freeze
5151

52-
# The default port to use if connecting using a Cloud ID.
53-
#
54-
# @since 7.2.0
55-
DEFAULT_CLOUD_PORT = 9243
56-
5752
# The default port to use if not otherwise specified.
5853
#
5954
# @since 7.2.0
@@ -144,13 +139,12 @@ def initialize(arguments = {}, &block)
144139

145140
set_api_key if (@api_key = @arguments[:api_key])
146141

147-
@seeds = extract_cloud_creds(@arguments)
148-
@seeds ||= __extract_hosts(@arguments[:hosts] ||
149-
@arguments[:host] ||
150-
@arguments[:url] ||
151-
@arguments[:urls] ||
152-
ENV['ELASTICSEARCH_URL'] ||
153-
DEFAULT_HOST)
142+
@hosts = __extract_hosts(@arguments[:hosts] ||
143+
@arguments[:host] ||
144+
@arguments[:url] ||
145+
@arguments[:urls] ||
146+
ENV['ELASTICSEARCH_URL'] ||
147+
DEFAULT_HOST)
154148

155149
@send_get_body_as = @arguments[:send_get_body_as] || 'GET'
156150
@opaque_id_prefix = @arguments[:opaque_id_prefix] || nil
@@ -166,13 +160,13 @@ def initialize(arguments = {}, &block)
166160
@transport = if @transport_class == Transport::HTTP::Faraday
167161
@arguments[:adapter] ||= __auto_detect_adapter
168162
set_meta_header # from include MetaHeader
169-
@transport_class.new(hosts: @seeds, options: @arguments) do |faraday|
163+
@transport_class.new(hosts: @hosts, options: @arguments) do |faraday|
170164
faraday.adapter(@arguments[:adapter])
171165
block&.call faraday
172166
end
173167
else
174168
set_meta_header # from include MetaHeader
175-
@transport_class.new(hosts: @seeds, options: @arguments)
169+
@transport_class.new(hosts: @hosts, options: @arguments)
176170
end
177171
end
178172
end
@@ -205,30 +199,6 @@ def add_header(header)
205199
)
206200
end
207201

208-
def extract_cloud_creds(arguments)
209-
return unless arguments[:cloud_id] && !arguments[:cloud_id].empty?
210-
211-
name = arguments[:cloud_id].split(':')[0]
212-
cloud_url, elasticsearch_instance = Base64.decode64(arguments[:cloud_id].gsub("#{name}:", '')).split('$')
213-
214-
if cloud_url.include?(':')
215-
url, port = cloud_url.split(':')
216-
host = "#{elasticsearch_instance}.#{url}"
217-
else
218-
host = "#{elasticsearch_instance}.#{cloud_url}"
219-
port = arguments[:port] || DEFAULT_CLOUD_PORT
220-
end
221-
[
222-
{
223-
scheme: 'https',
224-
user: arguments[:user],
225-
password: arguments[:password],
226-
host: host,
227-
port: port.to_i
228-
}
229-
]
230-
end
231-
232202
# Normalizes and returns hosts configuration.
233203
#
234204
# Arrayifies the `hosts_config` argument and extracts `host` and `port` info from strings.

elasticsearch-transport/spec/elasticsearch/transport/client_spec.rb

Lines changed: 0 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -327,158 +327,6 @@
327327
end
328328
end
329329

330-
context 'when cloud credentials are provided' do
331-
let(:client) do
332-
described_class.new(
333-
cloud_id: 'name:bG9jYWxob3N0JGFiY2QkZWZnaA==',
334-
user: 'elastic',
335-
password: 'changeme'
336-
)
337-
end
338-
339-
let(:hosts) do
340-
client.transport.hosts
341-
end
342-
343-
it 'extracts the cloud credentials' do
344-
expect(hosts[0][:host]).to eq('abcd.localhost')
345-
expect(hosts[0][:protocol]).to eq('https')
346-
expect(hosts[0][:user]).to eq('elastic')
347-
expect(hosts[0][:password]).to eq('changeme')
348-
expect(hosts[0][:port]).to eq(9243)
349-
end
350-
351-
it 'creates the correct full url' do
352-
expect(
353-
client.transport.__full_url(client.transport.hosts[0])
354-
).to eq('https://elastic:[email protected]:9243')
355-
end
356-
357-
context 'when a port is specified' do
358-
let(:client) do
359-
described_class.new(
360-
cloud_id: 'name:bG9jYWxob3N0JGFiY2QkZWZnaA==',
361-
user: 'elastic',
362-
password: 'changeme',
363-
port: 9250
364-
)
365-
end
366-
367-
it 'sets the specified port along with the cloud credentials' do
368-
expect(hosts[0][:host]).to eq('abcd.localhost')
369-
expect(hosts[0][:protocol]).to eq('https')
370-
expect(hosts[0][:user]).to eq('elastic')
371-
expect(hosts[0][:password]).to eq('changeme')
372-
expect(hosts[0][:port]).to eq(9250)
373-
end
374-
375-
it 'creates the correct full url' do
376-
expect(client.transport.__full_url(client.transport.hosts[0])).to eq('https://elastic:[email protected]:9250')
377-
end
378-
end
379-
380-
context 'when the cluster has alternate names' do
381-
let(:client) do
382-
described_class.new(
383-
cloud_id: 'myCluster:bG9jYWxob3N0JGFiY2QkZWZnaA==',
384-
user: 'elasticfantastic',
385-
password: 'tobechanged'
386-
)
387-
end
388-
389-
let(:hosts) do
390-
client.transport.hosts
391-
end
392-
393-
it 'extracts the cloud credentials' do
394-
expect(hosts[0][:host]).to eq('abcd.localhost')
395-
expect(hosts[0][:protocol]).to eq('https')
396-
expect(hosts[0][:user]).to eq('elasticfantastic')
397-
expect(hosts[0][:password]).to eq('tobechanged')
398-
expect(hosts[0][:port]).to eq(9243)
399-
end
400-
401-
it 'creates the correct full url' do
402-
expect(
403-
client.transport.__full_url(client.transport.hosts[0])
404-
).to eq('https://elasticfantastic:[email protected]:9243')
405-
end
406-
end
407-
408-
context 'when decoded cloud id has a trailing dollar sign' do
409-
let(:client) do
410-
described_class.new(
411-
cloud_id: 'a_cluster:bG9jYWxob3N0JGFiY2Qk',
412-
user: 'elasticfantastic',
413-
password: 'changeme'
414-
)
415-
end
416-
417-
let(:hosts) do
418-
client.transport.hosts
419-
end
420-
421-
it 'extracts the cloud credentials' do
422-
expect(hosts[0][:host]).to eq('abcd.localhost')
423-
expect(hosts[0][:protocol]).to eq('https')
424-
expect(hosts[0][:user]).to eq('elasticfantastic')
425-
expect(hosts[0][:password]).to eq('changeme')
426-
expect(hosts[0][:port]).to eq(9243)
427-
end
428-
429-
it 'creates the correct full url' do
430-
expect(
431-
client.transport.__full_url(client.transport.hosts[0])
432-
).to eq('https://elasticfantastic:[email protected]:9243')
433-
end
434-
end
435-
436-
context 'when the cloud host provides a port' do
437-
let(:client) do
438-
described_class.new(
439-
cloud_id: 'name:ZWxhc3RpY19zZXJ2ZXI6OTI0MyRlbGFzdGljX2lk',
440-
user: 'elastic',
441-
password: 'changeme'
442-
)
443-
end
444-
445-
let(:hosts) do
446-
client.transport.hosts
447-
end
448-
449-
it 'creates the correct full url' do
450-
expect(hosts[0][:host]).to eq('elastic_id.elastic_server')
451-
expect(hosts[0][:protocol]).to eq('https')
452-
expect(hosts[0][:user]).to eq('elastic')
453-
expect(hosts[0][:password]).to eq('changeme')
454-
expect(hosts[0][:port]).to eq(9243)
455-
end
456-
end
457-
458-
context 'when the cloud host provides a port and the port is also specified' do
459-
let(:client) do
460-
described_class.new(
461-
cloud_id: 'name:ZWxhc3RpY19zZXJ2ZXI6OTI0MyRlbGFzdGljX2lk',
462-
user: 'elastic',
463-
password: 'changeme',
464-
port: 9200
465-
)
466-
end
467-
468-
let(:hosts) do
469-
client.transport.hosts
470-
end
471-
472-
it 'creates the correct full url' do
473-
expect(hosts[0][:host]).to eq('elastic_id.elastic_server')
474-
expect(hosts[0][:protocol]).to eq('https')
475-
expect(hosts[0][:user]).to eq('elastic')
476-
expect(hosts[0][:password]).to eq('changeme')
477-
expect(hosts[0][:port]).to eq(9243)
478-
end
479-
end
480-
end
481-
482330
shared_examples_for 'a client that extracts hosts' do
483331
context 'when the host is a String' do
484332
context 'when there is a protocol specified' do

elasticsearch/lib/elasticsearch.rb

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,28 @@
2020
require 'elasticsearch/api'
2121

2222
module Elasticsearch
23+
# This is the stateful Elasticsearch::Client, using an instance of elasticsearch-transport.
2324
class Client
2425
include Elasticsearch::API
26+
# The default port to use if connecting using a Cloud ID.
27+
# Updated from 9243 to 443 in client version 7.10.1
28+
#
29+
# @since 7.2.0
30+
DEFAULT_CLOUD_PORT = 443
2531

32+
# Create a client connected to an Elasticsearch cluster.
33+
#
34+
# @option arguments [String] :cloud_id - The Cloud ID to connect to Elastic Cloud
35+
#
2636
def initialize(arguments = {}, &block)
37+
if arguments[:cloud_id]
38+
arguments[:hosts] = setup_cloud_host(
39+
arguments[:cloud_id],
40+
arguments[:user],
41+
arguments[:password],
42+
arguments[:port]
43+
)
44+
end
2745
@transport = Elasticsearch::Transport::Client.new(arguments, &block)
2846
end
2947

@@ -38,9 +56,40 @@ def method_missing(name, *args, &block)
3856
def respond_to_missing?(method_name, *args)
3957
@transport.respond_to?(method_name) || super
4058
end
59+
60+
private
61+
62+
def setup_cloud_host(cloud_id, user, password, port)
63+
name = cloud_id.split(':')[0]
64+
cloud_url, elasticsearch_instance = Base64.decode64(cloud_id.gsub("#{name}:", '')).split('$')
65+
66+
if cloud_url.include?(':')
67+
url, port = cloud_url.split(':')
68+
host = "#{elasticsearch_instance}.#{url}"
69+
else
70+
host = "#{elasticsearch_instance}.#{cloud_url}"
71+
port ||= DEFAULT_CLOUD_PORT
72+
end
73+
[{ scheme: 'https', user: user, password: password, host: host, port: port.to_i }]
74+
end
75+
76+
def set_api_key
77+
@api_key = encode(@api_key) if @api_key.is_a? Hash
78+
add_header('Authorization' => "ApiKey #{@api_key}")
79+
@arguments.delete(:user)
80+
@arguments.delete(:password)
81+
end
82+
83+
# Encode credentials for the Authorization Header
84+
# Credentials is the base64 encoding of id and api_key joined by a colon
85+
# @see https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html
86+
def encode(api_key)
87+
Base64.strict_encode64([api_key[:id], api_key[:api_key]].join(':'))
88+
end
4189
end
4290
end
4391

92+
# Helper for the meta-header value for Cloud
4493
module Elastic
4594
# If the version is X.X.X.pre/alpha/beta, use X.X.Xp for the meta-header:
4695
def self.client_meta_version

0 commit comments

Comments
 (0)