Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4466461828 | |||
| 66fd94643d | |||
| 39bbd77bec | |||
| a4f893d563 | |||
| 6707a8603e | |||
| a38e89aa04 | |||
| 0311ce9e42 | |||
| 2e90d5b55e | |||
| 32836b4f6c | |||
| f8034c60bc | |||
| c68a5ce9a2 | |||
| 554bb1ff05 |
@ -8,7 +8,7 @@ The client is designed to be easily configured as you see fit for your needs, fo
|
||||
const { Client } = require('@elastic/elasticsearch')
|
||||
|
||||
const client = new Client({
|
||||
node: 'http://localhost:9200'
|
||||
node: 'http://localhost:9200',
|
||||
maxRetries: 5,
|
||||
requestTimeout: 60000,
|
||||
sniffOnStart: true
|
||||
@ -150,6 +150,26 @@ function generateRequestId (params, options) {
|
||||
|`name`
|
||||
|`string` - The name to identify the client instance in the events. +
|
||||
_Default:_ `elasticsearch-js`
|
||||
|
||||
|`headers`
|
||||
|`object` - A set of custom headers to send in every request. +
|
||||
_Default:_ `{}`
|
||||
|
||||
|`cloud`
|
||||
a|`object` - Custom configuration for connecting to https://cloud.elastic.co[Elastic Cloud]. See https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/auth-reference.html[Authentication] for more details. +
|
||||
_Default:_ `null` +
|
||||
_Cloud configuration example:_
|
||||
[source,js]
|
||||
----
|
||||
const client = new Client({
|
||||
cloud: {
|
||||
id: 'name:bG9jYWxob3N0JGFiY2QkZWZnaA==',
|
||||
username: 'elastic',
|
||||
password: 'changeme'
|
||||
}
|
||||
})
|
||||
----
|
||||
|
||||
|===
|
||||
|
||||
=== Advanced configuration
|
||||
|
||||
@ -59,7 +59,7 @@ async function run (): void {
|
||||
client
|
||||
.search(params)
|
||||
.then((result: ApiResponse) => {
|
||||
console.og(result.body.hits.hits)
|
||||
console.log(result.body.hits.hits)
|
||||
})
|
||||
.catch((err: Error) => {
|
||||
console.log(err)
|
||||
|
||||
22
index.d.ts
vendored
22
index.d.ts
vendored
@ -20,7 +20,7 @@
|
||||
/// <reference types="node" />
|
||||
|
||||
import { EventEmitter } from 'events';
|
||||
import { SecureContextOptions } from 'tls';
|
||||
import { ConnectionOptions as TlsConnectionOptions } from 'tls';
|
||||
import Transport, {
|
||||
ApiResponse,
|
||||
RequestEvent,
|
||||
@ -31,6 +31,7 @@ import Transport, {
|
||||
generateRequestIdFn,
|
||||
TransportRequestCallback
|
||||
} from './lib/Transport';
|
||||
import { URL } from 'url';
|
||||
import Connection, { AgentOptions, agentFn } from './lib/Connection';
|
||||
import ConnectionPool, { ResurrectEvent } from './lib/ConnectionPool';
|
||||
import Serializer from './lib/Serializer';
|
||||
@ -72,8 +73,22 @@ interface ClientExtends {
|
||||
}
|
||||
// /Extend API
|
||||
|
||||
interface NodeOptions {
|
||||
url: URL;
|
||||
id?: string;
|
||||
agent?: AgentOptions;
|
||||
ssl?: TlsConnectionOptions;
|
||||
headers?: anyObject;
|
||||
roles?: {
|
||||
master: boolean;
|
||||
data: boolean;
|
||||
ingest: boolean;
|
||||
ml: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
interface ClientOptions {
|
||||
node?: string | string[];
|
||||
node?: string | string[] | NodeOptions | NodeOptions[];
|
||||
nodes?: string | string[];
|
||||
Connection?: typeof Connection;
|
||||
ConnectionPool?: typeof ConnectionPool;
|
||||
@ -89,7 +104,7 @@ interface ClientOptions {
|
||||
resurrectStrategy?: 'ping' | 'optimistic' | 'none';
|
||||
suggestCompression?: boolean;
|
||||
compression?: 'gzip';
|
||||
ssl?: SecureContextOptions;
|
||||
ssl?: TlsConnectionOptions;
|
||||
agent?: AgentOptions | agentFn;
|
||||
nodeFilter?: nodeFilterFn;
|
||||
nodeSelector?: nodeSelectorFn | string;
|
||||
@ -327,5 +342,6 @@ export {
|
||||
ResurrectEvent,
|
||||
RequestParams,
|
||||
ClientOptions,
|
||||
NodeOptions,
|
||||
ClientExtendsCallbackOptions
|
||||
};
|
||||
|
||||
6
lib/Connection.d.ts
vendored
6
lib/Connection.d.ts
vendored
@ -22,13 +22,13 @@
|
||||
import { URL } from 'url';
|
||||
import { inspect, InspectOptions } from 'util';
|
||||
import * as http from 'http';
|
||||
import { SecureContextOptions } from 'tls';
|
||||
import { ConnectionOptions as TlsConnectionOptions } from 'tls';
|
||||
|
||||
export declare type agentFn = () => any;
|
||||
|
||||
interface ConnectionOptions {
|
||||
url: URL;
|
||||
ssl?: SecureContextOptions;
|
||||
ssl?: TlsConnectionOptions;
|
||||
id?: string;
|
||||
headers?: any;
|
||||
agent?: AgentOptions | agentFn;
|
||||
@ -59,7 +59,7 @@ export default class Connection {
|
||||
ML: string;
|
||||
};
|
||||
url: URL;
|
||||
ssl: SecureContextOptions | null;
|
||||
ssl: TlsConnectionOptions | null;
|
||||
id: string;
|
||||
headers: any;
|
||||
deadCount: number;
|
||||
|
||||
@ -35,6 +35,7 @@ class Connection {
|
||||
this.ssl = opts.ssl || null
|
||||
this.id = opts.id || stripAuth(opts.url.href)
|
||||
this.headers = opts.headers || null
|
||||
this.auth = opts.auth || { username: null, password: null }
|
||||
this.deadCount = 0
|
||||
this.resurrectTimeout = 0
|
||||
|
||||
@ -180,6 +181,7 @@ class Connection {
|
||||
|
||||
buildRequestObject (params) {
|
||||
const url = this.url
|
||||
const { username, password } = this.auth
|
||||
const request = {
|
||||
protocol: url.protocol,
|
||||
hostname: url.hostname[0] === '['
|
||||
@ -194,8 +196,8 @@ class Connection {
|
||||
// https://github.com/elastic/elasticsearch-js/issues/843
|
||||
port: url.port !== '' ? url.port : undefined,
|
||||
headers: this.headers,
|
||||
auth: !!url.username === true || !!url.password === true
|
||||
? `${url.username}:${url.password}`
|
||||
auth: username != null && password != null
|
||||
? `${username}:${password}`
|
||||
: undefined,
|
||||
agent: this.agent
|
||||
}
|
||||
@ -224,12 +226,12 @@ class Connection {
|
||||
}
|
||||
|
||||
// Handles console.log and utils.inspect invocations.
|
||||
// We want to hide `agent` and `ssl` since they made
|
||||
// We want to hide `auth`, `agent` and `ssl` since they made
|
||||
// the logs very hard to read. The user can still
|
||||
// access them with `instance.agent` and `instance.ssl`.
|
||||
[inspect.custom] (depth, options) {
|
||||
return {
|
||||
url: this.url,
|
||||
url: stripAuth(this.url.toString()),
|
||||
id: this.id,
|
||||
headers: this.headers,
|
||||
deadCount: this.deadCount,
|
||||
@ -242,7 +244,7 @@ class Connection {
|
||||
|
||||
toJSON () {
|
||||
return {
|
||||
url: this.url,
|
||||
url: stripAuth(this.url.toString()),
|
||||
id: this.id,
|
||||
headers: this.headers,
|
||||
deadCount: this.deadCount,
|
||||
|
||||
@ -222,21 +222,24 @@ class ConnectionPool {
|
||||
// we can add it to them once the connection instance has been created
|
||||
if (opts.url.username !== '' && opts.url.password !== '') {
|
||||
this._auth = {
|
||||
username: opts.url.username,
|
||||
password: opts.url.password
|
||||
username: decodeURIComponent(opts.url.username),
|
||||
password: decodeURIComponent(opts.url.password)
|
||||
}
|
||||
opts.auth = this._auth
|
||||
}
|
||||
|
||||
if (this._auth != null) {
|
||||
if (opts.auth == null || (opts.auth.username == null && opts.auth.password == null)) {
|
||||
opts.auth = this._auth
|
||||
opts.url.username = this._auth.username
|
||||
opts.url.password = this._auth.password
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.ssl == null) opts.ssl = this._ssl
|
||||
if (opts.agent == null) opts.agent = this._agent
|
||||
|
||||
const connection = new this.Connection(opts)
|
||||
if (connection.url.username === '' &&
|
||||
connection.url.password === '' &&
|
||||
this._auth != null) {
|
||||
connection.url.username = this._auth.username
|
||||
connection.url.password = this._auth.password
|
||||
}
|
||||
|
||||
debug('Adding a new connection', connection)
|
||||
if (this.connections.has(connection.id)) {
|
||||
throw new Error(`Connection with id '${connection.id}' is already present`)
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
"main": "index.js",
|
||||
"types": "index.d.ts",
|
||||
"homepage": "http://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/index.html",
|
||||
"version": "5.6.17",
|
||||
"version": "5.6.19",
|
||||
"keywords": [
|
||||
"elasticsearch",
|
||||
"elastic",
|
||||
|
||||
@ -35,12 +35,12 @@ const {
|
||||
} = require('./utils')
|
||||
|
||||
start(minimist(process.argv.slice(2), {
|
||||
string: ['tag']
|
||||
string: ['tag', 'branch']
|
||||
}))
|
||||
|
||||
function start (opts) {
|
||||
const log = ora('Loading Elasticsearch Repository').start()
|
||||
if (semver.valid(opts.tag) === null) {
|
||||
if (opts.branch == null && semver.valid(opts.tag) === null) {
|
||||
log.fail(`Missing or invalid tag: ${opts.tag}`)
|
||||
return
|
||||
}
|
||||
@ -55,7 +55,7 @@ function start (opts) {
|
||||
log.text = 'Cleaning API folder...'
|
||||
rimraf.sync(join(apiOutputFolder, '*.js'))
|
||||
|
||||
cloneAndCheckout({ log, tag: opts.tag }, (err, { apiFolder, xPackFolder }) => {
|
||||
cloneAndCheckout({ log, tag: opts.tag, branch: opts.branch }, (err, { apiFolder, xPackFolder }) => {
|
||||
if (err) {
|
||||
log.fail(err.message)
|
||||
return
|
||||
@ -74,7 +74,7 @@ function start (opts) {
|
||||
|
||||
writeFileSync(
|
||||
requestParamsOutputFile,
|
||||
generateRequestTypes(allSpec),
|
||||
generateRequestTypes(opts.branch || opts.tag, allSpec),
|
||||
{ encoding: 'utf8' }
|
||||
)
|
||||
|
||||
@ -118,7 +118,7 @@ function start (opts) {
|
||||
|
||||
const spec = require(join(apiFolder, file))
|
||||
allSpec.push(spec)
|
||||
const code = generate(spec, common)
|
||||
const code = generate(opts.branch || opts.tag, spec, common)
|
||||
const filePath = join(apiOutputFolder, `${file.slice(0, file.lastIndexOf('.'))}.js`)
|
||||
|
||||
writeFileSync(filePath, code, { encoding: 'utf8' })
|
||||
|
||||
@ -29,7 +29,7 @@ const apiFolder = join(esFolder, 'rest-api-spec', 'src', 'main', 'resources', 'r
|
||||
const xPackFolder = join(esFolder, 'x-pack', 'plugin', 'src', 'test', 'resources', 'rest-api-spec', 'api')
|
||||
|
||||
function cloneAndCheckout (opts, callback) {
|
||||
const { log, tag } = opts
|
||||
const { log, tag, branch } = opts
|
||||
withTag(tag, callback)
|
||||
|
||||
/**
|
||||
@ -57,13 +57,19 @@ function cloneAndCheckout (opts, callback) {
|
||||
|
||||
if (fresh) {
|
||||
clone(checkout)
|
||||
} else if (opts.branch) {
|
||||
checkout(true)
|
||||
} else {
|
||||
checkout()
|
||||
}
|
||||
|
||||
function checkout () {
|
||||
log.text = `Checking out tag '${tag}'`
|
||||
git.checkout(tag, err => {
|
||||
function checkout (alsoPull = false) {
|
||||
if (branch) {
|
||||
log.text = `Checking out branch '${branch}'`
|
||||
} else {
|
||||
log.text = `Checking out tag '${tag}'`
|
||||
}
|
||||
git.checkout(branch || tag, err => {
|
||||
if (err) {
|
||||
if (retry++ > 0) {
|
||||
callback(new Error(`Cannot checkout tag '${tag}'`), { apiFolder, xPackFolder })
|
||||
@ -71,6 +77,9 @@ function cloneAndCheckout (opts, callback) {
|
||||
}
|
||||
return pull(checkout)
|
||||
}
|
||||
if (alsoPull) {
|
||||
return pull(checkout)
|
||||
}
|
||||
callback(null, { apiFolder, xPackFolder })
|
||||
})
|
||||
}
|
||||
|
||||
@ -20,11 +20,16 @@
|
||||
'use strict'
|
||||
|
||||
const dedent = require('dedent')
|
||||
const semver = require('semver')
|
||||
const allowedMethods = {
|
||||
noBody: ['GET', 'HEAD', 'DELETE'],
|
||||
body: ['POST', 'PUT', 'DELETE']
|
||||
}
|
||||
|
||||
// if a parameter is depracted in a minor release
|
||||
// we should be able to support it until the next major
|
||||
const deprecatedParameters = require('./patch.json')
|
||||
|
||||
// list of apis that does not need any kind of validation
|
||||
// because of how the url is built or the `type` handling in ES7
|
||||
const noPathValidation = [
|
||||
@ -59,7 +64,8 @@ const ndjsonApi = [
|
||||
'xpack.monitoring.bulk'
|
||||
]
|
||||
|
||||
function generate (spec, common) {
|
||||
function generate (version, spec, common) {
|
||||
const release = semver.valid(version) ? semver.major(version) : version
|
||||
const api = Object.keys(spec)[0]
|
||||
const name = api
|
||||
.replace(/\.([a-z])/g, k => k[1].toUpperCase())
|
||||
@ -80,7 +86,11 @@ function generate (spec, common) {
|
||||
if (params[key].required) {
|
||||
required.push(key)
|
||||
}
|
||||
|
||||
acceptedQuerystring.push(key)
|
||||
if (deprecatedParameters[release] && deprecatedParameters[release][key]) {
|
||||
acceptedQuerystring.push(deprecatedParameters[release][key])
|
||||
}
|
||||
}
|
||||
|
||||
for (const key in spec[api]) {
|
||||
|
||||
@ -19,7 +19,11 @@
|
||||
|
||||
'use strict'
|
||||
|
||||
function generate (api) {
|
||||
const semver = require('semver')
|
||||
const deprecatedParameters = require('./patch.json')
|
||||
|
||||
function generate (version, api) {
|
||||
const release = semver.valid(version) ? semver.major(version) : version
|
||||
var types = `/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
@ -64,9 +68,20 @@ export interface Generic {
|
||||
|
||||
const partsArr = Object.keys(parts)
|
||||
.map(k => ({ key: k, value: parts[k] }))
|
||||
const deprecatedParametersToAdd = []
|
||||
const paramsArr = Object.keys(params)
|
||||
.filter(k => !Object.keys(parts).includes(k))
|
||||
.map(k => ({ key: k, value: params[k] }))
|
||||
.map(k => {
|
||||
if (deprecatedParameters[release] && deprecatedParameters[release][k]) {
|
||||
deprecatedParametersToAdd.push({
|
||||
key: deprecatedParameters[release][k],
|
||||
value: params[k]
|
||||
})
|
||||
}
|
||||
return { key: k, value: params[k] }
|
||||
})
|
||||
|
||||
deprecatedParametersToAdd.forEach(k => partsArr.push(k))
|
||||
|
||||
const genLine = e => {
|
||||
const optional = e.value.required ? '' : '?'
|
||||
|
||||
14
scripts/utils/patch.json
Normal file
14
scripts/utils/patch.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"6": {
|
||||
"_source_includes": "_source_include",
|
||||
"_source_excludes": "_source_exclude"
|
||||
},
|
||||
"7": {
|
||||
"_source_includes": "_source_include",
|
||||
"_source_excludes": "_source_exclude"
|
||||
},
|
||||
"master": {
|
||||
"_source_includes": "_source_include",
|
||||
"_source_excludes": "_source_exclude"
|
||||
}
|
||||
}
|
||||
@ -27,13 +27,29 @@ import {
|
||||
ResurrectEvent,
|
||||
events,
|
||||
errors,
|
||||
ClientExtendsCallbackOptions
|
||||
ClientExtendsCallbackOptions,
|
||||
NodeOptions
|
||||
} from '../../index'
|
||||
|
||||
import { TransportRequestParams, TransportRequestOptions } from '../../lib/Transport'
|
||||
import { URL } from 'url'
|
||||
|
||||
const client = new Client({ node: 'http://localhost:9200' })
|
||||
|
||||
const nodeOpts: NodeOptions = {
|
||||
url: new URL('http://localhost:9200'),
|
||||
id: 'winteriscoming',
|
||||
headers: { 'foo': 'bar' },
|
||||
roles: {
|
||||
master: false,
|
||||
data: true,
|
||||
ingest: false,
|
||||
ml: false
|
||||
}
|
||||
}
|
||||
|
||||
const client2 = new Client({ node: nodeOpts })
|
||||
|
||||
client.on(events.RESPONSE, (err: errors.ElasticsearchClientError | null, request: RequestEvent) => {
|
||||
if (err) console.log(err)
|
||||
const { body, statusCode } = request
|
||||
|
||||
@ -61,8 +61,23 @@ test('API', t => {
|
||||
t.deepEqual(pool._auth, { username: 'foo', password: 'bar' })
|
||||
|
||||
pool.addConnection('http://localhost:9201')
|
||||
t.strictEqual(pool.connections.get('http://localhost:9201/').url.username, 'foo')
|
||||
t.strictEqual(pool.connections.get('http://localhost:9201/').url.password, 'bar')
|
||||
const conn = pool.connections.get('http://localhost:9201/')
|
||||
t.strictEqual(conn.url.username, 'foo')
|
||||
t.strictEqual(conn.url.password, 'bar')
|
||||
t.strictEqual(conn.auth.username, 'foo')
|
||||
t.strictEqual(conn.auth.password, 'bar')
|
||||
t.end()
|
||||
})
|
||||
|
||||
t.test('addConnection should handle not-friendly url parameters for user and password', t => {
|
||||
const pool = new ConnectionPool({ Connection })
|
||||
const href = 'http://us"er:p@assword@localhost:9200/'
|
||||
pool.addConnection(href)
|
||||
const conn = pool.getConnection()
|
||||
t.strictEqual(conn.url.username, 'us%22er')
|
||||
t.strictEqual(conn.url.password, 'p%40assword')
|
||||
t.strictEqual(conn.auth.username, 'us"er')
|
||||
t.strictEqual(conn.auth.password, 'p@assword')
|
||||
t.end()
|
||||
})
|
||||
|
||||
|
||||
@ -526,7 +526,8 @@ test('Url with auth', t => {
|
||||
|
||||
buildServer(handler, ({ port }, server) => {
|
||||
const connection = new Connection({
|
||||
url: new URL(`http://foo:bar@localhost:${port}`)
|
||||
url: new URL(`http://foo:bar@localhost:${port}`),
|
||||
auth: { username: 'foo', password: 'bar' }
|
||||
})
|
||||
connection.request({
|
||||
path: '/hello',
|
||||
@ -722,11 +723,11 @@ test('setRole', t => {
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('Util.inspect Connection class should hide agent and ssl', t => {
|
||||
test('Util.inspect Connection class should hide agent, ssl and auth', t => {
|
||||
t.plan(1)
|
||||
|
||||
const connection = new Connection({
|
||||
url: new URL('http://localhost:9200'),
|
||||
url: new URL('http://user:password@localhost:9200'),
|
||||
id: 'node-id',
|
||||
headers: { foo: 'bar' }
|
||||
})
|
||||
@ -740,20 +741,7 @@ test('Util.inspect Connection class should hide agent and ssl', t => {
|
||||
.replace(/(\r\n|\n|\r)/gm, '')
|
||||
}
|
||||
|
||||
t.strictEqual(cleanStr(inspect(connection)), cleanStr(`{ url:
|
||||
URL {
|
||||
href: 'http://localhost:9200/',
|
||||
origin: 'http://localhost:9200',
|
||||
protocol: 'http:',
|
||||
username: '',
|
||||
password: '',
|
||||
host: 'localhost:9200',
|
||||
hostname: 'localhost',
|
||||
port: '9200',
|
||||
pathname: '/',
|
||||
search: '',
|
||||
searchParams: URLSearchParams {},
|
||||
hash: '' },
|
||||
t.strictEqual(cleanStr(inspect(connection)), cleanStr(`{ url: 'http://localhost:9200/',
|
||||
id: 'node-id',
|
||||
headers: { foo: 'bar' },
|
||||
deadCount: 0,
|
||||
@ -764,6 +752,34 @@ test('Util.inspect Connection class should hide agent and ssl', t => {
|
||||
)
|
||||
})
|
||||
|
||||
test('connection.toJSON should hide agent, ssl and auth', t => {
|
||||
t.plan(1)
|
||||
|
||||
const connection = new Connection({
|
||||
url: new URL('http://user:password@localhost:9200'),
|
||||
id: 'node-id',
|
||||
headers: { foo: 'bar' }
|
||||
})
|
||||
|
||||
t.deepEqual(connection.toJSON(), {
|
||||
url: 'http://localhost:9200/',
|
||||
id: 'node-id',
|
||||
headers: {
|
||||
foo: 'bar'
|
||||
},
|
||||
deadCount: 0,
|
||||
resurrectTimeout: 0,
|
||||
_openRequests: 0,
|
||||
status: 'alive',
|
||||
roles: {
|
||||
master: true,
|
||||
data: true,
|
||||
ingest: true,
|
||||
ml: false
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// https://github.com/elastic/elasticsearch-js/issues/843
|
||||
test('Port handling', t => {
|
||||
t.test('http 80', t => {
|
||||
|
||||
Reference in New Issue
Block a user