Skip to content

Commit

Permalink
[CLIENT] Update handling of publish_address in _nodes/http response
Browse files Browse the repository at this point in the history
  • Loading branch information
estolfo committed Apr 12, 2019
1 parent 2fe716e commit 53f37cb
Show file tree
Hide file tree
Showing 3 changed files with 294 additions and 198 deletions.
27 changes: 25 additions & 2 deletions lib/elasticsearch/transport/transport/sniffer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ def hosts
Timeout::timeout(timeout, SnifferTimeoutError) do
nodes = transport.perform_request('GET', '_nodes/http').body

hosts = nodes['nodes'].map do |id,info|
hosts = nodes['nodes'].map do |id, info|
if info[PROTOCOL]
host, port = info[PROTOCOL]['publish_address'].split(':')
host, port = parse_publish_address(info[PROTOCOL]['publish_address'])

{ :id => id,
:name => info['name'],
Expand All @@ -65,6 +65,29 @@ def hosts
hosts
end
end

private

def parse_publish_address(publish_address)
# publish_address is in the format hostname/ip:port
if publish_address =~ /\//
parts = publish_address.partition('/')
[ parts[0], parse_address_port(parts[2])[1] ]
else
parse_address_port(publish_address)
end
end

def parse_address_port(publish_address)
# address is ipv6
if publish_address =~ /[\[\]]/
if parts = publish_address.match(/\A\[(.+)\](?::(\d+))?\z/)
[ parts[1], parts[2] ]
end
else
publish_address.split(':')
end
end
end
end
end
Expand Down
269 changes: 269 additions & 0 deletions spec/elasticsearch/transport/sniffer_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
# Licensed to Elasticsearch B.V. under one or more contributor
# license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright
# ownership. Elasticsearch B.V. licenses this file to you under
# the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

require 'spec_helper'

describe Elasticsearch::Transport::Transport::Sniffer do

let(:transport) do
double('transport').tap do |t|
allow(t).to receive(:perform_request).and_return(response)
allow(t).to receive(:options).and_return(sniffer_timeout: 2)
end
end

let(:sniffer) do
described_class.new(transport)
end

let(:response) do
double('response').tap do |r|
allow(r).to receive(:body).and_return(raw_response)
end
end

let(:raw_response) do
{ 'nodes' => { 'n1' => { 'http' => { 'publish_address' => publish_address } } } }
end

let(:publish_address) do
'127.0.0.1:9250'
end

describe '#initialize' do

it 'has a transport instance' do
expect(sniffer.transport).to be(transport)
end

it 'inherits the sniffer timeout from the transport object' do
expect(sniffer.timeout).to eq(2)
end
end

describe '#timeout' do

let(:sniffer) do
described_class.new(double('transport', options: {}))
end

before do
sniffer.timeout = 3
end

it 'allows the timeout to be configured' do
expect(sniffer.timeout).to eq(3)
end
end

describe '#hosts' do

let(:hosts) do
sniffer.hosts
end

context 'when the entire response is parsed' do

let(:raw_response) do
{
"cluster_name" => "elasticsearch_test",
"nodes" => {
"N1" => {
"name" => "Node 1",
"transport_address" => "127.0.0.1:9300",
"host" => "testhost1",
"ip" => "127.0.0.1",
"version" => "7.0.0",
"roles" => [
"master",
"data",
"ingest"
],
"attributes" => {
"testattr" => "test"
},
"http" => {
"bound_address" => [
"[fe80::1]:9250",
"[::1]:9250",
"127.0.0.1:9250"
],
"publish_address" => "127.0.0.1:9250",
"max_content_length_in_bytes" => 104857600
}
}
}
}
end

it 'parses the id' do
expect(sniffer.hosts[0][:id]).to eq('N1')
end

it 'parses the name' do
expect(sniffer.hosts[0][:name]).to eq('Node 1')
end

it 'parses the version' do
expect(sniffer.hosts[0][:version]).to eq('7.0.0')
end

it 'parses the host' do
expect(sniffer.hosts[0][:host]).to eq('127.0.0.1')
end

it 'parses the port' do
expect(sniffer.hosts[0][:port]).to eq('9250')
end

it 'parses the roles' do
expect(sniffer.hosts[0][:roles]).to eq(['master',
'data',
'ingest'])
end

it 'parses the attributes' do
expect(sniffer.hosts[0][:attributes]).to eq('testattr' => 'test')
end
end

context 'when the transport protocol does not match' do

let(:raw_response) do
{ 'nodes' => { 'n1' => { 'foo' => { 'publish_address' => '127.0.0.1:9250' } } } }
end

it 'does not parse the addresses' do
expect(hosts).to eq([])
end
end

context 'when a list of nodes is returned' do

let(:raw_response) do
{ 'nodes' => { 'n1' => { 'http' => { 'publish_address' => '127.0.0.1:9250' } },
'n2' => { 'http' => { 'publish_address' => '127.0.0.1:9251' } } } }
end

it 'parses the response' do
expect(hosts.size).to eq(2)
end

it 'correctly parses the hosts' do
expect(hosts[0][:host]).to eq('127.0.0.1')
expect(hosts[1][:host]).to eq('127.0.0.1')
end

it 'correctly parses the ports' do
expect(hosts[0][:port]).to eq('9250')
expect(hosts[1][:port]).to eq('9251')
end
end

context 'when the host and port are an ip address and port' do

it 'parses the response' do
expect(hosts.size).to eq(1)
end

it 'correctly parses the host' do
expect(hosts[0][:host]).to eq('127.0.0.1')
end

it 'correctly parses the port' do
expect(hosts[0][:port]).to eq('9250')
end
end

context 'when the host and port are a hostname and port' do

let(:publish_address) do
'testhost1.com:9250'
end

let(:hosts) do
sniffer.hosts
end

it 'parses the response' do
expect(hosts.size).to eq(1)
end

it 'correctly parses the host' do
expect(hosts[0][:host]).to eq('testhost1.com')
end

it 'correctly parses the port' do
expect(hosts[0][:port]).to eq('9250')
end
end

context 'when the host and port are in the format: hostname/ip:port' do

let(:publish_address) do
'example.com/127.0.0.1:9250'
end

it 'parses the response' do
expect(hosts.size).to eq(1)
end

it 'uses the hostname' do
expect(hosts[0][:host]).to eq('example.com')
end

it 'correctly parses the port' do
expect(hosts[0][:port]).to eq('9250')
end
end

context 'when the address is IPv6' do

let(:publish_address) do
'[::1]:9250'
end

it 'parses the response' do
expect(hosts.size).to eq(1)
end

it 'correctly parses the host' do
expect(hosts[0][:host]).to eq('::1')
end

it 'correctly parses the port' do
expect(hosts[0][:port]).to eq('9250')
end
end

context 'when the transport has :randomize_hosts option' do

let(:raw_response) do
{ 'nodes' => { 'n1' => { 'http' => { 'publish_address' => '127.0.0.1:9250' } },
'n2' => { 'http' => { 'publish_address' => '127.0.0.1:9251' } } } }
end

before do
allow(transport).to receive(:options).and_return(randomize_hosts: true)
end

it 'shuffles the list' do
expect(hosts.size).to eq(2)
end
end
end
end
Loading

0 comments on commit 53f37cb

Please sign in to comment.