From 4178cab431d281bdaaee724856675c926a3d06c8 Mon Sep 17 00:00:00 2001 From: Court Ewing Date: Wed, 19 Jul 2017 16:38:37 -0400 Subject: [PATCH] Remove the es_admin proxy Saved object access is now handled through the saved object client rather than by making direct requests to the admin cluster through a proxy. The indices module and scanner module were both still relying on the proxy, so temporary "legacy" endpoints have been created for their specific use-cases. We should add more purposeful endpoints to the public API in the future to replace these. The admin cluster itself is still readily available on the server and should still be used for all requests for internal kibana indices. --- .../elasticsearch/lib/create_proxy.js | 1 - src/core_plugins/kibana/index.js | 4 ++ .../public/dashboard/__tests__/panel.js | 10 +--- .../saved_dashboard/saved_dashboards.js | 4 +- .../discover/saved_searches/saved_searches.js | 4 +- .../saved_visualizations.js | 4 +- .../server/routes/api/admin_indices/index.js | 50 +++++++++++++++++++ .../server/routes/api/scroll_search/index.js | 34 +++++++++++++ .../timelion/public/services/saved_sheets.js | 4 +- src/ui/public/chrome/api/angular.js | 5 -- .../public/courier/__tests__/saved_object.js | 25 +--------- .../courier/data_source/_doc_send_to_es.js | 5 +- src/ui/public/courier/fetch/call_client.js | 6 +-- .../saved_object/saved_object_loader.js | 5 +- src/ui/public/es.js | 12 ----- .../public/indices/__tests__/get_indices.js | 43 +++++++++------- .../__tests__/get_template_index_patterns.js | 8 ++- src/ui/public/indices/get_indices.js | 13 +++-- .../indices/get_template_index_patterns.js | 8 +-- src/ui/public/utils/__tests__/scanner.js | 48 +++++++++--------- src/ui/public/utils/scanner.js | 34 +++++++++---- 21 files changed, 192 insertions(+), 135 deletions(-) create mode 100644 src/core_plugins/kibana/server/routes/api/admin_indices/index.js create mode 100644 src/core_plugins/kibana/server/routes/api/scroll_search/index.js diff --git a/src/core_plugins/elasticsearch/lib/create_proxy.js b/src/core_plugins/elasticsearch/lib/create_proxy.js index 93986c952c9d5..3802312be7a82 100644 --- a/src/core_plugins/elasticsearch/lib/create_proxy.js +++ b/src/core_plugins/elasticsearch/lib/create_proxy.js @@ -12,7 +12,6 @@ export function createPath(prefix, path) { export 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) { diff --git a/src/core_plugins/kibana/index.js b/src/core_plugins/kibana/index.js index d2a15195e29b2..6694471361ef5 100644 --- a/src/core_plugins/kibana/index.js +++ b/src/core_plugins/kibana/index.js @@ -6,6 +6,8 @@ import { mkdirp as mkdirpNode } from 'mkdirp'; import manageUuid from './server/lib/manage_uuid'; import search from './server/routes/api/search'; import settings from './server/routes/api/settings'; +import { adminIndicesApi } from './server/routes/api/admin_indices'; +import { scrollSearchApi } from './server/routes/api/scroll_search'; import { importApi } from './server/routes/api/import'; import { exportApi } from './server/routes/api/export'; import scripts from './server/routes/api/scripts'; @@ -143,6 +145,8 @@ export default function (kibana) { search(server); settings(server); scripts(server); + adminIndicesApi(server); + scrollSearchApi(server); importApi(server); exportApi(server); registerSuggestionsApi(server); diff --git a/src/core_plugins/kibana/public/dashboard/__tests__/panel.js b/src/core_plugins/kibana/public/dashboard/__tests__/panel.js index 12ecb45c3e986..677a3731526b7 100644 --- a/src/core_plugins/kibana/public/dashboard/__tests__/panel.js +++ b/src/core_plugins/kibana/public/dashboard/__tests__/panel.js @@ -15,21 +15,13 @@ describe('dashboard panel', function () { function init(mockDocResponse) { ngMock.module('kibana'); - ngMock.inject(($rootScope, $compile, Private, esAdmin) => { + ngMock.inject(($rootScope, $compile, Private) => { Private.swap(SavedObjectsClientProvider, () => { return { get: sinon.stub().returns(Promise.resolve(mockDocResponse)) }; }); - sinon.stub(esAdmin.indices, 'getFieldMapping').returns(Promise.resolve({ - '.kibana': { - mappings: { - visualization: {} - } - } - })); - parentScope = $rootScope.$new(); parentScope.saveState = sinon.stub(); parentScope.createChildUiState = sinon.stub().returns(mockUiState); diff --git a/src/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboards.js b/src/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboards.js index 76607a88b2949..bdf914243015d 100644 --- a/src/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboards.js +++ b/src/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboards.js @@ -13,6 +13,6 @@ savedObjectManagementRegistry.register({ }); // This is the only thing that gets injected into controllers -module.service('savedDashboards', function (SavedDashboard, kbnIndex, esAdmin, kbnUrl, $http) { - return new SavedObjectLoader(SavedDashboard, kbnIndex, esAdmin, kbnUrl, $http); +module.service('savedDashboards', function (SavedDashboard, kbnIndex, kbnUrl, $http) { + return new SavedObjectLoader(SavedDashboard, kbnIndex, kbnUrl, $http); }); 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 51bb21b6ef5d5..c08a785bca5e7 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 @@ -14,8 +14,8 @@ savedObjectManagementRegistry.register({ title: 'searches' }); -module.service('savedSearches', function (Promise, config, kbnIndex, esAdmin, createNotifier, SavedSearch, kbnUrl, $http) { - const savedSearchLoader = new SavedObjectLoader(SavedSearch, kbnIndex, esAdmin, kbnUrl, $http); +module.service('savedSearches', function (Promise, config, kbnIndex, createNotifier, SavedSearch, kbnUrl, $http) { + const savedSearchLoader = new SavedObjectLoader(SavedSearch, kbnIndex, kbnUrl, $http); // Customize loader properties since adding an 's' on type doesn't work for type 'search' . savedSearchLoader.loaderProperties = { name: 'searches', 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 dbb0960e1aaeb..6e2781b640272 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,13 +13,13 @@ savedObjectManagementRegistry.register({ title: 'visualizations' }); -app.service('savedVisualizations', function (Promise, esAdmin, kbnIndex, SavedVis, Private, Notifier, kbnUrl, $http) { +app.service('savedVisualizations', function (Promise, kbnIndex, SavedVis, Private, Notifier, kbnUrl, $http) { const visTypes = Private(VisTypesRegistryProvider); const notify = new Notifier({ location: 'Saved Visualization Service' }); - const saveVisualizationLoader = new SavedObjectLoader(SavedVis, kbnIndex, esAdmin, kbnUrl, $http); + const saveVisualizationLoader = new SavedObjectLoader(SavedVis, kbnIndex, kbnUrl, $http); saveVisualizationLoader.mapHitSource = function (source, id) { source.id = id; diff --git a/src/core_plugins/kibana/server/routes/api/admin_indices/index.js b/src/core_plugins/kibana/server/routes/api/admin_indices/index.js new file mode 100644 index 0000000000000..152f940e4a07a --- /dev/null +++ b/src/core_plugins/kibana/server/routes/api/admin_indices/index.js @@ -0,0 +1,50 @@ +import handleESError from '../../../lib/handle_es_error'; + +export function adminIndicesApi(server) { + server.route({ + path: '/api/kibana/legacy_admin_indices', + method: ['GET'], + handler: (req, reply) => { + const { callWithRequest } = server.plugins.elasticsearch.getCluster('admin'); + const params = { + index: req.query.index, + format: 'json', + ignore: 404, + }; + return callWithRequest(req, 'cat.indices', params) + .then(reply) + .catch(error => reply(handleESError(error))); + } + }); + + server.route({ + path: '/api/kibana/legacy_admin_aliases', + method: ['GET'], + handler: (req, reply) => { + const { callWithRequest } = server.plugins.elasticsearch.getCluster('admin'); + const params = { + index: req.query.index, + allowNoIndices: true, + ignore: 404, + }; + return callWithRequest(req, 'indices.getAlias', params) + .then(reply) + .catch(error => reply(handleESError(error))); + } + }); + + server.route({ + path: '/api/kibana/legacy_admin_index_template', + method: ['GET'], + handler: (req, reply) => { + const { callWithRequest } = server.plugins.elasticsearch.getCluster('admin'); + const params = { + name: req.query.name, + ignore: 404, + }; + return callWithRequest(req, 'indices.getTemplate', params) + .then(reply) + .catch(error => reply(handleESError(error))); + } + }); +} diff --git a/src/core_plugins/kibana/server/routes/api/scroll_search/index.js b/src/core_plugins/kibana/server/routes/api/scroll_search/index.js new file mode 100644 index 0000000000000..8757600e26d26 --- /dev/null +++ b/src/core_plugins/kibana/server/routes/api/scroll_search/index.js @@ -0,0 +1,34 @@ +import handleESError from '../../../lib/handle_es_error'; + +export function scrollSearchApi(server) { + server.route({ + path: '/api/kibana/legacy_scroll_start', + method: ['POST'], + handler: (req, reply) => { + const { callWithRequest } = server.plugins.elasticsearch.getCluster('admin'); + const { index, size, body } = req.payload; + const params = { + index, + size, + body, + scroll: '1m', + sort: '_doc', + }; + return callWithRequest(req, 'search', params) + .then(reply) + .catch(error => reply(handleESError(error))); + } + }); + + server.route({ + path: '/api/kibana/legacy_scroll_continue', + method: ['POST'], + handler: (req, reply) => { + const { callWithRequest } = server.plugins.elasticsearch.getCluster('admin'); + const { scrollId } = req.payload; + return callWithRequest(req, 'scroll', { scrollId }) + .then(reply) + .catch(error => reply(handleESError(error))); + } + }); +} diff --git a/src/core_plugins/timelion/public/services/saved_sheets.js b/src/core_plugins/timelion/public/services/saved_sheets.js index da455c97428b8..0edb3e54a0d3b 100644 --- a/src/core_plugins/timelion/public/services/saved_sheets.js +++ b/src/core_plugins/timelion/public/services/saved_sheets.js @@ -13,8 +13,8 @@ savedObjectManagementRegistry.register({ }); // This is the only thing that gets injected into controllers -module.service('savedSheets', function (Promise, SavedSheet, kbnIndex, esAdmin, kbnUrl, $http) { - const savedSheetLoader = new SavedObjectLoader(SavedSheet, kbnIndex, esAdmin, kbnUrl, $http); +module.service('savedSheets', function (Promise, SavedSheet, kbnIndex, kbnUrl, $http) { + const savedSheetLoader = new SavedObjectLoader(SavedSheet, kbnIndex, kbnUrl, $http); savedSheetLoader.urlFor = function (id) { return kbnUrl.eval('#/{{id}}', { id: id }); }; diff --git a/src/ui/public/chrome/api/angular.js b/src/ui/public/chrome/api/angular.js index 11e6a1b52d9f2..191a7a2cc0784 100644 --- a/src/ui/public/chrome/api/angular.js +++ b/src/ui/public/chrome/api/angular.js @@ -32,11 +32,6 @@ export function initAngularApi(chrome, internals) { a.href = chrome.addBasePath('/elasticsearch'); return a.href; }())) - .value('esAdminUrl', (function () { - const 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__/saved_object.js b/src/ui/public/courier/__tests__/saved_object.js index 66db8176e0815..d547b5990e072 100644 --- a/src/ui/public/courier/__tests__/saved_object.js +++ b/src/ui/public/courier/__tests__/saved_object.js @@ -14,30 +14,10 @@ describe('Saved Object', function () { let SavedObject; let IndexPattern; - let esAdminStub; let esDataStub; let savedObjectsClientStub; let window; - /** - * Some default es stubbing to avoid timeouts and allow a default type of 'dashboard'. - */ - function mockEsService() { - // 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(esAdminStub.indices, 'getFieldMapping').returns(BluebirdPromise.resolve({ - '.kibana' : { - 'mappings': { - 'dashboard': {} - } - } - })); - - // Necessary to avoid a timeout condition. - sinon.stub(esAdminStub.indices, 'putMapping').returns(BluebirdPromise.resolve()); - } - /** * Returns a fake doc response with the given index and id, of type dashboard * that can be used to stub es calls. @@ -94,15 +74,12 @@ describe('Saved Object', function () { }) ); - beforeEach(ngMock.inject(function (es, esAdmin, Private, $window) { + beforeEach(ngMock.inject(function (es, Private, $window) { SavedObject = Private(SavedObjectProvider); IndexPattern = Private(IndexPatternProvider); - esAdminStub = esAdmin; esDataStub = es; savedObjectsClientStub = Private(SavedObjectsClientProvider); window = $window; - - mockEsService(); })); describe('save', function () { 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 2205f3e650871..afe7f49fc91f1 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 { VersionConflict, RequestFailure } from 'ui/errors'; import { RequestQueueProvider } from 'ui/courier/_request_queue'; import { FetchProvider } from 'ui/courier/fetch/fetch'; -export function DocSendToEsProvider(Promise, Private, es, esAdmin, kbnIndex) { +export function DocSendToEsProvider(Promise, Private, es) { const requestQueue = Private(RequestQueueProvider); const courierFetch = Private(FetchProvider); @@ -33,8 +33,7 @@ export function DocSendToEsProvider(Promise, Private, es, esAdmin, kbnIndex) { params.version = doc._getVersion(); } - const client = [].concat(params.index).includes(kbnIndex) ? esAdmin : es; - return client[method](params) + return es[method](params) .then(function (resp) { if (resp.status === 409) throw new VersionConflict(resp); diff --git a/src/ui/public/courier/fetch/call_client.js b/src/ui/public/courier/fetch/call_client.js index db900bf207bcb..d8dc0ed3ea5db 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 function CallClientProvider(Private, Promise, esAdmin, es) { +export function CallClientProvider(Private, Promise, es) { const isRequest = Private(IsRequestProvider); const mergeDuplicateRequests = Private(MergeDuplicatesRequestProvider); @@ -115,9 +115,7 @@ export function CallClientProvider(Private, Promise, esAdmin, es) { throw ABORTED; } - const id = strategy.id; - const client = (id && id.includes('admin')) ? esAdmin : es; - return (esPromise = client[strategy.clientMethod]({ body })); + return (esPromise = es[strategy.clientMethod]({ body })); }) .then(function (clientResp) { return strategy.getResponses(clientResp); diff --git a/src/ui/public/courier/saved_object/saved_object_loader.js b/src/ui/public/courier/saved_object/saved_object_loader.js index 102a48a46f57c..36a07628c999f 100644 --- a/src/ui/public/courier/saved_object/saved_object_loader.js +++ b/src/ui/public/courier/saved_object/saved_object_loader.js @@ -4,15 +4,14 @@ import { StringUtils } from 'ui/utils/string_utils'; import { SavedObjectsClient } from 'ui/saved_objects'; export class SavedObjectLoader { - constructor(SavedObjectClass, kbnIndex, esAdmin, kbnUrl, $http) { + constructor(SavedObjectClass, kbnIndex, kbnUrl, $http) { this.type = SavedObjectClass.type; this.Class = SavedObjectClass; this.lowercaseType = this.type.toLowerCase(); this.kbnIndex = kbnIndex; this.kbnUrl = kbnUrl; - this.esAdmin = esAdmin; - this.scanner = new Scanner(esAdmin, { + this.scanner = new Scanner($http, { index: kbnIndex, type: this.lowercaseType }); diff --git a/src/ui/public/es.js b/src/ui/public/es.js index c2a427c01cbfa..b93c46bf44bca 100644 --- a/src/ui/public/es.js +++ b/src/ui/public/es.js @@ -38,16 +38,4 @@ uiModules apiVersion: esApiVersion, 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, - log: 'info', - requestTimeout: esRequestTimeout, - apiVersion: esApiVersion, - plugins - }); }); diff --git a/src/ui/public/indices/__tests__/get_indices.js b/src/ui/public/indices/__tests__/get_indices.js index 19f005af597dc..dcb2d02dfe0c6 100644 --- a/src/ui/public/indices/__tests__/get_indices.js +++ b/src/ui/public/indices/__tests__/get_indices.js @@ -8,28 +8,35 @@ describe('GetIndices', function () { let getIndices; beforeEach(ngMock.module('kibana', ($provide) => { - indicesResponse = [ - { index: '.kibana' }, - { index: '.monitoring-es-2' }, - { index: '.monitoring-es-3' }, - { index: '.monitoring-es-4' }, - { index: '.monitoring-es-5' } - ]; + indicesResponse = { + data: [ + { index: '.kibana' }, + { index: '.monitoring-es-2' }, + { index: '.monitoring-es-3' }, + { index: '.monitoring-es-4' }, + { index: '.monitoring-es-5' } + ] + }; aliasesResponse = { - '.monitoring-es-1': { - aliases: { - '.monitoring-es-active': {} + data: { + '.monitoring-es-1': { + aliases: { + '.monitoring-es-active': {} + } } } }; - $provide.service('esAdmin', function () { + $provide.service('$http', function () { return { - cat: { - indices: async () => indicesResponse - }, - indices: { - getAlias: async () => aliasesResponse + async get(path) { + if (path.includes('aliases')) { + return aliasesResponse; + } + if (path.includes('indices')) { + return indicesResponse; + } + throw new Error(`Unexpected path to $http.get(): ${path}`); } }; }); @@ -54,8 +61,8 @@ describe('GetIndices', function () { const aliasesResponseCopy = Object.assign({}, aliasesResponse); aliasesResponse = { status: 404 }; const indices = await getIndices(); - expect(indices.length).to.be(indicesResponse.length); - indicesResponse.forEach((indexObj, idx) => { + expect(indices.length).to.be(indicesResponse.data.length); + indicesResponse.data.forEach((indexObj, idx) => { expect(indices[idx]).to.be(indexObj.index); }); aliasesResponse = aliasesResponseCopy; diff --git a/src/ui/public/indices/__tests__/get_template_index_patterns.js b/src/ui/public/indices/__tests__/get_template_index_patterns.js index 72f4683fd2759..cc9c061c4479d 100644 --- a/src/ui/public/indices/__tests__/get_template_index_patterns.js +++ b/src/ui/public/indices/__tests__/get_template_index_patterns.js @@ -25,12 +25,10 @@ describe('GetTemplateIndexPatterns', function () { }, }; - $provide.service('esAdmin', function () { + $provide.service('$http', function () { return { - indices: { - getTemplate: async function () { - return response; - } + async get() { + return { data: response }; } }; }); diff --git a/src/ui/public/indices/get_indices.js b/src/ui/public/indices/get_indices.js index 8218c07408e87..1600cc0720a72 100644 --- a/src/ui/public/indices/get_indices.js +++ b/src/ui/public/indices/get_indices.js @@ -1,6 +1,7 @@ import { pluck, reduce, size } from 'lodash'; +import chrome from 'ui/chrome'; -export function IndicesGetIndicesProvider(esAdmin) { +export function IndicesGetIndicesProvider($http) { const getIndexNamesFromAliasesResponse = json => { // Assume this function won't be called in the event of a 404. return reduce(json, (list, { aliases }, indexName) => { @@ -21,14 +22,16 @@ export function IndicesGetIndicesProvider(esAdmin) { }; return async function getIndices(query) { - const aliases = await esAdmin.indices.getAlias({ index: query, allowNoIndices: true, ignore: 404 }); + const aliasesPath = chrome.addBasePath('/api/kibana/legacy_admin_aliases'); + const aliases = await $http.get(aliasesPath, { index: query }); // If aliases return 200, they'll include matching indices, too. if (aliases.status === 404) { - const indices = await esAdmin.cat.indices({ index: query, format: 'json', ignore: 404 }); - return getIndexNamesFromIndicesResponse(indices); + const indicesPath = chrome.addBasePath('/api/kibana/legacy_admin_indices'); + const indices = await $http.get(indicesPath, { index: query }); + return getIndexNamesFromIndicesResponse(indices.data); } - return getIndexNamesFromAliasesResponse(aliases); + return getIndexNamesFromAliasesResponse(aliases.data); }; } diff --git a/src/ui/public/indices/get_template_index_patterns.js b/src/ui/public/indices/get_template_index_patterns.js index 1a7941f1aab35..1e4c7bd134c4b 100644 --- a/src/ui/public/indices/get_template_index_patterns.js +++ b/src/ui/public/indices/get_template_index_patterns.js @@ -1,12 +1,14 @@ import { flatten, pluck, uniq } from 'lodash'; +import chrome from 'ui/chrome'; const getIndexPatternsFromResponse = json => { return uniq(flatten(pluck(json, 'index_patterns'))); }; -export function IndicesGetTemplateIndexPatternsProvider(esAdmin) { +export function IndicesGetTemplateIndexPatternsProvider($http) { return async function getTemplateIndexPatterns(query) { - const templatesJson = await esAdmin.indices.getTemplate({ name: query, ignore: 404 }); - return getIndexPatternsFromResponse(templatesJson); + const indexTemplatePath = chrome.addBasePath('/api/kibana/legacy_admin_index_template'); + const templatesJson = await $http.get(indexTemplatePath, { name: query }); + return getIndexPatternsFromResponse(templatesJson.data); }; } diff --git a/src/ui/public/utils/__tests__/scanner.js b/src/ui/public/utils/__tests__/scanner.js index 7921391320258..3963cb06a880f 100644 --- a/src/ui/public/utils/__tests__/scanner.js +++ b/src/ui/public/utils/__tests__/scanner.js @@ -1,36 +1,26 @@ import { Scanner } from 'ui/utils/scanner'; import expect from 'expect.js'; -import Bluebird from 'bluebird'; import 'elasticsearch-browser'; import ngMock from 'ng_mock'; import sinon from 'sinon'; -import url from 'url'; - -import { esTestServerUrlParts } from '../../../../../test/es_test_server_url_parts'; describe('Scanner', function () { - let es; + let http; beforeEach(ngMock.module('kibana')); - beforeEach(ngMock.inject(function (esFactory) { - es = esFactory({ - host: url.format(esTestServerUrlParts), - defer: function () { - return Bluebird.defer(); - } - }); + beforeEach(ngMock.inject(function ($http) { + http = $http; })); afterEach(function () { - es.close(); - es = null; + http = null; }); describe('initialization', function () { it('should throw errors if missing arguments on initialization', function () { expect(() => new Scanner()).to.throwError(); - expect(() => new Scanner(es)).to.throwError(); - expect(() => new Scanner(es, { + expect(() => new Scanner(http)).to.throwError(); + expect(() => new Scanner(http, { index: 'foo', type: 'bar' })).not.to.throwError(); @@ -38,6 +28,7 @@ describe('Scanner', function () { }); describe('scan', function () { + let httpPost; let search; let scroll; let scanner; @@ -54,17 +45,26 @@ describe('Scanner', function () { const mockScroll = { 'took':1,'timed_out':false,'_shards':{ 'total':1,'successful':1,'failed':0 },'hits':{ 'total':2,'max_score':0.0,'hits':hits } }; // eslint-disable-line max-len beforeEach(function () { - scanner = new Scanner(es, { + scanner = new Scanner(http, { index: 'foo', type: 'bar' }); - search = sinon.stub(scanner.client, 'search', (req, cb) => cb(null, mockSearch)); - scroll = sinon.stub(scanner.client, 'scroll', (req, cb) => cb(null, mockScroll)); + + search = sinon.stub().returns(Promise.resolve({ data: mockSearch })); + scroll = sinon.stub().returns(Promise.resolve({ data: mockScroll })); + httpPost = sinon.stub(scanner.$http, 'post', (path, ...args) => { + if (path.includes('legacy_scroll_start')) { + return search(...args); + } + if (path.includes('legacy_scroll_continue')) { + return scroll(...args); + } + throw new Error(`Unexpected path to $http.post(): ${path}`); + }); }); it('should reject when an error occurs', function () { - search.restore(); - search = sinon.stub(scanner.client, 'search', (req, cb) => cb(new Error('fail.'))); + search = search.returns(Promise.reject(new Error('fail.'))); return scanner.scanAndMap('') .then(function () { throw new Error('should reject'); @@ -103,9 +103,8 @@ describe('Scanner', function () { }); it('should scroll across multiple pages', function () { - scroll.restore(); const oneResult = { 'took':1,'timed_out':false,'_shards':{ 'total':1,'successful':1,'failed':0 },'hits':{ 'total':2,'max_score':0.0,'hits':['one'] } }; // eslint-disable-line max-len - scroll = sinon.stub(scanner.client, 'scroll', (req, cb) => cb(null, oneResult)); + scroll = sinon.stub().returns(Promise.resolve({ data: oneResult })); return scanner.scanAndMap(null, { pageSize: 1 }) .then(function (response) { expect(scroll.calledTwice); @@ -116,8 +115,7 @@ describe('Scanner', function () { }); afterEach(function () { - search.restore(); - scroll.restore(); + httpPost.restore(); }); }); diff --git a/src/ui/public/utils/scanner.js b/src/ui/public/utils/scanner.js index 4af59dfe2e3fb..8e005ee15df07 100644 --- a/src/ui/public/utils/scanner.js +++ b/src/ui/public/utils/scanner.js @@ -1,15 +1,28 @@ import _ from 'lodash'; +import chrome from 'ui/chrome'; -export const Scanner = function (client, { index, type } = {}) { +export const Scanner = function ($http, { index, type } = {}) { if (!index) throw new Error('Expected index'); if (!type) throw new Error('Expected type'); - if (!client) throw new Error('Expected client'); + if (!$http) throw new Error('Expected $http'); - this.client = client; + this.$http = $http; this.index = index; this.type = type; }; +Scanner.prototype.start = function (searchBody) { + const { addBasePath } = chrome; + const scrollStartPath = addBasePath('/api/kibana/legacy_scroll_start'); + return this.$http.post(scrollStartPath, searchBody); +}; + +Scanner.prototype.continue = function (scrollId) { + const { addBasePath } = chrome; + const scrollContinuePath = addBasePath('/api/kibana/legacy_scroll_continue'); + return this.$http.post(scrollContinuePath, { scrollId }); +}; + Scanner.prototype.scanAndMap = function (searchString, options, mapFn) { const bool = { must: [], filter: [] }; @@ -92,18 +105,19 @@ Scanner.prototype.scanAndMap = function (searchString, options, mapFn) { if (collectedAllResults) { resolve(allResults); } else { - this.client.scroll({ - scrollId - }, getMoreUntilDone); + this.continue(scrollId) + .then(response => getMoreUntilDone(null, response.data)) + .catch(error => getMoreUntilDone(error)); } }; - this.client.search({ + const searchBody = { index: this.index, size: opts.pageSize, body: { query: { bool } }, - scroll: '1m', - sort: '_doc', - }, getMoreUntilDone); + }; + this.start(searchBody) + .then(response => getMoreUntilDone(null, response.data)) + .catch(error => getMoreUntilDone(error)); }); };