Fix sniffing for 5.0

Fixes #477
This commit is contained in:
Honza Král
2016-12-06 12:17:57 +01:00
parent 594f194bff
commit fe53ab588e
2 changed files with 35 additions and 70 deletions
+6 -15
View File
@@ -22,12 +22,8 @@ def get_host_info(node_info, host):
:arg node_info: node information from `/_cluster/nodes` :arg node_info: node information from `/_cluster/nodes`
:arg host: connection information (host, port) extracted from the node info :arg host: connection information (host, port) extracted from the node info
""" """
attrs = node_info.get('attributes', {})
# ignore master only nodes # ignore master only nodes
if (attrs.get('data', 'true') == 'false' and if node_info.get('roles', []) == ['master']:
attrs.get('client', 'false') == 'false' and
attrs.get('master', 'true') == 'true'):
return None return None
return host return host
@@ -203,7 +199,8 @@ class Transport(object):
for c in chain(self.connection_pool.connections, self.seed_connections): for c in chain(self.connection_pool.connections, self.seed_connections):
try: try:
# use small timeout for the sniffing request, should be a fast api call # use small timeout for the sniffing request, should be a fast api call
_, headers, node_info = c.perform_request('GET', '/_nodes/_all/clear', _, headers, node_info = c.perform_request(
'GET', '/_nodes/_all/http',
timeout=self.sniff_timeout if not initial else None) timeout=self.sniff_timeout if not initial else None)
node_info = self.deserializer.loads(node_info, headers.get('content-type')) node_info = self.deserializer.loads(node_info, headers.get('content-type'))
break break
@@ -219,21 +216,15 @@ class Transport(object):
return list(node_info['nodes'].values()) return list(node_info['nodes'].values())
def _get_host_info(self, host_info): def _get_host_info(self, host_info):
address_key = self.connection_class.transport_schema + '_address'
host = {} host = {}
address = host_info.get(address_key, '') address = host_info.get('http', {}).get('publish_address')
if '/' in address:
host['host'], address = address.split('/', 1)
# malformed address # malformed address
if ':' not in address: if ':' not in address:
return None return None
ip, port = address.rsplit(':', 1) host['host'], host['port'] = address.rsplit(':', 1)
host['port'] = int(host['port'])
# use the ip if not overridden by publish_host
host.setdefault('host', ip)
host['port'] = int(port)
return self.host_info_callback(host_info, host) return self.host_info_callback(host_info, host)
+24 -50
View File
@@ -24,52 +24,41 @@ class DummyConnection(Connection):
return self.status, self.headers, self.data return self.status, self.headers, self.data
CLUSTER_NODES = '''{ CLUSTER_NODES = '''{
"ok" : true, "_nodes" : {
"cluster_name" : "super_cluster", "total" : 1,
"successful" : 1,
"failed" : 0
},
"cluster_name" : "elasticsearch",
"nodes" : { "nodes" : {
"wE_6OGBNSjGksbONNncIbg" : { "SRZpKFZdQguhhvifmN6UVA" : {
"name" : "Nightwind", "name" : "SRZpKFZ",
"transport_address" : "127.0.0.1:9300", "transport_address" : "127.0.0.1:9300",
"hostname" : "wind", "host" : "127.0.0.1",
"version" : "0.20.4", "ip" : "127.0.0.1",
"http_address" : "1.1.1.1:123", "version" : "5.0.0",
"thrift_address" : "1.1.1.1:9500" "build_hash" : "253032b",
} "roles" : [ "master", "data", "ingest" ],
} "http" : {
}''' "bound_address" : [ "[fe80::1]:9200", "[::1]:9200", "127.0.0.1:9200" ],
"publish_address" : "1.1.1.1:123",
CLUSTER_NODE_PUBLISH_HOST = '''{ "max_content_length_in_bytes" : 104857600
"ok" : true,
"cluster_name" : "super_cluster",
"nodes" : {
"wE_6OGBNSjGksbONNncIbg" : {
"name": "Thunderbird",
"transport_address": "obsidian/192.168.1.60:9300",
"host": "192.168.1.60",
"ip": "192.168.1.60",
"version": "2.1.0",
"build": "72cd1f1",
"http_address": "obsidian/192.168.1.60:9200",
"attributes": {
"testattr": "test"
} }
} }
} }
}''' }'''
class TestHostsInfoCallback(TestCase): class TestHostsInfoCallback(TestCase):
def test_master_only_nodes_are_ignored(self): def test_master_only_nodes_are_ignored(self):
nodes = [ nodes = [
{'attributes': {'data': 'false', 'client': 'true'}}, {'roles': [ "master"]},
{'attributes': {'data': 'false'}}, {'roles': [ "master", "data", "ingest"]},
{'attributes': {'data': 'false', 'master': 'true'}}, {'roles': [ "data", "ingest"]},
{'attributes': {'data': 'false', 'master': 'false'}}, {'roles': [ ]},
{'attributes': {}},
{} {}
] ]
chosen = [i for i, node_info in enumerate(nodes) if get_host_info(node_info, i) is not None] chosen = [i for i, node_info in enumerate(nodes) if get_host_info(node_info, i) is not None]
self.assertEquals([0, 3, 4, 5], chosen) self.assertEquals([1, 2, 3, 4], chosen)
class TestTransport(TestCase): class TestTransport(TestCase):
@@ -175,21 +164,6 @@ class TestTransport(TestCase):
self.assertEquals(1, len(t.connection_pool.connections)) self.assertEquals(1, len(t.connection_pool.connections))
self.assertEquals('http://1.1.1.1:123', t.get_connection().host) self.assertEquals('http://1.1.1.1:123', t.get_connection().host)
def test_sniff_will_pick_up_published_host(self):
t = Transport([{'data': CLUSTER_NODE_PUBLISH_HOST}], connection_class=DummyConnection)
t.sniff_hosts()
self.assertEquals(1, len(t.connection_pool.connections))
self.assertEquals('http://obsidian:9200', t.get_connection().host)
def test_sniff_on_start_fetches_and_uses_nodes_list_for_its_schema(self):
class DummyThriftConnection(DummyConnection):
transport_schema = 'thrift'
t = Transport([{'data': CLUSTER_NODES}], connection_class=DummyThriftConnection, sniff_on_start=True)
self.assertEquals(1, len(t.connection_pool.connections))
self.assertEquals('thrift://1.1.1.1:9500', t.get_connection().host)
def test_sniff_on_start_fetches_and_uses_nodes_list(self): def test_sniff_on_start_fetches_and_uses_nodes_list(self):
t = Transport([{'data': CLUSTER_NODES}], connection_class=DummyConnection, sniff_on_start=True) t = Transport([{'data': CLUSTER_NODES}], connection_class=DummyConnection, sniff_on_start=True)
self.assertEquals(1, len(t.connection_pool.connections)) self.assertEquals(1, len(t.connection_pool.connections))
@@ -197,12 +171,12 @@ class TestTransport(TestCase):
def test_sniff_on_start_ignores_sniff_timeout(self): def test_sniff_on_start_ignores_sniff_timeout(self):
t = Transport([{'data': CLUSTER_NODES}], connection_class=DummyConnection, sniff_on_start=True, sniff_timeout=12) t = Transport([{'data': CLUSTER_NODES}], connection_class=DummyConnection, sniff_on_start=True, sniff_timeout=12)
self.assertEquals((('GET', '/_nodes/_all/clear'), {'timeout': None}), t.seed_connections[0].calls[0]) self.assertEquals((('GET', '/_nodes/_all/http'), {'timeout': None}), t.seed_connections[0].calls[0])
def test_sniff_uses_sniff_timeout(self): def test_sniff_uses_sniff_timeout(self):
t = Transport([{'data': CLUSTER_NODES}], connection_class=DummyConnection, sniff_timeout=42) t = Transport([{'data': CLUSTER_NODES}], connection_class=DummyConnection, sniff_timeout=42)
t.sniff_hosts() t.sniff_hosts()
self.assertEquals((('GET', '/_nodes/_all/clear'), {'timeout': 42}), t.seed_connections[0].calls[0]) self.assertEquals((('GET', '/_nodes/_all/http'), {'timeout': 42}), t.seed_connections[0].calls[0])
def test_sniff_reuses_connection_instances_if_possible(self): def test_sniff_reuses_connection_instances_if_possible(self):