From 0d2f294c88869ddf45691c9489cbeebf7260d893 Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Fri, 9 Dec 2016 11:46:38 -0800 Subject: [PATCH 01/39] Adds support for Tribe nodes Signed-off-by: Tyler Smalley --- src/core_plugins/elasticsearch/index.js | 49 ++++- .../lib/__tests__/check_es_version.js | 37 ++-- .../lib/__tests__/check_for_tribe.js | 48 +++++ .../elasticsearch/lib/__tests__/cluster.js | 142 +++++++++++++++ .../lib/__tests__/create_kibana_index.js | 43 ++--- .../lib/__tests__/create_proxy.js | 19 +- .../lib/__tests__/health_check.js | 109 +++++++----- .../elasticsearch/lib/__tests__/map_uri.js | 73 ++++---- .../lib/__tests__/upgrade_config.js | 53 ++++-- .../elasticsearch/lib/call_with_request.js | 31 ---- .../elasticsearch/lib/check_es_version.js | 31 ++-- .../elasticsearch/lib/check_for_tribe.js | 18 ++ .../elasticsearch/lib/client_logger.js | 39 ++++ src/core_plugins/elasticsearch/lib/cluster.js | 100 +++++++++++ .../elasticsearch/lib/clusters.js | 14 ++ .../elasticsearch/lib/create_admin_cluster.js | 19 ++ .../elasticsearch/lib/create_agent.js | 17 +- .../elasticsearch/lib/create_client.js | 52 ++++++ .../elasticsearch/lib/create_data_cluster.js | 30 ++++ .../elasticsearch/lib/create_kibana_index.js | 6 +- .../elasticsearch/lib/create_proxy.js | 83 +++++---- .../elasticsearch/lib/expose_client.js | 99 ----------- .../elasticsearch/lib/health_check.js | 42 +++-- src/core_plugins/elasticsearch/lib/map_uri.js | 18 +- .../elasticsearch/lib/migrate_config.js | 5 +- .../elasticsearch/lib/upgrade_config.js | 10 +- src/core_plugins/kibana/index.js | 2 + .../dashboard/services/saved_dashboards.js | 6 +- .../kibana/public/dev_tools/hacks/disable.js | 16 ++ .../discover/saved_searches/saved_searches.js | 6 +- .../sections/indices/_refresh_kibana_index.js | 4 +- .../management/sections/objects/_objects.js | 6 +- .../management/sections/objects/_view.js | 10 +- .../saved_visualizations.js | 6 +- .../api/ingest/register_field_capabilities.js | 2 +- .../routes/api/scripts/register_languages.js | 2 +- .../routes/api/search/count/register_count.js | 2 +- .../timelion/public/services/saved_sheets.js | 4 +- .../timelion/server/routes/validate_es.js | 2 +- .../server/series_functions/__tests__/es.js | 17 +- .../server/series_functions/es/index.js | 2 +- src/server/http/short_url_lookup.js | 6 +- src/ui/public/chrome/api/angular.js | 5 + .../public/courier/__tests__/request_queue.js | 2 +- .../public/courier/__tests__/saved_object.js | 22 ++- src/ui/public/courier/courier.js | 12 +- .../data_source/_abstract_doc_source.js | 168 ++++++++++++++++++ .../courier/data_source/_doc_send_to_es.js | 6 +- .../courier/data_source/admin_doc_source.js | 26 +++ .../public/courier/data_source/doc_source.js | 158 +--------------- src/ui/public/courier/fetch/call_client.js | 6 +- src/ui/public/courier/fetch/request/doc.js | 3 - .../public/courier/fetch/request/doc_admin.js | 17 ++ .../public/courier/fetch/request/doc_data.js | 17 ++ .../courier/fetch/strategy/doc_admin.js | 26 +++ .../fetch/strategy/{doc.js => doc_data.js} | 0 src/ui/public/courier/looper/doc_admin.js | 19 ++ .../courier/looper/{doc.js => doc_data.js} | 2 +- .../courier/saved_object/saved_object.js | 8 +- src/ui/public/es.js | 61 ++++--- .../__tests__/_index_pattern.js | 2 +- src/ui/public/index_patterns/_get_ids.js | 4 +- .../public/index_patterns/_index_pattern.js | 2 +- src/ui/public/index_patterns/_mapper.js | 4 +- .../public/index_patterns/index_patterns.js | 4 +- src/ui/public/utils/mapping_setup.js | 6 +- src/ui/settings/__tests__/index.js | 46 +++-- src/ui/settings/index.js | 4 +- tasks/config/esvm.js | 75 ++++++++ 69 files changed, 1342 insertions(+), 643 deletions(-) create mode 100644 src/core_plugins/elasticsearch/lib/__tests__/check_for_tribe.js create mode 100644 src/core_plugins/elasticsearch/lib/__tests__/cluster.js delete mode 100644 src/core_plugins/elasticsearch/lib/call_with_request.js create mode 100644 src/core_plugins/elasticsearch/lib/check_for_tribe.js create mode 100644 src/core_plugins/elasticsearch/lib/client_logger.js create mode 100644 src/core_plugins/elasticsearch/lib/cluster.js create mode 100644 src/core_plugins/elasticsearch/lib/clusters.js create mode 100644 src/core_plugins/elasticsearch/lib/create_admin_cluster.js create mode 100644 src/core_plugins/elasticsearch/lib/create_client.js create mode 100644 src/core_plugins/elasticsearch/lib/create_data_cluster.js delete mode 100644 src/core_plugins/elasticsearch/lib/expose_client.js create mode 100644 src/core_plugins/kibana/public/dev_tools/hacks/disable.js create mode 100644 src/ui/public/courier/data_source/_abstract_doc_source.js create mode 100644 src/ui/public/courier/data_source/admin_doc_source.js create mode 100644 src/ui/public/courier/fetch/request/doc_admin.js create mode 100644 src/ui/public/courier/fetch/request/doc_data.js create mode 100644 src/ui/public/courier/fetch/strategy/doc_admin.js rename src/ui/public/courier/fetch/strategy/{doc.js => doc_data.js} (100%) create mode 100644 src/ui/public/courier/looper/doc_admin.js rename src/ui/public/courier/looper/{doc.js => doc_data.js} (88%) diff --git a/src/core_plugins/elasticsearch/index.js b/src/core_plugins/elasticsearch/index.js index 46cce51c73d59..fb8265adb7a26 100644 --- a/src/core_plugins/elasticsearch/index.js +++ b/src/core_plugins/elasticsearch/index.js @@ -1,8 +1,13 @@ -import { trim, trimRight } from 'lodash'; +import { trim, trimRight, bindKey } from 'lodash'; import { methodNotAllowed } from 'boom'; import healthCheck from './lib/health_check'; -import exposeClient from './lib/expose_client'; +import createDataCluster from './lib/create_data_cluster'; +import createAdminCluster from './lib/create_admin_cluster'; +import clientLogger from './lib/client_logger'; +import { getCluster, createCluster } from './lib/clusters'; +import filterHeaders from './lib/filter_headers'; + import createProxy, { createPath } from './lib/create_proxy'; const DEFAULT_REQUEST_HEADERS = [ 'authorization' ]; @@ -26,6 +31,7 @@ module.exports = function ({ Plugin }) { customHeaders: object().default({}), pingTimeout: number().default(ref('requestTimeout')), startupTimeout: number().default(5000), + logQueries: boolean().default(false), ssl: object({ verify: boolean().default(true), ca: array().single().items(string()), @@ -33,6 +39,29 @@ module.exports = function ({ Plugin }) { key: string() }).default(), apiVersion: Joi.string().default('master'), + healthCheck: object({ + delay: number().default(2500) + }).default(), + tribe: object({ + url: string().uri({ scheme: ['http', 'https'] }), + preserveHost: boolean().default(true), + username: string(), + password: string(), + shardTimeout: number().default(0), + requestTimeout: number().default(30000), + requestHeadersWhitelist: array().items().single().default(DEFAULT_REQUEST_HEADERS), + customHeaders: object().default({}), + pingTimeout: number().default(ref('requestTimeout')), + startupTimeout: number().default(5000), + logQueries: boolean().default(false), + ssl: object({ + verify: boolean().default(true), + ca: array().single().items(string()), + cert: string(), + key: string() + }).default(), + apiVersion: Joi.string().default('master'), + }).default() }).default(); }, @@ -42,6 +71,7 @@ module.exports = function ({ Plugin }) { esRequestTimeout: options.requestTimeout, esShardTimeout: options.shardTimeout, esApiVersion: options.apiVersion, + esDataIsTribe: options.tribe ? true : false, }; } }, @@ -49,8 +79,17 @@ module.exports = function ({ Plugin }) { init(server, options) { const kibanaIndex = server.config().get('kibana.index'); - // Expose the client to the server - exposeClient(server); + server.expose('getCluster', getCluster); + server.expose('createCluster', createCluster); + server.expose('filterHeaders', filterHeaders); + server.expose('ElasticsearchClientLogging', clientLogger(server)); + + const dataCluster = createDataCluster(server); + server.on('close', bindKey(dataCluster, 'close')); + + const adminCluster = createAdminCluster(server); + server.on('close', bindKey(adminCluster, 'close')); + createProxy(server, 'GET', '/{paths*}'); createProxy(server, 'POST', '/_mget'); createProxy(server, 'POST', '/{index}/_search'); @@ -69,7 +108,7 @@ module.exports = function ({ Plugin }) { function noDirectIndex({ path }, reply) { const requestPath = trimRight(trim(path), '/'); - const matchPath = createPath(kibanaIndex); + const matchPath = createPath('/elasticsearch', kibanaIndex); if (requestPath === matchPath) { return reply(methodNotAllowed('You cannot modify the primary kibana index through this interface.')); diff --git a/src/core_plugins/elasticsearch/lib/__tests__/check_es_version.js b/src/core_plugins/elasticsearch/lib/__tests__/check_es_version.js index cc36d350d6eb0..dde0168bda955 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/check_es_version.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/check_es_version.js @@ -13,15 +13,14 @@ describe('plugins/elasticsearch', () => { let server; let plugin; + let callAsKibanaUser; beforeEach(function () { server = { log: sinon.stub(), plugins: { elasticsearch: { - client: { - nodes: {} - }, + getCluster: sinon.stub().withArgs('admin').returns({ callAsKibanaUser: sinon.stub() }), // Fix status: { red: sinon.stub() }, @@ -52,25 +51,27 @@ describe('plugins/elasticsearch', () => { nodes[name] = node; } - const client = server.plugins.elasticsearch.client; - client.nodes.info = sinon.stub().returns(Promise.resolve({ nodes: nodes })); + const cluster = server.plugins.elasticsearch.getCluster('admin'); + cluster.callAsKibanaUser.withArgs('nodes.info', sinon.match.any).returns(Promise.resolve({ nodes: nodes })); + callAsKibanaUser = cluster.callAsKibanaUser; } function setNodeWithoutHTTP(version) { const nodes = { 'node-without-http': { version, ip: 'ip' } }; - const client = server.plugins.elasticsearch.client; - client.nodes.info = sinon.stub().returns(Promise.resolve({ nodes: nodes })); + const cluster = server.plugins.elasticsearch.getCluster('admin'); + cluster.callAsKibanaUser.withArgs('nodes.info', sinon.match.any).returns(Promise.resolve({ nodes: nodes })); + callAsKibanaUser = cluster.callAsKibanaUser; } it('returns true with single a node that matches', async () => { setNodes('5.1.0'); - const result = await checkEsVersion(server, KIBANA_VERSION); + const result = await checkEsVersion(server, KIBANA_VERSION, callAsKibanaUser); expect(result).to.be(true); }); it('returns true with multiple nodes that satisfy', async () => { setNodes('5.1.0', '5.2.0', '5.1.1-Beta1'); - const result = await checkEsVersion(server, KIBANA_VERSION); + const result = await checkEsVersion(server, KIBANA_VERSION, callAsKibanaUser); expect(result).to.be(true); }); @@ -78,7 +79,7 @@ describe('plugins/elasticsearch', () => { // 5.0.0 ES is too old to work with a 5.1.0 version of Kibana. setNodes('5.1.0', '5.2.0', '5.0.0'); try { - await checkEsVersion(server, KIBANA_VERSION); + await checkEsVersion(server, KIBANA_VERSION, callAsKibanaUser); } catch (e) { expect(e).to.be.a(Error); } @@ -91,7 +92,7 @@ describe('plugins/elasticsearch', () => { { version: '5.0.0', attributes: { client: 'true' } }, ); try { - await checkEsVersion(server, KIBANA_VERSION); + await checkEsVersion(server, KIBANA_VERSION, callAsKibanaUser); } catch (e) { expect(e).to.be.a(Error); } @@ -99,7 +100,7 @@ describe('plugins/elasticsearch', () => { it('warns if a node is only off by a patch version', async () => { setNodes('5.1.1'); - await checkEsVersion(server, KIBANA_VERSION); + await checkEsVersion(server, KIBANA_VERSION, callAsKibanaUser); sinon.assert.callCount(server.log, 2); expect(server.log.getCall(0).args[0]).to.contain('debug'); expect(server.log.getCall(1).args[0]).to.contain('warning'); @@ -107,7 +108,7 @@ describe('plugins/elasticsearch', () => { it('warns if a node is off by a patch version and without http publish address', async () => { setNodeWithoutHTTP('5.1.1'); - await checkEsVersion(server, KIBANA_VERSION); + await checkEsVersion(server, KIBANA_VERSION, callAsKibanaUser); sinon.assert.callCount(server.log, 2); expect(server.log.getCall(0).args[0]).to.contain('debug'); expect(server.log.getCall(1).args[0]).to.contain('warning'); @@ -116,7 +117,7 @@ describe('plugins/elasticsearch', () => { it('errors if a node incompatible and without http publish address', async () => { setNodeWithoutHTTP('6.1.1'); try { - await checkEsVersion(server, KIBANA_VERSION); + await checkEsVersion(server, KIBANA_VERSION, callAsKibanaUser); } catch (e) { expect(e.message).to.contain('incompatible nodes'); expect(e).to.be.a(Error); @@ -126,12 +127,12 @@ describe('plugins/elasticsearch', () => { it('only warns once per node list', async () => { setNodes('5.1.1'); - await checkEsVersion(server, KIBANA_VERSION); + await checkEsVersion(server, KIBANA_VERSION, callAsKibanaUser); sinon.assert.callCount(server.log, 2); expect(server.log.getCall(0).args[0]).to.contain('debug'); expect(server.log.getCall(1).args[0]).to.contain('warning'); - await checkEsVersion(server, KIBANA_VERSION); + await checkEsVersion(server, KIBANA_VERSION, callAsKibanaUser); sinon.assert.callCount(server.log, 3); expect(server.log.getCall(2).args[0]).to.contain('debug'); }); @@ -139,13 +140,13 @@ describe('plugins/elasticsearch', () => { it('warns again if the node list changes', async () => { setNodes('5.1.1'); - await checkEsVersion(server, KIBANA_VERSION); + await checkEsVersion(server, KIBANA_VERSION, callAsKibanaUser); sinon.assert.callCount(server.log, 2); expect(server.log.getCall(0).args[0]).to.contain('debug'); expect(server.log.getCall(1).args[0]).to.contain('warning'); setNodes('5.1.2'); - await checkEsVersion(server, KIBANA_VERSION); + await checkEsVersion(server, KIBANA_VERSION, callAsKibanaUser); sinon.assert.callCount(server.log, 4); expect(server.log.getCall(2).args[0]).to.contain('debug'); expect(server.log.getCall(3).args[0]).to.contain('warning'); diff --git a/src/core_plugins/elasticsearch/lib/__tests__/check_for_tribe.js b/src/core_plugins/elasticsearch/lib/__tests__/check_for_tribe.js new file mode 100644 index 0000000000000..5eb5c4f624c85 --- /dev/null +++ b/src/core_plugins/elasticsearch/lib/__tests__/check_for_tribe.js @@ -0,0 +1,48 @@ +import expect from 'expect.js'; +import { noop } from 'lodash'; +import sinon from 'sinon'; + +import checkForTribe from '../check_for_tribe'; + +describe('plugins/elasticsearch checkForTribe', () => { + const sandbox = sinon.sandbox.create(); + afterEach(() => sandbox.restore()); + + const stubCallAsKibanaUser = (nodesInfoResp = { nodes: {} }) => { + return sinon.stub().withArgs( + 'nodes.info', + sinon.match.any + ).returns( + Promise.resolve(nodesInfoResp) + ); + }; + + + it('fetches the local node stats of the node that the elasticsearch client is connected to', async () => { + const callAsKibanaUser = stubCallAsKibanaUser(); + await checkForTribe(callAsKibanaUser); + sinon.assert.calledOnce(callAsKibanaUser); + }); + + it('throws a SetupError when the node info contains tribe settings', async () => { + const nodeInfo = { + nodes: { + __nodeId__: { + settings: { + tribe: { + t1: {}, + t2: {}, + } + } + } + } + }; + + try { + await checkForTribe(stubCallAsKibanaUser(nodeInfo)); + throw new Error('checkForTribe() should have thrown'); + } catch (err) { + expect(err).to.be.a(Error); + } + }); +}); diff --git a/src/core_plugins/elasticsearch/lib/__tests__/cluster.js b/src/core_plugins/elasticsearch/lib/__tests__/cluster.js new file mode 100644 index 0000000000000..845ba7132ede8 --- /dev/null +++ b/src/core_plugins/elasticsearch/lib/__tests__/cluster.js @@ -0,0 +1,142 @@ +import expect from 'expect.js'; +import Cluster from '../cluster'; +import sinon from 'sinon'; +import { errors as esErrors } from 'elasticsearch'; +import { set, partial, cloneDeep } from 'lodash'; +import Boom from 'boom'; + +describe('plugins/elasticsearch', function () { + describe('cluster', function () { + let cluster; + let client; + let config = { + url: 'http://localhost:9200', + ssl: { verify: false }, + requestHeadersWhitelist: [ 'authorization' ] + }; + + beforeEach(() => { + cluster = new Cluster(config); + }); + + it('persists the config', () => { + expect(cluster.config()).to.eql(config); + }); + + it('exposes error definitions', () => { + expect(cluster.errors).to.be(esErrors); + }); + + it('closes the clients', () => { + cluster._client.close = sinon.spy(); + cluster._noAuthClient.close = sinon.spy(); + cluster.close(); + + sinon.assert.calledOnce(cluster._client.close); + sinon.assert.calledOnce(cluster._noAuthClient.close); + }); + + it('protects the config from changes', () => { + const localConfig = cluster.config(); + localConfig.requestHeadersWhitelist.push('123'); + delete localConfig.url; + expect(localConfig).to.not.equal(config); + expect(localConfig.requestHeadersWhitelist.length).to.not.equal(config.requestHeadersWhitelist); + }); + + describe('callAsKibanaUserFactory', () => { + let callAsKibanaUser; + + beforeEach(() => { + client = sinon.stub(); + set(client, 'nodes.info', sinon.stub().returns(Promise.resolve())); + + callAsKibanaUser = cluster.callAsKibanaUserFactory(client); + }); + + it('should return a function', () => { + expect(callAsKibanaUser).to.be.a('function'); + }); + + it('throws an error for an invalid endpoint', () => { + const fn = partial(callAsKibanaUser, 'foo'); + expect(fn).to.throwException(/called with an invalid endpoint: foo/); + }); + + it('calls the client with params', () => { + const params = { foo: 'Foo' }; + callAsKibanaUser('nodes.info', params); + + sinon.assert.calledOnce(client.nodes.info); + expect(client.nodes.info.getCall(0).args[0]).to.eql(params); + }); + }); + + describe('callWithRequestFactory', () => { + let callWithRequest; + + beforeEach(() => { + client = sinon.stub(); + set(client, 'nodes.info', sinon.stub().returns(Promise.resolve())); + + callWithRequest = cluster.callWithRequestFactory(client); + }); + + it('should return a function', () => { + expect(callWithRequest).to.be.a('function'); + }); + + it('throws an error for an invalid endpoint', () => { + const fn = partial(callWithRequest, {}, 'foo'); + expect(fn).to.throwException(/called with an invalid endpoint: foo/); + }); + + it('calls the client with params', () => { + const params = { foo: 'Foo' }; + callWithRequest({}, 'nodes.info', params); + + sinon.assert.calledOnce(client.nodes.info); + expect(client.nodes.info.getCall(0).args[0]).to.eql(params); + }); + + it('passes only whitelisted headers', () => { + const headers = { authorization: 'Basic TEST' }; + const request = { headers: Object.assign({}, headers, { foo: 'Foo' }) }; + + callWithRequest(request, 'nodes.info'); + + sinon.assert.calledOnce(client.nodes.info); + expect(client.nodes.info.getCall(0).args[0]).to.eql({ + headers: headers + }); + }); + + describe('wrap401Errors', () => { + let handler; + const error = new Error('Authentication required'); + error.statusCode = 401; + + beforeEach(() => { + handler = sinon.stub(); + }); + + it('ensures WWW-Authenticate header', async () => { + set(client, 'mock.401', sinon.stub().returns(Promise.reject(error))); + await callWithRequest({}, 'mock.401', {}, { wrap401Errors: true }).catch(handler); + + sinon.assert.calledOnce(handler); + expect(handler.getCall(0).args[0].output.headers['WWW-Authenticate']).to.eql('Basic realm="Authorization Required"'); + }); + + it('persists WWW-Authenticate header', async () => { + set(error, 'body.error.header[WWW-Authenticate]', 'Basic realm="Test"'); + set(client, 'mock.401', sinon.stub().returns(Promise.reject(error))); + await callWithRequest({}, 'mock.401', {}, { wrap401Errors: true }).catch(handler); + + sinon.assert.calledOnce(handler); + expect(handler.getCall(0).args[0].output.headers['WWW-Authenticate']).to.eql('Basic realm="Test"'); + }); + }); + }); + }); +}); diff --git a/src/core_plugins/elasticsearch/lib/__tests__/create_kibana_index.js b/src/core_plugins/elasticsearch/lib/__tests__/create_kibana_index.js index 09b89472972a3..93b1e8c7a71a4 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/create_kibana_index.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/create_kibana_index.js @@ -9,39 +9,45 @@ describe('plugins/elasticsearch', function () { describe('lib/create_kibana_index', function () { let server; - let client; + let callAsKibanaUser; + let cluster; + beforeEach(function () { server = {}; - client = {}; + let config = { kibana: { index: '.my-kibana' } }; const get = sinon.stub(); + get.returns(config); get.withArgs('kibana.index').returns(config.kibana.index); config = function () { return { get: get }; }; - _.set(client, 'indices.create', sinon.stub()); - _.set(client, 'cluster.health', sinon.stub()); - _.set(server, 'plugins.elasticsearch.client', client); + + _.set(server, 'plugins.elasticsearch', {}); _.set(server, 'config', config); + + callAsKibanaUser = sinon.stub(); + cluster = { callAsKibanaUser: callAsKibanaUser }; + + server.plugins.elasticsearch.getCluster = sinon.stub().withArgs('admin').returns(cluster); }); describe('successful requests', function () { - beforeEach(function () { - client.indices.create.returns(Promise.resolve()); - client.cluster.health.returns(Promise.resolve()); + callAsKibanaUser.withArgs('indices.create', sinon.match.any).returns(Promise.resolve()); + callAsKibanaUser.withArgs('cluster.health', sinon.match.any).returns(Promise.resolve()); }); it('should check cluster.health upon successful index creation', function () { const fn = createKibanaIndex(server); return fn.then(function () { - sinon.assert.calledOnce(client.cluster.health); + sinon.assert.calledOnce(callAsKibanaUser.withArgs('cluster.health', sinon.match.any)); }); }); it('should be created with mappings for config.buildNum', function () { const fn = createKibanaIndex(server); return fn.then(function () { - const params = client.indices.create.args[0][0]; + const params = callAsKibanaUser.args[0][1]; expect(params) .to.have.property('body'); expect(params.body) @@ -60,7 +66,7 @@ describe('plugins/elasticsearch', function () { it('should be created with 1 shard and default replica', function () { const fn = createKibanaIndex(server); return fn.then(function () { - const params = client.indices.create.args[0][0]; + const params = callAsKibanaUser.args[0][1]; expect(params) .to.have.property('body'); expect(params.body) @@ -75,19 +81,17 @@ describe('plugins/elasticsearch', function () { it('should be created with index name set in the config', function () { const fn = createKibanaIndex(server); return fn.then(function () { - const params = client.indices.create.args[0][0]; + const params = callAsKibanaUser.args[0][1]; expect(params) .to.have.property('index', '.my-kibana'); }); }); - - }); describe('failure requests', function () { it('should reject with an Error', function () { const error = new Error('Oops!'); - client.indices.create.returns(Promise.reject(error)); + callAsKibanaUser.withArgs('indices.create', sinon.match.any).returns(Promise.reject(error)); const fn = createKibanaIndex(server); return fn.catch(function (err) { expect(err).to.be.a(Error); @@ -96,24 +100,21 @@ describe('plugins/elasticsearch', function () { it('should reject with an error if index creation fails', function () { const error = new Error('Oops!'); - client.indices.create.returns(Promise.reject(error)); + callAsKibanaUser.withArgs('indices.create', sinon.match.any).returns(Promise.reject(error)); const fn = createKibanaIndex(server); return fn.catch(function (err) { expect(err.message).to.be('Unable to create Kibana index ".my-kibana"'); }); }); - it('should reject with an error if health check fails', function () { - const error = new Error('Oops!'); - client.indices.create.returns(Promise.resolve()); - client.cluster.health.returns(Promise.reject(error)); + callAsKibanaUser.withArgs('indices.create', sinon.match.any).returns(Promise.resolve()); + callAsKibanaUser.withArgs('cluster.health', sinon.match.any).returns(Promise.reject(new Error())); const fn = createKibanaIndex(server); return fn.catch(function (err) { expect(err.message).to.be('Waiting for Kibana index ".my-kibana" to come online failed.'); }); }); }); - }); }); diff --git a/src/core_plugins/elasticsearch/lib/__tests__/create_proxy.js b/src/core_plugins/elasticsearch/lib/__tests__/create_proxy.js index b54621608d2e7..f09dae25fc99d 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/create_proxy.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/create_proxy.js @@ -3,20 +3,21 @@ import createProxy from '../create_proxy'; describe('plugins/elasticsearch', function () { describe('lib/create_proxy', function () { - describe('#createPath', function () { it('prepends /elasticsearch to route', function () { - const path = createProxy.createPath('/wat'); - expect(path).to.equal('/elasticsearch/wat'); + const path = createProxy.createPath('/foobar', '/wat'); + expect(path).to.equal('/foobar/wat'); }); - context('when arg does not start with a slash', function () { - it('adds slash anyway', function () { - const path = createProxy.createPath('wat'); - expect(path).to.equal('/elasticsearch/wat'); - }); + it('ensures leading slash for prefix', function () { + const path = createProxy.createPath('foobar', '/wat'); + expect(path).to.equal('/foobar/wat'); }); - }); + it('ensures leading slash for path', function () { + const path = createProxy.createPath('/foobar', 'wat'); + expect(path).to.equal('/foobar/wat'); + }); + }); }); }); diff --git a/src/core_plugins/elasticsearch/lib/__tests__/health_check.js b/src/core_plugins/elasticsearch/lib/__tests__/health_check.js index 58382d2b68526..6ddd8fb8b860b 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/health_check.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/health_check.js @@ -13,10 +13,12 @@ const esPort = serverConfig.servers.elasticsearch.port; const esUrl = url.format(serverConfig.servers.elasticsearch); describe('plugins/elasticsearch', () => { - describe('lib/health_check', () => { + describe('lib/health_check', function () { + this.timeout(3000); + let health; let plugin; - let client; + let cluster; beforeEach(() => { const COMPATIBLE_VERSION_NUMBER = '5.0.0'; @@ -34,19 +36,11 @@ describe('plugins/elasticsearch', () => { } }; - // set up the elasticsearch client stub - client = { - cluster: { health: sinon.stub() }, - indices: { create: sinon.stub() }, - nodes: { info: sinon.stub() }, - ping: sinon.stub(), - create: sinon.stub(), - index: sinon.stub().returns(Promise.resolve()), - get: sinon.stub().returns(Promise.resolve({ found: false })), - search: sinon.stub().returns(Promise.resolve({ hits: { hits: [] } })), - }; - - client.nodes.info.returns(Promise.resolve({ + cluster = { callAsKibanaUser: sinon.stub() }; + cluster.callAsKibanaUser.withArgs('index', sinon.match.any).returns(Promise.resolve()); + cluster.callAsKibanaUser.withArgs('get', sinon.match.any).returns(Promise.resolve({ found: false })); + cluster.callAsKibanaUser.withArgs('search', sinon.match.any).returns(Promise.resolve({ hits: { hits: [] } })); + cluster.callAsKibanaUser.withArgs('nodes.info', sinon.match.any).returns(Promise.resolve({ nodes: { 'node-01': { version: COMPATIBLE_VERSION_NUMBER, @@ -68,7 +62,11 @@ describe('plugins/elasticsearch', () => { log: sinon.stub(), info: { port: 5601 }, config: function () { return { get, set }; }, - plugins: { elasticsearch: { client } } + plugins: { + elasticsearch: { + getCluster: sinon.stub().returns(cluster) + } + } }; health = healthCheck(plugin, server); @@ -79,44 +77,59 @@ describe('plugins/elasticsearch', () => { }); it('should set the cluster green if everything is ready', function () { - client.ping.returns(Promise.resolve()); - client.cluster.health.returns(Promise.resolve({ timed_out: false, status: 'green' })); + cluster.callAsKibanaUser.withArgs('ping').returns(Promise.resolve()); + cluster.callAsKibanaUser.withArgs('cluster.health', sinon.match.any).returns( + Promise.resolve({ timed_out: false, status: 'green' }) + ); + return health.run() .then(function () { sinon.assert.calledOnce(plugin.status.yellow); expect(plugin.status.yellow.args[0][0]).to.be('Waiting for Elasticsearch'); - sinon.assert.calledOnce(client.ping); - sinon.assert.calledOnce(client.nodes.info); - sinon.assert.calledOnce(client.cluster.health); + + sinon.assert.calledOnce(cluster.callAsKibanaUser.withArgs('ping')); + sinon.assert.calledTwice(cluster.callAsKibanaUser.withArgs('nodes.info', sinon.match.any)); + sinon.assert.calledOnce(cluster.callAsKibanaUser.withArgs('cluster.health', sinon.match.any)); sinon.assert.calledOnce(plugin.status.green); + expect(plugin.status.green.args[0][0]).to.be('Kibana index ready'); }); }); it('should set the cluster red if the ping fails, then to green', function () { - client.ping.onCall(0).returns(Promise.reject(new NoConnections())); - client.ping.onCall(1).returns(Promise.resolve()); - client.cluster.health.returns(Promise.resolve({ timed_out: false, status: 'green' })); + const ping = cluster.callAsKibanaUser.withArgs('ping'); + ping.onCall(0).returns(Promise.reject(new NoConnections())); + ping.onCall(1).returns(Promise.resolve()); + + cluster.callAsKibanaUser.withArgs('cluster.health', sinon.match.any).returns( + Promise.resolve({ timed_out: false, status: 'green' }) + ); + return health.run() .then(function () { sinon.assert.calledOnce(plugin.status.yellow); expect(plugin.status.yellow.args[0][0]).to.be('Waiting for Elasticsearch'); + sinon.assert.calledOnce(plugin.status.red); expect(plugin.status.red.args[0][0]).to.be( `Unable to connect to Elasticsearch at ${esUrl}.` ); - sinon.assert.calledTwice(client.ping); - sinon.assert.calledOnce(client.nodes.info); - sinon.assert.calledOnce(client.cluster.health); + + sinon.assert.calledTwice(ping); + sinon.assert.calledTwice(cluster.callAsKibanaUser.withArgs('nodes.info', sinon.match.any)); + sinon.assert.calledOnce(cluster.callAsKibanaUser.withArgs('cluster.health', sinon.match.any)); sinon.assert.calledOnce(plugin.status.green); expect(plugin.status.green.args[0][0]).to.be('Kibana index ready'); }); }); it('should set the cluster red if the health check status is red, then to green', function () { - client.ping.returns(Promise.resolve()); - client.cluster.health.onCall(0).returns(Promise.resolve({ timed_out: false, status: 'red' })); - client.cluster.health.onCall(1).returns(Promise.resolve({ timed_out: false, status: 'green' })); + cluster.callAsKibanaUser.withArgs('ping').returns(Promise.resolve()); + + const clusterHealth = cluster.callAsKibanaUser.withArgs('cluster.health', sinon.match.any); + clusterHealth.onCall(0).returns(Promise.resolve({ timed_out: false, status: 'red' })); + clusterHealth.onCall(1).returns(Promise.resolve({ timed_out: false, status: 'green' })); + return health.run() .then(function () { sinon.assert.calledOnce(plugin.status.yellow); @@ -125,39 +138,45 @@ describe('plugins/elasticsearch', () => { expect(plugin.status.red.args[0][0]).to.be( 'Elasticsearch is still initializing the kibana index.' ); - sinon.assert.calledOnce(client.ping); - sinon.assert.calledOnce(client.nodes.info); - sinon.assert.calledTwice(client.cluster.health); + sinon.assert.calledOnce(cluster.callAsKibanaUser.withArgs('ping')); + sinon.assert.calledTwice(cluster.callAsKibanaUser.withArgs('nodes.info', sinon.match.any)); + sinon.assert.calledTwice(cluster.callAsKibanaUser.withArgs('cluster.health', sinon.match.any)); sinon.assert.calledOnce(plugin.status.green); expect(plugin.status.green.args[0][0]).to.be('Kibana index ready'); }); }); it('should set the cluster yellow if the health check timed_out and create index', function () { - client.ping.returns(Promise.resolve()); - client.cluster.health.onCall(0).returns(Promise.resolve({ timed_out: true, status: 'red' })); - client.cluster.health.onCall(1).returns(Promise.resolve({ timed_out: false, status: 'green' })); - client.indices.create.returns(Promise.resolve()); + cluster.callAsKibanaUser.withArgs('ping').returns(Promise.resolve()); + + const clusterHealth = cluster.callAsKibanaUser.withArgs('cluster.health', sinon.match.any); + clusterHealth.onCall(0).returns(Promise.resolve({ timed_out: true, status: 'red' })); + clusterHealth.onCall(1).returns(Promise.resolve({ timed_out: false, status: 'green' })); + + cluster.callAsKibanaUser.withArgs('indices.create', sinon.match.any).returns(Promise.resolve()); + return health.run() .then(function () { sinon.assert.calledTwice(plugin.status.yellow); expect(plugin.status.yellow.args[0][0]).to.be('Waiting for Elasticsearch'); expect(plugin.status.yellow.args[1][0]).to.be('No existing Kibana index found'); - sinon.assert.calledOnce(client.ping); - sinon.assert.calledOnce(client.indices.create); - sinon.assert.calledOnce(client.nodes.info); - sinon.assert.calledTwice(client.cluster.health); + + sinon.assert.calledOnce(cluster.callAsKibanaUser.withArgs('ping')); + sinon.assert.calledOnce(cluster.callAsKibanaUser.withArgs('indices.create', sinon.match.any)); + sinon.assert.calledTwice(cluster.callAsKibanaUser.withArgs('nodes.info', sinon.match.any)); + sinon.assert.calledTwice(clusterHealth); }); }); describe('#waitUntilReady', function () { it('polls health until index is ready', function () { - client.cluster.health.onCall(0).returns(Promise.resolve({ timed_out: true })); // no index - client.cluster.health.onCall(1).returns(Promise.resolve({ status: 'red' })); // initializing - client.cluster.health.onCall(2).returns(Promise.resolve({ status: 'green' })); // ready + const clusterHealth = cluster.callAsKibanaUser.withArgs('cluster.health', sinon.match.any); + clusterHealth.onCall(0).returns(Promise.resolve({ timed_out: true })); + clusterHealth.onCall(1).returns(Promise.resolve({ status: 'red' })); + clusterHealth.onCall(2).returns(Promise.resolve({ status: 'green' })); return health.waitUntilReady().then(function () { - sinon.assert.calledThrice(client.cluster.health); + sinon.assert.calledThrice(clusterHealth); }); }); }); diff --git a/src/core_plugins/elasticsearch/lib/__tests__/map_uri.js b/src/core_plugins/elasticsearch/lib/__tests__/map_uri.js index 0859ae8640b3f..45c850cbb65cf 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/map_uri.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/map_uri.js @@ -2,20 +2,23 @@ import expect from 'expect.js'; import mapUri from '../map_uri'; import { get, defaults } from 'lodash'; import sinon from 'sinon'; +import url from 'url'; describe('plugins/elasticsearch', function () { describe('lib/map_uri', function () { let request; - function stubServer(settings) { - const values = defaults(settings || {}, { - 'elasticsearch.url': 'http://localhost:9200', - 'elasticsearch.requestHeadersWhitelist': ['authorization'], - 'elasticsearch.customHeaders': {} + function stubCluster(settings) { + settings = defaults(settings || {}, { + url: 'http://localhost:9200', + requestHeadersWhitelist: ['authorization'], + customHeaders: {} }); - const config = { get: (key, def) => get(values, key, def) }; - return { config: () => config }; + + return { + config: (path) => path ? get(settings, path) : settings + }; } beforeEach(function () { @@ -34,34 +37,34 @@ describe('plugins/elasticsearch', function () { }); it('sends custom headers if set', function () { - const server = stubServer({ - 'elasticsearch.customHeaders': { foo: 'bar' } - }); + const settings = { + customHeaders: { foo: 'bar' } + }; - mapUri(server)(request, function (err, upstreamUri, upstreamHeaders) { + mapUri(stubCluster(settings), '/elasticsearch')(request, function (err, upstreamUri, upstreamHeaders) { expect(err).to.be(null); expect(upstreamHeaders).to.have.property('foo', 'bar'); }); }); it('sends configured custom headers even if the same named header exists in request', function () { - const server = stubServer({ - 'elasticsearch.requestHeadersWhitelist': ['x-my-custom-header'], - 'elasticsearch.customHeaders': {'x-my-custom-header': 'asconfigured'} - }); + const settings = { + requestHeadersWhitelist: ['x-my-custom-header'], + customHeaders: {'x-my-custom-header': 'asconfigured'} + }; - mapUri(server)(request, function (err, upstreamUri, upstreamHeaders) { + mapUri(stubCluster(settings), '/elasticsearch')(request, function (err, upstreamUri, upstreamHeaders) { expect(err).to.be(null); expect(upstreamHeaders).to.have.property('x-my-custom-header', 'asconfigured'); }); }); it('only proxies the whitelisted request headers', function () { - const server = stubServer({ - 'elasticsearch.requestHeadersWhitelist': ['x-my-custom-HEADER', 'Authorization'], - }); + const settings = { + requestHeadersWhitelist: ['x-my-custom-HEADER', 'Authorization'], + }; - mapUri(server)(request, function (err, upstreamUri, upstreamHeaders) { + mapUri(stubCluster(settings), '/elasticsearch')(request, function (err, upstreamUri, upstreamHeaders) { expect(err).to.be(null); expect(upstreamHeaders).to.have.property('authorization'); expect(upstreamHeaders).to.have.property('x-my-custom-header'); @@ -70,24 +73,24 @@ describe('plugins/elasticsearch', function () { }); it('proxies no headers if whitelist is set to []', function () { - const server = stubServer({ - 'elasticsearch.requestHeadersWhitelist': [], - }); + const settings = { + requestHeadersWhitelist: [], + }; - mapUri(server)(request, function (err, upstreamUri, upstreamHeaders) { + mapUri(stubCluster(settings), '/elasticsearch')(request, function (err, upstreamUri, upstreamHeaders) { expect(err).to.be(null); expect(Object.keys(upstreamHeaders).length).to.be(0); }); }); it('proxies no headers if whitelist is set to no value', function () { - const server = stubServer({ + const settings = { // joi converts `elasticsearch.requestHeadersWhitelist: null` into // an array with a null inside because of the `array().single()` rule. - 'elasticsearch.requestHeadersWhitelist': [ null ], - }); + requestHeadersWhitelist: [ null ], + }; - mapUri(server)(request, function (err, upstreamUri, upstreamHeaders) { + mapUri(stubCluster(settings), '/elasticsearch')(request, function (err, upstreamUri, upstreamHeaders) { expect(err).to.be(null); expect(Object.keys(upstreamHeaders).length).to.be(0); }); @@ -95,9 +98,8 @@ describe('plugins/elasticsearch', function () { it('strips the /elasticsearch prefix from the path', () => { request.path = '/elasticsearch/es/path'; - const server = stubServer(); - mapUri(server)(request, function (err, upstreamUri, upstreamHeaders) { + mapUri(stubCluster(), '/elasticsearch')(request, function (err, upstreamUri, upstreamHeaders) { expect(err).to.be(null); expect(upstreamUri).to.be('http://localhost:9200/es/path'); }); @@ -105,9 +107,9 @@ describe('plugins/elasticsearch', function () { it('extends the es.url path', function () { request.path = '/elasticsearch/index/type'; - const server = stubServer({ 'elasticsearch.url': 'https://localhost:9200/base-path' }); + const settings = { url: 'https://localhost:9200/base-path' }; - mapUri(server)(request, function (err, upstreamUri, upstreamHeaders) { + mapUri(stubCluster(settings), '/elasticsearch')(request, function (err, upstreamUri, upstreamHeaders) { expect(err).to.be(null); expect(upstreamUri).to.be('https://localhost:9200/base-path/index/type'); }); @@ -116,9 +118,9 @@ describe('plugins/elasticsearch', function () { it('extends the es.url query string', function () { request.path = '/elasticsearch/*'; request.query = { foo: 'bar' }; - const server = stubServer({ 'elasticsearch.url': 'https://localhost:9200/?base=query' }); + const settings = { url: 'https://localhost:9200/?base=query' }; - mapUri(server)(request, function (err, upstreamUri, upstreamHeaders) { + mapUri(stubCluster(settings), '/elasticsearch')(request, function (err, upstreamUri, upstreamHeaders) { expect(err).to.be(null); expect(upstreamUri).to.be('https://localhost:9200/*?foo=bar&base=query'); }); @@ -127,9 +129,8 @@ describe('plugins/elasticsearch', function () { it('filters the _ querystring param', function () { request.path = '/elasticsearch/*'; request.query = { _: Date.now() }; - const server = stubServer(); - mapUri(server)(request, function (err, upstreamUri, upstreamHeaders) { + mapUri(stubCluster(), '/elasticsearch')(request, function (err, upstreamUri, upstreamHeaders) { expect(err).to.be(null); expect(upstreamUri).to.be('http://localhost:9200/*'); }); diff --git a/src/core_plugins/elasticsearch/lib/__tests__/upgrade_config.js b/src/core_plugins/elasticsearch/lib/__tests__/upgrade_config.js index 96e744c11ac10..c6779398ad579 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/upgrade_config.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/upgrade_config.js @@ -9,7 +9,7 @@ describe('plugins/elasticsearch', function () { describe('lib/upgrade_config', function () { let get; let server; - let client; + let callAsKibanaUser; let config; let upgrade; @@ -18,7 +18,9 @@ describe('plugins/elasticsearch', function () { get.withArgs('kibana.index').returns('.my-kibana'); get.withArgs('pkg.version').returns('4.0.1'); get.withArgs('pkg.buildNum').returns(Math.random()); - client = { create: sinon.stub() }; + + callAsKibanaUser = sinon.stub(); + server = { log: sinon.stub(), config: function () { @@ -26,7 +28,13 @@ describe('plugins/elasticsearch', function () { get: get }; }, - plugins: { elasticsearch: { client: client } } + plugins: { + elasticsearch: { + getCluster: sinon.stub().withArgs('admin').returns({ + callAsKibanaUser: callAsKibanaUser + }) + } + } }; upgrade = upgradeConfig(server); }); @@ -35,7 +43,7 @@ describe('plugins/elasticsearch', function () { const response = { hits: { hits:[] } }; beforeEach(function () { - client.create.returns(Promise.resolve()); + callAsKibanaUser.withArgs('create', sinon.match.any).returns(Promise.resolve()); }); describe('production', function () { @@ -47,15 +55,15 @@ describe('plugins/elasticsearch', function () { it('should resolve buildNum to pkg.buildNum config', function () { return upgrade(response).then(function (resp) { - sinon.assert.calledOnce(client.create); - const params = client.create.args[0][0]; + sinon.assert.calledOnce(callAsKibanaUser); + const params = callAsKibanaUser.args[0][1]; expect(params.body).to.have.property('buildNum', get('pkg.buildNum')); }); }); it('should resolve version to pkg.version config', function () { return upgrade(response).then(function (resp) { - const params = client.create.args[0][0]; + const params = callAsKibanaUser.args[0][1]; expect(params).to.have.property('id', get('pkg.version')); }); }); @@ -70,14 +78,14 @@ describe('plugins/elasticsearch', function () { it('should resolve buildNum to pkg.buildNum config', function () { return upgrade(response).then(function (resp) { - const params = client.create.args[0][0]; + const params = callAsKibanaUser.args[0][1]; expect(params.body).to.have.property('buildNum', get('pkg.buildNum')); }); }); it('should resolve version to pkg.version config', function () { return upgrade(response).then(function (resp) { - const params = client.create.args[0][0]; + const params = callAsKibanaUser.args[0][1]; expect(params).to.have.property('id', get('pkg.version')); }); }); @@ -93,11 +101,12 @@ describe('plugins/elasticsearch', function () { it('should create new config if the nothing is upgradeable', function () { get.withArgs('pkg.buildNum').returns(9833); - client.create.returns(Promise.resolve()); + callAsKibanaUser.withArgs('create', sinon.match.any).returns(Promise.resolve()); + const response = { hits: { hits: [ { _id: '4.0.1-alpha3' }, { _id: '4.0.1-beta1' }, { _id: '4.0.0-SNAPSHOT1' } ] } }; return upgrade(response).then(function (resp) { - sinon.assert.calledOnce(client.create); - const params = client.create.args[0][0]; + sinon.assert.calledOnce(callAsKibanaUser); + const params = callAsKibanaUser.args[0][1]; expect(params).to.have.property('body'); expect(params.body).to.have.property('buildNum', 9833); expect(params).to.have.property('index', '.my-kibana'); @@ -108,11 +117,13 @@ describe('plugins/elasticsearch', function () { it('should update the build number on the new config', function () { get.withArgs('pkg.buildNum').returns(5801); - client.create.returns(Promise.resolve()); + callAsKibanaUser.withArgs('create', sinon.match.any).returns(Promise.resolve()); + const response = { hits: { hits: [ { _id: '4.0.0', _source: { buildNum: 1 } } ] } }; + return upgrade(response).then(function (resp) { - sinon.assert.calledOnce(client.create); - const params = client.create.args[0][0]; + sinon.assert.calledOnce(callAsKibanaUser); + const params = callAsKibanaUser.args[0][1]; expect(params).to.have.property('body'); expect(params.body).to.have.property('buildNum', 5801); expect(params).to.have.property('index', '.my-kibana'); @@ -123,8 +134,10 @@ describe('plugins/elasticsearch', function () { it('should log a message for upgrades', function () { get.withArgs('pkg.buildNum').returns(5801); - client.create.returns(Promise.resolve()); + callAsKibanaUser.withArgs('create', sinon.match.any).returns(Promise.resolve()); + const response = { hits: { hits: [ { _id: '4.0.0', _source: { buildNum: 1 } } ] } }; + return upgrade(response).then(function (resp) { sinon.assert.calledOnce(server.log); expect(server.log.args[0][0]).to.eql(['plugin', 'elasticsearch']); @@ -137,11 +150,13 @@ describe('plugins/elasticsearch', function () { it('should copy attributes from old config', function () { get.withArgs('pkg.buildNum').returns(5801); - client.create.returns(Promise.resolve()); + callAsKibanaUser.withArgs('create', sinon.match.any).returns(Promise.resolve()); + const response = { hits: { hits: [ { _id: '4.0.0', _source: { buildNum: 1, defaultIndex: 'logstash-*' } } ] } }; + return upgrade(response).then(function (resp) { - sinon.assert.calledOnce(client.create); - const params = client.create.args[0][0]; + sinon.assert.calledOnce(callAsKibanaUser); + const params = callAsKibanaUser.args[0][1]; expect(params).to.have.property('body'); expect(params.body).to.have.property('defaultIndex', 'logstash-*'); }); diff --git a/src/core_plugins/elasticsearch/lib/call_with_request.js b/src/core_plugins/elasticsearch/lib/call_with_request.js deleted file mode 100644 index ed53ee36ca372..0000000000000 --- a/src/core_plugins/elasticsearch/lib/call_with_request.js +++ /dev/null @@ -1,31 +0,0 @@ -import _ from 'lodash'; -import Promise from 'bluebird'; -import Boom from 'boom'; -import toPath from 'lodash/internal/toPath'; -import filterHeaders from './filter_headers'; - -module.exports = (server, client) => { - return (req, endpoint, clientParams = {}, options = {}) => { - const wrap401Errors = options.wrap401Errors !== false; - const filteredHeaders = filterHeaders(req.headers, server.config().get('elasticsearch.requestHeadersWhitelist')); - _.set(clientParams, 'headers', filteredHeaders); - const path = toPath(endpoint); - const api = _.get(client, path); - let apiContext = _.get(client, path.slice(0, -1)); - if (_.isEmpty(apiContext)) { - apiContext = client; - } - if (!api) throw new Error(`callWithRequest called with an invalid endpoint: ${endpoint}`); - return api.call(apiContext, clientParams) - .catch((err) => { - if (!wrap401Errors || err.statusCode !== 401) { - return Promise.reject(err); - } - - const boomError = Boom.wrap(err, err.statusCode); - const wwwAuthHeader = _.get(err, 'body.error.header[WWW-Authenticate]'); - boomError.output.headers['WWW-Authenticate'] = wwwAuthHeader || 'Basic realm="Authorization Required"'; - throw boomError; - }); - }; -}; diff --git a/src/core_plugins/elasticsearch/lib/check_es_version.js b/src/core_plugins/elasticsearch/lib/check_es_version.js index a6cc89978ac9b..59add2b0a707a 100644 --- a/src/core_plugins/elasticsearch/lib/check_es_version.js +++ b/src/core_plugins/elasticsearch/lib/check_es_version.js @@ -3,25 +3,30 @@ * that defined in Kibana's package.json. */ -import _ from 'lodash'; +import { forEach, get } from 'lodash'; import isEsCompatibleWithKibana from './is_es_compatible_with_kibana'; /** - * tracks the node descriptions that get logged in warnings so - * that we don't spam the log with the same message over and over. + * tracks the node descriptions that get logged in warnings so + * that we don't spam the log with the same message over and over. * - * There are situations, like in testing or multi-tenancy, where - * the server argument changes, so we must track the previous - * node warnings per server + * There are situations, like in testing or multi-tenancy, where + * the server argument changes, so we must track the previous + * node warnings per server */ const lastWarnedNodesForServer = new WeakMap(); module.exports = function checkEsVersion(server, kibanaVersion) { - server.log(['plugin', 'debug'], 'Checking Elasticsearch version'); - - const client = server.plugins.elasticsearch.client; + const { callAsKibanaUser } = server.plugins.elasticsearch.getCluster('admin'); - return client.nodes.info() + server.log(['plugin', 'debug'], 'Checking Elasticsearch version'); + return callAsKibanaUser('nodes.info', { + filterPath: [ + 'nodes.*.version', + 'nodes.*.http.publish_address', + 'nodes.*.ip', + ] + }) .then(function (info) { // Aggregate incompatible ES nodes. const incompatibleNodes = []; @@ -29,7 +34,7 @@ module.exports = function checkEsVersion(server, kibanaVersion) { // Aggregate ES nodes which should prompt a Kibana upgrade. const warningNodes = []; - _.forEach(info.nodes, esNode => { + forEach(info.nodes, esNode => { if (!isEsCompatibleWithKibana(esNode.version, kibanaVersion)) { // Exit early to avoid collecting ES nodes with newer major versions in the `warningNodes`. return incompatibleNodes.push(esNode); @@ -44,7 +49,7 @@ module.exports = function checkEsVersion(server, kibanaVersion) { function getHumanizedNodeNames(nodes) { return nodes.map(node => { - const publishAddress = _.get(node, 'http.publish_address') ? (_.get(node, 'http.publish_address') + ' ') : ''; + const publishAddress = get(node, 'http.publish_address') ? (get(node, 'http.publish_address') + ' ') : ''; return 'v' + node.version + ' @ ' + publishAddress + '(' + node.ip + ')'; }); } @@ -53,7 +58,7 @@ module.exports = function checkEsVersion(server, kibanaVersion) { const simplifiedNodes = warningNodes.map(node => ({ version: node.version, http: { - publish_address: _.get(node, 'http.publish_address') + publish_address: get(node, 'http.publish_address') }, ip: node.ip, })); diff --git a/src/core_plugins/elasticsearch/lib/check_for_tribe.js b/src/core_plugins/elasticsearch/lib/check_for_tribe.js new file mode 100644 index 0000000000000..09be5031509a1 --- /dev/null +++ b/src/core_plugins/elasticsearch/lib/check_for_tribe.js @@ -0,0 +1,18 @@ +import { get } from 'lodash'; + +export default function checkForTribe(callAsKibanaUser) { + return callAsKibanaUser('nodes.info', { + nodeId: '_local', + filterPath: 'nodes.*.settings.tribe' + }) + .then(function (info) { + const nodeId = Object.keys(info.nodes || {})[0]; + const tribeSettings = get(info, ['nodes', nodeId, 'settings', 'tribe']); + + if (tribeSettings) { + throw new Error('Kibana does not support using tribe nodes as the primary elasticsearch connection.'); + } + + return true; + }); +}; diff --git a/src/core_plugins/elasticsearch/lib/client_logger.js b/src/core_plugins/elasticsearch/lib/client_logger.js new file mode 100644 index 0000000000000..6e5a0dd6355d0 --- /dev/null +++ b/src/core_plugins/elasticsearch/lib/client_logger.js @@ -0,0 +1,39 @@ +module.exports = function (server) { + return class ElasticsearchClientLogging { + // additional tags to differentiate connection + get tags() { + return []; + } + + get logQueries() { + return false; + } + + error(err) { + server.log(['error', 'elasticsearch'].concat(this.tags), err); + } + + warning(message) { + server.log(['warning', 'elasticsearch'].concat(this.tags), message); + } + + info() {} + + debug() {} + + trace(method, options, query, _response, statusCode) { + /* Check if query logging is enabled + * It requires Kibana to be configured with verbose logging turned on. */ + if (this.logQueries) { + const methodAndPath = `${method} ${options.path}`; + const queryDsl = query ? query.trim() : ''; + server.log(['elasticsearch', 'query', 'debug'].concat(this.tags), [ + statusCode, + methodAndPath, + queryDsl + ].join('\n')); + } + } + close() {} + }; +}; diff --git a/src/core_plugins/elasticsearch/lib/cluster.js b/src/core_plugins/elasticsearch/lib/cluster.js new file mode 100644 index 0000000000000..79a97136bdffd --- /dev/null +++ b/src/core_plugins/elasticsearch/lib/cluster.js @@ -0,0 +1,100 @@ +import elasticsearch from 'elasticsearch'; +import { bindKey, partial, get, set, isEmpty, cloneDeep } from 'lodash'; +import toPath from 'lodash/internal/toPath'; +import Promise from 'bluebird'; +import Boom from 'boom'; + +import createClient from './create_client'; +import filterHeaders from './filter_headers'; + +export default class Cluster { + constructor(config) { + this._config = Object.assign({}, config); + this.errors = elasticsearch.errors; + + this._client = this.createClient(); + this.callAsKibanaUser = this.callAsKibanaUserFactory(this._client); + + this._noAuthClient = this.createClient({ auth: false }); + this.callWithRequest = this.callWithRequestFactory(this._noAuthClient); + + return this; + } + + /** + * callAsKibanaUser + * + * Makes a call to ES using the credentials in kibana.yml + * + * @param {string} endpoint + * @param {Object} clientParams + * @param {Object} options + * @param {boolean} options.wrap401Errors + * @returns {Promise} + */ + callAsKibanaUserFactory(client) { + return partial(this.callWithRequestFactory(client), undefined); + } + + callWithRequestFactory(client) { + /** + * callWithRequest + * + * Makes a call to ES, passing through whitelisted headers in the request + * + * The whitelisted headers are defined in the config under _requestHeadersWhitelist_ + * + * @param {Object|undefined} req - The request object + * @param {string} endpoint + * @param {Object} clientParams + * @param {Object} options + * @param {boolean} options.wrap401Errors + * @returns {Promise} + */ + return (req = {}, endpoint, clientParams = {}, options = {}) => { + const wrap401Errors = options.wrap401Errors !== false; + + if (req.headers) { + const filteredHeaders = filterHeaders(req.headers, this.config('requestHeadersWhitelist')); + set(clientParams, 'headers', filteredHeaders); + } + + const clientPath = toPath(endpoint); + const api = get(client, clientPath); + + let apiContext = get(client, clientPath.slice(0, -1)); + if (isEmpty(apiContext)) { + apiContext = client; + } + + if (!api) { + throw new Error(`called with an invalid endpoint: ${endpoint}`); + } + + return api.call(apiContext, clientParams).catch((err) => { + if (!wrap401Errors || err.statusCode !== 401) { + return Promise.reject(err); + } + + const boomError = Boom.wrap(err, err.statusCode); + const wwwAuthHeader = get(err, 'body.error.header[WWW-Authenticate]'); + boomError.output.headers['WWW-Authenticate'] = wwwAuthHeader || 'Basic realm="Authorization Required"'; + + throw boomError; + }); + }; + } + + config(path) { + return cloneDeep(path ? get(this._config, path) : this._config); + } + + createClient(options = {}) { + return createClient(Object.assign({}, this.config(), options)); + } + + close() { + this._client.close(); + this._noAuthClient.close(); + } +} diff --git a/src/core_plugins/elasticsearch/lib/clusters.js b/src/core_plugins/elasticsearch/lib/clusters.js new file mode 100644 index 0000000000000..607c198c3833c --- /dev/null +++ b/src/core_plugins/elasticsearch/lib/clusters.js @@ -0,0 +1,14 @@ +import Cluster from './cluster'; + +const clusters = new Map(); + +export function getCluster(name) { + return clusters.get(name); +} + +export function createCluster(name, config) { + const cluster = new Cluster(config); + clusters.set(name, cluster); + + return cluster; +} diff --git a/src/core_plugins/elasticsearch/lib/create_admin_cluster.js b/src/core_plugins/elasticsearch/lib/create_admin_cluster.js new file mode 100644 index 0000000000000..0c78e1f51ba6c --- /dev/null +++ b/src/core_plugins/elasticsearch/lib/create_admin_cluster.js @@ -0,0 +1,19 @@ +export default function (server) { + const config = server.config(); + const Logger = server.plugins.elasticsearch.ElasticsearchClientLogging; + + class AdminClientLogging extends Logger { + get tags() { + return ['admin']; + } + + get logQueries() { + return Boolean(config.get('elasticsearch.logQueries')); + } + } + + return server.plugins.elasticsearch.createCluster( + 'admin', + Object.assign({ log: AdminClientLogging }, config.get('elasticsearch')) + ); +}; diff --git a/src/core_plugins/elasticsearch/lib/create_agent.js b/src/core_plugins/elasticsearch/lib/create_agent.js index 9297fa637529a..d8c29adf711ee 100644 --- a/src/core_plugins/elasticsearch/lib/create_agent.js +++ b/src/core_plugins/elasticsearch/lib/create_agent.js @@ -4,24 +4,23 @@ const readFile = (file) => require('fs').readFileSync(file, 'utf8'); import http from 'http'; import https from 'https'; -module.exports = _.memoize(function (server) { - const config = server.config(); - const target = url.parse(config.get('elasticsearch.url')); +module.exports = _.memoize(function (config) { + const target = url.parse(_.get(config, 'url')); if (!/^https/.test(target.protocol)) return new http.Agent(); const agentOptions = { - rejectUnauthorized: config.get('elasticsearch.ssl.verify') + rejectUnauthorized: _.get(config, 'ssl.verify') }; - if (_.size(config.get('elasticsearch.ssl.ca'))) { - agentOptions.ca = config.get('elasticsearch.ssl.ca').map(readFile); + if (_.size(_.get(config, 'ssl.ca'))) { + agentOptions.ca = _.get(config, 'ssl.ca').map(readFile); } // Add client certificate and key if required by elasticsearch - if (config.get('elasticsearch.ssl.cert') && config.get('elasticsearch.ssl.key')) { - agentOptions.cert = readFile(config.get('elasticsearch.ssl.cert')); - agentOptions.key = readFile(config.get('elasticsearch.ssl.key')); + if (_.get(config, 'ssl.cert') && _.get(config, 'ssl.key')) { + agentOptions.cert = readFile(_.get(config, 'ssl.cert')); + agentOptions.key = readFile(_.get(config, 'ssl.key')); } return new https.Agent(agentOptions); diff --git a/src/core_plugins/elasticsearch/lib/create_client.js b/src/core_plugins/elasticsearch/lib/create_client.js new file mode 100644 index 0000000000000..aba35de84b955 --- /dev/null +++ b/src/core_plugins/elasticsearch/lib/create_client.js @@ -0,0 +1,52 @@ +import url from 'url'; +import util from 'util'; +import elasticsearch from 'elasticsearch'; +import Bluebird from 'bluebird'; +import { readFileSync } from 'fs'; + +const readFile = (file) => readFileSync(file, 'utf8'); + +module.exports = function (options) { + options = Object.assign({ keepAlive: true, auth: true }, options); + + const uri = url.parse(options.url); + + if (options.auth && options.username && options.password) { + uri.auth = util.format('%s:%s', options.username, options.password); + } + + const ssl = { rejectUnauthorized: options.ssl.verify }; + + if (options.ssl.cert && options.ssl.key) { + ssl.cert = readFile(options.ssl.cert); + ssl.key = readFile(options.ssl.key); + } + + if (options.ssl.ca) { + ssl.ca = options.ssl.ca.map(readFile); + } + + const host = { + host: uri.hostname, + port: uri.port, + protocol: uri.protocol, + path: uri.pathname, + auth: uri.auth, + query: uri.query, + headers: options.customHeaders + }; + + return new elasticsearch.Client({ + host, + ssl, + plugins: options.plugins, + apiVersion: options.apiVersion, + keepAlive: options.keepAlive, + pingTimeout: options.pingTimeout, + requestTimeout: options.requestTimeout, + defer: function () { + return Bluebird.defer(); + }, + log: options.log + }); +}; diff --git a/src/core_plugins/elasticsearch/lib/create_data_cluster.js b/src/core_plugins/elasticsearch/lib/create_data_cluster.js new file mode 100644 index 0000000000000..affc118bed7e4 --- /dev/null +++ b/src/core_plugins/elasticsearch/lib/create_data_cluster.js @@ -0,0 +1,30 @@ +export default function (server) { + const config = server.config(); + const esPlugins = server.plugins.elasticsearch; + const Logger = server.plugins.elasticsearch.ElasticsearchClientLogging; + + class DataClientLogging extends Logger { + get tags() { + return ['data']; + } + + get logQueries() { + return Boolean(getConfig().logQueries); + } + } + + function getConfig() { + const esConfig = config.get('elasticsearch.tribe'); + + if (!Boolean(esConfig.url)) { + return config.get('elasticsearch'); + } + + return esConfig; + } + + return server.plugins.elasticsearch.createCluster( + 'data', + Object.assign({ log: DataClientLogging }, getConfig()) + ); +}; diff --git a/src/core_plugins/elasticsearch/lib/create_kibana_index.js b/src/core_plugins/elasticsearch/lib/create_kibana_index.js index 54e48658dee79..d0afd647de5bc 100644 --- a/src/core_plugins/elasticsearch/lib/create_kibana_index.js +++ b/src/core_plugins/elasticsearch/lib/create_kibana_index.js @@ -2,10 +2,10 @@ import { format } from 'util'; import { mappings } from './kibana_index_mappings'; module.exports = function (server) { - const client = server.plugins.elasticsearch.client; + const callAsKibanaUser = server.plugins.elasticsearch.getCluster('admin').callAsKibanaUser; const index = server.config().get('kibana.index'); - return client.indices.create({ + return callAsKibanaUser('indices.create', { index: index, body: { settings: { @@ -18,7 +18,7 @@ module.exports = function (server) { throw new Error(`Unable to create Kibana index "${index}"`); }) .then(function () { - return client.cluster.health({ + return callAsKibanaUser('cluster.health', { waitForStatus: 'yellow', index: index }) diff --git a/src/core_plugins/elasticsearch/lib/create_proxy.js b/src/core_plugins/elasticsearch/lib/create_proxy.js index 068712ca9c70f..e228f4754cb87 100644 --- a/src/core_plugins/elasticsearch/lib/create_proxy.js +++ b/src/core_plugins/elasticsearch/lib/create_proxy.js @@ -3,48 +3,57 @@ import mapUri from './map_uri'; import { resolve } from 'url'; import { assign } from 'lodash'; -function createProxy(server, method, route, config) { - - const options = { - method: method, - path: createProxy.createPath(route), - config: { - timeout: { - socket: server.config().get('elasticsearch.requestTimeout') - } - }, - handler: { - proxy: { - mapUri: mapUri(server), - agent: createAgent(server), - xforward: true, - timeout: server.config().get('elasticsearch.requestTimeout'), - onResponse: function (err, responseFromUpstream, request, reply) { - if (err) { - reply(err); - return; - } - - if (responseFromUpstream.headers.location) { - // TODO: Workaround for #8705 until hapi has been updated to >= 15.0.0 - responseFromUpstream.headers.location = encodeURI(responseFromUpstream.headers.location); - } - - reply(null, responseFromUpstream); - } - } - }, +function createProxy(server, method, path, config) { + const proxies = new Map([ + ['/elasticsearch', server.plugins.elasticsearch.getCluster('data')], + ['/es_admin', server.plugins.elasticsearch.getCluster('admin')] + ]); + + const responseHandler = function (err, upstreamResponse, request, reply) { + if (err) { + reply(err); + return; + } + + if (upstreamResponse.headers.location) { + // TODO: Workaround for #8705 until hapi has been updated to >= 15.0.0 + upstreamResponse.headers.location = encodeURI(upstreamResponse.headers.location); + } + + reply(null, upstreamResponse); }; - assign(options.config, config); + for (let [proxyPrefix, cluster] of proxies) { + const options = { + method: method, + path: createProxy.createPath(proxyPrefix, path), + config: { + timeout: { + socket: server.config().get('elasticsearch.requestTimeout') + } + }, + handler: { + proxy: { + mapUri: mapUri(cluster, proxyPrefix), + agent: createAgent(cluster.config()), + xforward: true, + timeout: server.config().get('elasticsearch.requestTimeout'), + onResponse: responseHandler + } + }, + }; - server.route(options); + assign(options.config, config); + + server.route(options); + } }; -createProxy.createPath = function createPath(path) { - const pre = '/elasticsearch'; - const sep = path[0] === '/' ? '' : '/'; - return `${pre}${sep}${path}`; +createProxy.createPath = function createPath(prefix, path) { + path = path[0] === '/' ? path : `/${path}`; + prefix = prefix[0] === '/' ? prefix : `/${prefix}`; + + return `${prefix}${path}`; }; module.exports = createProxy; diff --git a/src/core_plugins/elasticsearch/lib/expose_client.js b/src/core_plugins/elasticsearch/lib/expose_client.js deleted file mode 100644 index a1748e54ebbeb..0000000000000 --- a/src/core_plugins/elasticsearch/lib/expose_client.js +++ /dev/null @@ -1,99 +0,0 @@ -import elasticsearch from 'elasticsearch'; -import _ from 'lodash'; -import Bluebird from 'bluebird'; -const readFile = (file) => require('fs').readFileSync(file, 'utf8'); -import util from 'util'; -import url from 'url'; -import callWithRequest from './call_with_request'; -import filterHeaders from './filter_headers'; - -module.exports = function (server) { - const config = server.config(); - - class ElasticsearchClientLogging { - error(err) { - server.log(['error', 'elasticsearch'], err); - } - warning(message) { - server.log(['warning', 'elasticsearch'], message); - } - info() {} - debug() {} - trace() {} - close() {} - } - - function createClient(options) { - options = _.defaults(options || {}, { - url: config.get('elasticsearch.url'), - username: config.get('elasticsearch.username'), - password: config.get('elasticsearch.password'), - verifySsl: config.get('elasticsearch.ssl.verify'), - clientCrt: config.get('elasticsearch.ssl.cert'), - clientKey: config.get('elasticsearch.ssl.key'), - ca: config.get('elasticsearch.ssl.ca'), - apiVersion: config.get('elasticsearch.apiVersion'), - pingTimeout: config.get('elasticsearch.pingTimeout'), - requestTimeout: config.get('elasticsearch.requestTimeout'), - keepAlive: true, - auth: true - }); - - const uri = url.parse(options.url); - - let authorization; - if (options.auth && options.username && options.password) { - uri.auth = util.format('%s:%s', options.username, options.password); - } - - const ssl = { rejectUnauthorized: options.verifySsl }; - if (options.clientCrt && options.clientKey) { - ssl.cert = readFile(options.clientCrt); - ssl.key = readFile(options.clientKey); - } - if (options.ca) { - ssl.ca = options.ca.map(readFile); - } - - const host = { - host: uri.hostname, - port: uri.port, - protocol: uri.protocol, - path: uri.pathname, - auth: uri.auth, - query: uri.query, - headers: config.get('elasticsearch.customHeaders') - }; - - return new elasticsearch.Client({ - host, - ssl, - plugins: options.plugins, - apiVersion: options.apiVersion, - keepAlive: options.keepAlive, - pingTimeout: options.pingTimeout, - requestTimeout: options.requestTimeout, - defer: function () { - return Bluebird.defer(); - }, - log: ElasticsearchClientLogging - }); - } - - const client = createClient(); - server.on('close', _.bindKey(client, 'close')); - - const noAuthClient = createClient({ auth: false }); - server.on('close', _.bindKey(noAuthClient, 'close')); - - server.expose('ElasticsearchClientLogging', ElasticsearchClientLogging); - server.expose('client', client); - server.expose('createClient', createClient); - server.expose('callWithRequestFactory', _.partial(callWithRequest, server)); - server.expose('callWithRequest', callWithRequest(server, noAuthClient)); - server.expose('filterHeaders', filterHeaders); - server.expose('errors', elasticsearch.errors); - - return client; - -}; diff --git a/src/core_plugins/elasticsearch/lib/health_check.js b/src/core_plugins/elasticsearch/lib/health_check.js index 00ab4e1686730..e1bbc8804d657 100644 --- a/src/core_plugins/elasticsearch/lib/health_check.js +++ b/src/core_plugins/elasticsearch/lib/health_check.js @@ -1,11 +1,11 @@ import _ from 'lodash'; import Promise from 'bluebird'; import elasticsearch from 'elasticsearch'; -import exposeClient from './expose_client'; import migrateConfig from './migrate_config'; import createKibanaIndex from './create_kibana_index'; import checkEsVersion from './check_es_version'; import kibanaVersion from './kibana_version'; +import checkForTribe from './check_for_tribe'; const NoConnections = elasticsearch.errors.NoConnections; import util from 'util'; @@ -15,27 +15,25 @@ const NO_INDEX = 'no_index'; const INITIALIZING = 'initializing'; const READY = 'ready'; -const REQUEST_DELAY = 2500; - module.exports = function (plugin, server) { const config = server.config(); - const client = server.plugins.elasticsearch.client; + const callAdminAsKibanaUser = server.plugins.elasticsearch.getCluster('admin').callAsKibanaUser; + const callDataAsKibanaUser = server.plugins.elasticsearch.getCluster('data').callAsKibanaUser; + const REQUEST_DELAY = config.get('elasticsearch.healthCheck.delay'); plugin.status.yellow('Waiting for Elasticsearch'); - - function waitForPong() { - return client.ping().catch(function (err) { + function waitForPong(callAsKibanaUser, url) { + return callAsKibanaUser('ping').catch(function (err) { if (!(err instanceof NoConnections)) throw err; + plugin.status.red(format('Unable to connect to Elasticsearch at %s.', url)); - plugin.status.red(format('Unable to connect to Elasticsearch at %s.', config.get('elasticsearch.url'))); - - return Promise.delay(REQUEST_DELAY).then(waitForPong); + return Promise.delay(REQUEST_DELAY).then(waitForPong.bind(null, callAsKibanaUser, url)); }); } // just figure out the current "health" of the es setup function getHealth() { - return client.cluster.health({ + return callAdminAsKibanaUser('cluster.health', { timeout: '5s', // tells es to not sit around and wait forever index: config.get('kibana.index'), ignore: [408] @@ -93,14 +91,28 @@ module.exports = function (plugin, server) { } function check() { - return waitForPong() - .then(waitForEsVersion) - .then(waitForShards) + const healthChecks = [ + waitForPong(callAdminAsKibanaUser, config.get('elasticsearch.url')) + .then(waitForEsVersion) + .then(checkForTribe.bind(this, callAdminAsKibanaUser)) + .then(waitForShards) + .then(_.partial(migrateConfig, server)) + ]; + + const tribeUrl = config.get('elasticsearch.tribe.url'); + if (tribeUrl) { + healthChecks.push( + waitForPong(callDataAsKibanaUser, tribeUrl) + .then(() => checkEsVersion(server, kibanaVersion.get(), callDataAsKibanaUser)) + ); + } + + return Promise.all(healthChecks) .then(setGreenStatus) - .then(_.partial(migrateConfig, server)) .catch(err => plugin.status.red(err)); } + let timeoutId = null; function scheduleCheck(ms) { diff --git a/src/core_plugins/elasticsearch/lib/map_uri.js b/src/core_plugins/elasticsearch/lib/map_uri.js index daaf9b73c9633..ec9e11bff8e77 100644 --- a/src/core_plugins/elasticsearch/lib/map_uri.js +++ b/src/core_plugins/elasticsearch/lib/map_uri.js @@ -3,9 +3,7 @@ import { parse as parseUrl, format as formatUrl, resolve } from 'url'; import filterHeaders from './filter_headers'; import setHeaders from './set_headers'; -export default function mapUri(server, prefix) { - const config = server.config(); - +export default function mapUri(cluster, proxyPrefix) { function joinPaths(pathA, pathB) { return trimRight(pathA, '/') + '/' + trimLeft(pathB, '/'); } @@ -19,29 +17,29 @@ export default function mapUri(server, prefix) { port: esUrlPort, pathname: esUrlBasePath, query: esUrlQuery - } = parseUrl(config.get('elasticsearch.url'), true); + } = parseUrl(cluster.config('url'), true); // copy most url components directly from the elasticsearch.url const mappedUrlComponents = { protocol: esUrlProtocol, - slashes: esUrlHasSlashes, - auth: esUrlAuth, + slashes: esUrlHasSlashes, // QUESTION: would it every be anything else? + auth: esUrlAuth, // QUESTION: should we pass this on? hostname: esUrlHostname, port: esUrlPort }; // pathname - const reqSubPath = request.path.replace('/elasticsearch', ''); + const reqSubPath = request.path.replace(proxyPrefix, ''); mappedUrlComponents.pathname = joinPaths(esUrlBasePath, reqSubPath); // querystring - const mappedQuery = defaults(omit(request.query, '_'), esUrlQuery || {}); + const mappedQuery = defaults(omit(request.query, '_'), esUrlQuery); if (Object.keys(mappedQuery).length) { mappedUrlComponents.query = mappedQuery; } - const filteredHeaders = filterHeaders(request.headers, config.get('elasticsearch.requestHeadersWhitelist')); - const mappedHeaders = setHeaders(filteredHeaders, config.get('elasticsearch.customHeaders')); + const filteredHeaders = filterHeaders(request.headers, cluster.config('requestHeadersWhitelist')); + const mappedHeaders = setHeaders(filteredHeaders, cluster.config('customHeaders')); const mappedUrl = formatUrl(mappedUrlComponents); done(null, mappedUrl, mappedHeaders); }; diff --git a/src/core_plugins/elasticsearch/lib/migrate_config.js b/src/core_plugins/elasticsearch/lib/migrate_config.js index 7b16990e21297..d90d0f16da55d 100644 --- a/src/core_plugins/elasticsearch/lib/migrate_config.js +++ b/src/core_plugins/elasticsearch/lib/migrate_config.js @@ -3,7 +3,8 @@ import { mappings } from './kibana_index_mappings'; module.exports = function (server) { const config = server.config(); - const client = server.plugins.elasticsearch.client; + const callAsKibanaUser = server.plugins.elasticsearch.getCluster('admin').callAsKibanaUser; + const options = { index: config.get('kibana.index'), type: 'config', @@ -20,5 +21,5 @@ module.exports = function (server) { } }; - return client.search(options).then(upgrade(server)); + return callAsKibanaUser('search', options).then(upgrade(server)); }; diff --git a/src/core_plugins/elasticsearch/lib/upgrade_config.js b/src/core_plugins/elasticsearch/lib/upgrade_config.js index 9050767d969ac..58a5878f13ae3 100644 --- a/src/core_plugins/elasticsearch/lib/upgrade_config.js +++ b/src/core_plugins/elasticsearch/lib/upgrade_config.js @@ -6,11 +6,11 @@ import { format } from 'util'; module.exports = function (server) { const MAX_INTEGER = Math.pow(2, 53) - 1; - const client = server.plugins.elasticsearch.client; + const callAsKibanaUser = server.plugins.elasticsearch.getCluster('admin').callAsKibanaUser; const config = server.config(); function createNewConfig() { - return client.create({ + return callAsKibanaUser('create', { index: config.get('kibana.index'), type: 'config', body: { buildNum: config.get('pkg.buildNum') }, @@ -31,7 +31,9 @@ module.exports = function (server) { return hit._id !== '@@version' && hit._id === config.get('pkg.version'); }); - if (devConfig) return Promise.resolve(); + if (devConfig) { + return Promise.resolve(); + } // Look for upgradeable configs. If none of them are upgradeable // then create a new one. @@ -50,7 +52,7 @@ module.exports = function (server) { newVersion: config.get('pkg.version') }); - return client.create({ + return callAsKibanaUser('create', { index: config.get('kibana.index'), type: 'config', body: body._source, diff --git a/src/core_plugins/kibana/index.js b/src/core_plugins/kibana/index.js index 85bc26a855046..1ae544ec1b55f 100644 --- a/src/core_plugins/kibana/index.js +++ b/src/core_plugins/kibana/index.js @@ -22,6 +22,7 @@ module.exports = function (kibana) { }, uiExports: { + hacks: ['plugins/kibana/dev_tools/hacks/disable'], app: { id: 'kibana', title: 'Kibana', @@ -70,6 +71,7 @@ module.exports = function (kibana) { description: 'compose visualizations for much win', icon: 'plugins/kibana/assets/dashboard.svg', }, { + id: 'kibana:dev_tools', title: 'Dev Tools', order: 9001, url: '/app/kibana#/dev_tools', diff --git a/src/core_plugins/kibana/public/dashboard/services/saved_dashboards.js b/src/core_plugins/kibana/public/dashboard/services/saved_dashboards.js index d90f5faa750f7..7e0502834a02c 100644 --- a/src/core_plugins/kibana/public/dashboard/services/saved_dashboards.js +++ b/src/core_plugins/kibana/public/dashboard/services/saved_dashboards.js @@ -15,8 +15,8 @@ require('plugins/kibana/management/saved_object_registry').register({ }); // This is the only thing that gets injected into controllers -module.service('savedDashboards', function (Promise, SavedDashboard, kbnIndex, es, kbnUrl) { - const scanner = new Scanner(es, { +module.service('savedDashboards', function (Promise, SavedDashboard, kbnIndex, esAdmin, kbnUrl) { + const scanner = new Scanner(esAdmin, { index: kbnIndex, type: 'dashboard' }); @@ -78,7 +78,7 @@ module.service('savedDashboards', function (Promise, SavedDashboard, kbnIndex, e body = { query: {match_all: {}}}; } - return es.search({ + return esAdmin.search({ index: kbnIndex, type: 'dashboard', body: body, diff --git a/src/core_plugins/kibana/public/dev_tools/hacks/disable.js b/src/core_plugins/kibana/public/dev_tools/hacks/disable.js new file mode 100644 index 0000000000000..c6fc97a9eae60 --- /dev/null +++ b/src/core_plugins/kibana/public/dev_tools/hacks/disable.js @@ -0,0 +1,16 @@ +import chrome from 'ui/chrome'; +import modules from 'ui/modules'; + +modules.get('kibana').run(function ($rootScope, $location) { + if (!chrome.getInjected('esDataIsTribe')) { + return; + } + const navLink = chrome.getNavLinkById('kibana:dev_tools'); + navLink.disabled = true; + navLink.tooltip = 'Dev Tools are disabled when using tribe nodes'; + $rootScope.$on('$locationChangeStart', function (event, newUrl) { + if (~newUrl.indexOf(navLink.url)) { + $location.path('/').replace(); + } + }); +}); diff --git a/src/core_plugins/kibana/public/discover/saved_searches/saved_searches.js b/src/core_plugins/kibana/public/discover/saved_searches/saved_searches.js index 0ad2526d78bc8..c11c5f87ba818 100644 --- a/src/core_plugins/kibana/public/discover/saved_searches/saved_searches.js +++ b/src/core_plugins/kibana/public/discover/saved_searches/saved_searches.js @@ -16,8 +16,8 @@ require('plugins/kibana/management/saved_object_registry').register({ title: 'searches' }); -module.service('savedSearches', function (Promise, config, kbnIndex, es, createNotifier, SavedSearch, kbnUrl) { - const scanner = new Scanner(es, { +module.service('savedSearches', function (Promise, config, kbnIndex, esAdmin, createNotifier, SavedSearch, kbnUrl) { + const scanner = new Scanner(esAdmin, { index: kbnIndex, type: 'search' }); @@ -82,7 +82,7 @@ module.service('savedSearches', function (Promise, config, kbnIndex, es, createN body = { query: {match_all: {}}}; } - return es.search({ + return esAdmin.search({ index: kbnIndex, type: 'search', body: body, diff --git a/src/core_plugins/kibana/public/management/sections/indices/_refresh_kibana_index.js b/src/core_plugins/kibana/public/management/sections/indices/_refresh_kibana_index.js index e0becc475ab43..ac3528b22dbb5 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/_refresh_kibana_index.js +++ b/src/core_plugins/kibana/public/management/sections/indices/_refresh_kibana_index.js @@ -1,6 +1,6 @@ -export default function RefreshKibanaIndexFn(es, kbnIndex) { +export default function RefreshKibanaIndexFn(esAdmin, kbnIndex) { return function () { - return es.indices.refresh({ + return esAdmin.indices.refresh({ index: kbnIndex }); }; diff --git a/src/core_plugins/kibana/public/management/sections/objects/_objects.js b/src/core_plugins/kibana/public/management/sections/objects/_objects.js index 1d68a35cb3fea..0e8b960e2a897 100644 --- a/src/core_plugins/kibana/public/management/sections/objects/_objects.js +++ b/src/core_plugins/kibana/public/management/sections/objects/_objects.js @@ -18,7 +18,7 @@ uiModules.get('apps/management') .directive('kbnManagementObjects', function (kbnIndex, Notifier, Private, kbnUrl, Promise) { return { restrict: 'E', - controller: function ($scope, $injector, $q, AppState, es) { + controller: function ($scope, $injector, $q, AppState, esAdmin) { const notify = new Notifier({ location: 'Saved Objects' }); const $state = $scope.state = new AppState(); @@ -106,7 +106,7 @@ uiModules.get('apps/management') function retrieveAndExportDocs(objs) { if (!objs.length) return notify.error('No saved objects to export.'); - es.mget({ + esAdmin.mget({ index: kbnIndex, body: {docs: objs.map(transformToMget)} }) @@ -147,7 +147,7 @@ uiModules.get('apps/management') }; function refreshIndex() { - return es.indices.refresh({ + return esAdmin.indices.refresh({ index: kbnIndex }); } diff --git a/src/core_plugins/kibana/public/management/sections/objects/_view.js b/src/core_plugins/kibana/public/management/sections/objects/_view.js index ef868fa6bfa90..72abb1a93b92a 100644 --- a/src/core_plugins/kibana/public/management/sections/objects/_view.js +++ b/src/core_plugins/kibana/public/management/sections/objects/_view.js @@ -16,7 +16,7 @@ uiModules.get('apps/management') .directive('kbnManagementObjectsView', function (kbnIndex, Notifier) { return { restrict: 'E', - controller: function ($scope, $injector, $routeParams, $location, $window, $rootScope, es, Private) { + controller: function ($scope, $injector, $routeParams, $location, $window, $rootScope, esAdmin, Private) { const notify = new Notifier({ location: 'SavedObject view' }); const castMappingType = Private(IndexPatternsCastMappingTypeProvider); const serviceObj = registry.get($routeParams.service); @@ -104,7 +104,7 @@ uiModules.get('apps/management') $scope.title = service.type; - es.get({ + esAdmin.get({ index: kbnIndex, type: service.type, id: $routeParams.id @@ -163,7 +163,7 @@ uiModules.get('apps/management') * @returns {type} description */ $scope.delete = function () { - es.delete({ + esAdmin.delete({ index: kbnIndex, type: service.type, id: $routeParams.id @@ -191,7 +191,7 @@ uiModules.get('apps/management') _.set(source, field.name, value); }); - es.index({ + esAdmin.index({ index: kbnIndex, type: service.type, id: $routeParams.id, @@ -204,7 +204,7 @@ uiModules.get('apps/management') }; function redirectHandler(action) { - return es.indices.refresh({ + return esAdmin.indices.refresh({ index: kbnIndex }) .then(function (resp) { diff --git a/src/core_plugins/kibana/public/visualize/saved_visualizations/saved_visualizations.js b/src/core_plugins/kibana/public/visualize/saved_visualizations/saved_visualizations.js index 2b845d6391563..d1a4178d89735 100644 --- a/src/core_plugins/kibana/public/visualize/saved_visualizations/saved_visualizations.js +++ b/src/core_plugins/kibana/public/visualize/saved_visualizations/saved_visualizations.js @@ -13,10 +13,10 @@ require('plugins/kibana/management/saved_object_registry').register({ title: 'visualizations' }); -app.service('savedVisualizations', function (Promise, es, kbnIndex, SavedVis, Private, Notifier, kbnUrl) { +app.service('savedVisualizations', function (Promise, esAdmin, kbnIndex, SavedVis, Private, Notifier, kbnUrl) { const visTypes = Private(RegistryVisTypesProvider); - const scanner = new Scanner(es, { + const scanner = new Scanner(esAdmin, { index: kbnIndex, type: 'visualization' }); @@ -95,7 +95,7 @@ app.service('savedVisualizations', function (Promise, es, kbnIndex, SavedVis, Pr body = { query: {match_all: {}}}; } - return es.search({ + return esAdmin.search({ index: kbnIndex, type: 'visualization', body: body, diff --git a/src/core_plugins/kibana/server/routes/api/ingest/register_field_capabilities.js b/src/core_plugins/kibana/server/routes/api/ingest/register_field_capabilities.js index e4d619ab1e322..0cf643af2d8fa 100644 --- a/src/core_plugins/kibana/server/routes/api/ingest/register_field_capabilities.js +++ b/src/core_plugins/kibana/server/routes/api/ingest/register_field_capabilities.js @@ -6,7 +6,7 @@ export function registerFieldCapabilities(server) { path: '/api/kibana/{indices}/field_capabilities', method: ['GET'], handler: function (req, reply) { - const callWithRequest = server.plugins.elasticsearch.callWithRequest; + const callWithRequest = server.plugins.elasticsearch.getCluster('data').callWithRequest; const indices = req.params.indices || ''; return callWithRequest(req, 'fieldStats', { diff --git a/src/core_plugins/kibana/server/routes/api/scripts/register_languages.js b/src/core_plugins/kibana/server/routes/api/scripts/register_languages.js index 82bb5cc9ba22c..9ad34df3b2643 100644 --- a/src/core_plugins/kibana/server/routes/api/scripts/register_languages.js +++ b/src/core_plugins/kibana/server/routes/api/scripts/register_languages.js @@ -6,7 +6,7 @@ export function registerLanguages(server) { path: '/api/kibana/scripts/languages', method: 'GET', handler: function (request, reply) { - const callWithRequest = server.plugins.elasticsearch.callWithRequest; + const callWithRequest = server.plugins.elasticsearch.getCluster('data').callWithRequest; return callWithRequest(request, 'cluster.getSettings', { include_defaults: true, diff --git a/src/core_plugins/kibana/server/routes/api/search/count/register_count.js b/src/core_plugins/kibana/server/routes/api/search/count/register_count.js index 8e542afe70cf0..efb65a0a81b1e 100644 --- a/src/core_plugins/kibana/server/routes/api/search/count/register_count.js +++ b/src/core_plugins/kibana/server/routes/api/search/count/register_count.js @@ -6,7 +6,7 @@ export default function registerCount(server) { path: '/api/kibana/{id}/_count', method: ['POST', 'GET'], handler: function (req, reply) { - const boundCallWithRequest = _.partial(server.plugins.elasticsearch.callWithRequest, req); + const boundCallWithRequest = _.partial(server.plugins.elasticsearch.getCluster('data').callWithRequest, req); boundCallWithRequest('count', { allowNoIndices: false, diff --git a/src/core_plugins/timelion/public/services/saved_sheets.js b/src/core_plugins/timelion/public/services/saved_sheets.js index 53f6e0616ed3a..bb10f12dda92f 100644 --- a/src/core_plugins/timelion/public/services/saved_sheets.js +++ b/src/core_plugins/timelion/public/services/saved_sheets.js @@ -13,7 +13,7 @@ define(function (require) { }); // This is the only thing that gets injected into controllers - module.service('savedSheets', function (Promise, SavedSheet, kbnIndex, es, kbnUrl) { + module.service('savedSheets', function (Promise, SavedSheet, kbnIndex, esAdmin, kbnUrl) { this.type = SavedSheet.type; this.Class = SavedSheet; @@ -57,7 +57,7 @@ define(function (require) { body = { query: {match_all: {}}}; } - return es.search({ + return esAdmin.search({ index: kbnIndex, type: 'timelion-sheet', body: body, diff --git a/src/core_plugins/timelion/server/routes/validate_es.js b/src/core_plugins/timelion/server/routes/validate_es.js index eaa625beca177..65d7d0039e025 100644 --- a/src/core_plugins/timelion/server/routes/validate_es.js +++ b/src/core_plugins/timelion/server/routes/validate_es.js @@ -5,7 +5,7 @@ module.exports = function (server) { handler: function (request, reply) { return server.uiSettings().getAll(request).then((uiSettings) => { - var callWithRequest = server.plugins.elasticsearch.callWithRequest; + var callWithRequest = server.plugins.elasticsearch.getCluster('data').callWithRequest; var timefield = uiSettings['timelion:es.timefield']; diff --git a/src/core_plugins/timelion/server/series_functions/__tests__/es.js b/src/core_plugins/timelion/server/series_functions/__tests__/es.js index 6e227b49889e5..d45485f3757c9 100644 --- a/src/core_plugins/timelion/server/series_functions/__tests__/es.js +++ b/src/core_plugins/timelion/server/series_functions/__tests__/es.js @@ -9,18 +9,23 @@ import esResponse from './fixtures/es_response'; import Promise from 'bluebird'; import _ from 'lodash'; -import {expect} from 'chai'; +import { expect } from 'chai'; +import sinon from 'sinon'; import invoke from './helpers/invoke_series_fn.js'; function stubResponse(response) { return { - server: {plugins:{ - elasticsearch: { - callWithRequest: function () { - return Promise.resolve(response); + server: { + plugins:{ + elasticsearch: { + getCluster: sinon.stub().withArgs('data').returns({ + callWithRequest: function () { + return Promise.resolve(response); + } + }) } } - }} + } }; } diff --git a/src/core_plugins/timelion/server/series_functions/es/index.js b/src/core_plugins/timelion/server/series_functions/es/index.js index 16b1c13fcc1bb..c861a505cc730 100644 --- a/src/core_plugins/timelion/server/series_functions/es/index.js +++ b/src/core_plugins/timelion/server/series_functions/es/index.js @@ -61,7 +61,7 @@ module.exports = new Datasource('es', { fit: 'nearest' }); - var callWithRequest = tlConfig.server.plugins.elasticsearch.callWithRequest; + var callWithRequest = tlConfig.server.plugins.elasticsearch.getCluster('data').callWithRequest; var body = buildRequest(config, tlConfig); return callWithRequest(tlConfig.request, 'search', body).then(function (resp) { diff --git a/src/server/http/short_url_lookup.js b/src/server/http/short_url_lookup.js index 1341128c5ee99..1ded80229067a 100644 --- a/src/server/http/short_url_lookup.js +++ b/src/server/http/short_url_lookup.js @@ -2,7 +2,7 @@ import crypto from 'crypto'; export default function (server) { async function updateMetadata(urlId, urlDoc, req) { - const callWithRequest = server.plugins.elasticsearch.callWithRequest; + const callWithRequest = server.plugins.elasticsearch.getCluster('admin').callWithRequest; const kibanaIndex = server.config().get('kibana.index'); try { @@ -25,7 +25,7 @@ export default function (server) { async function getUrlDoc(urlId, req) { const urlDoc = await new Promise((resolve, reject) => { - const callWithRequest = server.plugins.elasticsearch.callWithRequest; + const callWithRequest = server.plugins.elasticsearch.getCluster('admin').callWithRequest; const kibanaIndex = server.config().get('kibana.index'); callWithRequest(req, 'get', { @@ -46,7 +46,7 @@ export default function (server) { async function createUrlDoc(url, urlId, req) { const newUrlId = await new Promise((resolve, reject) => { - const callWithRequest = server.plugins.elasticsearch.callWithRequest; + const callWithRequest = server.plugins.elasticsearch.getCluster('admin').callWithRequest; const kibanaIndex = server.config().get('kibana.index'); callWithRequest(req, 'index', { diff --git a/src/ui/public/chrome/api/angular.js b/src/ui/public/chrome/api/angular.js index 5755dafff9166..06a9d64d76af4 100644 --- a/src/ui/public/chrome/api/angular.js +++ b/src/ui/public/chrome/api/angular.js @@ -31,6 +31,11 @@ module.exports = function (chrome, internals) { a.href = chrome.addBasePath('/elasticsearch'); return a.href; }())) + .value('esAdminUrl', (function () { + let a = document.createElement('a'); + a.href = chrome.addBasePath('/es_admin'); + return a.href; + }())) .config(chrome.$setupXsrfRequestInterceptor) .config(['$compileProvider', function ($compileProvider) { if (!internals.devMode) { diff --git a/src/ui/public/courier/__tests__/request_queue.js b/src/ui/public/courier/__tests__/request_queue.js index 947671686e1bd..e693852231acc 100644 --- a/src/ui/public/courier/__tests__/request_queue.js +++ b/src/ui/public/courier/__tests__/request_queue.js @@ -4,7 +4,7 @@ import sinon from 'auto-release-sinon'; import RequestQueueProv from '../_request_queue'; import SearchStrategyProv from '../fetch/strategy/search'; -import DocStrategyProv from '../fetch/strategy/doc'; +import DocStrategyProv from '../fetch/strategy/doc_data'; describe('Courier Request Queue', function () { let docStrategy; diff --git a/src/ui/public/courier/__tests__/saved_object.js b/src/ui/public/courier/__tests__/saved_object.js index 23adcde6eab50..b8dfacaa39162 100644 --- a/src/ui/public/courier/__tests__/saved_object.js +++ b/src/ui/public/courier/__tests__/saved_object.js @@ -9,7 +9,7 @@ import BluebirdPromise from 'bluebird'; import SavedObjectFactory from '../saved_object/saved_object'; import IndexPatternFactory from 'ui/index_patterns/_index_pattern'; -import DocSourceProvider from '../data_source/doc_source'; +import DocSourceProvider from '../data_source/admin_doc_source'; import { stubMapper } from 'test_utils/stub_mapper'; @@ -19,7 +19,8 @@ describe('Saved Object', function () { let SavedObject; let IndexPattern; - let esStub; + let esAdminStub; + let esDataStub; let DocSource; /** @@ -29,7 +30,7 @@ describe('Saved Object', function () { // Allows the type 'dashboard' to be used. // Unfortunately we need to use bluebird here instead of native promises because there is // a call to finally. - sinon.stub(esStub.indices, 'getFieldMapping').returns(BluebirdPromise.resolve({ + sinon.stub(esAdminStub.indices, 'getFieldMapping').returns(BluebirdPromise.resolve({ '.kibana' : { 'mappings': { 'dashboard': {} @@ -38,8 +39,8 @@ describe('Saved Object', function () { })); // Necessary to avoid a timeout condition. - sinon.stub(esStub.indices, 'putMapping').returns(BluebirdPromise.resolve()); - sinon.stub(esStub.indices, 'refresh').returns(BluebirdPromise.resolve()); + sinon.stub(esAdminStub.indices, 'putMapping').returns(BluebirdPromise.resolve()); + sinon.stub(esAdminStub.indices, 'refresh').returns(BluebirdPromise.resolve()); } /** @@ -66,8 +67,10 @@ describe('Saved Object', function () { * @param {Object} mockDocResponse */ function stubESResponse(mockDocResponse) { - sinon.stub(esStub, 'mget').returns(BluebirdPromise.resolve({ docs: [mockDocResponse] })); - sinon.stub(esStub, 'index').returns(BluebirdPromise.resolve(mockDocResponse)); + sinon.stub(esDataStub, 'mget').returns(BluebirdPromise.resolve({ docs: [mockDocResponse] })); + sinon.stub(esDataStub, 'index').returns(BluebirdPromise.resolve(mockDocResponse)); + sinon.stub(esAdminStub, 'mget').returns(BluebirdPromise.resolve({ docs: [mockDocResponse] })); + sinon.stub(esAdminStub, 'index').returns(BluebirdPromise.resolve(mockDocResponse)); } /** @@ -84,10 +87,11 @@ describe('Saved Object', function () { } beforeEach(ngMock.module('kibana')); - beforeEach(ngMock.inject(function (es, Private) { + beforeEach(ngMock.inject(function (es, esAdmin, Private) { SavedObject = Private(SavedObjectFactory); IndexPattern = Private(IndexPatternFactory); - esStub = es; + esAdminStub = esAdmin; + esDataStub = es; DocSource = Private(DocSourceProvider); mockEsService(); diff --git a/src/ui/public/courier/courier.js b/src/ui/public/courier/courier.js index 4e09d24a8ef82..4111f3500c21c 100644 --- a/src/ui/public/courier/courier.js +++ b/src/ui/public/courier/courier.js @@ -14,7 +14,8 @@ import SearchStrategyProvider from './fetch/strategy/search'; import RequestQueueProvider from './_request_queue'; import ErrorHandlersProvider from './_error_handlers'; import FetchProvider from './fetch'; -import DocLooperProvider from './looper/doc'; +import DocDataLooperProvider from './looper/doc_data'; +import DocAdminLooperProvider from './looper/doc_admin'; import SearchLooperProvider from './looper/search'; import RootSearchSourceProvider from './data_source/_root_search_source'; import SavedObjectProvider from './saved_object'; @@ -34,7 +35,8 @@ uiModules.get('kibana/courier') let errorHandlers = Private(ErrorHandlersProvider); let fetch = Private(FetchProvider); - let docLooper = self.docLooper = Private(DocLooperProvider); + let docDataLooper = self.docLooper = Private(DocDataLooperProvider); + let docAdminLooper = self.docLooper = Private(DocAdminLooperProvider); let searchLooper = self.searchLooper = Private(SearchLooperProvider); // expose some internal modules @@ -65,7 +67,8 @@ uiModules.get('kibana/courier') */ self.start = function () { searchLooper.start(); - docLooper.start(); + docDataLooper.start(); + docAdminLooper.start(); return this; }; @@ -124,7 +127,8 @@ uiModules.get('kibana/courier') */ self.close = function () { searchLooper.stop(); - docLooper.stop(); + docAdminLooper.stop(); + docDataLooper.stop(); _.invoke(requestQueue, 'abort'); diff --git a/src/ui/public/courier/data_source/_abstract_doc_source.js b/src/ui/public/courier/data_source/_abstract_doc_source.js new file mode 100644 index 0000000000000..058466ebf1aa0 --- /dev/null +++ b/src/ui/public/courier/data_source/_abstract_doc_source.js @@ -0,0 +1,168 @@ +/** + * @name AbstractDocSource + * + * NOTE: This class is tightly coupled with _doc_send_to_es. Its primary + * methods (`doUpdate`, `doIndex`, `doCreate`) are all proxies for methods + * exposed by _doc_send_to_es (`update`, `index`, `create`). These methods are + * called with AbstractDocSource as the context. When called, they depend on “private” + * AbstractDocSource methods within their execution. + */ + +import _ from 'lodash'; + +import 'ui/es'; +import 'ui/storage'; + +import DocSendToEsProvider from './_doc_send_to_es'; +import AbstractDataSourceProvider from './_abstract'; +import DocRequestProvider from '../fetch/request/doc'; + +export default function AbstractDocSourceFactory(Private, Promise, es, sessionStorage) { + let sendToEs = Private(DocSendToEsProvider); + let SourceAbstract = Private(AbstractDataSourceProvider); + let DocRequest = Private(DocRequestProvider); + + _.class(AbstractDocSource).inherits(SourceAbstract); + function AbstractDocSource(initialState, strategy) { + AbstractDocSource.Super.call(this, initialState, strategy); + } + + AbstractDocSource.prototype.onUpdate = SourceAbstract.prototype.onResults; + AbstractDocSource.prototype.onResults = void 0; + + /***** + * PUBLIC API + *****/ + + AbstractDocSource.prototype._createRequest = function (defer) { + return new DocRequest(this, defer); + }; + + /** + * List of methods that is turned into a chainable API in the constructor + * @type {Array} + */ + AbstractDocSource.prototype._methods = [ + 'index', + 'type', + 'id', + 'sourceInclude', + 'sourceExclude' + ]; + + /** + * Applies a partial update to the document + * @param {object} fields - The fields to change and their new values (es doc field) + * @return {undefined} + */ + AbstractDocSource.prototype.doUpdate = function (fields) { + if (!this._state.id) return this.doIndex(fields); + return sendToEs.call(this, 'update', false, { doc: fields }); + }; + + /** + * Update the document stored + * @param {[type]} body [description] + * @return {[type]} [description] + */ + AbstractDocSource.prototype.doIndex = function (body) { + return sendToEs.call(this, 'index', false, body); + }; + + AbstractDocSource.prototype.doCreate = function (body) { + return sendToEs.call(this, 'create', false, body, []); + }; + + /***** + * PRIVATE API + *****/ + + /** + * Get the type of this SourceAbstract + * @return {string} - 'doc' + */ + AbstractDocSource.prototype._getType = function () { + return 'doc'; + }; + + /** + * Used to merge properties into the state within ._flatten(). + * The state is passed in and modified by the function + * + * @param {object} state - the current merged state + * @param {*} val - the value at `key` + * @param {*} key - The key of `val` + * @return {undefined} + */ + AbstractDocSource.prototype._mergeProp = function (state, val, key) { + key = '_' + key; + + if (val != null && state[key] == null) { + state[key] = val; + } + }; + + /** + * Creates a key based on the doc's index/type/id + * @return {string} + */ + AbstractDocSource.prototype._versionKey = function () { + let state = this._state; + + if (!state.index || !state.type || !state.id) return; + return 'DocVersion:' + ( + [ state.index, state.type, state.id ] + .map(encodeURIComponent) + .join('/') + ); + }; + + /** + * Get the cached version number, not the version that is + * stored/shared with other tabs + * + * @return {number} - the version number, or undefined + */ + AbstractDocSource.prototype._getVersion = function () { + if (this._version) return this._version; + else return this._getStoredVersion(); + }; + + /** + * Fetches the stored version from storage + * @return {[type]} [description] + */ + AbstractDocSource.prototype._getStoredVersion = function () { + let key = this._versionKey(); + if (!key) return; + + let v = sessionStorage.get(key); + this._version = v ? _.parseInt(v) : void 0; + return this._version; + }; + + /** + * Stores the version into storage + * @param {number, NaN} version - the current version number, NaN works well forcing a refresh + * @return {undefined} + */ + AbstractDocSource.prototype._storeVersion = function (version) { + if (!version) return this._clearVersion(); + + let key = this._versionKey(); + if (!key) return; + this._version = version; + sessionStorage.set(key, version); + }; + + /** + * Clears the stored version for a AbstractDocSource + */ + AbstractDocSource.prototype._clearVersion = function () { + let key = this._versionKey(); + if (!key) return; + sessionStorage.remove(key); + }; + + return AbstractDocSource; +}; diff --git a/src/ui/public/courier/data_source/_doc_send_to_es.js b/src/ui/public/courier/data_source/_doc_send_to_es.js index f7191b03100a9..9ea2e68391e31 100644 --- a/src/ui/public/courier/data_source/_doc_send_to_es.js +++ b/src/ui/public/courier/data_source/_doc_send_to_es.js @@ -11,7 +11,7 @@ import errors from 'ui/errors'; import RequestQueueProvider from 'ui/courier/_request_queue'; import FetchProvider from 'ui/courier/fetch/fetch'; -export default function (Promise, Private, es) { +export default function (Promise, Private, es, esAdmin, kbnIndex) { let requestQueue = Private(RequestQueueProvider); let courierFetch = Private(FetchProvider); @@ -32,8 +32,8 @@ export default function (Promise, Private, es) { if (validateVersion && params.id) { params.version = doc._getVersion(); } - - return es[method](params) + const client = _.includes(params.index, kbnIndex) ? esAdmin : es; + return client[method](params) .then(function (resp) { if (resp.status === 409) throw new errors.VersionConflict(resp); diff --git a/src/ui/public/courier/data_source/admin_doc_source.js b/src/ui/public/courier/data_source/admin_doc_source.js new file mode 100644 index 0000000000000..378a8ccc001b0 --- /dev/null +++ b/src/ui/public/courier/data_source/admin_doc_source.js @@ -0,0 +1,26 @@ +/** + * @name AdminDocSource + */ + +import _ from 'lodash'; + +import AbstractDocSource from './_abstract_doc_source'; +import DocStrategyProvider from '../fetch/strategy/doc_admin'; +import DocRequestProvider from '../fetch/request/doc_admin'; + +export default function DocSourceFactory(Private) { + let DocSourceAbstract = Private(AbstractDocSource); + let docStrategy = Private(DocStrategyProvider); + let DocRequest = Private(DocRequestProvider); + + _.class(AdminDocSource).inherits(DocSourceAbstract); + function AdminDocSource(initialState) { + AdminDocSource.Super.call(this, initialState, docStrategy); + } + + AdminDocSource.prototype._createRequest = function (defer) { + return new DocRequest(this, defer); + }; + + return AdminDocSource; +}; diff --git a/src/ui/public/courier/data_source/doc_source.js b/src/ui/public/courier/data_source/doc_source.js index 80be1cf7b6095..6e3fa696fd8b5 100644 --- a/src/ui/public/courier/data_source/doc_source.js +++ b/src/ui/public/courier/data_source/doc_source.js @@ -1,170 +1,26 @@ /** * @name DocSource - * - * NOTE: This class is tightly coupled with _doc_send_to_es. Its primary - * methods (`doUpdate`, `doIndex`, `doCreate`) are all proxies for methods - * exposed by _doc_send_to_es (`update`, `index`, `create`). These methods are - * called with DocSource as the context. When called, they depend on “private” - * DocSource methods within their execution. */ import _ from 'lodash'; -import 'ui/es'; -import 'ui/storage'; +import AbstractDocSource from './_abstract_doc_source'; +import DocStrategyProvider from '../fetch/strategy/doc_data'; +import DocRequestProvider from '../fetch/request/doc_data'; -import DocSendToEsProvider from './_doc_send_to_es'; -import AbstractDataSourceProvider from './_abstract'; -import DocRequestProvider from '../fetch/request/doc'; -import DocStrategyProvider from '../fetch/strategy/doc'; - -export default function DocSourceFactory(Private, Promise, es, sessionStorage) { - let sendToEs = Private(DocSendToEsProvider); - let SourceAbstract = Private(AbstractDataSourceProvider); - let DocRequest = Private(DocRequestProvider); +export default function DocSourceFactory(Private) { + let DocSourceAbstract = Private(AbstractDocSource); let docStrategy = Private(DocStrategyProvider); + let DocRequest = Private(DocRequestProvider); - _.class(DocSource).inherits(SourceAbstract); + _.class(DocSource).inherits(DocSourceAbstract); function DocSource(initialState) { DocSource.Super.call(this, initialState, docStrategy); } - DocSource.prototype.onUpdate = SourceAbstract.prototype.onResults; - DocSource.prototype.onResults = void 0; - - /***** - * PUBLIC API - *****/ - DocSource.prototype._createRequest = function (defer) { return new DocRequest(this, defer); }; - /** - * List of methods that is turned into a chainable API in the constructor - * @type {Array} - */ - DocSource.prototype._methods = [ - 'index', - 'type', - 'id', - 'sourceInclude', - 'sourceExclude' - ]; - - /** - * Applies a partial update to the document - * @param {object} fields - The fields to change and their new values (es doc field) - * @return {undefined} - */ - DocSource.prototype.doUpdate = function (fields) { - if (!this._state.id) return this.doIndex(fields); - return sendToEs.call(this, 'update', false, { doc: fields }); - }; - - /** - * Update the document stored - * @param {[type]} body [description] - * @return {[type]} [description] - */ - DocSource.prototype.doIndex = function (body) { - return sendToEs.call(this, 'index', false, body); - }; - - DocSource.prototype.doCreate = function (body) { - return sendToEs.call(this, 'create', false, body, []); - }; - - /***** - * PRIVATE API - *****/ - - /** - * Get the type of this SourceAbstract - * @return {string} - 'doc' - */ - DocSource.prototype._getType = function () { - return 'doc'; - }; - - /** - * Used to merge properties into the state within ._flatten(). - * The state is passed in and modified by the function - * - * @param {object} state - the current merged state - * @param {*} val - the value at `key` - * @param {*} key - The key of `val` - * @return {undefined} - */ - DocSource.prototype._mergeProp = function (state, val, key) { - key = '_' + key; - - if (val != null && state[key] == null) { - state[key] = val; - } - }; - - /** - * Creates a key based on the doc's index/type/id - * @return {string} - */ - DocSource.prototype._versionKey = function () { - let state = this._state; - - if (!state.index || !state.type || !state.id) return; - return 'DocVersion:' + ( - [ state.index, state.type, state.id ] - .map(encodeURIComponent) - .join('/') - ); - }; - - /** - * Get the cached version number, not the version that is - * stored/shared with other tabs - * - * @return {number} - the version number, or undefined - */ - DocSource.prototype._getVersion = function () { - if (this._version) return this._version; - else return this._getStoredVersion(); - }; - - /** - * Fetches the stored version from storage - * @return {[type]} [description] - */ - DocSource.prototype._getStoredVersion = function () { - let key = this._versionKey(); - if (!key) return; - - let v = sessionStorage.get(key); - this._version = v ? _.parseInt(v) : void 0; - return this._version; - }; - - /** - * Stores the version into storage - * @param {number, NaN} version - the current version number, NaN works well forcing a refresh - * @return {undefined} - */ - DocSource.prototype._storeVersion = function (version) { - if (!version) return this._clearVersion(); - - let key = this._versionKey(); - if (!key) return; - this._version = version; - sessionStorage.set(key, version); - }; - - /** - * Clears the stored version for a DocSource - */ - DocSource.prototype._clearVersion = function () { - let key = this._versionKey(); - if (!key) return; - sessionStorage.remove(key); - }; - return DocSource; }; diff --git a/src/ui/public/courier/fetch/call_client.js b/src/ui/public/courier/fetch/call_client.js index 21c130cde4809..8b41206463760 100644 --- a/src/ui/public/courier/fetch/call_client.js +++ b/src/ui/public/courier/fetch/call_client.js @@ -4,7 +4,7 @@ import IsRequestProvider from './is_request'; import MergeDuplicatesRequestProvider from './merge_duplicate_requests'; import ReqStatusProvider from './req_status'; -export default function CourierFetchCallClient(Private, Promise, es) { +export default function CourierFetchCallClient(Private, Promise, esAdmin, es) { const isRequest = Private(IsRequestProvider); const mergeDuplicateRequests = Private(MergeDuplicatesRequestProvider); @@ -94,7 +94,9 @@ export default function CourierFetchCallClient(Private, Promise, es) { throw ABORTED; } - return (esPromise = es[strategy.clientMethod]({ body })); + const id = strategy.id; + const client = (id && ~id.indexOf('admin')) ? esAdmin : es; + return (esPromise = client[strategy.clientMethod]({ body })); }) .then(function (clientResp) { return strategy.getResponses(clientResp); diff --git a/src/ui/public/courier/fetch/request/doc.js b/src/ui/public/courier/fetch/request/doc.js index bbe0d12e7ee6c..6fff6a33d326b 100644 --- a/src/ui/public/courier/fetch/request/doc.js +++ b/src/ui/public/courier/fetch/request/doc.js @@ -1,9 +1,7 @@ -import DocStrategyProvider from '../strategy/doc'; import AbstractRequestProvider from './request'; export default function DocRequestProvider(Private) { - const docStrategy = Private(DocStrategyProvider); const AbstractRequest = Private(AbstractRequestProvider); class DocRequest extends AbstractRequest { @@ -11,7 +9,6 @@ export default function DocRequestProvider(Private) { super(...args); this.type = 'doc'; - this.strategy = docStrategy; } canStart() { diff --git a/src/ui/public/courier/fetch/request/doc_admin.js b/src/ui/public/courier/fetch/request/doc_admin.js new file mode 100644 index 0000000000000..657708a3d72ba --- /dev/null +++ b/src/ui/public/courier/fetch/request/doc_admin.js @@ -0,0 +1,17 @@ +import DocStrategyProvider from '../strategy/doc_admin'; +import AbstractDocRequestProvider from './doc'; + +export default function DocRequestProvider(Private) { + + const docStrategy = Private(DocStrategyProvider); + const AbstractDocRequest = Private(AbstractDocRequestProvider); + + class AdminDocRequest extends AbstractDocRequest { + constructor(...args) { + super(...args); + this.strategy = docStrategy; + } + } + + return AdminDocRequest; +}; diff --git a/src/ui/public/courier/fetch/request/doc_data.js b/src/ui/public/courier/fetch/request/doc_data.js new file mode 100644 index 0000000000000..8e70d865aaa5b --- /dev/null +++ b/src/ui/public/courier/fetch/request/doc_data.js @@ -0,0 +1,17 @@ +import DocStrategyProvider from '../strategy/doc_data'; +import AbstractDocRequestProvider from './doc'; + +export default function DocRequestProvider(Private) { + + const docStrategy = Private(DocStrategyProvider); + const AbstractDocRequest = Private(AbstractDocRequestProvider); + + class DataDocRequest extends AbstractDocRequest { + constructor(...args) { + super(...args); + this.strategy = docStrategy; + } + } + + return DataDocRequest; +}; diff --git a/src/ui/public/courier/fetch/strategy/doc_admin.js b/src/ui/public/courier/fetch/strategy/doc_admin.js new file mode 100644 index 0000000000000..1df32329af244 --- /dev/null +++ b/src/ui/public/courier/fetch/strategy/doc_admin.js @@ -0,0 +1,26 @@ +export default function FetchStrategyForDoc(Promise) { + return { + id: 'doc_admin', + clientMethod: 'mget', + + /** + * Flatten a series of requests into as ES request body + * @param {array} requests - an array of flattened requests + * @return {Promise} - a promise that is fulfilled by the request body + */ + reqsFetchParamsToBody: function (reqsFetchParams) { + return Promise.resolve({ + docs: reqsFetchParams + }); + }, + + /** + * Fetch the multiple responses from the ES Response + * @param {object} resp - The response sent from Elasticsearch + * @return {array} - the list of responses + */ + getResponses: function (resp) { + return resp.docs; + } + }; +}; diff --git a/src/ui/public/courier/fetch/strategy/doc.js b/src/ui/public/courier/fetch/strategy/doc_data.js similarity index 100% rename from src/ui/public/courier/fetch/strategy/doc.js rename to src/ui/public/courier/fetch/strategy/doc_data.js diff --git a/src/ui/public/courier/looper/doc_admin.js b/src/ui/public/courier/looper/doc_admin.js new file mode 100644 index 0000000000000..c3a3fed852ede --- /dev/null +++ b/src/ui/public/courier/looper/doc_admin.js @@ -0,0 +1,19 @@ +import FetchProvider from '../fetch'; +import LooperProvider from './_looper'; +import DocStrategyProvider from '../fetch/strategy/doc_admin'; + +export default function DocLooperService(Private) { + let fetch = Private(FetchProvider); + let Looper = Private(LooperProvider); + let DocStrategy = Private(DocStrategyProvider); + + /** + * The Looper which will manage the doc fetch interval + * @type {Looper} + */ + let docLooper = new Looper(1500, function () { + fetch.fetchQueued(DocStrategy); + }); + + return docLooper; +}; diff --git a/src/ui/public/courier/looper/doc.js b/src/ui/public/courier/looper/doc_data.js similarity index 88% rename from src/ui/public/courier/looper/doc.js rename to src/ui/public/courier/looper/doc_data.js index e0f21394777c8..b8f8d9e3081a8 100644 --- a/src/ui/public/courier/looper/doc.js +++ b/src/ui/public/courier/looper/doc_data.js @@ -1,6 +1,6 @@ import FetchProvider from '../fetch'; import LooperProvider from './_looper'; -import DocStrategyProvider from '../fetch/strategy/doc'; +import DocStrategyProvider from '../fetch/strategy/doc_data'; export default function DocLooperService(Private) { let fetch = Private(FetchProvider); diff --git a/src/ui/public/courier/saved_object/saved_object.js b/src/ui/public/courier/saved_object/saved_object.js index d2a3c11d23ef8..bd7b32dedf7db 100644 --- a/src/ui/public/courier/saved_object/saved_object.js +++ b/src/ui/public/courier/saved_object/saved_object.js @@ -16,10 +16,10 @@ import errors from 'ui/errors'; import uuid from 'node-uuid'; import MappingSetupProvider from 'ui/utils/mapping_setup'; -import DocSourceProvider from '../data_source/doc_source'; +import DocSourceProvider from '../data_source/admin_doc_source'; import SearchSourceProvider from '../data_source/search_source'; -export default function SavedObjectFactory(es, kbnIndex, Promise, Private, Notifier, safeConfirm, indexPatterns) { +export default function SavedObjectFactory(esAdmin, kbnIndex, Promise, Private, Notifier, safeConfirm, indexPatterns) { let DocSource = Private(DocSourceProvider); let SearchSource = Private(SearchSourceProvider); @@ -255,7 +255,7 @@ export default function SavedObjectFactory(es, kbnIndex, Promise, Private, Notif * @returns {Promise} */ function refreshIndex() { - return es.indices.refresh({ index: kbnIndex }); + return esAdmin.indices.refresh({ index: kbnIndex }); } /** @@ -312,7 +312,7 @@ export default function SavedObjectFactory(es, kbnIndex, Promise, Private, Notif * @return {promise} */ this.delete = () => { - return es.delete( + return esAdmin.delete( { index: kbnIndex, type: type, diff --git a/src/ui/public/es.js b/src/ui/public/es.js index def095dc08b41..702ddd0688fe1 100644 --- a/src/ui/public/es.js +++ b/src/ui/public/es.js @@ -9,38 +9,53 @@ import 'elasticsearch-browser'; import _ from 'lodash'; import uiModules from 'ui/modules'; -let es; // share the client amongst all apps +const plugins = [function (Client, config) { + // esFactory automatically injects the AngularConnector to the config + // https://github.com/elastic/elasticsearch-js/blob/master/src/lib/connectors/angular.js + _.class(CustomAngularConnector).inherits(config.connectionClass); + function CustomAngularConnector(host, config) { + CustomAngularConnector.Super.call(this, host, config); + + this.request = _.wrap(this.request, function (request, params, cb) { + if (String(params.method).toUpperCase() === 'GET') { + params.query = _.defaults({ _: Date.now() }, params.query); + } + + return request.call(this, params, cb); + }); + } + + config.connectionClass = CustomAngularConnector; +}]; + + +// share the clients amongst all apps +let es; +let esAdmin; + uiModules .get('kibana', ['elasticsearch', 'kibana/config']) - .service('es', function (esFactory, esUrl, $q, esApiVersion, esRequestTimeout) { + .service('es', function (esFactory, esUrl, esApiVersion, esRequestTimeout) { if (es) return es; - es = esFactory({ host: esUrl, log: 'info', requestTimeout: esRequestTimeout, apiVersion: esApiVersion, - plugins: [function (Client, config) { - - // esFactory automatically injects the AngularConnector to the config - // https://github.com/elastic/elasticsearch-js/blob/master/src/lib/connectors/angular.js - _.class(CustomAngularConnector).inherits(config.connectionClass); - function CustomAngularConnector(host, config) { - CustomAngularConnector.Super.call(this, host, config); - - this.request = _.wrap(this.request, function (request, params, cb) { - if (String(params.method).toUpperCase() === 'GET') { - params.query = _.defaults({ _: Date.now() }, params.query); - } - - return request.call(this, params, cb); - }); - } - - config.connectionClass = CustomAngularConnector; - - }] + plugins }); return es; + }) + .service('esAdmin', function (esFactory, esAdminUrl, esApiVersion, esRequestTimeout) { + if (esAdmin) return esAdmin; + esAdmin = esFactory({ + host: esAdminUrl, + log: 'info', + requestTimeout: esRequestTimeout, + apiVersion: esApiVersion, + plugins + }); + + return esAdmin; }); diff --git a/src/ui/public/index_patterns/__tests__/_index_pattern.js b/src/ui/public/index_patterns/__tests__/_index_pattern.js index 5acab51892973..156a1b6ec8152 100644 --- a/src/ui/public/index_patterns/__tests__/_index_pattern.js +++ b/src/ui/public/index_patterns/__tests__/_index_pattern.js @@ -7,7 +7,7 @@ import errors from 'ui/errors'; import IndexedArray from 'ui/indexed_array'; import FixturesLogstashFieldsProvider from 'fixtures/logstash_fields'; import FixturesStubbedDocSourceResponseProvider from 'fixtures/stubbed_doc_source_response'; -import DocSourceProvider from 'ui/courier/data_source/doc_source'; +import DocSourceProvider from 'ui/courier/data_source/admin_doc_source'; import UtilsMappingSetupProvider from 'ui/utils/mapping_setup'; import IndexPatternsIntervalsProvider from 'ui/index_patterns/_intervals'; import IndexPatternsIndexPatternProvider from 'ui/index_patterns/_index_pattern'; diff --git a/src/ui/public/index_patterns/_get_ids.js b/src/ui/public/index_patterns/_get_ids.js index b499b1dd3859d..99c067d84e5a5 100644 --- a/src/ui/public/index_patterns/_get_ids.js +++ b/src/ui/public/index_patterns/_get_ids.js @@ -1,5 +1,5 @@ import _ from 'lodash'; -export default function GetIndexPatternIdsFn(es, kbnIndex) { +export default function GetIndexPatternIdsFn(esAdmin, kbnIndex) { // many places may require the id list, so we will cache it seperately // didn't incorportate with the indexPattern cache to prevent id collisions. @@ -13,7 +13,7 @@ export default function GetIndexPatternIdsFn(es, kbnIndex) { }); } - cachedPromise = es.search({ + cachedPromise = esAdmin.search({ index: kbnIndex, type: 'index-pattern', storedFields: [], diff --git a/src/ui/public/index_patterns/_index_pattern.js b/src/ui/public/index_patterns/_index_pattern.js index b12ce6e57844c..f616534b355ae 100644 --- a/src/ui/public/index_patterns/_index_pattern.js +++ b/src/ui/public/index_patterns/_index_pattern.js @@ -7,7 +7,7 @@ import RegistryFieldFormatsProvider from 'ui/registry/field_formats'; import IndexPatternsGetIdsProvider from 'ui/index_patterns/_get_ids'; import IndexPatternsMapperProvider from 'ui/index_patterns/_mapper'; import IndexPatternsIntervalsProvider from 'ui/index_patterns/_intervals'; -import DocSourceProvider from 'ui/courier/data_source/doc_source'; +import DocSourceProvider from 'ui/courier/data_source/admin_doc_source'; import UtilsMappingSetupProvider from 'ui/utils/mapping_setup'; import IndexPatternsFieldListProvider from 'ui/index_patterns/_field_list'; import IndexPatternsFlattenHitProvider from 'ui/index_patterns/_flatten_hit'; diff --git a/src/ui/public/index_patterns/_mapper.js b/src/ui/public/index_patterns/_mapper.js index b3a0d5b4584e2..ac3c9a4833c8a 100644 --- a/src/ui/public/index_patterns/_mapper.js +++ b/src/ui/public/index_patterns/_mapper.js @@ -6,7 +6,7 @@ import IndexPatternsTransformMappingIntoFieldsProvider from 'ui/index_patterns/_ import IndexPatternsIntervalsProvider from 'ui/index_patterns/_intervals'; import IndexPatternsPatternToWildcardProvider from 'ui/index_patterns/_pattern_to_wildcard'; import IndexPatternsLocalCacheProvider from 'ui/index_patterns/_local_cache'; -export default function MapperService(Private, Promise, es, config, kbnIndex) { +export default function MapperService(Private, Promise, es, esAdmin, config, kbnIndex) { let enhanceFieldsWithCapabilities = Private(EnhanceFieldsWithCapabilitiesProvider); let transformMappingIntoFields = Private(IndexPatternsTransformMappingIntoFieldsProvider); @@ -37,7 +37,7 @@ export default function MapperService(Private, Promise, es, config, kbnIndex) { if (cache) return Promise.resolve(cache); if (!skipIndexPatternCache) { - return es.get({ + return esAdmin.get({ index: kbnIndex, type: 'index-pattern', id: id, diff --git a/src/ui/public/index_patterns/index_patterns.js b/src/ui/public/index_patterns/index_patterns.js index 18ea1b7c95cfd..190f3f7fe86c7 100644 --- a/src/ui/public/index_patterns/index_patterns.js +++ b/src/ui/public/index_patterns/index_patterns.js @@ -11,7 +11,7 @@ import RegistryFieldFormatsProvider from 'ui/registry/field_formats'; import uiModules from 'ui/modules'; let module = uiModules.get('kibana/index_patterns'); -function IndexPatternsProvider(es, Notifier, Private, Promise, kbnIndex) { +function IndexPatternsProvider(esAdmin, Notifier, Private, Promise, kbnIndex) { let self = this; let IndexPattern = Private(IndexPatternsIndexPatternProvider); @@ -34,7 +34,7 @@ function IndexPatternsProvider(es, Notifier, Private, Promise, kbnIndex) { self.getIds.clearCache(); pattern.destroy(); - return es.delete({ + return esAdmin.delete({ index: kbnIndex, type: 'index-pattern', id: pattern.id diff --git a/src/ui/public/utils/mapping_setup.js b/src/ui/public/utils/mapping_setup.js index 47ef8e10d4a83..71aca22a42de3 100644 --- a/src/ui/public/utils/mapping_setup.js +++ b/src/ui/public/utils/mapping_setup.js @@ -1,7 +1,7 @@ import angular from 'angular'; import _ from 'lodash'; define(function () { - return function MappingSetupService(kbnIndex, es) { + return function MappingSetupService(kbnIndex, esAdmin) { let mappingSetup = this; let json = { @@ -23,7 +23,7 @@ define(function () { * @return {[type]} [description] */ let getKnownKibanaTypes = _.once(function () { - return es.indices.getFieldMapping({ + return esAdmin.indices.getFieldMapping({ // only concerned with types in this kibana index index: kbnIndex, // check all types @@ -83,7 +83,7 @@ define(function () { properties: mapping }; - return es.indices.putMapping({ + return esAdmin.indices.putMapping({ index: kbnIndex, type: type, body: body diff --git a/src/ui/settings/__tests__/index.js b/src/ui/settings/__tests__/index.js index d2ffc25764641..d303214fe9596 100644 --- a/src/ui/settings/__tests__/index.js +++ b/src/ui/settings/__tests__/index.js @@ -343,7 +343,7 @@ describe('ui settings', function () { }); function expectElasticsearchGetQuery(server, req, configGet) { - const { callWithRequest } = server.plugins.elasticsearch; + const { callWithRequest } = server.plugins.elasticsearch.getCluster('admin'); sinon.assert.calledOnce(callWithRequest); const [reqPassed, method, params] = callWithRequest.args[0]; expect(reqPassed).to.be(req); @@ -356,7 +356,7 @@ function expectElasticsearchGetQuery(server, req, configGet) { } function expectElasticsearchUpdateQuery(server, req, configGet, doc) { - const { callWithRequest } = server.plugins.elasticsearch; + const { callWithRequest } = server.plugins.elasticsearch.getCluster('admin'); sinon.assert.calledOnce(callWithRequest); const [reqPassed, method, params] = callWithRequest.args[0]; expect(reqPassed).to.be(req); @@ -388,27 +388,37 @@ function instantiate({ getResult, callWithRequest, settingsStatusOverrides } = { }, ready: sinon.stub().returns(Promise.resolve()) }; + const req = { __stubHapiRequest: true, path: '', headers: {} }; + + const adminCluster = { + errors: esErrors, + callAsKibanaUser: sinon.stub(), + callWithRequest: sinon.spy((withReq, method, params) => { + if (callWithRequest) { + return callWithRequest(withReq, method, params); + } + + expect(withReq).to.be(req); + switch (method) { + case 'get': + return Promise.resolve({ _source: getResult }); + case 'update': + return Promise.resolve(); + default: + throw new Error(`callWithRequest() is using unexpected method "${method}"`); + } + }) + }; + + adminCluster.callAsKibanaUser.withArgs('get', sinon.match.any).returns(Promise.resolve({ _source: getResult })); + adminCluster.callAsKibanaUser.withArgs('update', sinon.match.any).returns(Promise.resolve()); + const server = { decorate: (_, key, value) => server[key] = value, plugins: { elasticsearch: { - errors: esErrors, - callWithRequest: sinon.spy((withReq, method, params) => { - if (callWithRequest) { - return callWithRequest(withReq, method, params); - } - - expect(withReq).to.be(req); - switch (method) { - case 'get': - return Promise.resolve({ _source: getResult }); - case 'update': - return Promise.resolve(); - default: - throw new Error(`callWithRequest() is using unexpected method "${method}"`); - } - }) + getCluster: sinon.stub().withArgs('admin').returns(adminCluster) } } }; diff --git a/src/ui/settings/index.js b/src/ui/settings/index.js index 986f2f8428fd9..261f1e678e951 100644 --- a/src/ui/settings/index.js +++ b/src/ui/settings/index.js @@ -66,7 +66,7 @@ export default function setupSettings(kbnServer, server, config) { async function getUserProvided(req, { ignore401Errors = false } = {}) { assertRequest(req); - const { callWithRequest, errors } = server.plugins.elasticsearch; + const { callWithRequest, errors } = server.plugins.elasticsearch.getCluster('admin'); // If the ui settings status isn't green, we shouldn't be attempting to get // user settings, since we can't be sure that all the necessary conditions @@ -87,7 +87,7 @@ export default function setupSettings(kbnServer, server, config) { async function setMany(req, changes) { assertRequest(req); - const { callWithRequest } = server.plugins.elasticsearch; + const { callWithRequest } = server.plugins.elasticsearch.getCluster('admin'); const clientParams = { ...getClientSettings(config), body: { doc: changes } diff --git a/tasks/config/esvm.js b/tasks/config/esvm.js index 91ebfb7b40b0e..f80a304289370 100644 --- a/tasks/config/esvm.js +++ b/tasks/config/esvm.js @@ -14,6 +14,7 @@ module.exports = function (grunt) { } } }, + dev: { options: { directory: resolve(directory, 'dev'), @@ -27,6 +28,60 @@ module.exports = function (grunt) { } } }, + + tribe: { + options: { + directory: resolve(directory, 'tribe'), + config: { + path: { + data: dataDir + } + }, + nodes: [{ + cluster: { name: 'data-01' }, + http: { port: 9201 }, + node: { name: 'node-01', data: true, master: true, max_local_storage_nodes: 4 } + }, { + cluster: { name: 'data-02' }, + http: { port: 9202 }, + node: { name: 'node-02', data: true, master: true, max_local_storage_nodes: 4 } + }, { + cluster: { name: 'admin-01' }, + http: { port: 9203 }, + node: { name: 'node-03', data: true, master: true, max_local_storage_nodes: 4 } + }, { + cluster: { name: 'tribe-01' }, + http: { port: 9200 }, + node: { name: 'node-04', max_local_storage_nodes: 4 }, + tribe: { + c1: { + cluster: { + name: 'data-01' + } + }, + c2: { + cluster: { + name: 'data-02' + } + }, + on_conflict: 'prefer_c1', + blocks: { + write: true + } + }, + discovery: { + zen: { + ping: { + unicast: { + hosts: [ 'localhost:9201', 'localhost:9202' ] + } + } + } + } + }] + }, + }, + test: { options: { directory: resolve(directory, 'test'), @@ -37,10 +92,20 @@ module.exports = function (grunt) { }, cluster: { name: 'esvm-test' + }, + discovery: { + zen: { + ping: { + unicast: { + hosts: [ `localhost:${serverConfig.servers.elasticsearch.port}` ] + } + } + } } } } }, + ui: { options: { directory: resolve(directory, 'test'), @@ -51,10 +116,20 @@ module.exports = function (grunt) { }, cluster: { name: 'esvm-ui' + }, + discovery: { + zen: { + ping: { + unicast: { + hosts: [ `localhost:${serverConfig.servers.elasticsearch.port}` ] + } + } + } } } } }, + withPlugins: { options: { version: '2.1.0', From 0ac6c11d8694f2dd8b932e39370adc04deb34b3d Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Sun, 11 Dec 2016 18:50:02 -0800 Subject: [PATCH 02/39] @spalger review feedback * Close create{Admin,Data}Cluster handles closing the connection * Remove callAsKibanaUser argument from tests * ClientLogger uses ES6 properties for tags and logQueries * Ensure were destructuring cluster to access callAsKibanaUser Signed-off-by: Tyler Smalley --- src/core_plugins/elasticsearch/index.js | 7 ++---- .../lib/__tests__/check_es_version.js | 22 ++++++++--------- .../elasticsearch/lib/client_logger.js | 8 ++----- .../elasticsearch/lib/create_admin_cluster.js | 15 ++++++------ .../elasticsearch/lib/create_agent.js | 24 ++++++++----------- .../elasticsearch/lib/create_data_cluster.js | 15 ++++++------ .../elasticsearch/lib/create_kibana_index.js | 2 +- .../elasticsearch/lib/migrate_config.js | 2 +- .../elasticsearch/lib/upgrade_config.js | 2 +- .../api/ingest/register_field_capabilities.js | 2 +- .../routes/api/scripts/register_languages.js | 2 +- .../routes/api/search/count/register_count.js | 3 ++- .../timelion/server/routes/validate_es.js | 7 +++--- .../server/series_functions/es/index.js | 7 +++--- src/server/http/short_url_lookup.js | 6 ++--- 15 files changed, 56 insertions(+), 68 deletions(-) diff --git a/src/core_plugins/elasticsearch/index.js b/src/core_plugins/elasticsearch/index.js index fb8265adb7a26..6c0d1062ee4a8 100644 --- a/src/core_plugins/elasticsearch/index.js +++ b/src/core_plugins/elasticsearch/index.js @@ -84,11 +84,8 @@ module.exports = function ({ Plugin }) { server.expose('filterHeaders', filterHeaders); server.expose('ElasticsearchClientLogging', clientLogger(server)); - const dataCluster = createDataCluster(server); - server.on('close', bindKey(dataCluster, 'close')); - - const adminCluster = createAdminCluster(server); - server.on('close', bindKey(adminCluster, 'close')); + createDataCluster(server); + createAdminCluster(server); createProxy(server, 'GET', '/{paths*}'); createProxy(server, 'POST', '/_mget'); diff --git a/src/core_plugins/elasticsearch/lib/__tests__/check_es_version.js b/src/core_plugins/elasticsearch/lib/__tests__/check_es_version.js index dde0168bda955..ab9b2179e84ac 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/check_es_version.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/check_es_version.js @@ -65,13 +65,13 @@ describe('plugins/elasticsearch', () => { it('returns true with single a node that matches', async () => { setNodes('5.1.0'); - const result = await checkEsVersion(server, KIBANA_VERSION, callAsKibanaUser); + const result = await checkEsVersion(server, KIBANA_VERSION); expect(result).to.be(true); }); it('returns true with multiple nodes that satisfy', async () => { setNodes('5.1.0', '5.2.0', '5.1.1-Beta1'); - const result = await checkEsVersion(server, KIBANA_VERSION, callAsKibanaUser); + const result = await checkEsVersion(server, KIBANA_VERSION); expect(result).to.be(true); }); @@ -79,7 +79,7 @@ describe('plugins/elasticsearch', () => { // 5.0.0 ES is too old to work with a 5.1.0 version of Kibana. setNodes('5.1.0', '5.2.0', '5.0.0'); try { - await checkEsVersion(server, KIBANA_VERSION, callAsKibanaUser); + await checkEsVersion(server, KIBANA_VERSION); } catch (e) { expect(e).to.be.a(Error); } @@ -92,7 +92,7 @@ describe('plugins/elasticsearch', () => { { version: '5.0.0', attributes: { client: 'true' } }, ); try { - await checkEsVersion(server, KIBANA_VERSION, callAsKibanaUser); + await checkEsVersion(server, KIBANA_VERSION); } catch (e) { expect(e).to.be.a(Error); } @@ -100,7 +100,7 @@ describe('plugins/elasticsearch', () => { it('warns if a node is only off by a patch version', async () => { setNodes('5.1.1'); - await checkEsVersion(server, KIBANA_VERSION, callAsKibanaUser); + await checkEsVersion(server, KIBANA_VERSION); sinon.assert.callCount(server.log, 2); expect(server.log.getCall(0).args[0]).to.contain('debug'); expect(server.log.getCall(1).args[0]).to.contain('warning'); @@ -108,7 +108,7 @@ describe('plugins/elasticsearch', () => { it('warns if a node is off by a patch version and without http publish address', async () => { setNodeWithoutHTTP('5.1.1'); - await checkEsVersion(server, KIBANA_VERSION, callAsKibanaUser); + await checkEsVersion(server, KIBANA_VERSION); sinon.assert.callCount(server.log, 2); expect(server.log.getCall(0).args[0]).to.contain('debug'); expect(server.log.getCall(1).args[0]).to.contain('warning'); @@ -117,7 +117,7 @@ describe('plugins/elasticsearch', () => { it('errors if a node incompatible and without http publish address', async () => { setNodeWithoutHTTP('6.1.1'); try { - await checkEsVersion(server, KIBANA_VERSION, callAsKibanaUser); + await checkEsVersion(server, KIBANA_VERSION); } catch (e) { expect(e.message).to.contain('incompatible nodes'); expect(e).to.be.a(Error); @@ -127,12 +127,12 @@ describe('plugins/elasticsearch', () => { it('only warns once per node list', async () => { setNodes('5.1.1'); - await checkEsVersion(server, KIBANA_VERSION, callAsKibanaUser); + await checkEsVersion(server, KIBANA_VERSION); sinon.assert.callCount(server.log, 2); expect(server.log.getCall(0).args[0]).to.contain('debug'); expect(server.log.getCall(1).args[0]).to.contain('warning'); - await checkEsVersion(server, KIBANA_VERSION, callAsKibanaUser); + await checkEsVersion(server, KIBANA_VERSION); sinon.assert.callCount(server.log, 3); expect(server.log.getCall(2).args[0]).to.contain('debug'); }); @@ -140,13 +140,13 @@ describe('plugins/elasticsearch', () => { it('warns again if the node list changes', async () => { setNodes('5.1.1'); - await checkEsVersion(server, KIBANA_VERSION, callAsKibanaUser); + await checkEsVersion(server, KIBANA_VERSION); sinon.assert.callCount(server.log, 2); expect(server.log.getCall(0).args[0]).to.contain('debug'); expect(server.log.getCall(1).args[0]).to.contain('warning'); setNodes('5.1.2'); - await checkEsVersion(server, KIBANA_VERSION, callAsKibanaUser); + await checkEsVersion(server, KIBANA_VERSION); sinon.assert.callCount(server.log, 4); expect(server.log.getCall(2).args[0]).to.contain('debug'); expect(server.log.getCall(3).args[0]).to.contain('warning'); diff --git a/src/core_plugins/elasticsearch/lib/client_logger.js b/src/core_plugins/elasticsearch/lib/client_logger.js index 6e5a0dd6355d0..54fb4896d189f 100644 --- a/src/core_plugins/elasticsearch/lib/client_logger.js +++ b/src/core_plugins/elasticsearch/lib/client_logger.js @@ -1,13 +1,9 @@ module.exports = function (server) { return class ElasticsearchClientLogging { // additional tags to differentiate connection - get tags() { - return []; - } + tags = ['admin']; - get logQueries() { - return false; - } + logQueries = false; error(err) { server.log(['error', 'elasticsearch'].concat(this.tags), err); diff --git a/src/core_plugins/elasticsearch/lib/create_admin_cluster.js b/src/core_plugins/elasticsearch/lib/create_admin_cluster.js index 0c78e1f51ba6c..b252f7e0fcdaf 100644 --- a/src/core_plugins/elasticsearch/lib/create_admin_cluster.js +++ b/src/core_plugins/elasticsearch/lib/create_admin_cluster.js @@ -1,19 +1,18 @@ +import { bindKey } from 'lodash'; + export default function (server) { const config = server.config(); const Logger = server.plugins.elasticsearch.ElasticsearchClientLogging; class AdminClientLogging extends Logger { - get tags() { - return ['admin']; - } - - get logQueries() { - return Boolean(config.get('elasticsearch.logQueries')); - } + tags = ['admin']; + logQueries = Boolean(config.get('elasticsearch.logQueries')); } - return server.plugins.elasticsearch.createCluster( + const adminCluster = server.plugins.elasticsearch.createCluster( 'admin', Object.assign({ log: AdminClientLogging }, config.get('elasticsearch')) ); + + server.on('close', bindKey(adminCluster, 'close')); }; diff --git a/src/core_plugins/elasticsearch/lib/create_agent.js b/src/core_plugins/elasticsearch/lib/create_agent.js index d8c29adf711ee..1beb1de795268 100644 --- a/src/core_plugins/elasticsearch/lib/create_agent.js +++ b/src/core_plugins/elasticsearch/lib/create_agent.js @@ -1,31 +1,27 @@ import url from 'url'; -import _ from 'lodash'; +import { get, size } from 'lodash'; const readFile = (file) => require('fs').readFileSync(file, 'utf8'); import http from 'http'; import https from 'https'; -module.exports = _.memoize(function (config) { - const target = url.parse(_.get(config, 'url')); +export default function (config) { + const target = url.parse(get(config, 'url')); if (!/^https/.test(target.protocol)) return new http.Agent(); const agentOptions = { - rejectUnauthorized: _.get(config, 'ssl.verify') + rejectUnauthorized: get(config, 'ssl.verify') }; - if (_.size(_.get(config, 'ssl.ca'))) { - agentOptions.ca = _.get(config, 'ssl.ca').map(readFile); + if (size(get(config, 'ssl.ca'))) { + agentOptions.ca = get(config, 'ssl.ca').map(readFile); } // Add client certificate and key if required by elasticsearch - if (_.get(config, 'ssl.cert') && _.get(config, 'ssl.key')) { - agentOptions.cert = readFile(_.get(config, 'ssl.cert')); - agentOptions.key = readFile(_.get(config, 'ssl.key')); + if (get(config, 'ssl.cert') && get(config, 'ssl.key')) { + agentOptions.cert = readFile(get(config, 'ssl.cert')); + agentOptions.key = readFile(get(config, 'ssl.key')); } return new https.Agent(agentOptions); -}); - -// See https://lodash.com/docs#memoize: We use a Map() instead of the default, because we want the keys in the cache -// to be the server objects, and by default these would be coerced to strings as keys (which wouldn't be useful) -module.exports.cache = new Map(); +}; diff --git a/src/core_plugins/elasticsearch/lib/create_data_cluster.js b/src/core_plugins/elasticsearch/lib/create_data_cluster.js index affc118bed7e4..ee866847734ad 100644 --- a/src/core_plugins/elasticsearch/lib/create_data_cluster.js +++ b/src/core_plugins/elasticsearch/lib/create_data_cluster.js @@ -1,16 +1,13 @@ +import { bindKey } from 'lodash'; + export default function (server) { const config = server.config(); const esPlugins = server.plugins.elasticsearch; const Logger = server.plugins.elasticsearch.ElasticsearchClientLogging; class DataClientLogging extends Logger { - get tags() { - return ['data']; - } - - get logQueries() { - return Boolean(getConfig().logQueries); - } + tags = ['data']; + logQueries = Boolean(getConfig().logQueries); } function getConfig() { @@ -23,8 +20,10 @@ export default function (server) { return esConfig; } - return server.plugins.elasticsearch.createCluster( + const dataCluster = server.plugins.elasticsearch.createCluster( 'data', Object.assign({ log: DataClientLogging }, getConfig()) ); + + server.on('close', bindKey(dataCluster, 'close')); }; diff --git a/src/core_plugins/elasticsearch/lib/create_kibana_index.js b/src/core_plugins/elasticsearch/lib/create_kibana_index.js index d0afd647de5bc..7a075ca33d192 100644 --- a/src/core_plugins/elasticsearch/lib/create_kibana_index.js +++ b/src/core_plugins/elasticsearch/lib/create_kibana_index.js @@ -2,7 +2,7 @@ import { format } from 'util'; import { mappings } from './kibana_index_mappings'; module.exports = function (server) { - const callAsKibanaUser = server.plugins.elasticsearch.getCluster('admin').callAsKibanaUser; + const { callAsKibanaUser } = server.plugins.elasticsearch.getCluster('admin'); const index = server.config().get('kibana.index'); return callAsKibanaUser('indices.create', { diff --git a/src/core_plugins/elasticsearch/lib/migrate_config.js b/src/core_plugins/elasticsearch/lib/migrate_config.js index d90d0f16da55d..08d20c8f2f883 100644 --- a/src/core_plugins/elasticsearch/lib/migrate_config.js +++ b/src/core_plugins/elasticsearch/lib/migrate_config.js @@ -3,7 +3,7 @@ import { mappings } from './kibana_index_mappings'; module.exports = function (server) { const config = server.config(); - const callAsKibanaUser = server.plugins.elasticsearch.getCluster('admin').callAsKibanaUser; + const { callAsKibanaUser } = server.plugins.elasticsearch.getCluster('admin'); const options = { index: config.get('kibana.index'), diff --git a/src/core_plugins/elasticsearch/lib/upgrade_config.js b/src/core_plugins/elasticsearch/lib/upgrade_config.js index 58a5878f13ae3..a5552ec976085 100644 --- a/src/core_plugins/elasticsearch/lib/upgrade_config.js +++ b/src/core_plugins/elasticsearch/lib/upgrade_config.js @@ -6,7 +6,7 @@ import { format } from 'util'; module.exports = function (server) { const MAX_INTEGER = Math.pow(2, 53) - 1; - const callAsKibanaUser = server.plugins.elasticsearch.getCluster('admin').callAsKibanaUser; + const { callAsKibanaUser } = server.plugins.elasticsearch.getCluster('admin'); const config = server.config(); function createNewConfig() { diff --git a/src/core_plugins/kibana/server/routes/api/ingest/register_field_capabilities.js b/src/core_plugins/kibana/server/routes/api/ingest/register_field_capabilities.js index 0cf643af2d8fa..67c0f560339fb 100644 --- a/src/core_plugins/kibana/server/routes/api/ingest/register_field_capabilities.js +++ b/src/core_plugins/kibana/server/routes/api/ingest/register_field_capabilities.js @@ -6,7 +6,7 @@ export function registerFieldCapabilities(server) { path: '/api/kibana/{indices}/field_capabilities', method: ['GET'], handler: function (req, reply) { - const callWithRequest = server.plugins.elasticsearch.getCluster('data').callWithRequest; + const { callWithRequest } = server.plugins.elasticsearch.getCluster('data'); const indices = req.params.indices || ''; return callWithRequest(req, 'fieldStats', { diff --git a/src/core_plugins/kibana/server/routes/api/scripts/register_languages.js b/src/core_plugins/kibana/server/routes/api/scripts/register_languages.js index 9ad34df3b2643..125e4b7734ce8 100644 --- a/src/core_plugins/kibana/server/routes/api/scripts/register_languages.js +++ b/src/core_plugins/kibana/server/routes/api/scripts/register_languages.js @@ -6,7 +6,7 @@ export function registerLanguages(server) { path: '/api/kibana/scripts/languages', method: 'GET', handler: function (request, reply) { - const callWithRequest = server.plugins.elasticsearch.getCluster('data').callWithRequest; + const { callWithRequest } = server.plugins.elasticsearch.getCluster('data'); return callWithRequest(request, 'cluster.getSettings', { include_defaults: true, diff --git a/src/core_plugins/kibana/server/routes/api/search/count/register_count.js b/src/core_plugins/kibana/server/routes/api/search/count/register_count.js index efb65a0a81b1e..f7b1c9af2c901 100644 --- a/src/core_plugins/kibana/server/routes/api/search/count/register_count.js +++ b/src/core_plugins/kibana/server/routes/api/search/count/register_count.js @@ -6,7 +6,8 @@ export default function registerCount(server) { path: '/api/kibana/{id}/_count', method: ['POST', 'GET'], handler: function (req, reply) { - const boundCallWithRequest = _.partial(server.plugins.elasticsearch.getCluster('data').callWithRequest, req); + const { callWithRequest } = server.plugins.elasticsearch.getCluster('data'); + const boundCallWithRequest = _.partial(callWithRequest, req); boundCallWithRequest('count', { allowNoIndices: false, diff --git a/src/core_plugins/timelion/server/routes/validate_es.js b/src/core_plugins/timelion/server/routes/validate_es.js index 65d7d0039e025..7733befea43bd 100644 --- a/src/core_plugins/timelion/server/routes/validate_es.js +++ b/src/core_plugins/timelion/server/routes/validate_es.js @@ -3,13 +3,12 @@ module.exports = function (server) { method: 'GET', path: '/api/timelion/validate/es', handler: function (request, reply) { - return server.uiSettings().getAll(request).then((uiSettings) => { - var callWithRequest = server.plugins.elasticsearch.getCluster('data').callWithRequest; + const { callWithRequest } = server.plugins.elasticsearch.getCluster('data'); - var timefield = uiSettings['timelion:es.timefield']; + const timefield = uiSettings['timelion:es.timefield']; - var body = { + const body = { index: uiSettings['es.default_index'], fields:timefield }; diff --git a/src/core_plugins/timelion/server/series_functions/es/index.js b/src/core_plugins/timelion/server/series_functions/es/index.js index c861a505cc730..184a00e9c2585 100644 --- a/src/core_plugins/timelion/server/series_functions/es/index.js +++ b/src/core_plugins/timelion/server/series_functions/es/index.js @@ -51,7 +51,7 @@ module.exports = new Datasource('es', { aliases: ['elasticsearch'], fn: function esFn(args, tlConfig) { - var config = _.defaults(_.clone(args.byName), { + const config = _.defaults(_.clone(args.byName), { q: '*', metric: ['count'], index: tlConfig.settings['timelion:es.default_index'], @@ -61,9 +61,10 @@ module.exports = new Datasource('es', { fit: 'nearest' }); - var callWithRequest = tlConfig.server.plugins.elasticsearch.getCluster('data').callWithRequest; + const { callWithRequest } = tlConfig.server.plugins.elasticsearch.getCluster('data'); + + const body = buildRequest(config, tlConfig); - var body = buildRequest(config, tlConfig); return callWithRequest(tlConfig.request, 'search', body).then(function (resp) { if (!resp._shards.total) throw new Error('Elasticsearch index not found: ' + config.index); return { diff --git a/src/server/http/short_url_lookup.js b/src/server/http/short_url_lookup.js index 1ded80229067a..8e64405a34377 100644 --- a/src/server/http/short_url_lookup.js +++ b/src/server/http/short_url_lookup.js @@ -2,7 +2,7 @@ import crypto from 'crypto'; export default function (server) { async function updateMetadata(urlId, urlDoc, req) { - const callWithRequest = server.plugins.elasticsearch.getCluster('admin').callWithRequest; + const { callWithRequest } = server.plugins.elasticsearch.getCluster('admin'); const kibanaIndex = server.config().get('kibana.index'); try { @@ -25,7 +25,7 @@ export default function (server) { async function getUrlDoc(urlId, req) { const urlDoc = await new Promise((resolve, reject) => { - const callWithRequest = server.plugins.elasticsearch.getCluster('admin').callWithRequest; + const { callWithRequest } = server.plugins.elasticsearch.getCluster('admin'); const kibanaIndex = server.config().get('kibana.index'); callWithRequest(req, 'get', { @@ -46,7 +46,7 @@ export default function (server) { async function createUrlDoc(url, urlId, req) { const newUrlId = await new Promise((resolve, reject) => { - const callWithRequest = server.plugins.elasticsearch.getCluster('admin').callWithRequest; + const { callWithRequest } = server.plugins.elasticsearch.getCluster('admin'); const kibanaIndex = server.config().get('kibana.index'); callWithRequest(req, 'index', { From 80680313754004c64ece399acbd5cde7768799d5 Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Tue, 13 Dec 2016 10:25:14 -0600 Subject: [PATCH 03/39] [tribe] Use class syntax on new data sources --- .../courier/data_source/admin_doc_source.js | 19 ++++++++++--------- .../public/courier/data_source/doc_source.js | 19 ++++++++++--------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/ui/public/courier/data_source/admin_doc_source.js b/src/ui/public/courier/data_source/admin_doc_source.js index 378a8ccc001b0..86cb42f607200 100644 --- a/src/ui/public/courier/data_source/admin_doc_source.js +++ b/src/ui/public/courier/data_source/admin_doc_source.js @@ -4,23 +4,24 @@ import _ from 'lodash'; -import AbstractDocSource from './_abstract_doc_source'; +import AbstractDocSourceProvider from './_abstract_doc_source'; import DocStrategyProvider from '../fetch/strategy/doc_admin'; import DocRequestProvider from '../fetch/request/doc_admin'; export default function DocSourceFactory(Private) { - let DocSourceAbstract = Private(AbstractDocSource); + let AbstractDocSource = Private(AbstractDocSourceProvider); let docStrategy = Private(DocStrategyProvider); let DocRequest = Private(DocRequestProvider); - _.class(AdminDocSource).inherits(DocSourceAbstract); - function AdminDocSource(initialState) { - AdminDocSource.Super.call(this, initialState, docStrategy); - } + class AdminDocSource extends AbstractDocSource { + constructor(initialState) { + super(initialState, docStrategy); + } - AdminDocSource.prototype._createRequest = function (defer) { - return new DocRequest(this, defer); - }; + _createRequest(defer) { + return new DocRequest(this, defer); + }; + } return AdminDocSource; }; diff --git a/src/ui/public/courier/data_source/doc_source.js b/src/ui/public/courier/data_source/doc_source.js index 6e3fa696fd8b5..5d810dad245a1 100644 --- a/src/ui/public/courier/data_source/doc_source.js +++ b/src/ui/public/courier/data_source/doc_source.js @@ -4,23 +4,24 @@ import _ from 'lodash'; -import AbstractDocSource from './_abstract_doc_source'; +import AbstractDocSourceProvider from './_abstract_doc_source'; import DocStrategyProvider from '../fetch/strategy/doc_data'; import DocRequestProvider from '../fetch/request/doc_data'; export default function DocSourceFactory(Private) { - let DocSourceAbstract = Private(AbstractDocSource); + let AbstractDocSource = Private(AbstractDocSourceProvider); let docStrategy = Private(DocStrategyProvider); let DocRequest = Private(DocRequestProvider); - _.class(DocSource).inherits(DocSourceAbstract); - function DocSource(initialState) { - DocSource.Super.call(this, initialState, docStrategy); - } + class DocSource extends AbstractDocSource { + constructor(initialState) { + super(initialState, docStrategy); + } - DocSource.prototype._createRequest = function (defer) { - return new DocRequest(this, defer); - }; + _createRequest(defer) { + return new DocRequest(this, defer); + }; + } return DocSource; }; From c541bf00b072a6f9fc89dcbb089ab0fff8181863 Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Tue, 13 Dec 2016 10:28:16 -0600 Subject: [PATCH 04/39] [tribe] Use includes instead of indexOf in call_client --- src/ui/public/courier/fetch/call_client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/public/courier/fetch/call_client.js b/src/ui/public/courier/fetch/call_client.js index 8b41206463760..2b2a0c5669d40 100644 --- a/src/ui/public/courier/fetch/call_client.js +++ b/src/ui/public/courier/fetch/call_client.js @@ -95,7 +95,7 @@ export default function CourierFetchCallClient(Private, Promise, esAdmin, es) { } const id = strategy.id; - const client = (id && ~id.indexOf('admin')) ? esAdmin : es; + const client = (id && id.includes('admin')) ? esAdmin : es; return (esPromise = client[strategy.clientMethod]({ body })); }) .then(function (clientResp) { From 654779e4914737ecc618ac307e5ffd0cecd9d896 Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Tue, 13 Dec 2016 10:37:40 -0600 Subject: [PATCH 05/39] [tribe] DocRequest --> AbstractDocRequest --- src/ui/public/courier/data_source/_abstract_doc_source.js | 2 +- .../public/courier/fetch/request/{doc.js => _abstract_doc.js} | 4 ++-- src/ui/public/courier/fetch/request/doc_admin.js | 2 +- src/ui/public/courier/fetch/request/doc_data.js | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) rename src/ui/public/courier/fetch/request/{doc.js => _abstract_doc.js} (91%) diff --git a/src/ui/public/courier/data_source/_abstract_doc_source.js b/src/ui/public/courier/data_source/_abstract_doc_source.js index 058466ebf1aa0..27733208fe6bf 100644 --- a/src/ui/public/courier/data_source/_abstract_doc_source.js +++ b/src/ui/public/courier/data_source/_abstract_doc_source.js @@ -15,7 +15,7 @@ import 'ui/storage'; import DocSendToEsProvider from './_doc_send_to_es'; import AbstractDataSourceProvider from './_abstract'; -import DocRequestProvider from '../fetch/request/doc'; +import DocRequestProvider from '../fetch/request/_abstract_doc'; export default function AbstractDocSourceFactory(Private, Promise, es, sessionStorage) { let sendToEs = Private(DocSendToEsProvider); diff --git a/src/ui/public/courier/fetch/request/doc.js b/src/ui/public/courier/fetch/request/_abstract_doc.js similarity index 91% rename from src/ui/public/courier/fetch/request/doc.js rename to src/ui/public/courier/fetch/request/_abstract_doc.js index 6fff6a33d326b..74059dfa1dcde 100644 --- a/src/ui/public/courier/fetch/request/doc.js +++ b/src/ui/public/courier/fetch/request/_abstract_doc.js @@ -4,7 +4,7 @@ export default function DocRequestProvider(Private) { const AbstractRequest = Private(AbstractRequestProvider); - class DocRequest extends AbstractRequest { + class AbstractDocRequest extends AbstractRequest { constructor(...args) { super(...args); @@ -36,5 +36,5 @@ export default function DocRequestProvider(Private) { } } - return DocRequest; + return AbstractDocRequest; }; diff --git a/src/ui/public/courier/fetch/request/doc_admin.js b/src/ui/public/courier/fetch/request/doc_admin.js index 657708a3d72ba..faab35de2902b 100644 --- a/src/ui/public/courier/fetch/request/doc_admin.js +++ b/src/ui/public/courier/fetch/request/doc_admin.js @@ -1,5 +1,5 @@ import DocStrategyProvider from '../strategy/doc_admin'; -import AbstractDocRequestProvider from './doc'; +import AbstractDocRequestProvider from './_abstract_doc'; export default function DocRequestProvider(Private) { diff --git a/src/ui/public/courier/fetch/request/doc_data.js b/src/ui/public/courier/fetch/request/doc_data.js index 8e70d865aaa5b..c7bdc634a8950 100644 --- a/src/ui/public/courier/fetch/request/doc_data.js +++ b/src/ui/public/courier/fetch/request/doc_data.js @@ -1,5 +1,5 @@ import DocStrategyProvider from '../strategy/doc_data'; -import AbstractDocRequestProvider from './doc'; +import AbstractDocRequestProvider from './_abstract_doc'; export default function DocRequestProvider(Private) { From 4deefddce68a2baee47449f844278b72d02e60a2 Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Tue, 13 Dec 2016 15:04:23 -0600 Subject: [PATCH 06/39] [tribe] Fix AbstractDoc test rename --- src/ui/public/courier/fetch/__tests__/doc.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/public/courier/fetch/__tests__/doc.js b/src/ui/public/courier/fetch/__tests__/doc.js index ebecce6b32b98..e33a14273dbeb 100644 --- a/src/ui/public/courier/fetch/__tests__/doc.js +++ b/src/ui/public/courier/fetch/__tests__/doc.js @@ -3,7 +3,7 @@ import expect from 'expect.js'; import ngMock from 'ng_mock'; import DocSourceProvider from '../../data_source/doc_source'; -import DocRequestProvider from '../request/doc'; +import DocRequestProvider from '../request/doc_data'; describe('Courier DocFetchRequest class', function () { let storage; From 0cfffb7cfd24dabf5e168fb39f70a511e26f082a Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Wed, 14 Dec 2016 08:45:01 -0800 Subject: [PATCH 07/39] Removes factory objects and adds addClientPlugin to Cluster (#9467) Signed-off-by: Tyler Smalley --- .../elasticsearch/lib/__tests__/cluster.js | 73 ++++++--- src/core_plugins/elasticsearch/lib/cluster.js | 140 ++++++++++-------- 2 files changed, 130 insertions(+), 83 deletions(-) diff --git a/src/core_plugins/elasticsearch/lib/__tests__/cluster.js b/src/core_plugins/elasticsearch/lib/__tests__/cluster.js index 845ba7132ede8..2f734d52d534f 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/cluster.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/cluster.js @@ -8,7 +8,6 @@ import Boom from 'boom'; describe('plugins/elasticsearch', function () { describe('cluster', function () { let cluster; - let client; let config = { url: 'http://localhost:9200', ssl: { verify: false }, @@ -44,56 +43,90 @@ describe('plugins/elasticsearch', function () { expect(localConfig.requestHeadersWhitelist.length).to.not.equal(config.requestHeadersWhitelist); }); - describe('callAsKibanaUserFactory', () => { - let callAsKibanaUser; + describe('adding a plugin', () => { + const plugin = (Client, config, components) => { + Client.prototype.marco = () => { + return Promise.resolve('polo'); + }; + }; beforeEach(() => { - client = sinon.stub(); - set(client, 'nodes.info', sinon.stub().returns(Promise.resolve())); + cluster.addClientPlugins([plugin]); + }); + + it('persists previous plugins', () => { + const pluginTwo = (Client, config, components) => { + Client.prototype.foo = () => { + return Promise.resolve('bar'); + }; + }; + + expect(cluster.config().plugins).to.have.length(1); + expect(cluster.config().plugins[0]).to.be(plugin); + + cluster.addClientPlugins([pluginTwo]); + + expect(cluster.config().plugins).to.have.length(2); + expect(cluster.config().plugins).to.eql([plugin, pluginTwo]); + }); + + it('is available for callAsKibanUser', async () => { + const marco = await cluster.callAsKibanaUser('marco'); + expect(marco).to.eql('polo'); + }); + + it('is available for callWithRequest', async () => { + const marco = await cluster.callWithRequest({}, 'marco'); + expect(marco).to.eql('polo'); + }); + }); - callAsKibanaUser = cluster.callAsKibanaUserFactory(client); + describe('callAsKibanaUser', () => { + let client; + + beforeEach(() => { + client = cluster._client = sinon.stub(); + set(client, 'nodes.info', sinon.stub().returns(Promise.resolve())); }); it('should return a function', () => { - expect(callAsKibanaUser).to.be.a('function'); + expect(cluster.callAsKibanaUser).to.be.a('function'); }); it('throws an error for an invalid endpoint', () => { - const fn = partial(callAsKibanaUser, 'foo'); + const fn = partial(cluster.callAsKibanaUser, 'foo'); expect(fn).to.throwException(/called with an invalid endpoint: foo/); }); it('calls the client with params', () => { const params = { foo: 'Foo' }; - callAsKibanaUser('nodes.info', params); + cluster.callAsKibanaUser('nodes.info', params); sinon.assert.calledOnce(client.nodes.info); expect(client.nodes.info.getCall(0).args[0]).to.eql(params); }); }); - describe('callWithRequestFactory', () => { - let callWithRequest; + describe('callWithRequest', () => { + let client; beforeEach(() => { - client = sinon.stub(); + client = cluster._noAuthClient = sinon.stub(); set(client, 'nodes.info', sinon.stub().returns(Promise.resolve())); - - callWithRequest = cluster.callWithRequestFactory(client); }); it('should return a function', () => { - expect(callWithRequest).to.be.a('function'); + expect(cluster.callWithRequest).to.be.a('function'); }); it('throws an error for an invalid endpoint', () => { - const fn = partial(callWithRequest, {}, 'foo'); + const fn = partial(cluster.callWithRequest, {}, 'foo'); expect(fn).to.throwException(/called with an invalid endpoint: foo/); }); it('calls the client with params', () => { const params = { foo: 'Foo' }; - callWithRequest({}, 'nodes.info', params); + cluster.callWithRequest({}, 'nodes.info', params); sinon.assert.calledOnce(client.nodes.info); expect(client.nodes.info.getCall(0).args[0]).to.eql(params); @@ -103,7 +136,7 @@ describe('plugins/elasticsearch', function () { const headers = { authorization: 'Basic TEST' }; const request = { headers: Object.assign({}, headers, { foo: 'Foo' }) }; - callWithRequest(request, 'nodes.info'); + cluster.callWithRequest(request, 'nodes.info'); sinon.assert.calledOnce(client.nodes.info); expect(client.nodes.info.getCall(0).args[0]).to.eql({ @@ -122,7 +155,7 @@ describe('plugins/elasticsearch', function () { it('ensures WWW-Authenticate header', async () => { set(client, 'mock.401', sinon.stub().returns(Promise.reject(error))); - await callWithRequest({}, 'mock.401', {}, { wrap401Errors: true }).catch(handler); + await cluster.callWithRequest({}, 'mock.401', {}, { wrap401Errors: true }).catch(handler); sinon.assert.calledOnce(handler); expect(handler.getCall(0).args[0].output.headers['WWW-Authenticate']).to.eql('Basic realm="Authorization Required"'); @@ -131,7 +164,7 @@ describe('plugins/elasticsearch', function () { it('persists WWW-Authenticate header', async () => { set(error, 'body.error.header[WWW-Authenticate]', 'Basic realm="Test"'); set(client, 'mock.401', sinon.stub().returns(Promise.reject(error))); - await callWithRequest({}, 'mock.401', {}, { wrap401Errors: true }).catch(handler); + await cluster.callWithRequest({}, 'mock.401', {}, { wrap401Errors: true }).catch(handler); sinon.assert.calledOnce(handler); expect(handler.getCall(0).args[0].output.headers['WWW-Authenticate']).to.eql('Basic realm="Test"'); diff --git a/src/core_plugins/elasticsearch/lib/cluster.js b/src/core_plugins/elasticsearch/lib/cluster.js index 79a97136bdffd..24f3be22b2ce0 100644 --- a/src/core_plugins/elasticsearch/lib/cluster.js +++ b/src/core_plugins/elasticsearch/lib/cluster.js @@ -1,7 +1,6 @@ import elasticsearch from 'elasticsearch'; -import { bindKey, partial, get, set, isEmpty, cloneDeep } from 'lodash'; +import { get, set, isEmpty, cloneDeep } from 'lodash'; import toPath from 'lodash/internal/toPath'; -import Promise from 'bluebird'; import Boom from 'boom'; import createClient from './create_client'; @@ -12,89 +11,104 @@ export default class Cluster { this._config = Object.assign({}, config); this.errors = elasticsearch.errors; - this._client = this.createClient(); - this.callAsKibanaUser = this.callAsKibanaUserFactory(this._client); - - this._noAuthClient = this.createClient({ auth: false }); - this.callWithRequest = this.callWithRequestFactory(this._noAuthClient); + createClients.call(this); return this; } /** - * callAsKibanaUser + * callWithRequest * - * Makes a call to ES using the credentials in kibana.yml + * Performs a call to ES, passing through whitelisted headers in the request * + * The whitelisted headers are defined in the config under _requestHeadersWhitelist_ + * + * @param {Object|undefined} req - The request object * @param {string} endpoint * @param {Object} clientParams * @param {Object} options * @param {boolean} options.wrap401Errors * @returns {Promise} */ - callAsKibanaUserFactory(client) { - return partial(this.callWithRequestFactory(client), undefined); + callWithRequest = (req = {}, endpoint, clientParams = {}, options = {}) => { + if (req.headers) { + const filteredHeaders = filterHeaders(req.headers, this.config('requestHeadersWhitelist')); + set(clientParams, 'headers', filteredHeaders); + } + + return callAPI(this._noAuthClient, endpoint, clientParams, options); } - callWithRequestFactory(client) { - /** - * callWithRequest - * - * Makes a call to ES, passing through whitelisted headers in the request - * - * The whitelisted headers are defined in the config under _requestHeadersWhitelist_ - * - * @param {Object|undefined} req - The request object - * @param {string} endpoint - * @param {Object} clientParams - * @param {Object} options - * @param {boolean} options.wrap401Errors - * @returns {Promise} - */ - return (req = {}, endpoint, clientParams = {}, options = {}) => { - const wrap401Errors = options.wrap401Errors !== false; - - if (req.headers) { - const filteredHeaders = filterHeaders(req.headers, this.config('requestHeadersWhitelist')); - set(clientParams, 'headers', filteredHeaders); - } - - const clientPath = toPath(endpoint); - const api = get(client, clientPath); - - let apiContext = get(client, clientPath.slice(0, -1)); - if (isEmpty(apiContext)) { - apiContext = client; - } - - if (!api) { - throw new Error(`called with an invalid endpoint: ${endpoint}`); - } - - return api.call(apiContext, clientParams).catch((err) => { - if (!wrap401Errors || err.statusCode !== 401) { - return Promise.reject(err); - } - - const boomError = Boom.wrap(err, err.statusCode); - const wwwAuthHeader = get(err, 'body.error.header[WWW-Authenticate]'); - boomError.output.headers['WWW-Authenticate'] = wwwAuthHeader || 'Basic realm="Authorization Required"'; - - throw boomError; - }); - }; + /** + * callAsKibanaUser + * + * Performs a call to ES using the credentials in kibana.yml + * + * @param {string} endpoint + * @param {Object} clientParams + * @param {Object} options + * @returns {Promise} + */ + + callAsKibanaUser = (endpoint, clientParams = {}, options = {}) => { + return callAPI(this._client, endpoint, clientParams, options); } - config(path) { + config = (path) => { return cloneDeep(path ? get(this._config, path) : this._config); } - createClient(options = {}) { - return createClient(Object.assign({}, this.config(), options)); + addClientPlugins(plugins = []) { + this.close(); // close existing client connections + + if (Array.isArray(this._config.plugins)) { + this._config.plugins = this._config.plugins.concat(plugins); + } else { + this._config.plugins = plugins; + } + + createClients.call(this); } close() { - this._client.close(); - this._noAuthClient.close(); + if (this._client) { + this._client.close(); + } + + if (this._noAuthClient) { + this._noAuthClient.close(); + } + } +} + +function callAPI(client, endpoint, clientParams = {}, options = {}) { + const wrap401Errors = options.wrap401Errors !== false; + const clientPath = toPath(endpoint); + const api = get(client, clientPath); + + let apiContext = get(client, clientPath.slice(0, -1)); + if (isEmpty(apiContext)) { + apiContext = client; } + + if (!api) { + throw new Error(`called with an invalid endpoint: ${endpoint}`); + } + + return api.call(apiContext, clientParams).catch((err) => { + if (!wrap401Errors || err.statusCode !== 401) { + return Promise.reject(err); + } + + const boomError = Boom.wrap(err, err.statusCode); + const wwwAuthHeader = get(err, 'body.error.header[WWW-Authenticate]'); + boomError.output.headers['WWW-Authenticate'] = wwwAuthHeader || 'Basic realm="Authorization Required"'; + + throw boomError; + }); +} + +function createClients() { + this._client = createClient(this.config()); + this._noAuthClient = createClient(Object.assign({}, this.config(), { auth: false })); } From 7eaf1d8d575fc0928585bcf23947887182a6af62 Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Wed, 14 Dec 2016 14:39:59 -0800 Subject: [PATCH 08/39] Resolves eslint error Signed-off-by: Tyler Smalley --- src/core_plugins/elasticsearch/lib/__tests__/map_uri.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core_plugins/elasticsearch/lib/__tests__/map_uri.js b/src/core_plugins/elasticsearch/lib/__tests__/map_uri.js index 45c850cbb65cf..697fff3097ccb 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/map_uri.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/map_uri.js @@ -50,7 +50,7 @@ describe('plugins/elasticsearch', function () { it('sends configured custom headers even if the same named header exists in request', function () { const settings = { requestHeadersWhitelist: ['x-my-custom-header'], - customHeaders: {'x-my-custom-header': 'asconfigured'} + customHeaders: { 'x-my-custom-header': 'asconfigured' } }; mapUri(stubCluster(settings), '/elasticsearch')(request, function (err, upstreamUri, upstreamHeaders) { From ebd06ae591a433e11bce52a2292c3857bf16898d Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Thu, 15 Dec 2016 15:11:34 -0800 Subject: [PATCH 09/39] Use properties on the instance instead of class properties Class properties are still in the very eary stages and not widely supported. Signed-off-by: Tyler Smalley --- src/core_plugins/elasticsearch/lib/client_logger.js | 5 ----- .../elasticsearch/lib/create_admin_cluster.js | 8 ++++++-- src/core_plugins/elasticsearch/lib/create_data_cluster.js | 8 ++++++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/core_plugins/elasticsearch/lib/client_logger.js b/src/core_plugins/elasticsearch/lib/client_logger.js index 54fb4896d189f..b27c09e55e946 100644 --- a/src/core_plugins/elasticsearch/lib/client_logger.js +++ b/src/core_plugins/elasticsearch/lib/client_logger.js @@ -1,10 +1,5 @@ module.exports = function (server) { return class ElasticsearchClientLogging { - // additional tags to differentiate connection - tags = ['admin']; - - logQueries = false; - error(err) { server.log(['error', 'elasticsearch'].concat(this.tags), err); } diff --git a/src/core_plugins/elasticsearch/lib/create_admin_cluster.js b/src/core_plugins/elasticsearch/lib/create_admin_cluster.js index fc542fb46d5fa..442ef036ca7b9 100644 --- a/src/core_plugins/elasticsearch/lib/create_admin_cluster.js +++ b/src/core_plugins/elasticsearch/lib/create_admin_cluster.js @@ -5,8 +5,12 @@ export default function (server) { const Logger = server.plugins.elasticsearch.ElasticsearchClientLogging; class AdminClientLogging extends Logger { - tags = ['admin']; - logQueries = Boolean(config.get('elasticsearch.logQueries')); + constructor() { + super(); + + this.tags = ['admin']; + this.logQueries = config.get('elasticsearch.logQueries'); + } } const adminCluster = server.plugins.elasticsearch.createCluster( diff --git a/src/core_plugins/elasticsearch/lib/create_data_cluster.js b/src/core_plugins/elasticsearch/lib/create_data_cluster.js index 2cab5ee7345c1..77873728dd132 100644 --- a/src/core_plugins/elasticsearch/lib/create_data_cluster.js +++ b/src/core_plugins/elasticsearch/lib/create_data_cluster.js @@ -6,8 +6,12 @@ export default function (server) { const Logger = server.plugins.elasticsearch.ElasticsearchClientLogging; class DataClientLogging extends Logger { - tags = ['data']; - logQueries = Boolean(getConfig().logQueries); + constructor() { + super(); + + this.tags = ['data']; + this.logQueries = getConfig().logQueries; + } } function getConfig() { From 30cbf87b41369afc7ecbd928df3ba8bb1043ea7f Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Fri, 16 Dec 2016 11:01:08 -0600 Subject: [PATCH 10/39] [tribe] Remove disabled dev tools app, do not bundle console when tribe is enabled --- src/core_plugins/kibana/index.js | 1 - .../kibana/public/dev_tools/hacks/disable.js | 16 ---------------- src/server/plugins/check_enabled.js | 14 ++++++++++++-- 3 files changed, 12 insertions(+), 19 deletions(-) delete mode 100644 src/core_plugins/kibana/public/dev_tools/hacks/disable.js diff --git a/src/core_plugins/kibana/index.js b/src/core_plugins/kibana/index.js index 04320c4d4fa12..447dc00f578ab 100644 --- a/src/core_plugins/kibana/index.js +++ b/src/core_plugins/kibana/index.js @@ -26,7 +26,6 @@ module.exports = function (kibana) { }, uiExports: { - hacks: ['plugins/kibana/dev_tools/hacks/disable'], app: { id: 'kibana', title: 'Kibana', diff --git a/src/core_plugins/kibana/public/dev_tools/hacks/disable.js b/src/core_plugins/kibana/public/dev_tools/hacks/disable.js deleted file mode 100644 index c6fc97a9eae60..0000000000000 --- a/src/core_plugins/kibana/public/dev_tools/hacks/disable.js +++ /dev/null @@ -1,16 +0,0 @@ -import chrome from 'ui/chrome'; -import modules from 'ui/modules'; - -modules.get('kibana').run(function ($rootScope, $location) { - if (!chrome.getInjected('esDataIsTribe')) { - return; - } - const navLink = chrome.getNavLinkById('kibana:dev_tools'); - navLink.disabled = true; - navLink.tooltip = 'Dev Tools are disabled when using tribe nodes'; - $rootScope.$on('$locationChangeStart', function (event, newUrl) { - if (~newUrl.indexOf(navLink.url)) { - $location.path('/').replace(); - } - }); -}); diff --git a/src/server/plugins/check_enabled.js b/src/server/plugins/check_enabled.js index 846716ad37477..70f163527193f 100644 --- a/src/server/plugins/check_enabled.js +++ b/src/server/plugins/check_enabled.js @@ -1,12 +1,22 @@ import toPath from 'lodash/internal/toPath'; export default async function (kbnServer, server, config) { + const forcedOverride = { + console: function (enabledInConfig) { + return !config.get('elasticsearch.tribe.url') && enabledInConfig; + } + }; + const { plugins } = kbnServer; for (const plugin of plugins) { const enabledInConfig = config.get([...toPath(plugin.configPrefix), 'enabled']); - - if (!enabledInConfig) { + const hasOveride = forcedOverride.hasOwnProperty(plugin.id); + if (hasOveride) { + if (!forcedOverride[plugin.id](enabledInConfig)) { + plugins.disable(plugin); + } + } else if (!enabledInConfig) { plugins.disable(plugin); } } From 77af89df74183242cbc74e57603a7380e669004a Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Fri, 16 Dec 2016 14:45:18 -0600 Subject: [PATCH 11/39] [tribe] Use destructuring, don't reassign args --- src/core_plugins/elasticsearch/lib/create_admin_cluster.js | 4 ++-- src/core_plugins/elasticsearch/lib/create_client.js | 6 +++--- src/core_plugins/elasticsearch/lib/create_data_cluster.js | 4 ++-- src/core_plugins/elasticsearch/lib/create_proxy.js | 2 +- src/ui/public/courier/data_source/_abstract_doc_source.js | 6 +++--- src/ui/public/courier/data_source/_doc_send_to_es.js | 3 ++- 6 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/core_plugins/elasticsearch/lib/create_admin_cluster.js b/src/core_plugins/elasticsearch/lib/create_admin_cluster.js index 442ef036ca7b9..41f27e7033ae5 100644 --- a/src/core_plugins/elasticsearch/lib/create_admin_cluster.js +++ b/src/core_plugins/elasticsearch/lib/create_admin_cluster.js @@ -2,9 +2,9 @@ import { bindKey } from 'lodash'; export default function (server) { const config = server.config(); - const Logger = server.plugins.elasticsearch.ElasticsearchClientLogging; + const { ElasticsearchClientLogging } = server.plugins.elasticsearch; - class AdminClientLogging extends Logger { + class AdminClientLogging extends ElasticsearchClientLogging { constructor() { super(); diff --git a/src/core_plugins/elasticsearch/lib/create_client.js b/src/core_plugins/elasticsearch/lib/create_client.js index aba35de84b955..8d0aaf94da136 100644 --- a/src/core_plugins/elasticsearch/lib/create_client.js +++ b/src/core_plugins/elasticsearch/lib/create_client.js @@ -6,8 +6,8 @@ import { readFileSync } from 'fs'; const readFile = (file) => readFileSync(file, 'utf8'); -module.exports = function (options) { - options = Object.assign({ keepAlive: true, auth: true }, options); +export default function (optionOverrides) { + const options = Object.assign({ keepAlive: true, auth: true }, optionOverrides); const uri = url.parse(options.url); @@ -49,4 +49,4 @@ module.exports = function (options) { }, log: options.log }); -}; +} diff --git a/src/core_plugins/elasticsearch/lib/create_data_cluster.js b/src/core_plugins/elasticsearch/lib/create_data_cluster.js index 77873728dd132..2c9e360cb4472 100644 --- a/src/core_plugins/elasticsearch/lib/create_data_cluster.js +++ b/src/core_plugins/elasticsearch/lib/create_data_cluster.js @@ -3,9 +3,9 @@ import { bindKey } from 'lodash'; export default function (server) { const config = server.config(); const esPlugins = server.plugins.elasticsearch; - const Logger = server.plugins.elasticsearch.ElasticsearchClientLogging; + const { ElasticsearchClientLogging } = server.plugins.elasticsearch; - class DataClientLogging extends Logger { + class DataClientLogging extends ElasticsearchClientLogging { constructor() { super(); diff --git a/src/core_plugins/elasticsearch/lib/create_proxy.js b/src/core_plugins/elasticsearch/lib/create_proxy.js index 663957051275f..cb53070c56139 100644 --- a/src/core_plugins/elasticsearch/lib/create_proxy.js +++ b/src/core_plugins/elasticsearch/lib/create_proxy.js @@ -25,7 +25,7 @@ function createProxy(server, method, path, config) { for (const [proxyPrefix, cluster] of proxies) { const options = { - method: method, + method, path: createProxy.createPath(proxyPrefix, path), config: { timeout: { diff --git a/src/ui/public/courier/data_source/_abstract_doc_source.js b/src/ui/public/courier/data_source/_abstract_doc_source.js index 61bb0580d9340..fe74d379fc1aa 100644 --- a/src/ui/public/courier/data_source/_abstract_doc_source.js +++ b/src/ui/public/courier/data_source/_abstract_doc_source.js @@ -95,10 +95,10 @@ export default function AbstractDocSourceFactory(Private, Promise, es, sessionSt * @return {undefined} */ AbstractDocSource.prototype._mergeProp = function (state, val, key) { - key = '_' + key; + const flatKey = '_' + key; - if (val != null && state[key] == null) { - state[key] = val; + if (val != null && state[flatKey] == null) { + state[flatKey] = val; } }; diff --git a/src/ui/public/courier/data_source/_doc_send_to_es.js b/src/ui/public/courier/data_source/_doc_send_to_es.js index 3c19c4687a59d..393df5aa550c4 100644 --- a/src/ui/public/courier/data_source/_doc_send_to_es.js +++ b/src/ui/public/courier/data_source/_doc_send_to_es.js @@ -32,7 +32,8 @@ export default function (Promise, Private, es, esAdmin, kbnIndex) { if (validateVersion && params.id) { params.version = doc._getVersion(); } - const client = _.includes(params.index, kbnIndex) ? esAdmin : es; + + const client = [].concat(params.index).includes(kbnIndex) ? esAdmin : es; return client[method](params) .then(function (resp) { if (resp.status === 409) throw new errors.VersionConflict(resp); From 1e4f1e600600bf69c24a340874932715a4fc2e93 Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Fri, 16 Dec 2016 15:47:46 -0600 Subject: [PATCH 12/39] [tribe] Use class syntax for client request wrapper --- src/ui/public/es.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/ui/public/es.js b/src/ui/public/es.js index 702ddd0688fe1..93af84e192a9a 100644 --- a/src/ui/public/es.js +++ b/src/ui/public/es.js @@ -12,11 +12,8 @@ import uiModules from 'ui/modules'; const plugins = [function (Client, config) { // esFactory automatically injects the AngularConnector to the config // https://github.com/elastic/elasticsearch-js/blob/master/src/lib/connectors/angular.js - _.class(CustomAngularConnector).inherits(config.connectionClass); - function CustomAngularConnector(host, config) { - CustomAngularConnector.Super.call(this, host, config); - - this.request = _.wrap(this.request, function (request, params, cb) { + class CustomAngularConnector extends config.connectionClass { + request = _.wrap(this.request, function (request, params, cb) { if (String(params.method).toUpperCase() === 'GET') { params.query = _.defaults({ _: Date.now() }, params.query); } From e3b4fd7e84d93571a1fbc167629afa5f5cce3439 Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Fri, 16 Dec 2016 15:52:58 -0600 Subject: [PATCH 13/39] [tribe] callAsKibanaUser -> callWithInternalUser --- .../lib/__tests__/check_es_version.js | 12 ++--- .../lib/__tests__/check_for_tribe.js | 10 ++-- .../elasticsearch/lib/__tests__/cluster.js | 10 ++-- .../lib/__tests__/create_kibana_index.js | 26 +++++----- .../lib/__tests__/health_check.js | 52 +++++++++---------- .../lib/__tests__/upgrade_config.js | 38 +++++++------- .../elasticsearch/lib/check_es_version.js | 4 +- .../elasticsearch/lib/check_for_tribe.js | 4 +- src/core_plugins/elasticsearch/lib/cluster.js | 4 +- .../elasticsearch/lib/create_kibana_index.js | 6 +-- .../elasticsearch/lib/health_check.js | 10 ++-- .../elasticsearch/lib/migrate_config.js | 4 +- .../elasticsearch/lib/upgrade_config.js | 6 +-- src/ui/settings/__tests__/index.js | 6 +-- 14 files changed, 96 insertions(+), 96 deletions(-) diff --git a/src/core_plugins/elasticsearch/lib/__tests__/check_es_version.js b/src/core_plugins/elasticsearch/lib/__tests__/check_es_version.js index ab9b2179e84ac..2c8a1cde1eefa 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/check_es_version.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/check_es_version.js @@ -13,14 +13,14 @@ describe('plugins/elasticsearch', () => { let server; let plugin; - let callAsKibanaUser; + let callWithInternalUser; beforeEach(function () { server = { log: sinon.stub(), plugins: { elasticsearch: { - getCluster: sinon.stub().withArgs('admin').returns({ callAsKibanaUser: sinon.stub() }), // Fix + getCluster: sinon.stub().withArgs('admin').returns({ callWithInternalUser: sinon.stub() }), // Fix status: { red: sinon.stub() }, @@ -52,15 +52,15 @@ describe('plugins/elasticsearch', () => { } const cluster = server.plugins.elasticsearch.getCluster('admin'); - cluster.callAsKibanaUser.withArgs('nodes.info', sinon.match.any).returns(Promise.resolve({ nodes: nodes })); - callAsKibanaUser = cluster.callAsKibanaUser; + cluster.callWithInternalUser.withArgs('nodes.info', sinon.match.any).returns(Promise.resolve({ nodes: nodes })); + callWithInternalUser = cluster.callWithInternalUser; } function setNodeWithoutHTTP(version) { const nodes = { 'node-without-http': { version, ip: 'ip' } }; const cluster = server.plugins.elasticsearch.getCluster('admin'); - cluster.callAsKibanaUser.withArgs('nodes.info', sinon.match.any).returns(Promise.resolve({ nodes: nodes })); - callAsKibanaUser = cluster.callAsKibanaUser; + cluster.callWithInternalUser.withArgs('nodes.info', sinon.match.any).returns(Promise.resolve({ nodes: nodes })); + callWithInternalUser = cluster.callWithInternalUser; } it('returns true with single a node that matches', async () => { diff --git a/src/core_plugins/elasticsearch/lib/__tests__/check_for_tribe.js b/src/core_plugins/elasticsearch/lib/__tests__/check_for_tribe.js index 5eb5c4f624c85..4149d30b90835 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/check_for_tribe.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/check_for_tribe.js @@ -8,7 +8,7 @@ describe('plugins/elasticsearch checkForTribe', () => { const sandbox = sinon.sandbox.create(); afterEach(() => sandbox.restore()); - const stubCallAsKibanaUser = (nodesInfoResp = { nodes: {} }) => { + const stubcallWithInternalUser = (nodesInfoResp = { nodes: {} }) => { return sinon.stub().withArgs( 'nodes.info', sinon.match.any @@ -19,9 +19,9 @@ describe('plugins/elasticsearch checkForTribe', () => { it('fetches the local node stats of the node that the elasticsearch client is connected to', async () => { - const callAsKibanaUser = stubCallAsKibanaUser(); - await checkForTribe(callAsKibanaUser); - sinon.assert.calledOnce(callAsKibanaUser); + const callWithInternalUser = stubcallWithInternalUser(); + await checkForTribe(callWithInternalUser); + sinon.assert.calledOnce(callWithInternalUser); }); it('throws a SetupError when the node info contains tribe settings', async () => { @@ -39,7 +39,7 @@ describe('plugins/elasticsearch checkForTribe', () => { }; try { - await checkForTribe(stubCallAsKibanaUser(nodeInfo)); + await checkForTribe(stubcallWithInternalUser(nodeInfo)); throw new Error('checkForTribe() should have thrown'); } catch (err) { expect(err).to.be.a(Error); diff --git a/src/core_plugins/elasticsearch/lib/__tests__/cluster.js b/src/core_plugins/elasticsearch/lib/__tests__/cluster.js index 95e65f498e773..914fc075b125e 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/cluster.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/cluster.js @@ -71,7 +71,7 @@ describe('plugins/elasticsearch', function () { }); it('is available for callAsKibanUser', async () => { - const marco = await cluster.callAsKibanaUser('marco'); + const marco = await cluster.callWithInternalUser('marco'); expect(marco).to.eql('polo'); }); @@ -81,7 +81,7 @@ describe('plugins/elasticsearch', function () { }); }); - describe('callAsKibanaUser', () => { + describe('callWithInternalUser', () => { let client; beforeEach(() => { @@ -90,17 +90,17 @@ describe('plugins/elasticsearch', function () { }); it('should return a function', () => { - expect(cluster.callAsKibanaUser).to.be.a('function'); + expect(cluster.callWithInternalUser).to.be.a('function'); }); it('throws an error for an invalid endpoint', () => { - const fn = partial(cluster.callAsKibanaUser, 'foo'); + const fn = partial(cluster.callWithInternalUser, 'foo'); expect(fn).to.throwException(/called with an invalid endpoint: foo/); }); it('calls the client with params', () => { const params = { foo: 'Foo' }; - cluster.callAsKibanaUser('nodes.info', params); + cluster.callWithInternalUser('nodes.info', params); sinon.assert.calledOnce(client.nodes.info); expect(client.nodes.info.getCall(0).args[0]).to.eql(params); diff --git a/src/core_plugins/elasticsearch/lib/__tests__/create_kibana_index.js b/src/core_plugins/elasticsearch/lib/__tests__/create_kibana_index.js index 93b1e8c7a71a4..51262e180e91f 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/create_kibana_index.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/create_kibana_index.js @@ -9,7 +9,7 @@ describe('plugins/elasticsearch', function () { describe('lib/create_kibana_index', function () { let server; - let callAsKibanaUser; + let callWithInternalUser; let cluster; beforeEach(function () { @@ -25,29 +25,29 @@ describe('plugins/elasticsearch', function () { _.set(server, 'plugins.elasticsearch', {}); _.set(server, 'config', config); - callAsKibanaUser = sinon.stub(); - cluster = { callAsKibanaUser: callAsKibanaUser }; + callWithInternalUser = sinon.stub(); + cluster = { callWithInternalUser: callWithInternalUser }; server.plugins.elasticsearch.getCluster = sinon.stub().withArgs('admin').returns(cluster); }); describe('successful requests', function () { beforeEach(function () { - callAsKibanaUser.withArgs('indices.create', sinon.match.any).returns(Promise.resolve()); - callAsKibanaUser.withArgs('cluster.health', sinon.match.any).returns(Promise.resolve()); + callWithInternalUser.withArgs('indices.create', sinon.match.any).returns(Promise.resolve()); + callWithInternalUser.withArgs('cluster.health', sinon.match.any).returns(Promise.resolve()); }); it('should check cluster.health upon successful index creation', function () { const fn = createKibanaIndex(server); return fn.then(function () { - sinon.assert.calledOnce(callAsKibanaUser.withArgs('cluster.health', sinon.match.any)); + sinon.assert.calledOnce(callWithInternalUser.withArgs('cluster.health', sinon.match.any)); }); }); it('should be created with mappings for config.buildNum', function () { const fn = createKibanaIndex(server); return fn.then(function () { - const params = callAsKibanaUser.args[0][1]; + const params = callWithInternalUser.args[0][1]; expect(params) .to.have.property('body'); expect(params.body) @@ -66,7 +66,7 @@ describe('plugins/elasticsearch', function () { it('should be created with 1 shard and default replica', function () { const fn = createKibanaIndex(server); return fn.then(function () { - const params = callAsKibanaUser.args[0][1]; + const params = callWithInternalUser.args[0][1]; expect(params) .to.have.property('body'); expect(params.body) @@ -81,7 +81,7 @@ describe('plugins/elasticsearch', function () { it('should be created with index name set in the config', function () { const fn = createKibanaIndex(server); return fn.then(function () { - const params = callAsKibanaUser.args[0][1]; + const params = callWithInternalUser.args[0][1]; expect(params) .to.have.property('index', '.my-kibana'); }); @@ -91,7 +91,7 @@ describe('plugins/elasticsearch', function () { describe('failure requests', function () { it('should reject with an Error', function () { const error = new Error('Oops!'); - callAsKibanaUser.withArgs('indices.create', sinon.match.any).returns(Promise.reject(error)); + callWithInternalUser.withArgs('indices.create', sinon.match.any).returns(Promise.reject(error)); const fn = createKibanaIndex(server); return fn.catch(function (err) { expect(err).to.be.a(Error); @@ -100,7 +100,7 @@ describe('plugins/elasticsearch', function () { it('should reject with an error if index creation fails', function () { const error = new Error('Oops!'); - callAsKibanaUser.withArgs('indices.create', sinon.match.any).returns(Promise.reject(error)); + callWithInternalUser.withArgs('indices.create', sinon.match.any).returns(Promise.reject(error)); const fn = createKibanaIndex(server); return fn.catch(function (err) { expect(err.message).to.be('Unable to create Kibana index ".my-kibana"'); @@ -108,8 +108,8 @@ describe('plugins/elasticsearch', function () { }); it('should reject with an error if health check fails', function () { - callAsKibanaUser.withArgs('indices.create', sinon.match.any).returns(Promise.resolve()); - callAsKibanaUser.withArgs('cluster.health', sinon.match.any).returns(Promise.reject(new Error())); + callWithInternalUser.withArgs('indices.create', sinon.match.any).returns(Promise.resolve()); + callWithInternalUser.withArgs('cluster.health', sinon.match.any).returns(Promise.reject(new Error())); const fn = createKibanaIndex(server); return fn.catch(function (err) { expect(err.message).to.be('Waiting for Kibana index ".my-kibana" to come online failed.'); diff --git a/src/core_plugins/elasticsearch/lib/__tests__/health_check.js b/src/core_plugins/elasticsearch/lib/__tests__/health_check.js index 6ddd8fb8b860b..016b22c164733 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/health_check.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/health_check.js @@ -36,11 +36,11 @@ describe('plugins/elasticsearch', () => { } }; - cluster = { callAsKibanaUser: sinon.stub() }; - cluster.callAsKibanaUser.withArgs('index', sinon.match.any).returns(Promise.resolve()); - cluster.callAsKibanaUser.withArgs('get', sinon.match.any).returns(Promise.resolve({ found: false })); - cluster.callAsKibanaUser.withArgs('search', sinon.match.any).returns(Promise.resolve({ hits: { hits: [] } })); - cluster.callAsKibanaUser.withArgs('nodes.info', sinon.match.any).returns(Promise.resolve({ + cluster = { callWithInternalUser: sinon.stub() }; + cluster.callWithInternalUser.withArgs('index', sinon.match.any).returns(Promise.resolve()); + cluster.callWithInternalUser.withArgs('get', sinon.match.any).returns(Promise.resolve({ found: false })); + cluster.callWithInternalUser.withArgs('search', sinon.match.any).returns(Promise.resolve({ hits: { hits: [] } })); + cluster.callWithInternalUser.withArgs('nodes.info', sinon.match.any).returns(Promise.resolve({ nodes: { 'node-01': { version: COMPATIBLE_VERSION_NUMBER, @@ -77,8 +77,8 @@ describe('plugins/elasticsearch', () => { }); it('should set the cluster green if everything is ready', function () { - cluster.callAsKibanaUser.withArgs('ping').returns(Promise.resolve()); - cluster.callAsKibanaUser.withArgs('cluster.health', sinon.match.any).returns( + cluster.callWithInternalUser.withArgs('ping').returns(Promise.resolve()); + cluster.callWithInternalUser.withArgs('cluster.health', sinon.match.any).returns( Promise.resolve({ timed_out: false, status: 'green' }) ); @@ -87,9 +87,9 @@ describe('plugins/elasticsearch', () => { sinon.assert.calledOnce(plugin.status.yellow); expect(plugin.status.yellow.args[0][0]).to.be('Waiting for Elasticsearch'); - sinon.assert.calledOnce(cluster.callAsKibanaUser.withArgs('ping')); - sinon.assert.calledTwice(cluster.callAsKibanaUser.withArgs('nodes.info', sinon.match.any)); - sinon.assert.calledOnce(cluster.callAsKibanaUser.withArgs('cluster.health', sinon.match.any)); + sinon.assert.calledOnce(cluster.callWithInternalUser.withArgs('ping')); + sinon.assert.calledTwice(cluster.callWithInternalUser.withArgs('nodes.info', sinon.match.any)); + sinon.assert.calledOnce(cluster.callWithInternalUser.withArgs('cluster.health', sinon.match.any)); sinon.assert.calledOnce(plugin.status.green); expect(plugin.status.green.args[0][0]).to.be('Kibana index ready'); @@ -97,11 +97,11 @@ describe('plugins/elasticsearch', () => { }); it('should set the cluster red if the ping fails, then to green', function () { - const ping = cluster.callAsKibanaUser.withArgs('ping'); + const ping = cluster.callWithInternalUser.withArgs('ping'); ping.onCall(0).returns(Promise.reject(new NoConnections())); ping.onCall(1).returns(Promise.resolve()); - cluster.callAsKibanaUser.withArgs('cluster.health', sinon.match.any).returns( + cluster.callWithInternalUser.withArgs('cluster.health', sinon.match.any).returns( Promise.resolve({ timed_out: false, status: 'green' }) ); @@ -116,17 +116,17 @@ describe('plugins/elasticsearch', () => { ); sinon.assert.calledTwice(ping); - sinon.assert.calledTwice(cluster.callAsKibanaUser.withArgs('nodes.info', sinon.match.any)); - sinon.assert.calledOnce(cluster.callAsKibanaUser.withArgs('cluster.health', sinon.match.any)); + sinon.assert.calledTwice(cluster.callWithInternalUser.withArgs('nodes.info', sinon.match.any)); + sinon.assert.calledOnce(cluster.callWithInternalUser.withArgs('cluster.health', sinon.match.any)); sinon.assert.calledOnce(plugin.status.green); expect(plugin.status.green.args[0][0]).to.be('Kibana index ready'); }); }); it('should set the cluster red if the health check status is red, then to green', function () { - cluster.callAsKibanaUser.withArgs('ping').returns(Promise.resolve()); + cluster.callWithInternalUser.withArgs('ping').returns(Promise.resolve()); - const clusterHealth = cluster.callAsKibanaUser.withArgs('cluster.health', sinon.match.any); + const clusterHealth = cluster.callWithInternalUser.withArgs('cluster.health', sinon.match.any); clusterHealth.onCall(0).returns(Promise.resolve({ timed_out: false, status: 'red' })); clusterHealth.onCall(1).returns(Promise.resolve({ timed_out: false, status: 'green' })); @@ -138,22 +138,22 @@ describe('plugins/elasticsearch', () => { expect(plugin.status.red.args[0][0]).to.be( 'Elasticsearch is still initializing the kibana index.' ); - sinon.assert.calledOnce(cluster.callAsKibanaUser.withArgs('ping')); - sinon.assert.calledTwice(cluster.callAsKibanaUser.withArgs('nodes.info', sinon.match.any)); - sinon.assert.calledTwice(cluster.callAsKibanaUser.withArgs('cluster.health', sinon.match.any)); + sinon.assert.calledOnce(cluster.callWithInternalUser.withArgs('ping')); + sinon.assert.calledTwice(cluster.callWithInternalUser.withArgs('nodes.info', sinon.match.any)); + sinon.assert.calledTwice(cluster.callWithInternalUser.withArgs('cluster.health', sinon.match.any)); sinon.assert.calledOnce(plugin.status.green); expect(plugin.status.green.args[0][0]).to.be('Kibana index ready'); }); }); it('should set the cluster yellow if the health check timed_out and create index', function () { - cluster.callAsKibanaUser.withArgs('ping').returns(Promise.resolve()); + cluster.callWithInternalUser.withArgs('ping').returns(Promise.resolve()); - const clusterHealth = cluster.callAsKibanaUser.withArgs('cluster.health', sinon.match.any); + const clusterHealth = cluster.callWithInternalUser.withArgs('cluster.health', sinon.match.any); clusterHealth.onCall(0).returns(Promise.resolve({ timed_out: true, status: 'red' })); clusterHealth.onCall(1).returns(Promise.resolve({ timed_out: false, status: 'green' })); - cluster.callAsKibanaUser.withArgs('indices.create', sinon.match.any).returns(Promise.resolve()); + cluster.callWithInternalUser.withArgs('indices.create', sinon.match.any).returns(Promise.resolve()); return health.run() .then(function () { @@ -161,16 +161,16 @@ describe('plugins/elasticsearch', () => { expect(plugin.status.yellow.args[0][0]).to.be('Waiting for Elasticsearch'); expect(plugin.status.yellow.args[1][0]).to.be('No existing Kibana index found'); - sinon.assert.calledOnce(cluster.callAsKibanaUser.withArgs('ping')); - sinon.assert.calledOnce(cluster.callAsKibanaUser.withArgs('indices.create', sinon.match.any)); - sinon.assert.calledTwice(cluster.callAsKibanaUser.withArgs('nodes.info', sinon.match.any)); + sinon.assert.calledOnce(cluster.callWithInternalUser.withArgs('ping')); + sinon.assert.calledOnce(cluster.callWithInternalUser.withArgs('indices.create', sinon.match.any)); + sinon.assert.calledTwice(cluster.callWithInternalUser.withArgs('nodes.info', sinon.match.any)); sinon.assert.calledTwice(clusterHealth); }); }); describe('#waitUntilReady', function () { it('polls health until index is ready', function () { - const clusterHealth = cluster.callAsKibanaUser.withArgs('cluster.health', sinon.match.any); + const clusterHealth = cluster.callWithInternalUser.withArgs('cluster.health', sinon.match.any); clusterHealth.onCall(0).returns(Promise.resolve({ timed_out: true })); clusterHealth.onCall(1).returns(Promise.resolve({ status: 'red' })); clusterHealth.onCall(2).returns(Promise.resolve({ status: 'green' })); diff --git a/src/core_plugins/elasticsearch/lib/__tests__/upgrade_config.js b/src/core_plugins/elasticsearch/lib/__tests__/upgrade_config.js index c6779398ad579..3648b015f03ca 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/upgrade_config.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/upgrade_config.js @@ -9,7 +9,7 @@ describe('plugins/elasticsearch', function () { describe('lib/upgrade_config', function () { let get; let server; - let callAsKibanaUser; + let callWithInternalUser; let config; let upgrade; @@ -19,7 +19,7 @@ describe('plugins/elasticsearch', function () { get.withArgs('pkg.version').returns('4.0.1'); get.withArgs('pkg.buildNum').returns(Math.random()); - callAsKibanaUser = sinon.stub(); + callWithInternalUser = sinon.stub(); server = { log: sinon.stub(), @@ -31,7 +31,7 @@ describe('plugins/elasticsearch', function () { plugins: { elasticsearch: { getCluster: sinon.stub().withArgs('admin').returns({ - callAsKibanaUser: callAsKibanaUser + callWithInternalUser: callWithInternalUser }) } } @@ -43,7 +43,7 @@ describe('plugins/elasticsearch', function () { const response = { hits: { hits:[] } }; beforeEach(function () { - callAsKibanaUser.withArgs('create', sinon.match.any).returns(Promise.resolve()); + callWithInternalUser.withArgs('create', sinon.match.any).returns(Promise.resolve()); }); describe('production', function () { @@ -55,15 +55,15 @@ describe('plugins/elasticsearch', function () { it('should resolve buildNum to pkg.buildNum config', function () { return upgrade(response).then(function (resp) { - sinon.assert.calledOnce(callAsKibanaUser); - const params = callAsKibanaUser.args[0][1]; + sinon.assert.calledOnce(callWithInternalUser); + const params = callWithInternalUser.args[0][1]; expect(params.body).to.have.property('buildNum', get('pkg.buildNum')); }); }); it('should resolve version to pkg.version config', function () { return upgrade(response).then(function (resp) { - const params = callAsKibanaUser.args[0][1]; + const params = callWithInternalUser.args[0][1]; expect(params).to.have.property('id', get('pkg.version')); }); }); @@ -78,14 +78,14 @@ describe('plugins/elasticsearch', function () { it('should resolve buildNum to pkg.buildNum config', function () { return upgrade(response).then(function (resp) { - const params = callAsKibanaUser.args[0][1]; + const params = callWithInternalUser.args[0][1]; expect(params.body).to.have.property('buildNum', get('pkg.buildNum')); }); }); it('should resolve version to pkg.version config', function () { return upgrade(response).then(function (resp) { - const params = callAsKibanaUser.args[0][1]; + const params = callWithInternalUser.args[0][1]; expect(params).to.have.property('id', get('pkg.version')); }); }); @@ -101,12 +101,12 @@ describe('plugins/elasticsearch', function () { it('should create new config if the nothing is upgradeable', function () { get.withArgs('pkg.buildNum').returns(9833); - callAsKibanaUser.withArgs('create', sinon.match.any).returns(Promise.resolve()); + callWithInternalUser.withArgs('create', sinon.match.any).returns(Promise.resolve()); const response = { hits: { hits: [ { _id: '4.0.1-alpha3' }, { _id: '4.0.1-beta1' }, { _id: '4.0.0-SNAPSHOT1' } ] } }; return upgrade(response).then(function (resp) { - sinon.assert.calledOnce(callAsKibanaUser); - const params = callAsKibanaUser.args[0][1]; + sinon.assert.calledOnce(callWithInternalUser); + const params = callWithInternalUser.args[0][1]; expect(params).to.have.property('body'); expect(params.body).to.have.property('buildNum', 9833); expect(params).to.have.property('index', '.my-kibana'); @@ -117,13 +117,13 @@ describe('plugins/elasticsearch', function () { it('should update the build number on the new config', function () { get.withArgs('pkg.buildNum').returns(5801); - callAsKibanaUser.withArgs('create', sinon.match.any).returns(Promise.resolve()); + callWithInternalUser.withArgs('create', sinon.match.any).returns(Promise.resolve()); const response = { hits: { hits: [ { _id: '4.0.0', _source: { buildNum: 1 } } ] } }; return upgrade(response).then(function (resp) { - sinon.assert.calledOnce(callAsKibanaUser); - const params = callAsKibanaUser.args[0][1]; + sinon.assert.calledOnce(callWithInternalUser); + const params = callWithInternalUser.args[0][1]; expect(params).to.have.property('body'); expect(params.body).to.have.property('buildNum', 5801); expect(params).to.have.property('index', '.my-kibana'); @@ -134,7 +134,7 @@ describe('plugins/elasticsearch', function () { it('should log a message for upgrades', function () { get.withArgs('pkg.buildNum').returns(5801); - callAsKibanaUser.withArgs('create', sinon.match.any).returns(Promise.resolve()); + callWithInternalUser.withArgs('create', sinon.match.any).returns(Promise.resolve()); const response = { hits: { hits: [ { _id: '4.0.0', _source: { buildNum: 1 } } ] } }; @@ -150,13 +150,13 @@ describe('plugins/elasticsearch', function () { it('should copy attributes from old config', function () { get.withArgs('pkg.buildNum').returns(5801); - callAsKibanaUser.withArgs('create', sinon.match.any).returns(Promise.resolve()); + callWithInternalUser.withArgs('create', sinon.match.any).returns(Promise.resolve()); const response = { hits: { hits: [ { _id: '4.0.0', _source: { buildNum: 1, defaultIndex: 'logstash-*' } } ] } }; return upgrade(response).then(function (resp) { - sinon.assert.calledOnce(callAsKibanaUser); - const params = callAsKibanaUser.args[0][1]; + sinon.assert.calledOnce(callWithInternalUser); + const params = callWithInternalUser.args[0][1]; expect(params).to.have.property('body'); expect(params.body).to.have.property('defaultIndex', 'logstash-*'); }); diff --git a/src/core_plugins/elasticsearch/lib/check_es_version.js b/src/core_plugins/elasticsearch/lib/check_es_version.js index 59add2b0a707a..35593e1d71a29 100644 --- a/src/core_plugins/elasticsearch/lib/check_es_version.js +++ b/src/core_plugins/elasticsearch/lib/check_es_version.js @@ -17,10 +17,10 @@ import isEsCompatibleWithKibana from './is_es_compatible_with_kibana'; const lastWarnedNodesForServer = new WeakMap(); module.exports = function checkEsVersion(server, kibanaVersion) { - const { callAsKibanaUser } = server.plugins.elasticsearch.getCluster('admin'); + const { callWithInternalUser } = server.plugins.elasticsearch.getCluster('admin'); server.log(['plugin', 'debug'], 'Checking Elasticsearch version'); - return callAsKibanaUser('nodes.info', { + return callWithInternalUser('nodes.info', { filterPath: [ 'nodes.*.version', 'nodes.*.http.publish_address', diff --git a/src/core_plugins/elasticsearch/lib/check_for_tribe.js b/src/core_plugins/elasticsearch/lib/check_for_tribe.js index c52b91970b442..80b82810cbd64 100644 --- a/src/core_plugins/elasticsearch/lib/check_for_tribe.js +++ b/src/core_plugins/elasticsearch/lib/check_for_tribe.js @@ -1,7 +1,7 @@ import { get } from 'lodash'; -export default function checkForTribe(callAsKibanaUser) { - return callAsKibanaUser('nodes.info', { +export default function checkForTribe(callWithInternalUser) { + return callWithInternalUser('nodes.info', { nodeId: '_local', filterPath: 'nodes.*.settings.tribe' }) diff --git a/src/core_plugins/elasticsearch/lib/cluster.js b/src/core_plugins/elasticsearch/lib/cluster.js index 24f3be22b2ce0..101400f7a52ac 100644 --- a/src/core_plugins/elasticsearch/lib/cluster.js +++ b/src/core_plugins/elasticsearch/lib/cluster.js @@ -40,7 +40,7 @@ export default class Cluster { } /** - * callAsKibanaUser + * callWithInternalUser * * Performs a call to ES using the credentials in kibana.yml * @@ -50,7 +50,7 @@ export default class Cluster { * @returns {Promise} */ - callAsKibanaUser = (endpoint, clientParams = {}, options = {}) => { + callWithInternalUser = (endpoint, clientParams = {}, options = {}) => { return callAPI(this._client, endpoint, clientParams, options); } diff --git a/src/core_plugins/elasticsearch/lib/create_kibana_index.js b/src/core_plugins/elasticsearch/lib/create_kibana_index.js index 7a075ca33d192..b1e4b61bdabe8 100644 --- a/src/core_plugins/elasticsearch/lib/create_kibana_index.js +++ b/src/core_plugins/elasticsearch/lib/create_kibana_index.js @@ -2,10 +2,10 @@ import { format } from 'util'; import { mappings } from './kibana_index_mappings'; module.exports = function (server) { - const { callAsKibanaUser } = server.plugins.elasticsearch.getCluster('admin'); + const { callWithInternalUser } = server.plugins.elasticsearch.getCluster('admin'); const index = server.config().get('kibana.index'); - return callAsKibanaUser('indices.create', { + return callWithInternalUser('indices.create', { index: index, body: { settings: { @@ -18,7 +18,7 @@ module.exports = function (server) { throw new Error(`Unable to create Kibana index "${index}"`); }) .then(function () { - return callAsKibanaUser('cluster.health', { + return callWithInternalUser('cluster.health', { waitForStatus: 'yellow', index: index }) diff --git a/src/core_plugins/elasticsearch/lib/health_check.js b/src/core_plugins/elasticsearch/lib/health_check.js index e1bbc8804d657..e340232070a7d 100644 --- a/src/core_plugins/elasticsearch/lib/health_check.js +++ b/src/core_plugins/elasticsearch/lib/health_check.js @@ -17,17 +17,17 @@ const READY = 'ready'; module.exports = function (plugin, server) { const config = server.config(); - const callAdminAsKibanaUser = server.plugins.elasticsearch.getCluster('admin').callAsKibanaUser; - const callDataAsKibanaUser = server.plugins.elasticsearch.getCluster('data').callAsKibanaUser; + const callAdminAsKibanaUser = server.plugins.elasticsearch.getCluster('admin').callWithInternalUser; + const callDataAsKibanaUser = server.plugins.elasticsearch.getCluster('data').callWithInternalUser; const REQUEST_DELAY = config.get('elasticsearch.healthCheck.delay'); plugin.status.yellow('Waiting for Elasticsearch'); - function waitForPong(callAsKibanaUser, url) { - return callAsKibanaUser('ping').catch(function (err) { + function waitForPong(callWithInternalUser, url) { + return callWithInternalUser('ping').catch(function (err) { if (!(err instanceof NoConnections)) throw err; plugin.status.red(format('Unable to connect to Elasticsearch at %s.', url)); - return Promise.delay(REQUEST_DELAY).then(waitForPong.bind(null, callAsKibanaUser, url)); + return Promise.delay(REQUEST_DELAY).then(waitForPong.bind(null, callWithInternalUser, url)); }); } diff --git a/src/core_plugins/elasticsearch/lib/migrate_config.js b/src/core_plugins/elasticsearch/lib/migrate_config.js index 08d20c8f2f883..a1d256200a51e 100644 --- a/src/core_plugins/elasticsearch/lib/migrate_config.js +++ b/src/core_plugins/elasticsearch/lib/migrate_config.js @@ -3,7 +3,7 @@ import { mappings } from './kibana_index_mappings'; module.exports = function (server) { const config = server.config(); - const { callAsKibanaUser } = server.plugins.elasticsearch.getCluster('admin'); + const { callWithInternalUser } = server.plugins.elasticsearch.getCluster('admin'); const options = { index: config.get('kibana.index'), @@ -21,5 +21,5 @@ module.exports = function (server) { } }; - return callAsKibanaUser('search', options).then(upgrade(server)); + return callWithInternalUser('search', options).then(upgrade(server)); }; diff --git a/src/core_plugins/elasticsearch/lib/upgrade_config.js b/src/core_plugins/elasticsearch/lib/upgrade_config.js index a5552ec976085..645e95b9852fc 100644 --- a/src/core_plugins/elasticsearch/lib/upgrade_config.js +++ b/src/core_plugins/elasticsearch/lib/upgrade_config.js @@ -6,11 +6,11 @@ import { format } from 'util'; module.exports = function (server) { const MAX_INTEGER = Math.pow(2, 53) - 1; - const { callAsKibanaUser } = server.plugins.elasticsearch.getCluster('admin'); + const { callWithInternalUser } = server.plugins.elasticsearch.getCluster('admin'); const config = server.config(); function createNewConfig() { - return callAsKibanaUser('create', { + return callWithInternalUser('create', { index: config.get('kibana.index'), type: 'config', body: { buildNum: config.get('pkg.buildNum') }, @@ -52,7 +52,7 @@ module.exports = function (server) { newVersion: config.get('pkg.version') }); - return callAsKibanaUser('create', { + return callWithInternalUser('create', { index: config.get('kibana.index'), type: 'config', body: body._source, diff --git a/src/ui/settings/__tests__/index.js b/src/ui/settings/__tests__/index.js index 0c159948116bf..698abf176d864 100644 --- a/src/ui/settings/__tests__/index.js +++ b/src/ui/settings/__tests__/index.js @@ -393,7 +393,7 @@ function instantiate({ getResult, callWithRequest, settingsStatusOverrides } = { const adminCluster = { errors: esErrors, - callAsKibanaUser: sinon.stub(), + callWithInternalUser: sinon.stub(), callWithRequest: sinon.spy((withReq, method, params) => { if (callWithRequest) { return callWithRequest(withReq, method, params); @@ -411,8 +411,8 @@ function instantiate({ getResult, callWithRequest, settingsStatusOverrides } = { }) }; - adminCluster.callAsKibanaUser.withArgs('get', sinon.match.any).returns(Promise.resolve({ _source: getResult })); - adminCluster.callAsKibanaUser.withArgs('update', sinon.match.any).returns(Promise.resolve()); + adminCluster.callWithInternalUser.withArgs('get', sinon.match.any).returns(Promise.resolve({ _source: getResult })); + adminCluster.callWithInternalUser.withArgs('update', sinon.match.any).returns(Promise.resolve()); const server = { decorate: (_, key, value) => server[key] = value, From e21723b558e34cd69e6f7420b631b24db098637c Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Fri, 16 Dec 2016 16:35:01 -0600 Subject: [PATCH 14/39] [tribe] Remove clients from module context, service is a singleton --- src/ui/public/es.js | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/ui/public/es.js b/src/ui/public/es.js index 93af84e192a9a..ac77acbe2e8bb 100644 --- a/src/ui/public/es.js +++ b/src/ui/public/es.js @@ -25,34 +25,23 @@ const plugins = [function (Client, config) { config.connectionClass = CustomAngularConnector; }]; - -// share the clients amongst all apps -let es; -let esAdmin; - uiModules .get('kibana', ['elasticsearch', 'kibana/config']) .service('es', function (esFactory, esUrl, esApiVersion, esRequestTimeout) { - if (es) return es; - es = esFactory({ + return esFactory({ host: esUrl, log: 'info', requestTimeout: esRequestTimeout, apiVersion: esApiVersion, plugins }); - - return es; }) .service('esAdmin', function (esFactory, esAdminUrl, esApiVersion, esRequestTimeout) { - if (esAdmin) return esAdmin; - esAdmin = esFactory({ + return esFactory({ host: esAdminUrl, log: 'info', requestTimeout: esRequestTimeout, apiVersion: esApiVersion, plugins }); - - return esAdmin; }); From 51672fa281cc14883fbdc79ee3eea9d84c2e4a78 Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Fri, 16 Dec 2016 16:54:54 -0600 Subject: [PATCH 15/39] [tribe] Use instance property shorthand for admin and data DocRequests --- src/ui/public/courier/fetch/request/doc_admin.js | 5 +---- src/ui/public/courier/fetch/request/doc_data.js | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/ui/public/courier/fetch/request/doc_admin.js b/src/ui/public/courier/fetch/request/doc_admin.js index ac76e9ee85407..9549766cbd36b 100644 --- a/src/ui/public/courier/fetch/request/doc_admin.js +++ b/src/ui/public/courier/fetch/request/doc_admin.js @@ -7,10 +7,7 @@ export default function DocRequestProvider(Private) { const AbstractDocRequest = Private(AbstractDocRequestProvider); class AdminDocRequest extends AbstractDocRequest { - constructor(...args) { - super(...args); - this.strategy = docStrategy; - } + strategy = docStrategy; } return AdminDocRequest; diff --git a/src/ui/public/courier/fetch/request/doc_data.js b/src/ui/public/courier/fetch/request/doc_data.js index f70be6b621b72..832e31e3c9770 100644 --- a/src/ui/public/courier/fetch/request/doc_data.js +++ b/src/ui/public/courier/fetch/request/doc_data.js @@ -7,10 +7,7 @@ export default function DocRequestProvider(Private) { const AbstractDocRequest = Private(AbstractDocRequestProvider); class DataDocRequest extends AbstractDocRequest { - constructor(...args) { - super(...args); - this.strategy = docStrategy; - } + strategy = docStrategy; } return DataDocRequest; From fb866a84aa42b86e936413c460ccc3c8325adba4 Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Mon, 19 Dec 2016 08:27:13 -0800 Subject: [PATCH 16/39] Removes questions Signed-off-by: Tyler Smalley --- src/core_plugins/elasticsearch/lib/map_uri.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core_plugins/elasticsearch/lib/map_uri.js b/src/core_plugins/elasticsearch/lib/map_uri.js index 70c0999f57a39..2d3ffbd153615 100644 --- a/src/core_plugins/elasticsearch/lib/map_uri.js +++ b/src/core_plugins/elasticsearch/lib/map_uri.js @@ -22,8 +22,8 @@ export default function mapUri(cluster, proxyPrefix) { // copy most url components directly from the elasticsearch.url const mappedUrlComponents = { protocol: esUrlProtocol, - slashes: esUrlHasSlashes, // QUESTION: would it every be anything else? - auth: esUrlAuth, // QUESTION: should we pass this on? + slashes: esUrlHasSlashes, + auth: esUrlAuth, hostname: esUrlHostname, port: esUrlPort }; From b0fbd6599d4014b3fb3eb6dd797aae04b218e1f4 Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Mon, 19 Dec 2016 08:51:52 -0800 Subject: [PATCH 17/39] Fixes typo in tests Signed-off-by: Tyler Smalley --- src/core_plugins/elasticsearch/lib/__tests__/cluster.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core_plugins/elasticsearch/lib/__tests__/cluster.js b/src/core_plugins/elasticsearch/lib/__tests__/cluster.js index 914fc075b125e..45f74f0efd1cd 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/cluster.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/cluster.js @@ -70,7 +70,7 @@ describe('plugins/elasticsearch', function () { expect(cluster.config().plugins).to.eql([plugin, pluginTwo]); }); - it('is available for callAsKibanUser', async () => { + it('is available for callAsKibanaUser', async () => { const marco = await cluster.callWithInternalUser('marco'); expect(marco).to.eql('polo'); }); From 0d52a0407bd4a525cc631dbf746af2c050fc94c2 Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Mon, 19 Dec 2016 08:53:15 -0800 Subject: [PATCH 18/39] Correctly names test case Signed-off-by: Tyler Smalley --- src/core_plugins/elasticsearch/lib/__tests__/cluster.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core_plugins/elasticsearch/lib/__tests__/cluster.js b/src/core_plugins/elasticsearch/lib/__tests__/cluster.js index 45f74f0efd1cd..02c5976dc3ad6 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/cluster.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/cluster.js @@ -70,7 +70,7 @@ describe('plugins/elasticsearch', function () { expect(cluster.config().plugins).to.eql([plugin, pluginTwo]); }); - it('is available for callAsKibanaUser', async () => { + it('is available for callWithInternalUser', async () => { const marco = await cluster.callWithInternalUser('marco'); expect(marco).to.eql('polo'); }); From 927e775c537b21af31028525e4ac99243ed6e71e Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Fri, 16 Dec 2016 17:00:17 -0600 Subject: [PATCH 19/39] Revert "Use properties on the instance instead of class properties" This reverts commit ebd06ae591a433e11bce52a2292c3857bf16898d. --- src/core_plugins/elasticsearch/lib/client_logger.js | 5 +++++ .../elasticsearch/lib/create_admin_cluster.js | 8 ++------ src/core_plugins/elasticsearch/lib/create_data_cluster.js | 8 ++------ 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/core_plugins/elasticsearch/lib/client_logger.js b/src/core_plugins/elasticsearch/lib/client_logger.js index b27c09e55e946..54fb4896d189f 100644 --- a/src/core_plugins/elasticsearch/lib/client_logger.js +++ b/src/core_plugins/elasticsearch/lib/client_logger.js @@ -1,5 +1,10 @@ module.exports = function (server) { return class ElasticsearchClientLogging { + // additional tags to differentiate connection + tags = ['admin']; + + logQueries = false; + error(err) { server.log(['error', 'elasticsearch'].concat(this.tags), err); } diff --git a/src/core_plugins/elasticsearch/lib/create_admin_cluster.js b/src/core_plugins/elasticsearch/lib/create_admin_cluster.js index 41f27e7033ae5..4d93ac6bb8adb 100644 --- a/src/core_plugins/elasticsearch/lib/create_admin_cluster.js +++ b/src/core_plugins/elasticsearch/lib/create_admin_cluster.js @@ -5,12 +5,8 @@ export default function (server) { const { ElasticsearchClientLogging } = server.plugins.elasticsearch; class AdminClientLogging extends ElasticsearchClientLogging { - constructor() { - super(); - - this.tags = ['admin']; - this.logQueries = config.get('elasticsearch.logQueries'); - } + tags = ['admin']; + logQueries = config.get('elasticsearch.logQueries'); } const adminCluster = server.plugins.elasticsearch.createCluster( diff --git a/src/core_plugins/elasticsearch/lib/create_data_cluster.js b/src/core_plugins/elasticsearch/lib/create_data_cluster.js index 2c9e360cb4472..4ffedd7e99c72 100644 --- a/src/core_plugins/elasticsearch/lib/create_data_cluster.js +++ b/src/core_plugins/elasticsearch/lib/create_data_cluster.js @@ -6,12 +6,8 @@ export default function (server) { const { ElasticsearchClientLogging } = server.plugins.elasticsearch; class DataClientLogging extends ElasticsearchClientLogging { - constructor() { - super(); - - this.tags = ['data']; - this.logQueries = getConfig().logQueries; - } + tags = ['data']; + logQueries = getConfig().logQueries; } function getConfig() { From 98553213a0742d5aeb2a41953a4d8f12d5e11a27 Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Mon, 19 Dec 2016 11:59:14 -0800 Subject: [PATCH 20/39] Adds tests for create_{admin,data}_cluster Signed-off-by: Tyler Smalley --- .../lib/__tests__/create_admin_cluster.js | 66 ++++++++++++++ .../lib/__tests__/create_data_cluster.js | 85 +++++++++++++++++++ .../elasticsearch/lib/create_admin_cluster.js | 3 +- .../elasticsearch/lib/create_data_cluster.js | 11 ++- 4 files changed, 158 insertions(+), 7 deletions(-) create mode 100644 src/core_plugins/elasticsearch/lib/__tests__/create_admin_cluster.js create mode 100644 src/core_plugins/elasticsearch/lib/__tests__/create_data_cluster.js diff --git a/src/core_plugins/elasticsearch/lib/__tests__/create_admin_cluster.js b/src/core_plugins/elasticsearch/lib/__tests__/create_admin_cluster.js new file mode 100644 index 0000000000000..851f61ad58c0d --- /dev/null +++ b/src/core_plugins/elasticsearch/lib/__tests__/create_admin_cluster.js @@ -0,0 +1,66 @@ +import expect from 'expect.js'; +import sinon from 'sinon'; +import { bindKey, set, get, partial } from 'lodash'; +import createAdminCluster from '../create_admin_cluster'; + +describe('plugins/elasticsearch', function () { + describe('create_admin_cluster', function () { + let cluster; + let server; + + beforeEach(() => { + const config = { + elasticsearch: { + url: 'http://localhost:9200', + logQueries: true + } + }; + + server = sinon.spy(); + + cluster = { + close: sinon.spy() + }; + + set(server, 'plugins.elasticsearch.createCluster', sinon.mock().returns(cluster)); + set(server, 'on', sinon.spy()); + + server.config = () => { + return { get: partial(get, config) }; + }; + + createAdminCluster(server); + }); + + it('creates the cluster', () => { + const { createCluster } = server.plugins.elasticsearch; + + sinon.assert.calledOnce(createCluster); + expect(createCluster.getCall(0).args[0]).to.eql('admin'); + expect(createCluster.getCall(0).args[1].url).to.eql('http://localhost:9200'); + }); + + it('sets client logger for cluster options', () => { + const { createCluster } = server.plugins.elasticsearch; + const firstCall = createCluster.getCall(0); + const Log = firstCall.args[1].log; + const logger = new Log; + + sinon.assert.calledOnce(createCluster); + expect(firstCall.args[0]).to.eql('admin'); + expect(firstCall.args[1].url).to.eql('http://localhost:9200'); + expect(logger.tags).to.eql(['admin']); + expect(logger.logQueries).to.eql(true); + }); + + it('close cluster of server close', () => { + const clusterClose = server.on.getCall(0).args[1]; + + clusterClose(); + + sinon.assert.calledOnce(cluster.close); + sinon.assert.calledOnce(server.on); + expect(server.on.getCall(0).args[0]).to.eql('close'); + }); + }); +}); diff --git a/src/core_plugins/elasticsearch/lib/__tests__/create_data_cluster.js b/src/core_plugins/elasticsearch/lib/__tests__/create_data_cluster.js new file mode 100644 index 0000000000000..cd76936445f23 --- /dev/null +++ b/src/core_plugins/elasticsearch/lib/__tests__/create_data_cluster.js @@ -0,0 +1,85 @@ +import expect from 'expect.js'; +import sinon from 'sinon'; +import { bindKey, set, get, partial } from 'lodash'; +import createDataCluster from '../create_data_cluster'; + +describe('plugins/elasticsearch', function () { + describe('create_data_cluster', function () { + let cluster; + let server; + let config; + + beforeEach(() => { + config = { + elasticsearch: { + url: 'http://localhost:9200', + logQueries: true + } + }; + + server = sinon.spy(); + + cluster = { + close: sinon.spy() + }; + + set(server, 'plugins.elasticsearch.createCluster', sinon.mock().returns(cluster)); + set(server, 'on', sinon.spy()); + + server.config = () => { + return { get: partial(get, config) }; + }; + }); + + it('creates the cluster with elasticsearch config', () => { + createDataCluster(server); + + const { createCluster } = server.plugins.elasticsearch; + + sinon.assert.calledOnce(createCluster); + expect(createCluster.getCall(0).args[0]).to.eql('data'); + expect(createCluster.getCall(0).args[1].url).to.eql('http://localhost:9200'); + }); + + it('creates the cluster with elasticsearch.tribe config', () => { + config.elasticsearch.tribe = { + url: 'http://localhost:9201' + }; + + createDataCluster(server); + + const { createCluster } = server.plugins.elasticsearch; + + sinon.assert.calledOnce(createCluster); + expect(createCluster.getCall(0).args[0]).to.eql('data'); + expect(createCluster.getCall(0).args[1].url).to.eql('http://localhost:9201'); + }); + + it('sets client logger for cluster options', () => { + createDataCluster(server); + + const { createCluster } = server.plugins.elasticsearch; + const firstCall = createCluster.getCall(0); + const Log = firstCall.args[1].log; + const logger = new Log; + + sinon.assert.calledOnce(createCluster); + expect(firstCall.args[0]).to.eql('data'); + expect(firstCall.args[1].url).to.eql('http://localhost:9200'); + expect(logger.tags).to.eql(['data']); + expect(logger.logQueries).to.eql(true); + }); + + it('close cluster of server close', () => { + createDataCluster(server); + + const clusterClose = server.on.getCall(0).args[1]; + + clusterClose(); + + sinon.assert.calledOnce(cluster.close); + sinon.assert.calledOnce(server.on); + expect(server.on.getCall(0).args[0]).to.eql('close'); + }); + }); +}); diff --git a/src/core_plugins/elasticsearch/lib/create_admin_cluster.js b/src/core_plugins/elasticsearch/lib/create_admin_cluster.js index 4d93ac6bb8adb..a0fec254e051a 100644 --- a/src/core_plugins/elasticsearch/lib/create_admin_cluster.js +++ b/src/core_plugins/elasticsearch/lib/create_admin_cluster.js @@ -1,8 +1,9 @@ import { bindKey } from 'lodash'; +import clientLogger from './client_logger'; export default function (server) { const config = server.config(); - const { ElasticsearchClientLogging } = server.plugins.elasticsearch; + const ElasticsearchClientLogging = clientLogger(server); class AdminClientLogging extends ElasticsearchClientLogging { tags = ['admin']; diff --git a/src/core_plugins/elasticsearch/lib/create_data_cluster.js b/src/core_plugins/elasticsearch/lib/create_data_cluster.js index 4ffedd7e99c72..b66bef6d53500 100644 --- a/src/core_plugins/elasticsearch/lib/create_data_cluster.js +++ b/src/core_plugins/elasticsearch/lib/create_data_cluster.js @@ -1,9 +1,10 @@ import { bindKey } from 'lodash'; +import clientLogger from './client_logger'; export default function (server) { const config = server.config(); const esPlugins = server.plugins.elasticsearch; - const { ElasticsearchClientLogging } = server.plugins.elasticsearch; + const ElasticsearchClientLogging = clientLogger(server); class DataClientLogging extends ElasticsearchClientLogging { tags = ['data']; @@ -11,13 +12,11 @@ export default function (server) { } function getConfig() { - const esConfig = config.get('elasticsearch.tribe'); - - if (!Boolean(esConfig.url)) { - return config.get('elasticsearch'); + if (Boolean(config.get('elasticsearch.tribe.url'))) { + return config.get('elasticsearch.tribe'); } - return esConfig; + return config.get('elasticsearch'); } const dataCluster = server.plugins.elasticsearch.createCluster( From 97ff6ceaca1bcfe35cc5333e7a2534b3a2442cef Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Mon, 19 Dec 2016 16:21:25 -0800 Subject: [PATCH 21/39] Persists clusters to server Signed-off-by: Tyler Smalley --- src/core_plugins/elasticsearch/index.js | 8 +-- .../lib/__tests__/create_clusters.js | 50 +++++++++++++++++++ .../elasticsearch/lib/clusters.js | 14 ------ .../elasticsearch/lib/create_clusters.js | 25 ++++++++++ 4 files changed, 80 insertions(+), 17 deletions(-) create mode 100644 src/core_plugins/elasticsearch/lib/__tests__/create_clusters.js delete mode 100644 src/core_plugins/elasticsearch/lib/clusters.js create mode 100644 src/core_plugins/elasticsearch/lib/create_clusters.js diff --git a/src/core_plugins/elasticsearch/index.js b/src/core_plugins/elasticsearch/index.js index 6c0d1062ee4a8..8759346501705 100644 --- a/src/core_plugins/elasticsearch/index.js +++ b/src/core_plugins/elasticsearch/index.js @@ -5,7 +5,7 @@ import healthCheck from './lib/health_check'; import createDataCluster from './lib/create_data_cluster'; import createAdminCluster from './lib/create_admin_cluster'; import clientLogger from './lib/client_logger'; -import { getCluster, createCluster } from './lib/clusters'; +import { createClusters } from './lib/create_clusters'; import filterHeaders from './lib/filter_headers'; import createProxy, { createPath } from './lib/create_proxy'; @@ -78,9 +78,11 @@ module.exports = function ({ Plugin }) { init(server, options) { const kibanaIndex = server.config().get('kibana.index'); + const clusters = createClusters(server); + + server.expose('getCluster', clusters.get); + server.expose('createCluster', clusters.create); - server.expose('getCluster', getCluster); - server.expose('createCluster', createCluster); server.expose('filterHeaders', filterHeaders); server.expose('ElasticsearchClientLogging', clientLogger(server)); diff --git a/src/core_plugins/elasticsearch/lib/__tests__/create_clusters.js b/src/core_plugins/elasticsearch/lib/__tests__/create_clusters.js new file mode 100644 index 0000000000000..678c6750bfaaf --- /dev/null +++ b/src/core_plugins/elasticsearch/lib/__tests__/create_clusters.js @@ -0,0 +1,50 @@ +import expect from 'expect.js'; +import { createClusters } from '../create_clusters'; +import Cluster from '../cluster'; +import sinon from 'sinon'; +import { partial } from 'lodash'; + +describe('plugins/elasticsearch', function () { + describe('createClusters', function () { + let clusters; + let server; + + beforeEach(() => { + server = { + plugins: { + elasticsearch: {} + }, + expose: sinon.mock() + }; + + clusters = createClusters(server); + }); + + describe('createCluster', () => { + let cluster; + const config = { + url: 'http://localhost:9200', + ssl: { + verify: false + } + }; + + beforeEach(() => { + cluster = clusters.create('admin', config); + }); + + it('returns a cluster', () => { + expect(cluster).to.be.a(Cluster); + }); + + it('persists the cluster', () => { + expect(clusters.get('admin')).to.be.a(Cluster); + }); + + it('throws if cluster already exists', () => { + const fn = partial(clusters.create, 'admin', config); + expect(fn).to.throwException(/cluster \'admin\' already exists/); + }); + }); + }); +}); diff --git a/src/core_plugins/elasticsearch/lib/clusters.js b/src/core_plugins/elasticsearch/lib/clusters.js deleted file mode 100644 index 607c198c3833c..0000000000000 --- a/src/core_plugins/elasticsearch/lib/clusters.js +++ /dev/null @@ -1,14 +0,0 @@ -import Cluster from './cluster'; - -const clusters = new Map(); - -export function getCluster(name) { - return clusters.get(name); -} - -export function createCluster(name, config) { - const cluster = new Cluster(config); - clusters.set(name, cluster); - - return cluster; -} diff --git a/src/core_plugins/elasticsearch/lib/create_clusters.js b/src/core_plugins/elasticsearch/lib/create_clusters.js new file mode 100644 index 0000000000000..92e2cea00a126 --- /dev/null +++ b/src/core_plugins/elasticsearch/lib/create_clusters.js @@ -0,0 +1,25 @@ +import Cluster from './cluster'; +import { get, set } from 'lodash'; + +export function createClusters(server) { + const esPlugin = server.plugins.elasticsearch; + esPlugin._clusters = esPlugin._clusters || new Map(); + + return { + get(name) { + return esPlugin._clusters.get(name); + }, + + create(name, config) { + const cluster = new Cluster(config); + + if (esPlugin._clusters.has(name)) { + throw new Error(`cluster '${name}' already exists`); + } + + esPlugin._clusters.set(name, cluster); + + return cluster; + } + }; +} From ad85ab3498a6bebb9ca4d0165eedc82f4c4a1072 Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Tue, 20 Dec 2016 10:02:02 -0600 Subject: [PATCH 22/39] [tribe] Move cluster config requests to distinct getters --- .../elasticsearch/lib/__tests__/cluster.js | 17 +++---- .../elasticsearch/lib/__tests__/map_uri.js | 4 +- src/core_plugins/elasticsearch/lib/cluster.js | 47 +++++++++++++++---- .../elasticsearch/lib/create_proxy.js | 9 ++-- src/core_plugins/elasticsearch/lib/map_uri.js | 6 +-- 5 files changed, 57 insertions(+), 26 deletions(-) diff --git a/src/core_plugins/elasticsearch/lib/__tests__/cluster.js b/src/core_plugins/elasticsearch/lib/__tests__/cluster.js index 02c5976dc3ad6..b97640ad9d83f 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/cluster.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/cluster.js @@ -19,7 +19,7 @@ describe('plugins/elasticsearch', function () { }); it('persists the config', () => { - expect(cluster.config()).to.eql(config); + expect(cluster._config).to.eql(config); }); it('exposes error definitions', () => { @@ -36,11 +36,8 @@ describe('plugins/elasticsearch', function () { }); it('protects the config from changes', () => { - const localConfig = cluster.config(); - localConfig.requestHeadersWhitelist.push('123'); - delete localConfig.url; - expect(localConfig).to.not.equal(config); - expect(localConfig.requestHeadersWhitelist.length).to.not.equal(config.requestHeadersWhitelist); + const localRequestHeadersWhitelist = cluster.getRequestHeadersWhitelist(); + expect(localRequestHeadersWhitelist.length).to.not.equal(config.requestHeadersWhitelist); }); describe('adding a plugin', () => { @@ -61,13 +58,13 @@ describe('plugins/elasticsearch', function () { }; }; - expect(cluster.config().plugins).to.have.length(1); - expect(cluster.config().plugins[0]).to.be(plugin); + expect(cluster._config.plugins).to.have.length(1); + expect(cluster._config.plugins[0]).to.be(plugin); cluster.addClientPlugins([pluginTwo]); - expect(cluster.config().plugins).to.have.length(2); - expect(cluster.config().plugins).to.eql([plugin, pluginTwo]); + expect(cluster._config.plugins).to.have.length(2); + expect(cluster._config.plugins).to.eql([plugin, pluginTwo]); }); it('is available for callWithInternalUser', async () => { diff --git a/src/core_plugins/elasticsearch/lib/__tests__/map_uri.js b/src/core_plugins/elasticsearch/lib/__tests__/map_uri.js index 697fff3097ccb..1aad55a799bbb 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/map_uri.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/map_uri.js @@ -17,7 +17,9 @@ describe('plugins/elasticsearch', function () { }); return { - config: (path) => path ? get(settings, path) : settings + getUrl: () => settings.url, + getCustomHeaders: () => settings.customHeaders, + getRequestHeadersWhitelist: () => settings.requestHeadersWhitelist }; } diff --git a/src/core_plugins/elasticsearch/lib/cluster.js b/src/core_plugins/elasticsearch/lib/cluster.js index 101400f7a52ac..5a686ff62f9b8 100644 --- a/src/core_plugins/elasticsearch/lib/cluster.js +++ b/src/core_plugins/elasticsearch/lib/cluster.js @@ -1,11 +1,20 @@ import elasticsearch from 'elasticsearch'; -import { get, set, isEmpty, cloneDeep } from 'lodash'; +import { get, set, isEmpty, cloneDeep, pick } from 'lodash'; import toPath from 'lodash/internal/toPath'; import Boom from 'boom'; import createClient from './create_client'; import filterHeaders from './filter_headers'; +function getClonedProperties(config, paths) { + return cloneDeep(paths ? pick(config, paths) : config); +} + +function getClonedProperty(config, path) { + return cloneDeep(path ? get(config, path) : config); +} + + export default class Cluster { constructor(config) { this._config = Object.assign({}, config); @@ -21,8 +30,6 @@ export default class Cluster { * * Performs a call to ES, passing through whitelisted headers in the request * - * The whitelisted headers are defined in the config under _requestHeadersWhitelist_ - * * @param {Object|undefined} req - The request object * @param {string} endpoint * @param {Object} clientParams @@ -32,7 +39,7 @@ export default class Cluster { */ callWithRequest = (req = {}, endpoint, clientParams = {}, options = {}) => { if (req.headers) { - const filteredHeaders = filterHeaders(req.headers, this.config('requestHeadersWhitelist')); + const filteredHeaders = filterHeaders(req.headers, this.getRequestHeadersWhitelist()); set(clientParams, 'headers', filteredHeaders); } @@ -54,9 +61,15 @@ export default class Cluster { return callAPI(this._client, endpoint, clientParams, options); } - config = (path) => { - return cloneDeep(path ? get(this._config, path) : this._config); - } + getRequestHeadersWhitelist = () => getClonedProperty(this._config, 'requestHeadersWhitelist'); + + getCustomHeaders = () => getClonedProperty(this._config, 'customHeaders'); + + getRequestTimeout = () => getClonedProperty(this._config, 'requestTimeout'); + + getUrl = () => getClonedProperty(this._config, 'url'); + + getSsl = () => getClonedProperty(this._config, 'ssl'); addClientPlugins(plugins = []) { this.close(); // close existing client connections @@ -79,6 +92,22 @@ export default class Cluster { this._noAuthClient.close(); } } + + _getClientConfig = () => { + return getClonedProperties(this._config, [ + 'url', + 'ssl', + 'username', + 'password', + 'customHeaders', + 'plugins', + 'apiVersion', + 'keepAlive', + 'pingTimeout', + 'requestTimeout', + 'log' + ]); + } } function callAPI(client, endpoint, clientParams = {}, options = {}) { @@ -109,6 +138,6 @@ function callAPI(client, endpoint, clientParams = {}, options = {}) { } function createClients() { - this._client = createClient(this.config()); - this._noAuthClient = createClient(Object.assign({}, this.config(), { auth: false })); + this._client = createClient(this._getClientConfig()); + this._noAuthClient = createClient(Object.assign({}, this._getClientConfig(), { auth: false })); } diff --git a/src/core_plugins/elasticsearch/lib/create_proxy.js b/src/core_plugins/elasticsearch/lib/create_proxy.js index cb53070c56139..0ce4a2b33bc87 100644 --- a/src/core_plugins/elasticsearch/lib/create_proxy.js +++ b/src/core_plugins/elasticsearch/lib/create_proxy.js @@ -29,15 +29,18 @@ function createProxy(server, method, path, config) { path: createProxy.createPath(proxyPrefix, path), config: { timeout: { - socket: server.config().get('elasticsearch.requestTimeout') + socket: cluster.getRequestTimeout() } }, handler: { proxy: { mapUri: mapUri(cluster, proxyPrefix), - agent: createAgent(cluster.config()), + agent: createAgent({ + url: cluster.getUrl(), + ssl: cluster.getSsl() + }), xforward: true, - timeout: server.config().get('elasticsearch.requestTimeout'), + timeout: cluster.getRequestTimeout(), onResponse: responseHandler } }, diff --git a/src/core_plugins/elasticsearch/lib/map_uri.js b/src/core_plugins/elasticsearch/lib/map_uri.js index 2d3ffbd153615..8ebc8ee724384 100644 --- a/src/core_plugins/elasticsearch/lib/map_uri.js +++ b/src/core_plugins/elasticsearch/lib/map_uri.js @@ -17,7 +17,7 @@ export default function mapUri(cluster, proxyPrefix) { port: esUrlPort, pathname: esUrlBasePath, query: esUrlQuery - } = parseUrl(cluster.config('url'), true); + } = parseUrl(cluster.getUrl(), true); // copy most url components directly from the elasticsearch.url const mappedUrlComponents = { @@ -38,8 +38,8 @@ export default function mapUri(cluster, proxyPrefix) { mappedUrlComponents.query = mappedQuery; } - const filteredHeaders = filterHeaders(request.headers, cluster.config('requestHeadersWhitelist')); - const mappedHeaders = setHeaders(filteredHeaders, cluster.config('customHeaders')); + const filteredHeaders = filterHeaders(request.headers, cluster.getRequestHeadersWhitelist()); + const mappedHeaders = setHeaders(filteredHeaders, cluster.getCustomHeaders()); const mappedUrl = formatUrl(mappedUrlComponents); done(null, mappedUrl, mappedHeaders); }; From 8a8c18fd4cc1fe94226f39e42cb49a5f39da078c Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Tue, 20 Dec 2016 15:12:28 -0800 Subject: [PATCH 23/39] Adds getClient and removes addClientPlugin Signed-off-by: Tyler Smalley --- .../elasticsearch/lib/__tests__/cluster.js | 38 ------------------- src/core_plugins/elasticsearch/lib/cluster.js | 29 +++++--------- 2 files changed, 9 insertions(+), 58 deletions(-) diff --git a/src/core_plugins/elasticsearch/lib/__tests__/cluster.js b/src/core_plugins/elasticsearch/lib/__tests__/cluster.js index b97640ad9d83f..be28030e6d716 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/cluster.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/cluster.js @@ -40,44 +40,6 @@ describe('plugins/elasticsearch', function () { expect(localRequestHeadersWhitelist.length).to.not.equal(config.requestHeadersWhitelist); }); - describe('adding a plugin', () => { - const plugin = (Client, config, components) => { - Client.prototype.marco = () => { - return Promise.resolve('polo'); - }; - }; - - beforeEach(() => { - cluster.addClientPlugins([plugin]); - }); - - it('persists previous plugins', () => { - const pluginTwo = (Client, config, components) => { - Client.prototype.foo = () => { - return Promise.resolve('bar'); - }; - }; - - expect(cluster._config.plugins).to.have.length(1); - expect(cluster._config.plugins[0]).to.be(plugin); - - cluster.addClientPlugins([pluginTwo]); - - expect(cluster._config.plugins).to.have.length(2); - expect(cluster._config.plugins).to.eql([plugin, pluginTwo]); - }); - - it('is available for callWithInternalUser', async () => { - const marco = await cluster.callWithInternalUser('marco'); - expect(marco).to.eql('polo'); - }); - - it('is available for callWithRequest', async () => { - const marco = await cluster.callWithRequest({}, 'marco'); - expect(marco).to.eql('polo'); - }); - }); - describe('callWithInternalUser', () => { let client; diff --git a/src/core_plugins/elasticsearch/lib/cluster.js b/src/core_plugins/elasticsearch/lib/cluster.js index 5a686ff62f9b8..e684327c70d36 100644 --- a/src/core_plugins/elasticsearch/lib/cluster.js +++ b/src/core_plugins/elasticsearch/lib/cluster.js @@ -6,15 +6,6 @@ import Boom from 'boom'; import createClient from './create_client'; import filterHeaders from './filter_headers'; -function getClonedProperties(config, paths) { - return cloneDeep(paths ? pick(config, paths) : config); -} - -function getClonedProperty(config, path) { - return cloneDeep(path ? get(config, path) : config); -} - - export default class Cluster { constructor(config) { this._config = Object.assign({}, config); @@ -71,17 +62,7 @@ export default class Cluster { getSsl = () => getClonedProperty(this._config, 'ssl'); - addClientPlugins(plugins = []) { - this.close(); // close existing client connections - - if (Array.isArray(this._config.plugins)) { - this._config.plugins = this._config.plugins.concat(plugins); - } else { - this._config.plugins = plugins; - } - - createClients.call(this); - } + getClient = () => this._client; close() { if (this._client) { @@ -137,6 +118,14 @@ function callAPI(client, endpoint, clientParams = {}, options = {}) { }); } +function getClonedProperties(config, paths) { + return cloneDeep(paths ? pick(config, paths) : config); +} + +function getClonedProperty(config, path) { + return cloneDeep(path ? get(config, path) : config); +} + function createClients() { this._client = createClient(this._getClientConfig()); this._noAuthClient = createClient(Object.assign({}, this._getClientConfig(), { auth: false })); From fd7213723f38a15adff7aa004361b7bd2b91b619 Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Tue, 20 Dec 2016 16:41:56 -0800 Subject: [PATCH 24/39] Expose createClient, consolidate config parsing Signed-off-by: Tyler Smalley --- .../elasticsearch/lib/client_logger.js | 2 +- src/core_plugins/elasticsearch/lib/cluster.js | 11 ++-- .../elasticsearch/lib/create_agent.js | 18 ++----- .../elasticsearch/lib/create_client.js | 52 ------------------- .../elasticsearch/lib/parse_config.js | 47 +++++++++++++++++ 5 files changed, 59 insertions(+), 71 deletions(-) delete mode 100644 src/core_plugins/elasticsearch/lib/create_client.js create mode 100644 src/core_plugins/elasticsearch/lib/parse_config.js diff --git a/src/core_plugins/elasticsearch/lib/client_logger.js b/src/core_plugins/elasticsearch/lib/client_logger.js index 54fb4896d189f..aa6f8dc1fdba1 100644 --- a/src/core_plugins/elasticsearch/lib/client_logger.js +++ b/src/core_plugins/elasticsearch/lib/client_logger.js @@ -1,7 +1,7 @@ module.exports = function (server) { return class ElasticsearchClientLogging { // additional tags to differentiate connection - tags = ['admin']; + tags = []; logQueries = false; diff --git a/src/core_plugins/elasticsearch/lib/cluster.js b/src/core_plugins/elasticsearch/lib/cluster.js index e684327c70d36..f46a25149a616 100644 --- a/src/core_plugins/elasticsearch/lib/cluster.js +++ b/src/core_plugins/elasticsearch/lib/cluster.js @@ -3,8 +3,8 @@ import { get, set, isEmpty, cloneDeep, pick } from 'lodash'; import toPath from 'lodash/internal/toPath'; import Boom from 'boom'; -import createClient from './create_client'; import filterHeaders from './filter_headers'; +import { parseConfig } from './parse_config'; export default class Cluster { constructor(config) { @@ -74,6 +74,11 @@ export default class Cluster { } } + createClient = configOverrides => { + const config = Object.assign({}, this._getClientConfig(), configOverrides); + return new elasticsearch.Client(parseConfig(config)); + } + _getClientConfig = () => { return getClonedProperties(this._config, [ 'url', @@ -127,6 +132,6 @@ function getClonedProperty(config, path) { } function createClients() { - this._client = createClient(this._getClientConfig()); - this._noAuthClient = createClient(Object.assign({}, this._getClientConfig(), { auth: false })); + this._client = this.createClient(); + this._noAuthClient = this.createClient({ auth: false }); } diff --git a/src/core_plugins/elasticsearch/lib/create_agent.js b/src/core_plugins/elasticsearch/lib/create_agent.js index 6c401ffc51a88..ba82e41b761b0 100644 --- a/src/core_plugins/elasticsearch/lib/create_agent.js +++ b/src/core_plugins/elasticsearch/lib/create_agent.js @@ -4,24 +4,12 @@ const readFile = (file) => require('fs').readFileSync(file, 'utf8'); import http from 'http'; import https from 'https'; +import { parseConfig } from './parse_config'; + export default function (config) { const target = url.parse(get(config, 'url')); if (!/^https/.test(target.protocol)) return new http.Agent(); - const agentOptions = { - rejectUnauthorized: get(config, 'ssl.verify') - }; - - if (size(get(config, 'ssl.ca'))) { - agentOptions.ca = get(config, 'ssl.ca').map(readFile); - } - - // Add client certificate and key if required by elasticsearch - if (get(config, 'ssl.cert') && get(config, 'ssl.key')) { - agentOptions.cert = readFile(get(config, 'ssl.cert')); - agentOptions.key = readFile(get(config, 'ssl.key')); - } - - return new https.Agent(agentOptions); + return new https.Agent(parseConfig(config).ssl); } diff --git a/src/core_plugins/elasticsearch/lib/create_client.js b/src/core_plugins/elasticsearch/lib/create_client.js deleted file mode 100644 index 8d0aaf94da136..0000000000000 --- a/src/core_plugins/elasticsearch/lib/create_client.js +++ /dev/null @@ -1,52 +0,0 @@ -import url from 'url'; -import util from 'util'; -import elasticsearch from 'elasticsearch'; -import Bluebird from 'bluebird'; -import { readFileSync } from 'fs'; - -const readFile = (file) => readFileSync(file, 'utf8'); - -export default function (optionOverrides) { - const options = Object.assign({ keepAlive: true, auth: true }, optionOverrides); - - const uri = url.parse(options.url); - - if (options.auth && options.username && options.password) { - uri.auth = util.format('%s:%s', options.username, options.password); - } - - const ssl = { rejectUnauthorized: options.ssl.verify }; - - if (options.ssl.cert && options.ssl.key) { - ssl.cert = readFile(options.ssl.cert); - ssl.key = readFile(options.ssl.key); - } - - if (options.ssl.ca) { - ssl.ca = options.ssl.ca.map(readFile); - } - - const host = { - host: uri.hostname, - port: uri.port, - protocol: uri.protocol, - path: uri.pathname, - auth: uri.auth, - query: uri.query, - headers: options.customHeaders - }; - - return new elasticsearch.Client({ - host, - ssl, - plugins: options.plugins, - apiVersion: options.apiVersion, - keepAlive: options.keepAlive, - pingTimeout: options.pingTimeout, - requestTimeout: options.requestTimeout, - defer: function () { - return Bluebird.defer(); - }, - log: options.log - }); -} diff --git a/src/core_plugins/elasticsearch/lib/parse_config.js b/src/core_plugins/elasticsearch/lib/parse_config.js new file mode 100644 index 0000000000000..299b7d3061639 --- /dev/null +++ b/src/core_plugins/elasticsearch/lib/parse_config.js @@ -0,0 +1,47 @@ +import util from 'util'; +import url from 'url'; +import { get, size, pick } from 'lodash'; +import { readFileSync } from 'fs'; +import Bluebird from 'bluebird'; + +const readFile = (file) => readFileSync(file, 'utf8'); + +export function parseConfig(serverConfig = {}) { + const config = Object.assign({ + keepAlive: true + }, pick(serverConfig, [ + 'plugins', 'apiVersion', 'keepAlive', 'pingTimeout', + 'requestTimeout', 'log', 'logQueries' + ])); + + const uri = url.parse(serverConfig.url); + config.host = { + host: uri.hostname, + port: uri.port, + protocol: uri.protocol, + path: uri.pathname, + query: uri.query, + headers: serverConfig.customHeaders + }; + + // Auth + if (serverConfig.auth !== false && serverConfig.username && serverConfig.password) { + config.host.auth = util.format('%s:%s', serverConfig.username, serverConfig.password); + } + + // SSL + config.ssl = { rejectUnauthorized: get(serverConfig, 'ssl.verify') }; + + if (get(serverConfig, 'ssl.cert') && get(serverConfig, 'ssl.key')) { + config.ssl.cert = readFile(serverConfig.ssl.cert); + config.ssl.key = readFile(serverConfig.ssl.key); + } + + if (size(get(config, 'ssl.ca'))) { + config.ssl.ca = serverConfig.ssl.ca.map(readFile); + } + + config.defer = () => Bluebird.defer(); + + return config; +} From f52c88749e57c9e16770fd78ddb4d9041cdd9368 Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Wed, 21 Dec 2016 08:39:13 -0800 Subject: [PATCH 25/39] Removes createClients from Cluster Signed-off-by: Tyler Smalley --- src/core_plugins/elasticsearch/lib/cluster.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/core_plugins/elasticsearch/lib/cluster.js b/src/core_plugins/elasticsearch/lib/cluster.js index f46a25149a616..a94bb9aca794c 100644 --- a/src/core_plugins/elasticsearch/lib/cluster.js +++ b/src/core_plugins/elasticsearch/lib/cluster.js @@ -11,7 +11,8 @@ export default class Cluster { this._config = Object.assign({}, config); this.errors = elasticsearch.errors; - createClients.call(this); + this._client = this.createClient(); + this._noAuthClient = this.createClient({ auth: false }); return this; } @@ -130,8 +131,3 @@ function getClonedProperties(config, paths) { function getClonedProperty(config, path) { return cloneDeep(path ? get(config, path) : config); } - -function createClients() { - this._client = this.createClient(); - this._noAuthClient = this.createClient({ auth: false }); -} From b5ce38a811d01a5986affd7ce4fc5fccfd73072f Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Wed, 21 Dec 2016 12:57:39 -0800 Subject: [PATCH 26/39] Prevent status change from red to red Signed-off-by: Tyler Smalley --- .../elasticsearch/lib/health_check.js | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/core_plugins/elasticsearch/lib/health_check.js b/src/core_plugins/elasticsearch/lib/health_check.js index e340232070a7d..162d851c936df 100644 --- a/src/core_plugins/elasticsearch/lib/health_check.js +++ b/src/core_plugins/elasticsearch/lib/health_check.js @@ -91,23 +91,21 @@ module.exports = function (plugin, server) { } function check() { - const healthChecks = [ + const healthCheck = waitForPong(callAdminAsKibanaUser, config.get('elasticsearch.url')) .then(waitForEsVersion) .then(checkForTribe.bind(this, callAdminAsKibanaUser)) .then(waitForShards) .then(_.partial(migrateConfig, server)) - ]; - - const tribeUrl = config.get('elasticsearch.tribe.url'); - if (tribeUrl) { - healthChecks.push( - waitForPong(callDataAsKibanaUser, tribeUrl) - .then(() => checkEsVersion(server, kibanaVersion.get(), callDataAsKibanaUser)) - ); - } + .then(() => { + const tribeUrl = config.get('elasticsearch.tribe.url'); + if (tribeUrl) { + return waitForPong(callDataAsKibanaUser, tribeUrl) + .then(() => checkEsVersion(server, kibanaVersion.get(), callDataAsKibanaUser)); + } + }); - return Promise.all(healthChecks) + return healthCheck .then(setGreenStatus) .catch(err => plugin.status.red(err)); } From 40a4a4b9cc3a6590ab507e60724fcf538cc6aadc Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Thu, 22 Dec 2016 12:09:51 -0800 Subject: [PATCH 27/39] Updates esvm:tribe ports to be consistant with dev 9200 is admin 9201:9202 are both data clusters 9203 is a tribe node connecting to both data clusters Signed-off-by: Tyler Smalley --- tasks/config/esvm.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/tasks/config/esvm.js b/tasks/config/esvm.js index 74337fbed46ff..c3959b8917780 100644 --- a/tasks/config/esvm.js +++ b/tasks/config/esvm.js @@ -37,22 +37,25 @@ module.exports = function (grunt) { data: dataDir } }, + plugins: [{ + name: 'x-pack', path: 'http://download.elastic.co/esvm/xpack-snapshots/master.zip' + }], nodes: [{ cluster: { name: 'data-01' }, http: { port: 9201 }, - node: { name: 'node-01', data: true, master: true, max_local_storage_nodes: 4 } + node: { name: 'node-01', data: true, master: true, max_local_storage_nodes: 5 } }, { cluster: { name: 'data-02' }, http: { port: 9202 }, - node: { name: 'node-02', data: true, master: true, max_local_storage_nodes: 4 } + node: { name: 'node-02', data: true, master: true, max_local_storage_nodes: 5 } }, { - cluster: { name: 'admin-01' }, - http: { port: 9203 }, - node: { name: 'node-03', data: true, master: true, max_local_storage_nodes: 4 } - }, { - cluster: { name: 'tribe-01' }, + cluster: { name: 'admin' }, http: { port: 9200 }, - node: { name: 'node-04', max_local_storage_nodes: 4 }, + node: { name: 'node-03', data: true, master: true, max_local_storage_nodes: 5 } + }, { + cluster: { name: 'tribe' }, + http: { port: 9203 }, + node: { name: 'node-04', max_local_storage_nodes: 5 }, tribe: { c1: { cluster: { From d0610a3faf744d62c28d79646b12d697969df2dc Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Thu, 22 Dec 2016 16:27:36 -0600 Subject: [PATCH 28/39] [tribe] Get ssl.ca from serverConfig --- src/core_plugins/elasticsearch/lib/parse_config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core_plugins/elasticsearch/lib/parse_config.js b/src/core_plugins/elasticsearch/lib/parse_config.js index 299b7d3061639..05750535030ea 100644 --- a/src/core_plugins/elasticsearch/lib/parse_config.js +++ b/src/core_plugins/elasticsearch/lib/parse_config.js @@ -37,7 +37,7 @@ export function parseConfig(serverConfig = {}) { config.ssl.key = readFile(serverConfig.ssl.key); } - if (size(get(config, 'ssl.ca'))) { + if (size(get(serverConfig, 'ssl.ca'))) { config.ssl.ca = serverConfig.ssl.ca.map(readFile); } From f1773009c44f0171e74431083b3f56825b4ab06e Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Mon, 26 Dec 2016 12:08:08 -0500 Subject: [PATCH 29/39] [tribe/esvm] Remove plugin configuration --- tasks/config/esvm.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/tasks/config/esvm.js b/tasks/config/esvm.js index c3959b8917780..8e0500ad87842 100644 --- a/tasks/config/esvm.js +++ b/tasks/config/esvm.js @@ -37,9 +37,6 @@ module.exports = function (grunt) { data: dataDir } }, - plugins: [{ - name: 'x-pack', path: 'http://download.elastic.co/esvm/xpack-snapshots/master.zip' - }], nodes: [{ cluster: { name: 'data-01' }, http: { port: 9201 }, From 1707383457a42672ee443b8b9c489c03d5c96107 Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Wed, 28 Dec 2016 10:38:30 -0800 Subject: [PATCH 30/39] Removes unused variable Signed-off-by: Tyler Smalley --- src/core_plugins/elasticsearch/lib/create_data_cluster.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core_plugins/elasticsearch/lib/create_data_cluster.js b/src/core_plugins/elasticsearch/lib/create_data_cluster.js index b66bef6d53500..f1cf037438575 100644 --- a/src/core_plugins/elasticsearch/lib/create_data_cluster.js +++ b/src/core_plugins/elasticsearch/lib/create_data_cluster.js @@ -3,7 +3,6 @@ import clientLogger from './client_logger'; export default function (server) { const config = server.config(); - const esPlugins = server.plugins.elasticsearch; const ElasticsearchClientLogging = clientLogger(server); class DataClientLogging extends ElasticsearchClientLogging { From a6496a6a682d68bc92bb96af4c2cff295cbf972c Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Wed, 28 Dec 2016 15:09:43 -0600 Subject: [PATCH 31/39] [tribe] Named exports for creating clusters --- src/core_plugins/elasticsearch/index.js | 4 ++-- .../elasticsearch/lib/__tests__/create_admin_cluster.js | 2 +- .../elasticsearch/lib/__tests__/create_data_cluster.js | 2 +- src/core_plugins/elasticsearch/lib/create_admin_cluster.js | 2 +- src/core_plugins/elasticsearch/lib/create_data_cluster.js | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/core_plugins/elasticsearch/index.js b/src/core_plugins/elasticsearch/index.js index 8759346501705..a6fa02a6985e7 100644 --- a/src/core_plugins/elasticsearch/index.js +++ b/src/core_plugins/elasticsearch/index.js @@ -2,8 +2,8 @@ import { trim, trimRight, bindKey } from 'lodash'; import { methodNotAllowed } from 'boom'; import healthCheck from './lib/health_check'; -import createDataCluster from './lib/create_data_cluster'; -import createAdminCluster from './lib/create_admin_cluster'; +import { createDataCluster } from './lib/create_data_cluster'; +import { createAdminCluster } from './lib/create_admin_cluster'; import clientLogger from './lib/client_logger'; import { createClusters } from './lib/create_clusters'; import filterHeaders from './lib/filter_headers'; diff --git a/src/core_plugins/elasticsearch/lib/__tests__/create_admin_cluster.js b/src/core_plugins/elasticsearch/lib/__tests__/create_admin_cluster.js index 851f61ad58c0d..c1798ef315f2d 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/create_admin_cluster.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/create_admin_cluster.js @@ -1,7 +1,7 @@ import expect from 'expect.js'; import sinon from 'sinon'; import { bindKey, set, get, partial } from 'lodash'; -import createAdminCluster from '../create_admin_cluster'; +import { createAdminCluster } from '../create_admin_cluster'; describe('plugins/elasticsearch', function () { describe('create_admin_cluster', function () { diff --git a/src/core_plugins/elasticsearch/lib/__tests__/create_data_cluster.js b/src/core_plugins/elasticsearch/lib/__tests__/create_data_cluster.js index cd76936445f23..fc919060fb0b2 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/create_data_cluster.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/create_data_cluster.js @@ -1,7 +1,7 @@ import expect from 'expect.js'; import sinon from 'sinon'; import { bindKey, set, get, partial } from 'lodash'; -import createDataCluster from '../create_data_cluster'; +import { createDataCluster } from '../create_data_cluster'; describe('plugins/elasticsearch', function () { describe('create_data_cluster', function () { diff --git a/src/core_plugins/elasticsearch/lib/create_admin_cluster.js b/src/core_plugins/elasticsearch/lib/create_admin_cluster.js index a0fec254e051a..87a0d038e6164 100644 --- a/src/core_plugins/elasticsearch/lib/create_admin_cluster.js +++ b/src/core_plugins/elasticsearch/lib/create_admin_cluster.js @@ -1,7 +1,7 @@ import { bindKey } from 'lodash'; import clientLogger from './client_logger'; -export default function (server) { +export function createAdminCluster(server) { const config = server.config(); const ElasticsearchClientLogging = clientLogger(server); diff --git a/src/core_plugins/elasticsearch/lib/create_data_cluster.js b/src/core_plugins/elasticsearch/lib/create_data_cluster.js index f1cf037438575..250d250a4928a 100644 --- a/src/core_plugins/elasticsearch/lib/create_data_cluster.js +++ b/src/core_plugins/elasticsearch/lib/create_data_cluster.js @@ -1,7 +1,7 @@ import { bindKey } from 'lodash'; import clientLogger from './client_logger'; -export default function (server) { +export function createDataCluster(server) { const config = server.config(); const ElasticsearchClientLogging = clientLogger(server); From 7dd8d79f3f68ec88343e4e23627009f9da13828e Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Wed, 28 Dec 2016 15:16:06 -0600 Subject: [PATCH 32/39] [tribe] Named exports for client logger, cluster --- src/core_plugins/elasticsearch/index.js | 2 +- src/core_plugins/elasticsearch/lib/__tests__/cluster.js | 2 +- .../elasticsearch/lib/__tests__/create_clusters.js | 2 +- src/core_plugins/elasticsearch/lib/client_logger.js | 4 ++-- src/core_plugins/elasticsearch/lib/cluster.js | 2 +- src/core_plugins/elasticsearch/lib/create_admin_cluster.js | 2 +- src/core_plugins/elasticsearch/lib/create_clusters.js | 2 +- src/core_plugins/elasticsearch/lib/create_data_cluster.js | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/core_plugins/elasticsearch/index.js b/src/core_plugins/elasticsearch/index.js index a6fa02a6985e7..86ef7203ea766 100644 --- a/src/core_plugins/elasticsearch/index.js +++ b/src/core_plugins/elasticsearch/index.js @@ -4,7 +4,7 @@ import { methodNotAllowed } from 'boom'; import healthCheck from './lib/health_check'; import { createDataCluster } from './lib/create_data_cluster'; import { createAdminCluster } from './lib/create_admin_cluster'; -import clientLogger from './lib/client_logger'; +import { clientLogger } from './lib/client_logger'; import { createClusters } from './lib/create_clusters'; import filterHeaders from './lib/filter_headers'; diff --git a/src/core_plugins/elasticsearch/lib/__tests__/cluster.js b/src/core_plugins/elasticsearch/lib/__tests__/cluster.js index be28030e6d716..1d9c2ed0e717f 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/cluster.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/cluster.js @@ -1,5 +1,5 @@ import expect from 'expect.js'; -import Cluster from '../cluster'; +import { Cluster } from '../cluster'; import sinon from 'sinon'; import { errors as esErrors } from 'elasticsearch'; import { set, partial, cloneDeep } from 'lodash'; diff --git a/src/core_plugins/elasticsearch/lib/__tests__/create_clusters.js b/src/core_plugins/elasticsearch/lib/__tests__/create_clusters.js index 678c6750bfaaf..bf0e7e3d245ca 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/create_clusters.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/create_clusters.js @@ -1,6 +1,6 @@ import expect from 'expect.js'; import { createClusters } from '../create_clusters'; -import Cluster from '../cluster'; +import { Cluster } from '../cluster'; import sinon from 'sinon'; import { partial } from 'lodash'; diff --git a/src/core_plugins/elasticsearch/lib/client_logger.js b/src/core_plugins/elasticsearch/lib/client_logger.js index aa6f8dc1fdba1..d0def48a7ba03 100644 --- a/src/core_plugins/elasticsearch/lib/client_logger.js +++ b/src/core_plugins/elasticsearch/lib/client_logger.js @@ -1,4 +1,4 @@ -module.exports = function (server) { +export function clientLogger(server) { return class ElasticsearchClientLogging { // additional tags to differentiate connection tags = []; @@ -32,4 +32,4 @@ module.exports = function (server) { } close() {} }; -}; +} diff --git a/src/core_plugins/elasticsearch/lib/cluster.js b/src/core_plugins/elasticsearch/lib/cluster.js index a94bb9aca794c..dbaec568fa5b3 100644 --- a/src/core_plugins/elasticsearch/lib/cluster.js +++ b/src/core_plugins/elasticsearch/lib/cluster.js @@ -6,7 +6,7 @@ import Boom from 'boom'; import filterHeaders from './filter_headers'; import { parseConfig } from './parse_config'; -export default class Cluster { +export class Cluster { constructor(config) { this._config = Object.assign({}, config); this.errors = elasticsearch.errors; diff --git a/src/core_plugins/elasticsearch/lib/create_admin_cluster.js b/src/core_plugins/elasticsearch/lib/create_admin_cluster.js index 87a0d038e6164..be638a1c57de1 100644 --- a/src/core_plugins/elasticsearch/lib/create_admin_cluster.js +++ b/src/core_plugins/elasticsearch/lib/create_admin_cluster.js @@ -1,5 +1,5 @@ import { bindKey } from 'lodash'; -import clientLogger from './client_logger'; +import { clientLogger } from './client_logger'; export function createAdminCluster(server) { const config = server.config(); diff --git a/src/core_plugins/elasticsearch/lib/create_clusters.js b/src/core_plugins/elasticsearch/lib/create_clusters.js index 92e2cea00a126..b05ff51b3a043 100644 --- a/src/core_plugins/elasticsearch/lib/create_clusters.js +++ b/src/core_plugins/elasticsearch/lib/create_clusters.js @@ -1,4 +1,4 @@ -import Cluster from './cluster'; +import { Cluster } from './cluster'; import { get, set } from 'lodash'; export function createClusters(server) { diff --git a/src/core_plugins/elasticsearch/lib/create_data_cluster.js b/src/core_plugins/elasticsearch/lib/create_data_cluster.js index 250d250a4928a..90431b111f093 100644 --- a/src/core_plugins/elasticsearch/lib/create_data_cluster.js +++ b/src/core_plugins/elasticsearch/lib/create_data_cluster.js @@ -1,5 +1,5 @@ import { bindKey } from 'lodash'; -import clientLogger from './client_logger'; +import { clientLogger } from './client_logger'; export function createDataCluster(server) { const config = server.config(); From 2c1f7e33d4189455fe682175d27c70fc2eb0dd28 Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Wed, 28 Dec 2016 15:21:13 -0600 Subject: [PATCH 33/39] [tribe] Named exports for health check --- src/core_plugins/elasticsearch/lib/__tests__/check_for_tribe.js | 2 +- src/core_plugins/elasticsearch/lib/check_for_tribe.js | 2 +- src/core_plugins/elasticsearch/lib/health_check.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core_plugins/elasticsearch/lib/__tests__/check_for_tribe.js b/src/core_plugins/elasticsearch/lib/__tests__/check_for_tribe.js index 4149d30b90835..af5ea70efbed1 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/check_for_tribe.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/check_for_tribe.js @@ -2,7 +2,7 @@ import expect from 'expect.js'; import { noop } from 'lodash'; import sinon from 'sinon'; -import checkForTribe from '../check_for_tribe'; +import { checkForTribe } from '../check_for_tribe'; describe('plugins/elasticsearch checkForTribe', () => { const sandbox = sinon.sandbox.create(); diff --git a/src/core_plugins/elasticsearch/lib/check_for_tribe.js b/src/core_plugins/elasticsearch/lib/check_for_tribe.js index 80b82810cbd64..d6fdfec1404da 100644 --- a/src/core_plugins/elasticsearch/lib/check_for_tribe.js +++ b/src/core_plugins/elasticsearch/lib/check_for_tribe.js @@ -1,6 +1,6 @@ import { get } from 'lodash'; -export default function checkForTribe(callWithInternalUser) { +export function checkForTribe(callWithInternalUser) { return callWithInternalUser('nodes.info', { nodeId: '_local', filterPath: 'nodes.*.settings.tribe' diff --git a/src/core_plugins/elasticsearch/lib/health_check.js b/src/core_plugins/elasticsearch/lib/health_check.js index 162d851c936df..857a7b3b86926 100644 --- a/src/core_plugins/elasticsearch/lib/health_check.js +++ b/src/core_plugins/elasticsearch/lib/health_check.js @@ -5,7 +5,7 @@ import migrateConfig from './migrate_config'; import createKibanaIndex from './create_kibana_index'; import checkEsVersion from './check_es_version'; import kibanaVersion from './kibana_version'; -import checkForTribe from './check_for_tribe'; +import { checkForTribe } from './check_for_tribe'; const NoConnections = elasticsearch.errors.NoConnections; import util from 'util'; From cc90a92799ab97b923a1e7062d939afaf1637467 Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Wed, 28 Dec 2016 13:38:21 -0800 Subject: [PATCH 34/39] Remove invalid comment Signed-off-by: Tyler Smalley --- .../elasticsearch/lib/__tests__/check_es_version.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core_plugins/elasticsearch/lib/__tests__/check_es_version.js b/src/core_plugins/elasticsearch/lib/__tests__/check_es_version.js index 2c8a1cde1eefa..ae2a855a70485 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/check_es_version.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/check_es_version.js @@ -20,7 +20,7 @@ describe('plugins/elasticsearch', () => { log: sinon.stub(), plugins: { elasticsearch: { - getCluster: sinon.stub().withArgs('admin').returns({ callWithInternalUser: sinon.stub() }), // Fix + getCluster: sinon.stub().withArgs('admin').returns({ callWithInternalUser: sinon.stub() }), status: { red: sinon.stub() }, From 978d46786983b50ad698a7f9ca6c0ef8850cc211 Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Wed, 28 Dec 2016 16:31:08 -0600 Subject: [PATCH 35/39] [tribe] Comment explaining difference between admin and data browser clients --- src/ui/public/es.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ui/public/es.js b/src/ui/public/es.js index ac77acbe2e8bb..7bab5006cc1e5 100644 --- a/src/ui/public/es.js +++ b/src/ui/public/es.js @@ -27,6 +27,9 @@ const plugins = [function (Client, config) { uiModules .get('kibana', ['elasticsearch', 'kibana/config']) + + //Elasticsearch client used for requesting data. Connects to the /elasticsearch proxy, + //Uses a tribe node if configured, otherwise uses the base elasticsearch configuration .service('es', function (esFactory, esUrl, esApiVersion, esRequestTimeout) { return esFactory({ host: esUrl, @@ -36,6 +39,9 @@ uiModules plugins }); }) + + //Elasticsearch client used for managing Kibana's state. Connects to the /es-admin proxy, + //Always uses the base elasticsearch configuartion .service('esAdmin', function (esFactory, esAdminUrl, esApiVersion, esRequestTimeout) { return esFactory({ host: esAdminUrl, From cb5736aaf2e7bc8bcb2173de2086ef7cee2757ea Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Wed, 28 Dec 2016 15:28:30 -0800 Subject: [PATCH 36/39] Rename ES checks to be consistant with functionality Signed-off-by: Tyler Smalley --- ...eck_es_version.js => ensure_es_version.js} | 26 +++++++++---------- ...check_for_tribe.js => ensure_not_tribe.js} | 10 +++---- ...eck_es_version.js => ensure_es_version.js} | 4 +-- ...check_for_tribe.js => ensure_not_tribe.js} | 2 +- .../elasticsearch/lib/health_check.js | 10 +++---- 5 files changed, 26 insertions(+), 26 deletions(-) rename src/core_plugins/elasticsearch/lib/__tests__/{check_es_version.js => ensure_es_version.js} (86%) rename src/core_plugins/elasticsearch/lib/__tests__/{check_for_tribe.js => ensure_not_tribe.js} (77%) rename src/core_plugins/elasticsearch/lib/{check_es_version.js => ensure_es_version.js} (97%) rename src/core_plugins/elasticsearch/lib/{check_for_tribe.js => ensure_not_tribe.js} (89%) diff --git a/src/core_plugins/elasticsearch/lib/__tests__/check_es_version.js b/src/core_plugins/elasticsearch/lib/__tests__/ensure_es_version.js similarity index 86% rename from src/core_plugins/elasticsearch/lib/__tests__/check_es_version.js rename to src/core_plugins/elasticsearch/lib/__tests__/ensure_es_version.js index ae2a855a70485..8e7770ff2b0b8 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/check_es_version.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/ensure_es_version.js @@ -5,10 +5,10 @@ import expect from 'expect.js'; import url from 'url'; import serverConfig from '../../../../../test/server_config'; -import checkEsVersion from '../check_es_version'; +import { ensureEsVersion } from '../ensure_es_version'; describe('plugins/elasticsearch', () => { - describe('lib/check_es_version', () => { + describe('lib/ensure_es_version', () => { const KIBANA_VERSION = '5.1.0'; let server; @@ -65,13 +65,13 @@ describe('plugins/elasticsearch', () => { it('returns true with single a node that matches', async () => { setNodes('5.1.0'); - const result = await checkEsVersion(server, KIBANA_VERSION); + const result = await ensureEsVersion(server, KIBANA_VERSION); expect(result).to.be(true); }); it('returns true with multiple nodes that satisfy', async () => { setNodes('5.1.0', '5.2.0', '5.1.1-Beta1'); - const result = await checkEsVersion(server, KIBANA_VERSION); + const result = await ensureEsVersion(server, KIBANA_VERSION); expect(result).to.be(true); }); @@ -79,7 +79,7 @@ describe('plugins/elasticsearch', () => { // 5.0.0 ES is too old to work with a 5.1.0 version of Kibana. setNodes('5.1.0', '5.2.0', '5.0.0'); try { - await checkEsVersion(server, KIBANA_VERSION); + await ensureEsVersion(server, KIBANA_VERSION); } catch (e) { expect(e).to.be.a(Error); } @@ -92,7 +92,7 @@ describe('plugins/elasticsearch', () => { { version: '5.0.0', attributes: { client: 'true' } }, ); try { - await checkEsVersion(server, KIBANA_VERSION); + await ensureEsVersion(server, KIBANA_VERSION); } catch (e) { expect(e).to.be.a(Error); } @@ -100,7 +100,7 @@ describe('plugins/elasticsearch', () => { it('warns if a node is only off by a patch version', async () => { setNodes('5.1.1'); - await checkEsVersion(server, KIBANA_VERSION); + await ensureEsVersion(server, KIBANA_VERSION); sinon.assert.callCount(server.log, 2); expect(server.log.getCall(0).args[0]).to.contain('debug'); expect(server.log.getCall(1).args[0]).to.contain('warning'); @@ -108,7 +108,7 @@ describe('plugins/elasticsearch', () => { it('warns if a node is off by a patch version and without http publish address', async () => { setNodeWithoutHTTP('5.1.1'); - await checkEsVersion(server, KIBANA_VERSION); + await ensureEsVersion(server, KIBANA_VERSION); sinon.assert.callCount(server.log, 2); expect(server.log.getCall(0).args[0]).to.contain('debug'); expect(server.log.getCall(1).args[0]).to.contain('warning'); @@ -117,7 +117,7 @@ describe('plugins/elasticsearch', () => { it('errors if a node incompatible and without http publish address', async () => { setNodeWithoutHTTP('6.1.1'); try { - await checkEsVersion(server, KIBANA_VERSION); + await ensureEsVersion(server, KIBANA_VERSION); } catch (e) { expect(e.message).to.contain('incompatible nodes'); expect(e).to.be.a(Error); @@ -127,12 +127,12 @@ describe('plugins/elasticsearch', () => { it('only warns once per node list', async () => { setNodes('5.1.1'); - await checkEsVersion(server, KIBANA_VERSION); + await ensureEsVersion(server, KIBANA_VERSION); sinon.assert.callCount(server.log, 2); expect(server.log.getCall(0).args[0]).to.contain('debug'); expect(server.log.getCall(1).args[0]).to.contain('warning'); - await checkEsVersion(server, KIBANA_VERSION); + await ensureEsVersion(server, KIBANA_VERSION); sinon.assert.callCount(server.log, 3); expect(server.log.getCall(2).args[0]).to.contain('debug'); }); @@ -140,13 +140,13 @@ describe('plugins/elasticsearch', () => { it('warns again if the node list changes', async () => { setNodes('5.1.1'); - await checkEsVersion(server, KIBANA_VERSION); + await ensureEsVersion(server, KIBANA_VERSION); sinon.assert.callCount(server.log, 2); expect(server.log.getCall(0).args[0]).to.contain('debug'); expect(server.log.getCall(1).args[0]).to.contain('warning'); setNodes('5.1.2'); - await checkEsVersion(server, KIBANA_VERSION); + await ensureEsVersion(server, KIBANA_VERSION); sinon.assert.callCount(server.log, 4); expect(server.log.getCall(2).args[0]).to.contain('debug'); expect(server.log.getCall(3).args[0]).to.contain('warning'); diff --git a/src/core_plugins/elasticsearch/lib/__tests__/check_for_tribe.js b/src/core_plugins/elasticsearch/lib/__tests__/ensure_not_tribe.js similarity index 77% rename from src/core_plugins/elasticsearch/lib/__tests__/check_for_tribe.js rename to src/core_plugins/elasticsearch/lib/__tests__/ensure_not_tribe.js index af5ea70efbed1..38b5d0b865750 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/check_for_tribe.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/ensure_not_tribe.js @@ -2,9 +2,9 @@ import expect from 'expect.js'; import { noop } from 'lodash'; import sinon from 'sinon'; -import { checkForTribe } from '../check_for_tribe'; +import { ensureNotTribe } from '../ensure_not_tribe'; -describe('plugins/elasticsearch checkForTribe', () => { +describe('plugins/elasticsearch ensureNotTribe', () => { const sandbox = sinon.sandbox.create(); afterEach(() => sandbox.restore()); @@ -20,7 +20,7 @@ describe('plugins/elasticsearch checkForTribe', () => { it('fetches the local node stats of the node that the elasticsearch client is connected to', async () => { const callWithInternalUser = stubcallWithInternalUser(); - await checkForTribe(callWithInternalUser); + await ensureNotTribe(callWithInternalUser); sinon.assert.calledOnce(callWithInternalUser); }); @@ -39,8 +39,8 @@ describe('plugins/elasticsearch checkForTribe', () => { }; try { - await checkForTribe(stubcallWithInternalUser(nodeInfo)); - throw new Error('checkForTribe() should have thrown'); + await ensureNotTribe(stubcallWithInternalUser(nodeInfo)); + throw new Error('ensureNotTribe() should have thrown'); } catch (err) { expect(err).to.be.a(Error); } diff --git a/src/core_plugins/elasticsearch/lib/check_es_version.js b/src/core_plugins/elasticsearch/lib/ensure_es_version.js similarity index 97% rename from src/core_plugins/elasticsearch/lib/check_es_version.js rename to src/core_plugins/elasticsearch/lib/ensure_es_version.js index 35593e1d71a29..c8fd46aa3e2ea 100644 --- a/src/core_plugins/elasticsearch/lib/check_es_version.js +++ b/src/core_plugins/elasticsearch/lib/ensure_es_version.js @@ -16,7 +16,7 @@ import isEsCompatibleWithKibana from './is_es_compatible_with_kibana'; */ const lastWarnedNodesForServer = new WeakMap(); -module.exports = function checkEsVersion(server, kibanaVersion) { +export function ensureEsVersion(server, kibanaVersion) { const { callWithInternalUser } = server.plugins.elasticsearch.getCluster('admin'); server.log(['plugin', 'debug'], 'Checking Elasticsearch version'); @@ -90,4 +90,4 @@ module.exports = function checkEsVersion(server, kibanaVersion) { return true; }); -}; +} diff --git a/src/core_plugins/elasticsearch/lib/check_for_tribe.js b/src/core_plugins/elasticsearch/lib/ensure_not_tribe.js similarity index 89% rename from src/core_plugins/elasticsearch/lib/check_for_tribe.js rename to src/core_plugins/elasticsearch/lib/ensure_not_tribe.js index d6fdfec1404da..02e69af15f42d 100644 --- a/src/core_plugins/elasticsearch/lib/check_for_tribe.js +++ b/src/core_plugins/elasticsearch/lib/ensure_not_tribe.js @@ -1,6 +1,6 @@ import { get } from 'lodash'; -export function checkForTribe(callWithInternalUser) { +export function ensureNotTribe(callWithInternalUser) { return callWithInternalUser('nodes.info', { nodeId: '_local', filterPath: 'nodes.*.settings.tribe' diff --git a/src/core_plugins/elasticsearch/lib/health_check.js b/src/core_plugins/elasticsearch/lib/health_check.js index 857a7b3b86926..6b5e5f4085ea6 100644 --- a/src/core_plugins/elasticsearch/lib/health_check.js +++ b/src/core_plugins/elasticsearch/lib/health_check.js @@ -3,9 +3,9 @@ import Promise from 'bluebird'; import elasticsearch from 'elasticsearch'; import migrateConfig from './migrate_config'; import createKibanaIndex from './create_kibana_index'; -import checkEsVersion from './check_es_version'; import kibanaVersion from './kibana_version'; -import { checkForTribe } from './check_for_tribe'; +import { ensureEsVersion } from './ensure_es_version'; +import { ensureNotTribe } from './ensure_not_tribe'; const NoConnections = elasticsearch.errors.NoConnections; import util from 'util'; @@ -80,7 +80,7 @@ module.exports = function (plugin, server) { } function waitForEsVersion() { - return checkEsVersion(server, kibanaVersion.get()).catch(err => { + return ensureEsVersion(server, kibanaVersion.get()).catch(err => { plugin.status.red(err); return Promise.delay(REQUEST_DELAY).then(waitForEsVersion); }); @@ -94,14 +94,14 @@ module.exports = function (plugin, server) { const healthCheck = waitForPong(callAdminAsKibanaUser, config.get('elasticsearch.url')) .then(waitForEsVersion) - .then(checkForTribe.bind(this, callAdminAsKibanaUser)) + .then(ensureNotTribe.bind(this, callAdminAsKibanaUser)) .then(waitForShards) .then(_.partial(migrateConfig, server)) .then(() => { const tribeUrl = config.get('elasticsearch.tribe.url'); if (tribeUrl) { return waitForPong(callDataAsKibanaUser, tribeUrl) - .then(() => checkEsVersion(server, kibanaVersion.get(), callDataAsKibanaUser)); + .then(() => ensureEsVersion(server, kibanaVersion.get(), callDataAsKibanaUser)); } }); From 08cb58cffa3b683c9ef72b25e6c03f12136cc5a9 Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Wed, 28 Dec 2016 15:46:44 -0800 Subject: [PATCH 37/39] Organize NOOP functions Signed-off-by: Tyler Smalley --- src/core_plugins/elasticsearch/lib/client_logger.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/core_plugins/elasticsearch/lib/client_logger.js b/src/core_plugins/elasticsearch/lib/client_logger.js index d0def48a7ba03..dac94311f4bfc 100644 --- a/src/core_plugins/elasticsearch/lib/client_logger.js +++ b/src/core_plugins/elasticsearch/lib/client_logger.js @@ -13,10 +13,6 @@ export function clientLogger(server) { server.log(['warning', 'elasticsearch'].concat(this.tags), message); } - info() {} - - debug() {} - trace(method, options, query, _response, statusCode) { /* Check if query logging is enabled * It requires Kibana to be configured with verbose logging turned on. */ @@ -30,6 +26,14 @@ export function clientLogger(server) { ].join('\n')); } } + + + // elasticsearch-js expects the following functions to exist + + info() {} + + debug() {} + close() {} }; } From 94e4364101357dc1873b452d68883a404596d4c2 Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Wed, 28 Dec 2016 15:52:33 -0800 Subject: [PATCH 38/39] Removing function comments Signed-off-by: Tyler Smalley --- src/core_plugins/elasticsearch/lib/cluster.js | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/src/core_plugins/elasticsearch/lib/cluster.js b/src/core_plugins/elasticsearch/lib/cluster.js index dbaec568fa5b3..9172468e828fa 100644 --- a/src/core_plugins/elasticsearch/lib/cluster.js +++ b/src/core_plugins/elasticsearch/lib/cluster.js @@ -17,18 +17,6 @@ export class Cluster { return this; } - /** - * callWithRequest - * - * Performs a call to ES, passing through whitelisted headers in the request - * - * @param {Object|undefined} req - The request object - * @param {string} endpoint - * @param {Object} clientParams - * @param {Object} options - * @param {boolean} options.wrap401Errors - * @returns {Promise} - */ callWithRequest = (req = {}, endpoint, clientParams = {}, options = {}) => { if (req.headers) { const filteredHeaders = filterHeaders(req.headers, this.getRequestHeadersWhitelist()); @@ -38,17 +26,6 @@ export class Cluster { return callAPI(this._noAuthClient, endpoint, clientParams, options); } - /** - * callWithInternalUser - * - * Performs a call to ES using the credentials in kibana.yml - * - * @param {string} endpoint - * @param {Object} clientParams - * @param {Object} options - * @returns {Promise} - */ - callWithInternalUser = (endpoint, clientParams = {}, options = {}) => { return callAPI(this._client, endpoint, clientParams, options); } From 1b818dab973490bc5b98a94b8594616f7b751206 Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Thu, 29 Dec 2016 17:02:50 -0800 Subject: [PATCH 39/39] Explicitly check for presence of url in tribe Signed-off-by: Tyler Smalley --- src/core_plugins/elasticsearch/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core_plugins/elasticsearch/index.js b/src/core_plugins/elasticsearch/index.js index 86ef7203ea766..6f8c2928db56b 100644 --- a/src/core_plugins/elasticsearch/index.js +++ b/src/core_plugins/elasticsearch/index.js @@ -1,4 +1,4 @@ -import { trim, trimRight, bindKey } from 'lodash'; +import { trim, trimRight, bindKey, get } from 'lodash'; import { methodNotAllowed } from 'boom'; import healthCheck from './lib/health_check'; @@ -71,7 +71,7 @@ module.exports = function ({ Plugin }) { esRequestTimeout: options.requestTimeout, esShardTimeout: options.shardTimeout, esApiVersion: options.apiVersion, - esDataIsTribe: options.tribe ? true : false, + esDataIsTribe: get(options, 'tribe.url') ? true : false, }; } },