Skip to content

Commit bbd6b5a

Browse files
committed
Support for publish_address as hostname/ip:port (#804)
1 parent 729444c commit bbd6b5a

File tree

6 files changed

+159
-37
lines changed

6 files changed

+159
-37
lines changed

lib/ConnectionPool.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ export default class ConnectionPool {
127127
* @param {object} nodes
128128
* @returns {array} hosts
129129
*/
130-
nodesToHost(nodes: any): any[];
130+
nodesToHost(nodes: any, protocol: string): any[];
131131
/**
132132
* Transforms an url string to a host object
133133
*

lib/ConnectionPool.js

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -332,18 +332,33 @@ class ConnectionPool {
332332
* @param {object} nodes
333333
* @returns {array} hosts
334334
*/
335-
nodesToHost (nodes) {
335+
nodesToHost (nodes, protocol) {
336336
const ids = Object.keys(nodes)
337337
const hosts = []
338338

339339
for (var i = 0, len = ids.length; i < len; i++) {
340340
const node = nodes[ids[i]]
341341
// If there is no protocol in
342-
// the `publish_address` new URL wil throw
342+
// the `publish_address` new URL will throw
343+
// the publish_address can have two forms:
344+
// - ip:port
345+
// - hostname/ip:port
346+
// if we encounter the second case, we should
347+
// use the hostname instead of the ip
343348
var address = node.http.publish_address
349+
const hostAndIpRegex = /^[a-z0-9_.-]*\/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/gi
350+
const match = address.match(hostAndIpRegex)
351+
if (match !== null) {
352+
const ipRegex = /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/
353+
const ip = address.match(ipRegex)[0]
354+
// extract the hostname, the -1 at the end removes the final /
355+
const hostname = address.slice(0, address.indexOf(ip) - 1)
356+
const port = address.split(':')[1]
357+
address = `${hostname}:${port}`
358+
}
344359
address = address.slice(0, 4) === 'http'
345360
? address
346-
: 'http://' + address
361+
: `${protocol}//${address}`
347362
const roles = node.roles.reduce((acc, role) => {
348363
acc[role] = true
349364
return acc

lib/Transport.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,8 @@ class Transport {
353353
}
354354

355355
debug('Sniffing ended successfully', result.body)
356-
const hosts = this.connectionPool.nodesToHost(result.body.nodes)
356+
const protocol = result.meta.connection.url.protocol || 'http:'
357+
const hosts = this.connectionPool.nodesToHost(result.body.nodes, protocol)
357358
this.connectionPool.update(hosts)
358359

359360
result.meta.sniff = { hosts, reason }

test/behavior/sniff.test.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,39 @@ test('Should update the connection pool', t => {
9393
})
9494
})
9595

96+
test('Should handle hostnames in publish_address', t => {
97+
t.plan(10)
98+
99+
buildCluster({ hostPublishAddress: true }, ({ nodes, shutdown }) => {
100+
const client = new Client({
101+
node: nodes[Object.keys(nodes)[0]].url
102+
})
103+
t.strictEqual(client.connectionPool.connections.size, 1)
104+
105+
client.on(events.SNIFF, (err, request) => {
106+
t.error(err)
107+
t.strictEqual(
108+
request.meta.sniff.reason,
109+
Transport.sniffReasons.DEFAULT
110+
)
111+
})
112+
113+
// run the sniffer
114+
client.transport.sniff((err, hosts) => {
115+
t.error(err)
116+
t.strictEqual(hosts.length, 4)
117+
118+
for (var i = 0; i < hosts.length; i++) {
119+
// the first node will be an update of the existing one
120+
t.strictEqual(hosts[i].url.hostname, 'localhost')
121+
}
122+
123+
t.strictEqual(client.connectionPool.connections.size, 4)
124+
})
125+
t.teardown(shutdown)
126+
})
127+
})
128+
96129
test('Sniff interval', t => {
97130
t.plan(10)
98131

test/unit/connection-pool.test.js

Lines changed: 101 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -282,41 +282,112 @@ test('API', t => {
282282
})
283283

284284
t.test('nodesToHost', t => {
285-
const pool = new ConnectionPool({ Connection })
286-
const nodes = {
287-
a1: {
288-
http: {
289-
publish_address: '127.0.0.1:9200'
290-
},
291-
roles: ['master', 'data', 'ingest']
292-
},
293-
a2: {
294-
http: {
295-
publish_address: '127.0.0.1:9202'
285+
t.test('publish_address as ip address', t => {
286+
const pool = new ConnectionPool({ Connection })
287+
const nodes = {
288+
a1: {
289+
http: {
290+
publish_address: '127.0.0.1:9200'
291+
},
292+
roles: ['master', 'data', 'ingest']
296293
},
297-
roles: ['master', 'data', 'ingest']
294+
a2: {
295+
http: {
296+
publish_address: '127.0.0.1:9201'
297+
},
298+
roles: ['master', 'data', 'ingest']
299+
}
298300
}
299-
}
300301

301-
t.deepEqual(pool.nodesToHost(nodes), [{
302-
url: new URL('http://127.0.0.1:9200'),
303-
id: 'a1',
304-
roles: {
305-
master: true,
306-
data: true,
307-
ingest: true,
308-
ml: false
302+
t.deepEqual(pool.nodesToHost(nodes, 'http:'), [{
303+
url: new URL('http://127.0.0.1:9200'),
304+
id: 'a1',
305+
roles: {
306+
master: true,
307+
data: true,
308+
ingest: true,
309+
ml: false
310+
}
311+
}, {
312+
url: new URL('http://127.0.0.1:9201'),
313+
id: 'a2',
314+
roles: {
315+
master: true,
316+
data: true,
317+
ingest: true,
318+
ml: false
319+
}
320+
}])
321+
322+
t.strictEqual(pool.nodesToHost(nodes, 'http:')[0].url.host, '127.0.0.1:9200')
323+
t.strictEqual(pool.nodesToHost(nodes, 'http:')[1].url.host, '127.0.0.1:9201')
324+
t.end()
325+
})
326+
327+
t.test('publish_address as host/ip', t => {
328+
const pool = new ConnectionPool({ Connection })
329+
const nodes = {
330+
a1: {
331+
http: {
332+
publish_address: 'example.com/127.0.0.1:9200'
333+
},
334+
roles: ['master', 'data', 'ingest']
335+
},
336+
a2: {
337+
http: {
338+
publish_address: 'example.com/127.0.0.1:9201'
339+
},
340+
roles: ['master', 'data', 'ingest']
341+
}
309342
}
310-
}, {
311-
url: new URL('http://127.0.0.1:9201'),
312-
id: 'a2',
313-
roles: {
314-
master: true,
315-
data: true,
316-
ingest: true,
317-
ml: false
343+
344+
t.deepEqual(pool.nodesToHost(nodes, 'http:'), [{
345+
url: new URL('http://example.com:9200'),
346+
id: 'a1',
347+
roles: {
348+
master: true,
349+
data: true,
350+
ingest: true,
351+
ml: false
352+
}
353+
}, {
354+
url: new URL('http://example.com:9201'),
355+
id: 'a2',
356+
roles: {
357+
master: true,
358+
data: true,
359+
ingest: true,
360+
ml: false
361+
}
362+
}])
363+
364+
t.strictEqual(pool.nodesToHost(nodes, 'http:')[0].url.host, 'example.com:9200')
365+
t.strictEqual(pool.nodesToHost(nodes, 'http:')[1].url.host, 'example.com:9201')
366+
t.end()
367+
})
368+
369+
t.test('Should use the configure protocol', t => {
370+
const pool = new ConnectionPool({ Connection })
371+
const nodes = {
372+
a1: {
373+
http: {
374+
publish_address: 'example.com/127.0.0.1:9200'
375+
},
376+
roles: ['master', 'data', 'ingest']
377+
},
378+
a2: {
379+
http: {
380+
publish_address: 'example.com/127.0.0.1:9201'
381+
},
382+
roles: ['master', 'data', 'ingest']
383+
}
318384
}
319-
}])
385+
386+
t.strictEqual(pool.nodesToHost(nodes, 'https:')[0].url.protocol, 'https:')
387+
t.strictEqual(pool.nodesToHost(nodes, 'http:')[1].url.protocol, 'http:')
388+
t.end()
389+
})
390+
320391
t.end()
321392
})
322393

test/utils/buildCluster.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,14 @@ function buildCluster (options, callback) {
5353

5454
buildServer(options.handler || handler, ({ port }, server) => {
5555
nodes[opts.id] = {
56-
url: `http://localhost:${port}`,
56+
url: `http://127.0.0.1:${port}`,
5757
server
5858
}
5959
sniffResult.nodes[opts.id] = {
6060
http: {
61-
publish_address: `http://localhost:${port}`
61+
publish_address: options.hostPublishAddress
62+
? `localhost/127.0.0.1:${port}`
63+
: `127.0.0.1:${port}`
6264
},
6365
roles: ['master', 'data', 'ingest']
6466
}

0 commit comments

Comments
 (0)