From 7be744762d6bb8bbddce311c57137076eb1859a8 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Wed, 22 Jan 2020 13:38:04 -0500 Subject: [PATCH 01/13] init commit: convert server code to TS + create shim --- .../rollup/common/{index.js => index.ts} | 10 + .../common/{ui_metric.js => ui_metric.ts} | 0 .../plugins/rollup/{index.js => index.ts} | 68 ++++--- x-pack/legacy/plugins/rollup/kibana.json | 9 + ...ta_enricher.js => rollup_data_enricher.ts} | 2 +- ...arch_rollup.js => elasticsearch_rollup.ts} | 2 +- .../index.js => index.ts} | 4 +- .../call_with_request_factory.js | 21 --- .../call_with_request_factory.ts | 28 +++ .../{index.js => index.ts} | 0 .../check_license/__tests__/check_license.js | 145 -------------- .../server/lib/check_license/check_license.js | 66 ------- .../__tests__/wrap_custom_error.js | 21 --- .../error_wrappers/__tests__/wrap_es_error.js | 39 ---- .../__tests__/wrap_unknown_error.js | 19 -- .../rollup/server/lib/error_wrappers/index.js | 9 - .../lib/error_wrappers/wrap_custom_error.js | 18 -- .../lib/error_wrappers/wrap_es_error.js | 59 ------ .../lib/error_wrappers/wrap_unknown_error.js | 17 -- .../index.js => is_es_error/index.ts} | 2 +- .../index.js => is_es_error/is_es_error.ts} | 8 +- .../__tests__/is_es_error_factory.js | 44 ----- .../is_es_error_factory.js | 18 -- ...compatibility.js => jobs_compatibility.ts} | 0 .../{index.js => index.ts} | 0 .../license_pre_routing_factory.js | 28 --- .../license_pre_routing_factory.ts | 43 +++++ ...ap_capabilities.js => map_capabilities.ts} | 4 +- ...s.js => merge_capabilities_with_fields.ts} | 0 .../register_license_checker.js | 24 --- .../search_strategies/{index.js => index.ts} | 0 ...{interval_helper.js => interval_helper.ts} | 0 ....js => register_rollup_search_strategy.ts} | 0 ...ities.js => rollup_search_capabilities.ts} | 0 ...ch_request.js => rollup_search_request.ts} | 0 ..._strategy.js => rollup_search_strategy.ts} | 0 x-pack/legacy/plugins/rollup/server/plugin.ts | 48 +++++ .../server/routes/api/{index.js => index.ts} | 0 .../server/routes/api/index_patterns.js | 93 --------- .../server/routes/api/index_patterns.ts | 153 +++++++++++++++ .../rollup/server/routes/api/indices.js | 128 ------------- .../rollup/server/routes/api/indices.ts | 175 +++++++++++++++++ .../plugins/rollup/server/routes/api/jobs.js | 153 --------------- .../plugins/rollup/server/routes/api/jobs.ts | 178 ++++++++++++++++++ .../rollup/server/routes/api/search.js | 44 ----- .../rollup/server/routes/api/search.ts | 50 +++++ x-pack/legacy/plugins/rollup/server/types.ts | 22 +++ .../usage/{collector.js => collector.ts} | 0 .../server/usage/{index.js => index.ts} | 0 49 files changed, 772 insertions(+), 980 deletions(-) rename x-pack/legacy/plugins/rollup/common/{index.js => index.ts} (69%) rename x-pack/legacy/plugins/rollup/common/{ui_metric.js => ui_metric.ts} (100%) rename x-pack/legacy/plugins/rollup/{index.js => index.ts} (50%) create mode 100644 x-pack/legacy/plugins/rollup/kibana.json rename x-pack/legacy/plugins/rollup/{rollup_data_enricher.js => rollup_data_enricher.ts} (93%) rename x-pack/legacy/plugins/rollup/server/client/{elasticsearch_rollup.js => elasticsearch_rollup.ts} (96%) rename x-pack/legacy/plugins/rollup/server/{lib/register_license_checker/index.js => index.ts} (56%) delete mode 100644 x-pack/legacy/plugins/rollup/server/lib/call_with_request_factory/call_with_request_factory.js create mode 100644 x-pack/legacy/plugins/rollup/server/lib/call_with_request_factory/call_with_request_factory.ts rename x-pack/legacy/plugins/rollup/server/lib/call_with_request_factory/{index.js => index.ts} (100%) delete mode 100644 x-pack/legacy/plugins/rollup/server/lib/check_license/__tests__/check_license.js delete mode 100644 x-pack/legacy/plugins/rollup/server/lib/check_license/check_license.js delete mode 100644 x-pack/legacy/plugins/rollup/server/lib/error_wrappers/__tests__/wrap_custom_error.js delete mode 100644 x-pack/legacy/plugins/rollup/server/lib/error_wrappers/__tests__/wrap_es_error.js delete mode 100644 x-pack/legacy/plugins/rollup/server/lib/error_wrappers/__tests__/wrap_unknown_error.js delete mode 100644 x-pack/legacy/plugins/rollup/server/lib/error_wrappers/index.js delete mode 100644 x-pack/legacy/plugins/rollup/server/lib/error_wrappers/wrap_custom_error.js delete mode 100644 x-pack/legacy/plugins/rollup/server/lib/error_wrappers/wrap_es_error.js delete mode 100644 x-pack/legacy/plugins/rollup/server/lib/error_wrappers/wrap_unknown_error.js rename x-pack/legacy/plugins/rollup/server/lib/{check_license/index.js => is_es_error/index.ts} (83%) rename x-pack/legacy/plugins/rollup/server/lib/{is_es_error_factory/index.js => is_es_error/is_es_error.ts} (54%) delete mode 100644 x-pack/legacy/plugins/rollup/server/lib/is_es_error_factory/__tests__/is_es_error_factory.js delete mode 100644 x-pack/legacy/plugins/rollup/server/lib/is_es_error_factory/is_es_error_factory.js rename x-pack/legacy/plugins/rollup/server/lib/{jobs_compatibility.js => jobs_compatibility.ts} (100%) rename x-pack/legacy/plugins/rollup/server/lib/license_pre_routing_factory/{index.js => index.ts} (100%) delete mode 100644 x-pack/legacy/plugins/rollup/server/lib/license_pre_routing_factory/license_pre_routing_factory.js create mode 100644 x-pack/legacy/plugins/rollup/server/lib/license_pre_routing_factory/license_pre_routing_factory.ts rename x-pack/legacy/plugins/rollup/server/lib/{map_capabilities.js => map_capabilities.ts} (81%) rename x-pack/legacy/plugins/rollup/server/lib/{merge_capabilities_with_fields.js => merge_capabilities_with_fields.ts} (100%) delete mode 100644 x-pack/legacy/plugins/rollup/server/lib/register_license_checker/register_license_checker.js rename x-pack/legacy/plugins/rollup/server/lib/search_strategies/{index.js => index.ts} (100%) rename x-pack/legacy/plugins/rollup/server/lib/search_strategies/lib/{interval_helper.js => interval_helper.ts} (100%) rename x-pack/legacy/plugins/rollup/server/lib/search_strategies/{register_rollup_search_strategy.js => register_rollup_search_strategy.ts} (100%) rename x-pack/legacy/plugins/rollup/server/lib/search_strategies/{rollup_search_capabilities.js => rollup_search_capabilities.ts} (100%) rename x-pack/legacy/plugins/rollup/server/lib/search_strategies/{rollup_search_request.js => rollup_search_request.ts} (100%) rename x-pack/legacy/plugins/rollup/server/lib/search_strategies/{rollup_search_strategy.js => rollup_search_strategy.ts} (100%) create mode 100644 x-pack/legacy/plugins/rollup/server/plugin.ts rename x-pack/legacy/plugins/rollup/server/routes/api/{index.js => index.ts} (100%) delete mode 100644 x-pack/legacy/plugins/rollup/server/routes/api/index_patterns.js create mode 100644 x-pack/legacy/plugins/rollup/server/routes/api/index_patterns.ts delete mode 100644 x-pack/legacy/plugins/rollup/server/routes/api/indices.js create mode 100644 x-pack/legacy/plugins/rollup/server/routes/api/indices.ts delete mode 100644 x-pack/legacy/plugins/rollup/server/routes/api/jobs.js create mode 100644 x-pack/legacy/plugins/rollup/server/routes/api/jobs.ts delete mode 100644 x-pack/legacy/plugins/rollup/server/routes/api/search.js create mode 100644 x-pack/legacy/plugins/rollup/server/routes/api/search.ts create mode 100644 x-pack/legacy/plugins/rollup/server/types.ts rename x-pack/legacy/plugins/rollup/server/usage/{collector.js => collector.ts} (100%) rename x-pack/legacy/plugins/rollup/server/usage/{index.js => index.ts} (100%) diff --git a/x-pack/legacy/plugins/rollup/common/index.js b/x-pack/legacy/plugins/rollup/common/index.ts similarity index 69% rename from x-pack/legacy/plugins/rollup/common/index.js rename to x-pack/legacy/plugins/rollup/common/index.ts index 800da79552a57a..42298034622034 100644 --- a/x-pack/legacy/plugins/rollup/common/index.js +++ b/x-pack/legacy/plugins/rollup/common/index.ts @@ -4,12 +4,22 @@ * you may not use this file except in compliance with the Elastic License. */ +import { LICENSE_TYPE_BASIC, LicenseType } from '../../../common/constants'; + export const PLUGIN = { ID: 'rollup', + MINIMUM_LICENSE_REQUIRED: LICENSE_TYPE_BASIC as LicenseType, + getI18nName: (i18n: any): string => { + return i18n.translate('xpack.rollupJobs.appName', { + defaultMessage: 'Rollup jobs', + }); + }, }; export const CONFIG_ROLLUPS = 'rollups:enableIndexPatterns'; +export const API_BASE_PATH = '/api/rollup'; + export { UIM_APP_NAME, UIM_APP_LOAD, diff --git a/x-pack/legacy/plugins/rollup/common/ui_metric.js b/x-pack/legacy/plugins/rollup/common/ui_metric.ts similarity index 100% rename from x-pack/legacy/plugins/rollup/common/ui_metric.js rename to x-pack/legacy/plugins/rollup/common/ui_metric.ts diff --git a/x-pack/legacy/plugins/rollup/index.js b/x-pack/legacy/plugins/rollup/index.ts similarity index 50% rename from x-pack/legacy/plugins/rollup/index.js rename to x-pack/legacy/plugins/rollup/index.ts index f4210435abc09e..3edcc714eae61e 100644 --- a/x-pack/legacy/plugins/rollup/index.js +++ b/x-pack/legacy/plugins/rollup/index.ts @@ -5,20 +5,25 @@ */ import { resolve } from 'path'; -import { PLUGIN, CONFIG_ROLLUPS } from './common'; -import { registerLicenseChecker } from './server/lib/register_license_checker'; -import { rollupDataEnricher } from './rollup_data_enricher'; -import { registerRollupSearchStrategy } from './server/lib/search_strategies'; -import { - registerIndicesRoute, - registerFieldsForWildcardRoute, - registerSearchRoute, - registerJobsRoute, -} from './server/routes/api'; -import { registerRollupUsageCollector } from './server/usage'; import { i18n } from '@kbn/i18n'; +import { Legacy } from 'kibana'; +import { PLUGIN, CONFIG_ROLLUPS } from './common'; +import { plugin } from './server'; + +// import { registerLicenseChecker } from './server/lib/register_license_checker'; +// import { rollupDataEnricher } from './rollup_data_enricher'; +// import { registerRollupSearchStrategy } from './server/lib/search_strategies'; +// import { +// registerIndicesRoute, +// registerFieldsForWildcardRoute, +// registerSearchRoute, +// registerJobsRoute, +// } from './server/routes/api'; +// import { registerRollupUsageCollector } from './server/usage'; -export function rollup(kibana) { +export type ServerFacade = Legacy.Server; + +export function rollup(kibana: any) { return new kibana.Plugin({ id: PLUGIN.ID, configPrefix: 'xpack.rollup', @@ -49,22 +54,31 @@ export function rollup(kibana) { visualize: ['plugins/rollup/visualize'], search: ['plugins/rollup/search'], }, - init: function(server) { - const { usageCollection } = server.newPlatform.setup.plugins; - registerLicenseChecker(server); - registerIndicesRoute(server); - registerFieldsForWildcardRoute(server); - registerSearchRoute(server); - registerJobsRoute(server); - registerRollupUsageCollector(usageCollection, server); - if ( - server.plugins.index_management && - server.plugins.index_management.addIndexManagementDataEnricher - ) { - server.plugins.index_management.addIndexManagementDataEnricher(rollupDataEnricher); - } + init(server: ServerFacade) { + plugin({} as any).setup(server.newPlatform.setup.core, { + __LEGACY: { + route: server.route.bind(server), + plugins: { + xpack_main: server.plugins.xpack_main, + rollup: server.plugins[PLUGIN.ID], + }, + }, + }); - registerRollupSearchStrategy(this.kbnServer, server); + // const { usageCollection } = server.newPlatform.setup.plugins; + // registerLicenseChecker(server); + // registerIndicesRoute(server); + // registerFieldsForWildcardRoute(server); + // registerSearchRoute(server); + // registerJobsRoute(server); + // registerRollupUsageCollector(usageCollection, server); + // if ( + // server.plugins.index_management && + // server.plugins.index_management.addIndexManagementDataEnricher + // ) { + // server.plugins.index_management.addIndexManagementDataEnricher(rollupDataEnricher); + // } + // registerRollupSearchStrategy(this.kbnServer, server); }, }); } diff --git a/x-pack/legacy/plugins/rollup/kibana.json b/x-pack/legacy/plugins/rollup/kibana.json new file mode 100644 index 00000000000000..e9e999a341ae71 --- /dev/null +++ b/x-pack/legacy/plugins/rollup/kibana.json @@ -0,0 +1,9 @@ +{ + "id": "rollup", + "version": "kibana", + "requiredPlugins": [ + "home" + ], + "server": true, + "ui": false +} diff --git a/x-pack/legacy/plugins/rollup/rollup_data_enricher.js b/x-pack/legacy/plugins/rollup/rollup_data_enricher.ts similarity index 93% rename from x-pack/legacy/plugins/rollup/rollup_data_enricher.js rename to x-pack/legacy/plugins/rollup/rollup_data_enricher.ts index e92cd3b0b4fbc6..4768468f481b5d 100644 --- a/x-pack/legacy/plugins/rollup/rollup_data_enricher.js +++ b/x-pack/legacy/plugins/rollup/rollup_data_enricher.ts @@ -22,7 +22,7 @@ export const rollupDataEnricher = async (indicesList, callWithRequest) => { }; }); } catch (e) { - //swallow exceptions and return original list + // swallow exceptions and return original list return indicesList; } }; diff --git a/x-pack/legacy/plugins/rollup/server/client/elasticsearch_rollup.js b/x-pack/legacy/plugins/rollup/server/client/elasticsearch_rollup.ts similarity index 96% rename from x-pack/legacy/plugins/rollup/server/client/elasticsearch_rollup.js rename to x-pack/legacy/plugins/rollup/server/client/elasticsearch_rollup.ts index 3b073cd2139c18..840f66a056d2d3 100644 --- a/x-pack/legacy/plugins/rollup/server/client/elasticsearch_rollup.js +++ b/x-pack/legacy/plugins/rollup/server/client/elasticsearch_rollup.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -export const elasticsearchJsPlugin = (Client, config, components) => { +export const elasticsearchJsPlugin = (Client: any, config: any, components: any) => { const ca = components.clientAction.factory; Client.prototype.rollup = components.clientAction.namespaceFactory(); diff --git a/x-pack/legacy/plugins/rollup/server/lib/register_license_checker/index.js b/x-pack/legacy/plugins/rollup/server/index.ts similarity index 56% rename from x-pack/legacy/plugins/rollup/server/lib/register_license_checker/index.js rename to x-pack/legacy/plugins/rollup/server/index.ts index 7b0f97c38d1292..02bf2f30572196 100644 --- a/x-pack/legacy/plugins/rollup/server/lib/register_license_checker/index.js +++ b/x-pack/legacy/plugins/rollup/server/index.ts @@ -3,5 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import { PluginInitializerContext } from 'kibana/server'; +import { RollupsServerPlugin } from './plugin'; -export { registerLicenseChecker } from './register_license_checker'; +export const plugin = (ctx: PluginInitializerContext) => new RollupsServerPlugin(); diff --git a/x-pack/legacy/plugins/rollup/server/lib/call_with_request_factory/call_with_request_factory.js b/x-pack/legacy/plugins/rollup/server/lib/call_with_request_factory/call_with_request_factory.js deleted file mode 100644 index 537c5cf45ad61e..00000000000000 --- a/x-pack/legacy/plugins/rollup/server/lib/call_with_request_factory/call_with_request_factory.js +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { once } from 'lodash'; -import { elasticsearchJsPlugin } from '../../client/elasticsearch_rollup'; - -const callWithRequest = once(server => { - const config = { plugins: [elasticsearchJsPlugin] }; - const cluster = server.plugins.elasticsearch.createCluster('rollup', config); - - return cluster.callWithRequest; -}); - -export const callWithRequestFactory = (server, request) => { - return (...args) => { - return callWithRequest(server)(request, ...args); - }; -}; diff --git a/x-pack/legacy/plugins/rollup/server/lib/call_with_request_factory/call_with_request_factory.ts b/x-pack/legacy/plugins/rollup/server/lib/call_with_request_factory/call_with_request_factory.ts new file mode 100644 index 00000000000000..883b3552a7c020 --- /dev/null +++ b/x-pack/legacy/plugins/rollup/server/lib/call_with_request_factory/call_with_request_factory.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { ElasticsearchServiceSetup } from 'kibana/server'; +import { once } from 'lodash'; +import { elasticsearchJsPlugin } from '../../client/elasticsearch_rollup'; + +const callWithRequest = once((elasticsearchService: ElasticsearchServiceSetup) => { + const config = { plugins: [elasticsearchJsPlugin] }; + return elasticsearchService.createClient('rollup', config); +}); + +export const callWithRequestFactory = ( + elasticsearchService: ElasticsearchServiceSetup, + request: any +) => { + return (...args: any[]) => { + return ( + callWithRequest(elasticsearchService) + .asScoped(request) + // @ts-ignore + .callAsCurrentUser(...args) + ); + }; +}; diff --git a/x-pack/legacy/plugins/rollup/server/lib/call_with_request_factory/index.js b/x-pack/legacy/plugins/rollup/server/lib/call_with_request_factory/index.ts similarity index 100% rename from x-pack/legacy/plugins/rollup/server/lib/call_with_request_factory/index.js rename to x-pack/legacy/plugins/rollup/server/lib/call_with_request_factory/index.ts diff --git a/x-pack/legacy/plugins/rollup/server/lib/check_license/__tests__/check_license.js b/x-pack/legacy/plugins/rollup/server/lib/check_license/__tests__/check_license.js deleted file mode 100644 index 933fda01c055db..00000000000000 --- a/x-pack/legacy/plugins/rollup/server/lib/check_license/__tests__/check_license.js +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import expect from '@kbn/expect'; -import { set } from 'lodash'; -import { checkLicense } from '../check_license'; - -describe('check_license', function() { - let mockLicenseInfo; - beforeEach(() => (mockLicenseInfo = {})); - - describe('license information is undefined', () => { - beforeEach(() => (mockLicenseInfo = undefined)); - - it('should set isAvailable to false', () => { - expect(checkLicense(mockLicenseInfo).isAvailable).to.be(false); - }); - - it('should set showLinks to true', () => { - expect(checkLicense(mockLicenseInfo).showLinks).to.be(true); - }); - - it('should set enableLinks to false', () => { - expect(checkLicense(mockLicenseInfo).enableLinks).to.be(false); - }); - - it('should set a message', () => { - expect(checkLicense(mockLicenseInfo).message).to.not.be(undefined); - }); - }); - - describe('license information is not available', () => { - beforeEach(() => (mockLicenseInfo.isAvailable = () => false)); - - it('should set isAvailable to false', () => { - expect(checkLicense(mockLicenseInfo).isAvailable).to.be(false); - }); - - it('should set showLinks to true', () => { - expect(checkLicense(mockLicenseInfo).showLinks).to.be(true); - }); - - it('should set enableLinks to false', () => { - expect(checkLicense(mockLicenseInfo).enableLinks).to.be(false); - }); - - it('should set a message', () => { - expect(checkLicense(mockLicenseInfo).message).to.not.be(undefined); - }); - }); - - describe('license information is available', () => { - beforeEach(() => { - mockLicenseInfo.isAvailable = () => true; - set(mockLicenseInfo, 'license.getType', () => 'basic'); - }); - - describe('& license is > basic', () => { - beforeEach(() => set(mockLicenseInfo, 'license.isOneOf', () => true)); - - describe('& license is active', () => { - beforeEach(() => set(mockLicenseInfo, 'license.isActive', () => true)); - - it('should set isAvailable to true', () => { - expect(checkLicense(mockLicenseInfo).isAvailable).to.be(true); - }); - - it('should set showLinks to true', () => { - expect(checkLicense(mockLicenseInfo).showLinks).to.be(true); - }); - - it('should set enableLinks to true', () => { - expect(checkLicense(mockLicenseInfo).enableLinks).to.be(true); - }); - - it('should not set a message', () => { - expect(checkLicense(mockLicenseInfo).message).to.be(undefined); - }); - }); - - describe('& license is expired', () => { - beforeEach(() => set(mockLicenseInfo, 'license.isActive', () => false)); - - it('should set isAvailable to false', () => { - expect(checkLicense(mockLicenseInfo).isAvailable).to.be(false); - }); - - it('should set showLinks to true', () => { - expect(checkLicense(mockLicenseInfo).showLinks).to.be(true); - }); - - it('should set enableLinks to false', () => { - expect(checkLicense(mockLicenseInfo).enableLinks).to.be(false); - }); - - it('should set a message', () => { - expect(checkLicense(mockLicenseInfo).message).to.not.be(undefined); - }); - }); - }); - - describe('& license is basic', () => { - beforeEach(() => set(mockLicenseInfo, 'license.isOneOf', () => true)); - - describe('& license is active', () => { - beforeEach(() => set(mockLicenseInfo, 'license.isActive', () => true)); - - it('should set isAvailable to true', () => { - expect(checkLicense(mockLicenseInfo).isAvailable).to.be(true); - }); - - it('should set showLinks to true', () => { - expect(checkLicense(mockLicenseInfo).showLinks).to.be(true); - }); - - it('should set enableLinks to true', () => { - expect(checkLicense(mockLicenseInfo).enableLinks).to.be(true); - }); - - it('should not set a message', () => { - expect(checkLicense(mockLicenseInfo).message).to.be(undefined); - }); - }); - - describe('& license is expired', () => { - beforeEach(() => set(mockLicenseInfo, 'license.isActive', () => false)); - - it('should set isAvailable to false', () => { - expect(checkLicense(mockLicenseInfo).isAvailable).to.be(false); - }); - - it('should set showLinks to true', () => { - expect(checkLicense(mockLicenseInfo).showLinks).to.be(true); - }); - - it('should set a message', () => { - expect(checkLicense(mockLicenseInfo).message).to.not.be(undefined); - }); - }); - }); - }); -}); diff --git a/x-pack/legacy/plugins/rollup/server/lib/check_license/check_license.js b/x-pack/legacy/plugins/rollup/server/lib/check_license/check_license.js deleted file mode 100644 index 3885a20a1f358a..00000000000000 --- a/x-pack/legacy/plugins/rollup/server/lib/check_license/check_license.js +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { i18n } from '@kbn/i18n'; - -export function checkLicense(xpackLicenseInfo) { - const pluginName = 'Rollups'; - - // If, for some reason, we cannot get the license information - // from Elasticsearch, assume worst case and disable - if (!xpackLicenseInfo || !xpackLicenseInfo.isAvailable()) { - return { - isAvailable: false, - showLinks: true, - enableLinks: false, - message: i18n.translate('xpack.rollupJobs.checkLicense.errorUnavailableMessage', { - defaultMessage: - 'You cannot use {pluginName} because license information is not available at this time.', - values: { pluginName }, - }), - }; - } - - const VALID_LICENSE_MODES = ['trial', 'basic', 'standard', 'gold', 'platinum', 'enterprise']; - - const isLicenseModeValid = xpackLicenseInfo.license.isOneOf(VALID_LICENSE_MODES); - const isLicenseActive = xpackLicenseInfo.license.isActive(); - const licenseType = xpackLicenseInfo.license.getType(); - - // License is not valid - if (!isLicenseModeValid) { - return { - isAvailable: false, - showLinks: false, - message: i18n.translate('xpack.rollupJobs.checkLicense.errorUnsupportedMessage', { - defaultMessage: - 'Your {licenseType} license does not support {pluginName}. Please upgrade your license.', - values: { licenseType, pluginName }, - }), - }; - } - - // License is valid but not active - if (!isLicenseActive) { - return { - isAvailable: false, - showLinks: true, - enableLinks: false, - message: i18n.translate('xpack.rollupJobs.checkLicense.errorExpiredMessage', { - defaultMessage: - 'You cannot use {pluginName} because your {licenseType} license has expired', - values: { licenseType, pluginName }, - }), - }; - } - - // License is valid and active - return { - isAvailable: true, - showLinks: true, - enableLinks: true, - }; -} diff --git a/x-pack/legacy/plugins/rollup/server/lib/error_wrappers/__tests__/wrap_custom_error.js b/x-pack/legacy/plugins/rollup/server/lib/error_wrappers/__tests__/wrap_custom_error.js deleted file mode 100644 index f9c102be7a1ff3..00000000000000 --- a/x-pack/legacy/plugins/rollup/server/lib/error_wrappers/__tests__/wrap_custom_error.js +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import expect from '@kbn/expect'; -import { wrapCustomError } from '../wrap_custom_error'; - -describe('wrap_custom_error', () => { - describe('#wrapCustomError', () => { - it('should return a Boom object', () => { - const originalError = new Error('I am an error'); - const statusCode = 404; - const wrappedError = wrapCustomError(originalError, statusCode); - - expect(wrappedError.isBoom).to.be(true); - expect(wrappedError.output.statusCode).to.equal(statusCode); - }); - }); -}); diff --git a/x-pack/legacy/plugins/rollup/server/lib/error_wrappers/__tests__/wrap_es_error.js b/x-pack/legacy/plugins/rollup/server/lib/error_wrappers/__tests__/wrap_es_error.js deleted file mode 100644 index 8241dc43291371..00000000000000 --- a/x-pack/legacy/plugins/rollup/server/lib/error_wrappers/__tests__/wrap_es_error.js +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import expect from '@kbn/expect'; -import { wrapEsError } from '../wrap_es_error'; - -describe('wrap_es_error', () => { - describe('#wrapEsError', () => { - let originalError; - beforeEach(() => { - originalError = new Error('I am an error'); - originalError.statusCode = 404; - originalError.response = '{}'; - }); - - it('should return a Boom object', () => { - const wrappedError = wrapEsError(originalError); - - expect(wrappedError.isBoom).to.be(true); - }); - - it('should return the correct Boom object', () => { - const wrappedError = wrapEsError(originalError); - - expect(wrappedError.output.statusCode).to.be(originalError.statusCode); - expect(wrappedError.output.payload.message).to.be(originalError.message); - }); - - it('should return the correct Boom object with custom message', () => { - const wrappedError = wrapEsError(originalError, { 404: 'No encontrado!' }); - - expect(wrappedError.output.statusCode).to.be(originalError.statusCode); - expect(wrappedError.output.payload.message).to.be('No encontrado!'); - }); - }); -}); diff --git a/x-pack/legacy/plugins/rollup/server/lib/error_wrappers/__tests__/wrap_unknown_error.js b/x-pack/legacy/plugins/rollup/server/lib/error_wrappers/__tests__/wrap_unknown_error.js deleted file mode 100644 index 85e0b2b3033ad4..00000000000000 --- a/x-pack/legacy/plugins/rollup/server/lib/error_wrappers/__tests__/wrap_unknown_error.js +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import expect from '@kbn/expect'; -import { wrapUnknownError } from '../wrap_unknown_error'; - -describe('wrap_unknown_error', () => { - describe('#wrapUnknownError', () => { - it('should return a Boom object', () => { - const originalError = new Error('I am an error'); - const wrappedError = wrapUnknownError(originalError); - - expect(wrappedError.isBoom).to.be(true); - }); - }); -}); diff --git a/x-pack/legacy/plugins/rollup/server/lib/error_wrappers/index.js b/x-pack/legacy/plugins/rollup/server/lib/error_wrappers/index.js deleted file mode 100644 index f275f156370912..00000000000000 --- a/x-pack/legacy/plugins/rollup/server/lib/error_wrappers/index.js +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -export { wrapCustomError } from './wrap_custom_error'; -export { wrapEsError } from './wrap_es_error'; -export { wrapUnknownError } from './wrap_unknown_error'; diff --git a/x-pack/legacy/plugins/rollup/server/lib/error_wrappers/wrap_custom_error.js b/x-pack/legacy/plugins/rollup/server/lib/error_wrappers/wrap_custom_error.js deleted file mode 100644 index 3295113d38ee5a..00000000000000 --- a/x-pack/legacy/plugins/rollup/server/lib/error_wrappers/wrap_custom_error.js +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import Boom from 'boom'; - -/** - * Wraps a custom error into a Boom error response and returns it - * - * @param err Object error - * @param statusCode Error status code - * @return Object Boom error response - */ -export function wrapCustomError(err, statusCode) { - return Boom.boomify(err, { statusCode }); -} diff --git a/x-pack/legacy/plugins/rollup/server/lib/error_wrappers/wrap_es_error.js b/x-pack/legacy/plugins/rollup/server/lib/error_wrappers/wrap_es_error.js deleted file mode 100644 index 5f4884a3f2d266..00000000000000 --- a/x-pack/legacy/plugins/rollup/server/lib/error_wrappers/wrap_es_error.js +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import Boom from 'boom'; - -function extractCausedByChain(causedBy = {}, accumulator = []) { - const { reason, caused_by } = causedBy; // eslint-disable-line camelcase - - if (reason) { - accumulator.push(reason); - } - - // eslint-disable-next-line camelcase - if (caused_by) { - return extractCausedByChain(caused_by, accumulator); - } - - return accumulator; -} - -/** - * Wraps an error thrown by the ES JS client into a Boom error response and returns it - * - * @param err Object Error thrown by ES JS client - * @param statusCodeToMessageMap Object Optional map of HTTP status codes => error messages - * @return Object Boom error response - */ -export function wrapEsError(err, statusCodeToMessageMap = {}) { - const { statusCode, response } = err; - - const { - error: { - root_cause = [], // eslint-disable-line camelcase - caused_by, // eslint-disable-line camelcase - } = {}, - } = JSON.parse(response); - - // If no custom message if specified for the error's status code, just - // wrap the error as a Boom error response and return it - if (!statusCodeToMessageMap[statusCode]) { - const boomError = Boom.boomify(err, { statusCode }); - - // The caused_by chain has the most information so use that if it's available. If not then - // settle for the root_cause. - const causedByChain = extractCausedByChain(caused_by); - const defaultCause = root_cause.length ? extractCausedByChain(root_cause[0]) : undefined; - - boomError.output.payload.cause = causedByChain.length ? causedByChain : defaultCause; - return boomError; - } - - // Otherwise, use the custom message to create a Boom error response and - // return it - const message = statusCodeToMessageMap[statusCode]; - return new Boom(message, { statusCode }); -} diff --git a/x-pack/legacy/plugins/rollup/server/lib/error_wrappers/wrap_unknown_error.js b/x-pack/legacy/plugins/rollup/server/lib/error_wrappers/wrap_unknown_error.js deleted file mode 100644 index ffd915c5133626..00000000000000 --- a/x-pack/legacy/plugins/rollup/server/lib/error_wrappers/wrap_unknown_error.js +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import Boom from 'boom'; - -/** - * Wraps an unknown error into a Boom error response and returns it - * - * @param err Object Unknown error - * @return Object Boom error response - */ -export function wrapUnknownError(err) { - return Boom.boomify(err); -} diff --git a/x-pack/legacy/plugins/rollup/server/lib/check_license/index.js b/x-pack/legacy/plugins/rollup/server/lib/is_es_error/index.ts similarity index 83% rename from x-pack/legacy/plugins/rollup/server/lib/check_license/index.js rename to x-pack/legacy/plugins/rollup/server/lib/is_es_error/index.ts index f2c070fd44b6e6..a9a3c61472d8c7 100644 --- a/x-pack/legacy/plugins/rollup/server/lib/check_license/index.js +++ b/x-pack/legacy/plugins/rollup/server/lib/is_es_error/index.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { checkLicense } from './check_license'; +export { isEsError } from './is_es_error'; diff --git a/x-pack/legacy/plugins/rollup/server/lib/is_es_error_factory/index.js b/x-pack/legacy/plugins/rollup/server/lib/is_es_error/is_es_error.ts similarity index 54% rename from x-pack/legacy/plugins/rollup/server/lib/is_es_error_factory/index.js rename to x-pack/legacy/plugins/rollup/server/lib/is_es_error/is_es_error.ts index 441648a8701e08..4137293cf39c06 100644 --- a/x-pack/legacy/plugins/rollup/server/lib/is_es_error_factory/index.js +++ b/x-pack/legacy/plugins/rollup/server/lib/is_es_error/is_es_error.ts @@ -4,4 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -export { isEsErrorFactory } from './is_es_error_factory'; +import * as legacyElasticsearch from 'elasticsearch'; + +const esErrorsParent = legacyElasticsearch.errors._Abstract; + +export function isEsError(err: Error) { + return err instanceof esErrorsParent; +} diff --git a/x-pack/legacy/plugins/rollup/server/lib/is_es_error_factory/__tests__/is_es_error_factory.js b/x-pack/legacy/plugins/rollup/server/lib/is_es_error_factory/__tests__/is_es_error_factory.js deleted file mode 100644 index 5f2141cce93954..00000000000000 --- a/x-pack/legacy/plugins/rollup/server/lib/is_es_error_factory/__tests__/is_es_error_factory.js +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import expect from '@kbn/expect'; -import { isEsErrorFactory } from '../is_es_error_factory'; -import { set } from 'lodash'; - -class MockAbstractEsError {} - -describe('is_es_error_factory', () => { - let mockServer; - let isEsError; - - beforeEach(() => { - const mockEsErrors = { - _Abstract: MockAbstractEsError, - }; - mockServer = {}; - set(mockServer, 'plugins.elasticsearch.getCluster', () => ({ errors: mockEsErrors })); - - isEsError = isEsErrorFactory(mockServer); - }); - - describe('#isEsErrorFactory', () => { - it('should return a function', () => { - expect(isEsError).to.be.a(Function); - }); - - describe('returned function', () => { - it('should return true if passed-in err is a known esError', () => { - const knownEsError = new MockAbstractEsError(); - expect(isEsError(knownEsError)).to.be(true); - }); - - it('should return false if passed-in err is not a known esError', () => { - const unknownEsError = {}; - expect(isEsError(unknownEsError)).to.be(false); - }); - }); - }); -}); diff --git a/x-pack/legacy/plugins/rollup/server/lib/is_es_error_factory/is_es_error_factory.js b/x-pack/legacy/plugins/rollup/server/lib/is_es_error_factory/is_es_error_factory.js deleted file mode 100644 index 6c17554385ef85..00000000000000 --- a/x-pack/legacy/plugins/rollup/server/lib/is_es_error_factory/is_es_error_factory.js +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { memoize } from 'lodash'; - -const esErrorsFactory = memoize(server => { - return server.plugins.elasticsearch.getCluster('admin').errors; -}); - -export function isEsErrorFactory(server) { - const esErrors = esErrorsFactory(server); - return function isEsError(err) { - return err instanceof esErrors._Abstract; - }; -} diff --git a/x-pack/legacy/plugins/rollup/server/lib/jobs_compatibility.js b/x-pack/legacy/plugins/rollup/server/lib/jobs_compatibility.ts similarity index 100% rename from x-pack/legacy/plugins/rollup/server/lib/jobs_compatibility.js rename to x-pack/legacy/plugins/rollup/server/lib/jobs_compatibility.ts diff --git a/x-pack/legacy/plugins/rollup/server/lib/license_pre_routing_factory/index.js b/x-pack/legacy/plugins/rollup/server/lib/license_pre_routing_factory/index.ts similarity index 100% rename from x-pack/legacy/plugins/rollup/server/lib/license_pre_routing_factory/index.js rename to x-pack/legacy/plugins/rollup/server/lib/license_pre_routing_factory/index.ts diff --git a/x-pack/legacy/plugins/rollup/server/lib/license_pre_routing_factory/license_pre_routing_factory.js b/x-pack/legacy/plugins/rollup/server/lib/license_pre_routing_factory/license_pre_routing_factory.js deleted file mode 100644 index 1c2c9f2b2276b8..00000000000000 --- a/x-pack/legacy/plugins/rollup/server/lib/license_pre_routing_factory/license_pre_routing_factory.js +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { once } from 'lodash'; -import { wrapCustomError } from '../error_wrappers'; -import { PLUGIN } from '../../../common'; - -export const licensePreRoutingFactory = once(server => { - const xpackMainPlugin = server.plugins.xpack_main; - - // License checking and enable/disable logic - function licensePreRouting() { - const licenseCheckResults = xpackMainPlugin.info.feature(PLUGIN.ID).getLicenseCheckResults(); - if (!licenseCheckResults.isAvailable) { - const error = new Error(licenseCheckResults.message); - const statusCode = 403; - const wrappedError = wrapCustomError(error, statusCode); - return wrappedError; - } else { - return null; - } - } - - return licensePreRouting; -}); diff --git a/x-pack/legacy/plugins/rollup/server/lib/license_pre_routing_factory/license_pre_routing_factory.ts b/x-pack/legacy/plugins/rollup/server/lib/license_pre_routing_factory/license_pre_routing_factory.ts new file mode 100644 index 00000000000000..353510d96a00d4 --- /dev/null +++ b/x-pack/legacy/plugins/rollup/server/lib/license_pre_routing_factory/license_pre_routing_factory.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { + KibanaRequest, + KibanaResponseFactory, + RequestHandler, + RequestHandlerContext, +} from 'src/core/server'; +import { PLUGIN } from '../../../common'; +import { LICENSE_STATUS_VALID } from '../../../../../common/constants/license_status'; +import { ServerShim } from '../../types'; + +export const licensePreRoutingFactory = ( + server: ServerShim, + handler: RequestHandler +): RequestHandler => { + const xpackMainPlugin = server.plugins.xpack_main; + + // License checking and enable/disable logic + return function licensePreRouting( + ctx: RequestHandlerContext, + request: KibanaRequest, + response: KibanaResponseFactory + ) { + const licenseCheckResults = xpackMainPlugin.info.feature(PLUGIN.ID).getLicenseCheckResults(); + const { status } = licenseCheckResults; + + if (status !== LICENSE_STATUS_VALID) { + return response.customError({ + body: { + message: licenseCheckResults.messsage, + }, + statusCode: 403, + }); + } + + return handler(ctx, request, response); + }; +}; diff --git a/x-pack/legacy/plugins/rollup/server/lib/map_capabilities.js b/x-pack/legacy/plugins/rollup/server/lib/map_capabilities.ts similarity index 81% rename from x-pack/legacy/plugins/rollup/server/lib/map_capabilities.js rename to x-pack/legacy/plugins/rollup/server/lib/map_capabilities.ts index a365ca4c756166..e0f8af865beb44 100644 --- a/x-pack/legacy/plugins/rollup/server/lib/map_capabilities.js +++ b/x-pack/legacy/plugins/rollup/server/lib/map_capabilities.ts @@ -6,9 +6,9 @@ import { mergeJobConfigurations } from './jobs_compatibility'; -export function getCapabilitiesForRollupIndices(indices) { +export function getCapabilitiesForRollupIndices(indices: { [key: string]: any }) { const indexNames = Object.keys(indices); - const capabilities = {}; + const capabilities = {} as { [key: string]: any }; indexNames.forEach(index => { try { diff --git a/x-pack/legacy/plugins/rollup/server/lib/merge_capabilities_with_fields.js b/x-pack/legacy/plugins/rollup/server/lib/merge_capabilities_with_fields.ts similarity index 100% rename from x-pack/legacy/plugins/rollup/server/lib/merge_capabilities_with_fields.js rename to x-pack/legacy/plugins/rollup/server/lib/merge_capabilities_with_fields.ts diff --git a/x-pack/legacy/plugins/rollup/server/lib/register_license_checker/register_license_checker.js b/x-pack/legacy/plugins/rollup/server/lib/register_license_checker/register_license_checker.js deleted file mode 100644 index 5f1772800a0122..00000000000000 --- a/x-pack/legacy/plugins/rollup/server/lib/register_license_checker/register_license_checker.js +++ /dev/null @@ -1,24 +0,0 @@ -/* - - - - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { mirrorPluginStatus } from '../../../../../server/lib/mirror_plugin_status'; -import { checkLicense } from '../check_license'; -import { PLUGIN } from '../../../common'; - -export function registerLicenseChecker(server) { - const xpackMainPlugin = server.plugins.xpack_main; - const rollupPlugin = server.plugins[PLUGIN.ID]; - - mirrorPluginStatus(xpackMainPlugin, rollupPlugin); - xpackMainPlugin.status.once('green', () => { - // Register a function that is called whenever the xpack info changes, - // to re-compute the license check results for this plugin - xpackMainPlugin.info.feature(PLUGIN.ID).registerLicenseCheckResultsGenerator(checkLicense); - }); -} diff --git a/x-pack/legacy/plugins/rollup/server/lib/search_strategies/index.js b/x-pack/legacy/plugins/rollup/server/lib/search_strategies/index.ts similarity index 100% rename from x-pack/legacy/plugins/rollup/server/lib/search_strategies/index.js rename to x-pack/legacy/plugins/rollup/server/lib/search_strategies/index.ts diff --git a/x-pack/legacy/plugins/rollup/server/lib/search_strategies/lib/interval_helper.js b/x-pack/legacy/plugins/rollup/server/lib/search_strategies/lib/interval_helper.ts similarity index 100% rename from x-pack/legacy/plugins/rollup/server/lib/search_strategies/lib/interval_helper.js rename to x-pack/legacy/plugins/rollup/server/lib/search_strategies/lib/interval_helper.ts diff --git a/x-pack/legacy/plugins/rollup/server/lib/search_strategies/register_rollup_search_strategy.js b/x-pack/legacy/plugins/rollup/server/lib/search_strategies/register_rollup_search_strategy.ts similarity index 100% rename from x-pack/legacy/plugins/rollup/server/lib/search_strategies/register_rollup_search_strategy.js rename to x-pack/legacy/plugins/rollup/server/lib/search_strategies/register_rollup_search_strategy.ts diff --git a/x-pack/legacy/plugins/rollup/server/lib/search_strategies/rollup_search_capabilities.js b/x-pack/legacy/plugins/rollup/server/lib/search_strategies/rollup_search_capabilities.ts similarity index 100% rename from x-pack/legacy/plugins/rollup/server/lib/search_strategies/rollup_search_capabilities.js rename to x-pack/legacy/plugins/rollup/server/lib/search_strategies/rollup_search_capabilities.ts diff --git a/x-pack/legacy/plugins/rollup/server/lib/search_strategies/rollup_search_request.js b/x-pack/legacy/plugins/rollup/server/lib/search_strategies/rollup_search_request.ts similarity index 100% rename from x-pack/legacy/plugins/rollup/server/lib/search_strategies/rollup_search_request.js rename to x-pack/legacy/plugins/rollup/server/lib/search_strategies/rollup_search_request.ts diff --git a/x-pack/legacy/plugins/rollup/server/lib/search_strategies/rollup_search_strategy.js b/x-pack/legacy/plugins/rollup/server/lib/search_strategies/rollup_search_strategy.ts similarity index 100% rename from x-pack/legacy/plugins/rollup/server/lib/search_strategies/rollup_search_strategy.js rename to x-pack/legacy/plugins/rollup/server/lib/search_strategies/rollup_search_strategy.ts diff --git a/x-pack/legacy/plugins/rollup/server/plugin.ts b/x-pack/legacy/plugins/rollup/server/plugin.ts new file mode 100644 index 00000000000000..fc8f7a1e50035e --- /dev/null +++ b/x-pack/legacy/plugins/rollup/server/plugin.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { CoreSetup, Plugin } from 'src/core/server'; +import { i18n } from '@kbn/i18n'; + +import { registerLicenseChecker } from '../../../server/lib/register_license_checker'; +import { PLUGIN } from '../common'; +import { ServerShim, RouteDependencies } from './types'; + +import { + registerIndicesRoute, + // registerFieldsForWildcardRoute, + registerSearchRoute, + registerJobsRoute, +} from './routes/api'; + +export class RollupsServerPlugin implements Plugin { + async setup( + { http, elasticsearch: elasticsearchService }: CoreSetup, + { __LEGACY: serverShim }: { __LEGACY: ServerShim } + ) { + const elasticsearch = await elasticsearchService.adminClient; + const router = http.createRouter(); + const routeDependencies: RouteDependencies = { + elasticsearch, + elasticsearchService, + router, + }; + + // Register license checker + registerLicenseChecker( + serverShim as any, + PLUGIN.ID, + PLUGIN.getI18nName(i18n), + PLUGIN.MINIMUM_LICENSE_REQUIRED + ); + + registerIndicesRoute(routeDependencies, serverShim); + // registerFieldsForWildcardRoute(routeDependencies); + registerSearchRoute(routeDependencies, serverShim); + registerJobsRoute(routeDependencies, serverShim); + } + start() {} + stop() {} +} diff --git a/x-pack/legacy/plugins/rollup/server/routes/api/index.js b/x-pack/legacy/plugins/rollup/server/routes/api/index.ts similarity index 100% rename from x-pack/legacy/plugins/rollup/server/routes/api/index.js rename to x-pack/legacy/plugins/rollup/server/routes/api/index.ts diff --git a/x-pack/legacy/plugins/rollup/server/routes/api/index_patterns.js b/x-pack/legacy/plugins/rollup/server/routes/api/index_patterns.js deleted file mode 100644 index dfc486c030812e..00000000000000 --- a/x-pack/legacy/plugins/rollup/server/routes/api/index_patterns.js +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -import Joi from 'joi'; -import { callWithRequestFactory } from '../../lib/call_with_request_factory'; -import { isEsErrorFactory } from '../../lib/is_es_error_factory'; -import { wrapEsError, wrapUnknownError } from '../../lib/error_wrappers'; -import { licensePreRoutingFactory } from '../../lib/license_pre_routing_factory'; -import indexBy from 'lodash/collection/indexBy'; -import { getCapabilitiesForRollupIndices } from '../../lib/map_capabilities'; -import { mergeCapabilitiesWithFields } from '../../lib/merge_capabilities_with_fields'; -import querystring from 'querystring'; - -/** - * Get list of fields for rollup index pattern, in the format of regular index pattern fields - */ -export function registerFieldsForWildcardRoute(server) { - const isEsError = isEsErrorFactory(server); - const licensePreRouting = licensePreRoutingFactory(server); - - server.route({ - path: '/api/index_patterns/rollup/_fields_for_wildcard', - method: 'GET', - config: { - pre: [licensePreRouting], - validate: { - query: Joi.object() - .keys({ - pattern: Joi.string().required(), - meta_fields: Joi.array() - .items(Joi.string()) - .default([]), - params: Joi.object() - .keys({ - rollup_index: Joi.string().required(), - }) - .required(), - }) - .default(), - }, - }, - handler: async request => { - const { pattern, meta_fields: metaFields, params } = request.query; - - // Format call to standard index pattern `fields for wildcard` - const standardRequestQuery = querystring.stringify({ pattern, meta_fields: metaFields }); - const standardRequest = { - url: `${request.getBasePath()}/api/index_patterns/_fields_for_wildcard?${standardRequestQuery}`, - method: 'GET', - headers: request.headers, - }; - - try { - // Make call and use field information from response - const standardResponse = await server.inject(standardRequest); - const fields = standardResponse.result && standardResponse.result.fields; - - const rollupIndex = params.rollup_index; - const callWithRequest = callWithRequestFactory(server, request); - - const rollupFields = []; - const fieldsFromFieldCapsApi = indexBy(fields, 'name'); - const rollupIndexCapabilities = getCapabilitiesForRollupIndices( - await callWithRequest('rollup.rollupIndexCapabilities', { - indexPattern: rollupIndex, - }) - )[rollupIndex].aggs; - - // Keep meta fields - metaFields.forEach( - field => fieldsFromFieldCapsApi[field] && rollupFields.push(fieldsFromFieldCapsApi[field]) - ); - - const mergedRollupFields = mergeCapabilitiesWithFields( - rollupIndexCapabilities, - fieldsFromFieldCapsApi, - rollupFields - ); - - return { - fields: mergedRollupFields, - }; - } catch (err) { - if (isEsError(err)) { - return wrapEsError(err); - } - return wrapUnknownError(err); - } - }, - }); -} diff --git a/x-pack/legacy/plugins/rollup/server/routes/api/index_patterns.ts b/x-pack/legacy/plugins/rollup/server/routes/api/index_patterns.ts new file mode 100644 index 00000000000000..c7c3684da86d05 --- /dev/null +++ b/x-pack/legacy/plugins/rollup/server/routes/api/index_patterns.ts @@ -0,0 +1,153 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { schema } from '@kbn/config-schema'; +import { RequestHandler } from 'src/core/server'; + +import indexBy from 'lodash/collection/indexBy'; +import querystring from 'querystring'; +import { callWithRequestFactory } from '../../lib/call_with_request_factory'; +import { isEsError } from '../../lib/is_es_error'; +import { licensePreRoutingFactory } from '../../lib/license_pre_routing_factory'; +import { getCapabilitiesForRollupIndices } from '../../lib/map_capabilities'; +import { mergeCapabilitiesWithFields } from '../../lib/merge_capabilities_with_fields'; + +/** + * Get list of fields for rollup index pattern, in the format of regular index pattern fields + */ +export function registerFieldsForWildcardRoute(deps: RouteDependencies, legacy: ServerShim) { + const handler: RequestHandler = async (ctx, request, response) => { + // const { pattern, meta_fields: metaFields, params } = request.query; + // // Format call to standard index pattern `fields for wildcard` + // const standardRequestQuery = querystring.stringify({ pattern, meta_fields: metaFields }); + // const standardRequest = { + // url: `${request.getBasePath()}/api/index_patterns/_fields_for_wildcard?${standardRequestQuery}`, + // method: 'GET', + // headers: request.headers, + // }; + // try { + // // Make call and use field information from response + // const standardResponse = await server.inject(standardRequest); + // const fields = standardResponse.result && standardResponse.result.fields; + // const rollupIndex = params.rollup_index; + // const callWithRequest = callWithRequestFactory(deps.elasticsearchService, request); + // const rollupFields = []; + // const fieldsFromFieldCapsApi = indexBy(fields, 'name'); + // const rollupIndexCapabilities = getCapabilitiesForRollupIndices( + // await callWithRequest('rollup.rollupIndexCapabilities', { + // indexPattern: rollupIndex, + // }) + // )[rollupIndex].aggs; + // // Keep meta fields + // metaFields.forEach( + // field => fieldsFromFieldCapsApi[field] && rollupFields.push(fieldsFromFieldCapsApi[field]) + // ); + // const mergedRollupFields = mergeCapabilitiesWithFields( + // rollupIndexCapabilities, + // fieldsFromFieldCapsApi, + // rollupFields + // ); + // return { + // fields: mergedRollupFields, + // }; + // } catch (err) { + // if (isEsError(err)) { + // return response.customError({ statusCode: err.statusCode, body: err }); + // } + // return response.internalError({ body: err }); + // } + }; + + // deps.router.get( + // { + // path: '/api/index_patterns/rollup/_fields_for_wildcard', + // // validate: { + // // query: schema + // // .object() + // // .keys({ + // // pattern: schema.string().required(), + // // meta_fields: schema + // // .array() + // // .items(schema.string()) + // // .default([]), + // // params: schema + // // .object() + // // .keys({ + // // rollup_index: schema.string().required(), + // // }) + // // .required(), + // // }) + // // .default(), + // // }, + // }, + // licensePreRoutingFactory(legacy, handler) + // ); + + // const isEsError = isEsErrorFactory(server); + // const licensePreRouting = licensePreRoutingFactory(server); + // server.route({ + // path: '/api/index_patterns/rollup/_fields_for_wildcard', + // method: 'GET', + // config: { + // pre: [licensePreRouting], + // validate: { + // query: Joi.object() + // .keys({ + // pattern: Joi.string().required(), + // meta_fields: Joi.array() + // .items(Joi.string()) + // .default([]), + // params: Joi.object() + // .keys({ + // rollup_index: Joi.string().required(), + // }) + // .required(), + // }) + // .default(), + // }, + // }, + // handler: async request => { + // const { pattern, meta_fields: metaFields, params } = request.query; + // // Format call to standard index pattern `fields for wildcard` + // const standardRequestQuery = querystring.stringify({ pattern, meta_fields: metaFields }); + // const standardRequest = { + // url: `${request.getBasePath()}/api/index_patterns/_fields_for_wildcard?${standardRequestQuery}`, + // method: 'GET', + // headers: request.headers, + // }; + // try { + // // Make call and use field information from response + // const standardResponse = await server.inject(standardRequest); + // const fields = standardResponse.result && standardResponse.result.fields; + // const rollupIndex = params.rollup_index; + // const callWithRequest = callWithRequestFactory(server, request); + // const rollupFields = []; + // const fieldsFromFieldCapsApi = indexBy(fields, 'name'); + // const rollupIndexCapabilities = getCapabilitiesForRollupIndices( + // await callWithRequest('rollup.rollupIndexCapabilities', { + // indexPattern: rollupIndex, + // }) + // )[rollupIndex].aggs; + // // Keep meta fields + // metaFields.forEach( + // field => fieldsFromFieldCapsApi[field] && rollupFields.push(fieldsFromFieldCapsApi[field]) + // ); + // const mergedRollupFields = mergeCapabilitiesWithFields( + // rollupIndexCapabilities, + // fieldsFromFieldCapsApi, + // rollupFields + // ); + // return { + // fields: mergedRollupFields, + // }; + // } catch (err) { + // if (isEsError(err)) { + // return wrapEsError(err); + // } + // return wrapUnknownError(err); + // } + // }, + // }); +} diff --git a/x-pack/legacy/plugins/rollup/server/routes/api/indices.js b/x-pack/legacy/plugins/rollup/server/routes/api/indices.js deleted file mode 100644 index 3d1c6932575bc8..00000000000000 --- a/x-pack/legacy/plugins/rollup/server/routes/api/indices.js +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -import { callWithRequestFactory } from '../../lib/call_with_request_factory'; -import { isEsErrorFactory } from '../../lib/is_es_error_factory'; -import { wrapEsError, wrapUnknownError } from '../../lib/error_wrappers'; -import { licensePreRoutingFactory } from '../../lib/license_pre_routing_factory'; -import { getCapabilitiesForRollupIndices } from '../../lib/map_capabilities'; - -function isNumericField(fieldCapability) { - const numericTypes = [ - 'long', - 'integer', - 'short', - 'byte', - 'double', - 'float', - 'half_float', - 'scaled_float', - ]; - return numericTypes.some(numericType => fieldCapability[numericType] != null); -} - -export function registerIndicesRoute(server) { - const isEsError = isEsErrorFactory(server); - const licensePreRouting = licensePreRoutingFactory(server); - - /** - * Returns a list of all rollup index names - */ - server.route({ - path: '/api/rollup/indices', - method: 'GET', - config: { - pre: [licensePreRouting], - }, - handler: async request => { - const callWithRequest = callWithRequestFactory(server, request); - try { - const data = await callWithRequest('rollup.rollupIndexCapabilities', { - indexPattern: '_all', - }); - return getCapabilitiesForRollupIndices(data); - } catch (err) { - if (isEsError(err)) { - return wrapEsError(err); - } - return wrapUnknownError(err); - } - }, - }); - - /** - * Returns information on validity of an index pattern for creating a rollup job: - * - Does the index pattern match any indices? - * - Does the index pattern match rollup indices? - * - Which date fields, numeric fields, and keyword fields are available in the matching indices? - */ - server.route({ - path: '/api/rollup/index_pattern_validity/{indexPattern}', - method: 'GET', - config: { - pre: [licensePreRouting], - }, - handler: async request => { - const callWithRequest = callWithRequestFactory(server, request); - - try { - const { indexPattern } = request.params; - const [fieldCapabilities, rollupIndexCapabilities] = await Promise.all([ - callWithRequest('rollup.fieldCapabilities', { indexPattern }), - callWithRequest('rollup.rollupIndexCapabilities', { indexPattern }), - ]); - - const doesMatchIndices = Object.entries(fieldCapabilities.fields).length !== 0; - const doesMatchRollupIndices = Object.entries(rollupIndexCapabilities).length !== 0; - - const dateFields = []; - const numericFields = []; - const keywordFields = []; - - const fieldCapabilitiesEntries = Object.entries(fieldCapabilities.fields); - fieldCapabilitiesEntries.forEach(([fieldName, fieldCapability]) => { - if (fieldCapability.date) { - dateFields.push(fieldName); - return; - } - - if (isNumericField(fieldCapability)) { - numericFields.push(fieldName); - return; - } - - if (fieldCapability.keyword) { - keywordFields.push(fieldName); - } - }); - - return { - doesMatchIndices, - doesMatchRollupIndices, - dateFields, - numericFields, - keywordFields, - }; - } catch (err) { - // 404s are still valid results. - if (err.statusCode === 404) { - return { - doesMatchIndices: false, - doesMatchRollupIndices: false, - dateFields: [], - numericFields: [], - keywordFields: [], - }; - } - - if (isEsError(err)) { - return wrapEsError(err); - } - - return wrapUnknownError(err); - } - }, - }); -} diff --git a/x-pack/legacy/plugins/rollup/server/routes/api/indices.ts b/x-pack/legacy/plugins/rollup/server/routes/api/indices.ts new file mode 100644 index 00000000000000..e78f09a71876b1 --- /dev/null +++ b/x-pack/legacy/plugins/rollup/server/routes/api/indices.ts @@ -0,0 +1,175 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { schema } from '@kbn/config-schema'; +import { RequestHandler } from 'src/core/server'; +import { callWithRequestFactory } from '../../lib/call_with_request_factory'; +import { isEsError } from '../../lib/is_es_error'; +import { licensePreRoutingFactory } from '../../lib/license_pre_routing_factory'; +import { getCapabilitiesForRollupIndices } from '../../lib/map_capabilities'; +import { API_BASE_PATH } from '../../../common'; +import { RouteDependencies, ServerShim } from '../../types'; + +type NumericField = + | 'long' + | 'integer' + | 'short' + | 'byte' + | 'scaled_float' + | 'double' + | 'float' + | 'half_float'; + +interface FieldCapability { + date?: any; + keyword?: any; + long?: any; + integer?: any; + short?: any; + byte?: any; + double?: any; + float?: any; + half_float?: any; + scaled_float?: any; +} + +interface FieldCapabilities { + fields: FieldCapability[]; +} + +function isNumericField(fieldCapability: FieldCapability) { + const numericTypes = [ + 'long', + 'integer', + 'short', + 'byte', + 'double', + 'float', + 'half_float', + 'scaled_float', + ]; + return numericTypes.some(numericType => fieldCapability[numericType as NumericField] != null); +} + +export function registerIndicesRoute(deps: RouteDependencies, legacy: ServerShim) { + const getIndicesHandler: RequestHandler = async (ctx, request, response) => { + const callWithRequest = callWithRequestFactory(deps.elasticsearchService, request); + + try { + const data = await callWithRequest('rollup.rollupIndexCapabilities', { + indexPattern: '_all', + }); + return response.ok({ body: getCapabilitiesForRollupIndices(data) }); + } catch (err) { + if (isEsError(err)) { + return response.customError({ statusCode: err.statusCode, body: err }); + } + return response.internalError({ body: err }); + } + }; + + const validateIndexPatternHandler: RequestHandler = async ( + ctx, + request, + response + ) => { + const callWithRequest = callWithRequestFactory(deps.elasticsearchService, request); + + try { + const { indexPattern } = request.params; + const [fieldCapabilities, rollupIndexCapabilities]: [ + FieldCapabilities, + { [key: string]: any } + ] = await Promise.all([ + callWithRequest('rollup.fieldCapabilities', { indexPattern }), + callWithRequest('rollup.rollupIndexCapabilities', { indexPattern }), + ]); + + const doesMatchIndices = Object.entries(fieldCapabilities.fields).length !== 0; + const doesMatchRollupIndices = Object.entries(rollupIndexCapabilities).length !== 0; + + const dateFields: string[] = []; + const numericFields: string[] = []; + const keywordFields: string[] = []; + + const fieldCapabilitiesEntries = Object.entries(fieldCapabilities.fields); + + fieldCapabilitiesEntries.forEach( + ([fieldName, fieldCapability]: [string, FieldCapability]) => { + if (fieldCapability.date) { + dateFields.push(fieldName); + return; + } + + if (isNumericField(fieldCapability)) { + numericFields.push(fieldName); + return; + } + + if (fieldCapability.keyword) { + keywordFields.push(fieldName); + } + } + ); + + const body = { + doesMatchIndices, + doesMatchRollupIndices, + dateFields, + numericFields, + keywordFields, + }; + + return response.ok({ body }); + } catch (err) { + // 404s are still valid results. + if (err.statusCode === 404) { + const notFoundBody = { + doesMatchIndices: false, + doesMatchRollupIndices: false, + dateFields: [], + numericFields: [], + keywordFields: [], + }; + return response.ok({ body: notFoundBody }); + } + + if (isEsError(err)) { + return response.customError({ statusCode: err.statusCode, body: err }); + } + + return response.internalError({ body: err }); + } + }; + + /** + * Returns a list of all rollup index names + */ + deps.router.get( + { + path: `${API_BASE_PATH}/indices`, + validate: false, + }, + licensePreRoutingFactory(legacy, getIndicesHandler) + ); + + /** + * Returns information on validity of an index pattern for creating a rollup job: + * - Does the index pattern match any indices? + * - Does the index pattern match rollup indices? + * - Which date fields, numeric fields, and keyword fields are available in the matching indices? + */ + deps.router.get( + { + path: `${API_BASE_PATH}/index_pattern_validity/{indexPattern}`, + validate: { + params: schema.object({ + indexPattern: schema.string(), + }), + }, + }, + licensePreRoutingFactory(legacy, validateIndexPatternHandler) + ); +} diff --git a/x-pack/legacy/plugins/rollup/server/routes/api/jobs.js b/x-pack/legacy/plugins/rollup/server/routes/api/jobs.js deleted file mode 100644 index 1a9a402ad65180..00000000000000 --- a/x-pack/legacy/plugins/rollup/server/routes/api/jobs.js +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -import { callWithRequestFactory } from '../../lib/call_with_request_factory'; -import { isEsErrorFactory } from '../../lib/is_es_error_factory'; -import { licensePreRoutingFactory } from '../../lib/license_pre_routing_factory'; -import { wrapEsError, wrapUnknownError } from '../../lib/error_wrappers'; - -export function registerJobsRoute(server) { - const isEsError = isEsErrorFactory(server); - const licensePreRouting = licensePreRoutingFactory(server); - - server.route({ - path: '/api/rollup/jobs', - method: 'GET', - config: { - pre: [licensePreRouting], - }, - handler: async request => { - try { - const callWithRequest = callWithRequestFactory(server, request); - return await callWithRequest('rollup.jobs'); - } catch (err) { - if (isEsError(err)) { - return wrapEsError(err); - } - - return wrapUnknownError(err); - } - }, - }); - - server.route({ - path: '/api/rollup/create', - method: 'PUT', - config: { - pre: [licensePreRouting], - }, - handler: async request => { - try { - const { id, ...rest } = request.payload.job; - - const callWithRequest = callWithRequestFactory(server, request); - - // Create job. - await callWithRequest('rollup.createJob', { - id, - body: rest, - }); - - // Then request the newly created job. - const results = await callWithRequest('rollup.job', { id }); - return results.jobs[0]; - } catch (err) { - if (isEsError(err)) { - return wrapEsError(err); - } - - return wrapUnknownError(err); - } - }, - }); - - server.route({ - path: '/api/rollup/start', - method: 'POST', - config: { - pre: [licensePreRouting], - }, - handler: async request => { - try { - const { jobIds } = request.payload; - - const callWithRequest = callWithRequestFactory(server, request); - return await Promise.all( - jobIds.map(id => callWithRequest('rollup.startJob', { id })) - ).then(() => ({ success: true })); - } catch (err) { - if (isEsError(err)) { - return wrapEsError(err); - } - - return wrapUnknownError(err); - } - }, - }); - - server.route({ - path: '/api/rollup/stop', - method: 'POST', - config: { - pre: [licensePreRouting], - }, - handler: async request => { - try { - const { jobIds } = request.payload; - // For our API integration tests we need to wait for the jobs to be stopped - // in order to be able to delete them sequencially. - const { waitForCompletion } = request.query; - const callWithRequest = callWithRequestFactory(server, request); - - const stopRollupJob = id => - callWithRequest('rollup.stopJob', { - id, - waitForCompletion: waitForCompletion === 'true', - }); - - return await Promise.all(jobIds.map(stopRollupJob)).then(() => ({ success: true })); - } catch (err) { - if (isEsError(err)) { - return wrapEsError(err); - } - - return wrapUnknownError(err); - } - }, - }); - - server.route({ - path: '/api/rollup/delete', - method: 'POST', - config: { - pre: [licensePreRouting], - }, - handler: async request => { - try { - const { jobIds } = request.payload; - - const callWithRequest = callWithRequestFactory(server, request); - return await Promise.all( - jobIds.map(id => callWithRequest('rollup.deleteJob', { id })) - ).then(() => ({ success: true })); - } catch (err) { - // There is an issue opened on ES to handle the following error correctly - // https://github.com/elastic/elasticsearch/issues/42908 - // Until then we'll modify the response here. - if (err.response && err.response.includes('Job must be [STOPPED] before deletion')) { - err.status = 400; - err.statusCode = 400; - err.displayName = 'Bad request'; - err.message = JSON.parse(err.response).task_failures[0].reason.reason; - } - if (isEsError(err)) { - throw wrapEsError(err); - } - - throw wrapUnknownError(err); - } - }, - }); -} diff --git a/x-pack/legacy/plugins/rollup/server/routes/api/jobs.ts b/x-pack/legacy/plugins/rollup/server/routes/api/jobs.ts new file mode 100644 index 00000000000000..e58bc95b9a3753 --- /dev/null +++ b/x-pack/legacy/plugins/rollup/server/routes/api/jobs.ts @@ -0,0 +1,178 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { schema } from '@kbn/config-schema'; +import { RequestHandler } from 'src/core/server'; +import { callWithRequestFactory } from '../../lib/call_with_request_factory'; +import { isEsError } from '../../lib/is_es_error'; +import { licensePreRoutingFactory } from '../../lib/license_pre_routing_factory'; +import { API_BASE_PATH } from '../../../common'; +import { RouteDependencies, ServerShim } from '../../types'; + +export function registerJobsRoute(deps: RouteDependencies, legacy: ServerShim) { + const getJobsHandler: RequestHandler = async (ctx, request, response) => { + const callWithRequest = callWithRequestFactory(deps.elasticsearchService, request); + + try { + const data = await callWithRequest('rollup.jobs'); + return response.ok({ body: data }); + } catch (err) { + if (isEsError(err)) { + return response.customError({ statusCode: err.statusCode, body: err }); + } + return response.internalError({ body: err }); + } + }; + + const createJobsHandler: RequestHandler = async (ctx, request, response) => { + try { + const { id, ...rest } = request.body.job; + const callWithRequest = callWithRequestFactory(deps.elasticsearchService, request); + // Create job. + await callWithRequest('rollup.createJob', { + id, + body: rest, + }); + // Then request the newly created job. + const results = await callWithRequest('rollup.job', { id }); + return response.ok({ body: results.jobs[0] }); + } catch (err) { + if (isEsError(err)) { + return response.customError({ statusCode: err.statusCode, body: err }); + } + return response.internalError({ body: err }); + } + }; + + const startJobsHandler: RequestHandler = async (ctx, request, response) => { + try { + const { jobIds } = request.body; + const callWithRequest = callWithRequestFactory(deps.elasticsearchService, request); + + const data = await Promise.all( + jobIds.map((id: string) => callWithRequest('rollup.startJob', { id })) + ).then(() => ({ success: true })); + return response.ok({ body: data }); + } catch (err) { + if (isEsError(err)) { + return response.customError({ statusCode: err.statusCode, body: err }); + } + return response.internalError({ body: err }); + } + }; + + const stopJobsHandler: RequestHandler = async (ctx, request, response) => { + try { + const { jobIds } = request.body; + // For our API integration tests we need to wait for the jobs to be stopped + // in order to be able to delete them sequencially. + const { waitForCompletion } = request.query; + const callWithRequest = callWithRequestFactory(deps.elasticsearchService, request); + const stopRollupJob = (id: string) => + callWithRequest('rollup.stopJob', { + id, + waitForCompletion: waitForCompletion === 'true', + }); + const data = await Promise.all(jobIds.map(stopRollupJob)).then(() => ({ success: true })); + return response.ok({ body: data }); + } catch (err) { + if (isEsError(err)) { + return response.customError({ statusCode: err.statusCode, body: err }); + } + return response.internalError({ body: err }); + } + }; + + const deleteJobsHandler: RequestHandler = async (ctx, request, response) => { + try { + const { jobIds } = request.body; + const callWithRequest = callWithRequestFactory(deps.elasticsearchService, request); + const data = await Promise.all( + jobIds.map((id: string) => callWithRequest('rollup.deleteJob', { id })) + ).then(() => ({ success: true })); + return response.ok({ body: data }); + } catch (err) { + // There is an issue opened on ES to handle the following error correctly + // https://github.com/elastic/elasticsearch/issues/42908 + // Until then we'll modify the response here. + if (err.response && err.response.includes('Job must be [STOPPED] before deletion')) { + err.status = 400; + err.statusCode = 400; + err.displayName = 'Bad request'; + err.message = JSON.parse(err.response).task_failures[0].reason.reason; + } + if (isEsError(err)) { + return response.customError({ statusCode: err.statusCode, body: err }); + } + return response.internalError({ body: err }); + } + }; + + deps.router.get( + { + path: `${API_BASE_PATH}/jobs`, + validate: false, + }, + licensePreRoutingFactory(legacy, getJobsHandler) + ); + + deps.router.put( + { + path: `${API_BASE_PATH}/create`, + validate: { + body: schema.object({ + job: schema.object( + { + id: schema.string(), + }, + { allowUnknowns: true } + ), + }), + }, + }, + licensePreRoutingFactory(legacy, createJobsHandler) + ); + + deps.router.post( + { + path: `${API_BASE_PATH}/start`, + validate: { + body: schema.object({ + jobIds: schema.arrayOf(schema.string()), + }), + query: schema.maybe( + schema.object({ + waitForCompletion: schema.maybe(schema.string()), + }) + ), + }, + }, + licensePreRoutingFactory(legacy, startJobsHandler) + ); + + deps.router.post( + { + path: `${API_BASE_PATH}/stop`, + validate: { + body: schema.object({ + jobIds: schema.arrayOf(schema.string()), + }), + }, + }, + licensePreRoutingFactory(legacy, stopJobsHandler) + ); + + deps.router.post( + { + path: `${API_BASE_PATH}/delete`, + validate: { + body: schema.object({ + jobIds: schema.arrayOf(schema.string()), + }), + }, + }, + licensePreRoutingFactory(legacy, deleteJobsHandler) + ); +} diff --git a/x-pack/legacy/plugins/rollup/server/routes/api/search.js b/x-pack/legacy/plugins/rollup/server/routes/api/search.js deleted file mode 100644 index 58098421f0a8fb..00000000000000 --- a/x-pack/legacy/plugins/rollup/server/routes/api/search.js +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { callWithRequestFactory } from '../../lib/call_with_request_factory'; -import { isEsErrorFactory } from '../../lib/is_es_error_factory'; -import { licensePreRoutingFactory } from '../../lib/license_pre_routing_factory'; -import { wrapEsError, wrapUnknownError } from '../../lib/error_wrappers'; - -export function registerSearchRoute(server) { - const isEsError = isEsErrorFactory(server); - const licensePreRouting = licensePreRoutingFactory(server); - - server.route({ - path: '/api/rollup/search', - method: 'POST', - config: { - pre: [licensePreRouting], - }, - handler: async request => { - const callWithRequest = callWithRequestFactory(server, request); - - try { - const requests = request.payload.map(({ index, query }) => - callWithRequest('rollup.search', { - index, - rest_total_hits_as_int: true, - body: query, - }) - ); - - return await Promise.all(requests); - } catch (err) { - if (isEsError(err)) { - return wrapEsError(err); - } - - return wrapUnknownError(err); - } - }, - }); -} diff --git a/x-pack/legacy/plugins/rollup/server/routes/api/search.ts b/x-pack/legacy/plugins/rollup/server/routes/api/search.ts new file mode 100644 index 00000000000000..97999a4b5ce8d2 --- /dev/null +++ b/x-pack/legacy/plugins/rollup/server/routes/api/search.ts @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { schema } from '@kbn/config-schema'; +import { RequestHandler } from 'src/core/server'; +import { callWithRequestFactory } from '../../lib/call_with_request_factory'; +import { isEsError } from '../../lib/is_es_error'; +import { licensePreRoutingFactory } from '../../lib/license_pre_routing_factory'; +import { API_BASE_PATH } from '../../../common'; +import { RouteDependencies, ServerShim } from '../../types'; + +export function registerSearchRoute(deps: RouteDependencies, legacy: ServerShim) { + const handler: RequestHandler = async (ctx, request, response) => { + const callWithRequest = callWithRequestFactory(deps.elasticsearchService, request); + try { + const requests = request.body.map(({ index, query }: { index: string; query: any }) => + callWithRequest('rollup.search', { + index, + rest_total_hits_as_int: true, + body: query, + }) + ); + const data = await Promise.all(requests); + return response.ok({ body: data }); + } catch (err) { + if (isEsError(err)) { + return response.customError({ statusCode: err.statusCode, body: err }); + } + return response.internalError({ body: err }); + } + }; + + deps.router.post( + { + path: `${API_BASE_PATH}/search`, + validate: { + body: schema.arrayOf( + schema.object({ + index: schema.string(), + query: schema.any(), + }) + ), + }, + }, + licensePreRoutingFactory(legacy, handler) + ); +} diff --git a/x-pack/legacy/plugins/rollup/server/types.ts b/x-pack/legacy/plugins/rollup/server/types.ts new file mode 100644 index 00000000000000..0d85bcddac653f --- /dev/null +++ b/x-pack/legacy/plugins/rollup/server/types.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { IRouter, ElasticsearchServiceSetup, IClusterClient } from 'src/core/server'; +import { XPackMainPlugin } from '../../xpack_main/server/xpack_main'; + +export interface ServerShim { + route: any; + plugins: { + xpack_main: XPackMainPlugin; + rollup: any; + }; +} + +export interface RouteDependencies { + router: IRouter; + elasticsearchService: ElasticsearchServiceSetup; + elasticsearch: IClusterClient; +} diff --git a/x-pack/legacy/plugins/rollup/server/usage/collector.js b/x-pack/legacy/plugins/rollup/server/usage/collector.ts similarity index 100% rename from x-pack/legacy/plugins/rollup/server/usage/collector.js rename to x-pack/legacy/plugins/rollup/server/usage/collector.ts diff --git a/x-pack/legacy/plugins/rollup/server/usage/index.js b/x-pack/legacy/plugins/rollup/server/usage/index.ts similarity index 100% rename from x-pack/legacy/plugins/rollup/server/usage/index.js rename to x-pack/legacy/plugins/rollup/server/usage/index.ts From 8524ce531341ee53b9389bcd97912f772b81dc41 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Thu, 23 Jan 2020 15:37:44 -0500 Subject: [PATCH 02/13] added back support for rollup usage collector --- x-pack/legacy/plugins/rollup/index.ts | 29 ++++++------- x-pack/legacy/plugins/rollup/kibana.json | 3 ++ .../server/{usage => collectors}/index.ts | 2 +- .../collector.ts => collectors/register.ts} | 43 ++++++++++++------- x-pack/legacy/plugins/rollup/server/index.ts | 4 +- x-pack/legacy/plugins/rollup/server/plugin.ts | 27 +++++++++++- x-pack/plugins/rollup/kibana.json | 6 +++ x-pack/plugins/rollup/server/index.ts | 12 ++++++ x-pack/plugins/rollup/server/plugin.ts | 33 ++++++++++++++ 9 files changed, 122 insertions(+), 37 deletions(-) rename x-pack/legacy/plugins/rollup/server/{usage => collectors}/index.ts (80%) rename x-pack/legacy/plugins/rollup/server/{usage/collector.ts => collectors/register.ts} (83%) create mode 100644 x-pack/plugins/rollup/kibana.json create mode 100644 x-pack/plugins/rollup/server/index.ts create mode 100644 x-pack/plugins/rollup/server/plugin.ts diff --git a/x-pack/legacy/plugins/rollup/index.ts b/x-pack/legacy/plugins/rollup/index.ts index 3edcc714eae61e..4636e781accfba 100644 --- a/x-pack/legacy/plugins/rollup/index.ts +++ b/x-pack/legacy/plugins/rollup/index.ts @@ -7,19 +7,13 @@ import { resolve } from 'path'; import { i18n } from '@kbn/i18n'; import { Legacy } from 'kibana'; +import { RollupSetup } from '../../../plugins/rollup/server'; import { PLUGIN, CONFIG_ROLLUPS } from './common'; import { plugin } from './server'; +import { PluginInitializerContext } from '../siem/public/plugin'; -// import { registerLicenseChecker } from './server/lib/register_license_checker'; // import { rollupDataEnricher } from './rollup_data_enricher'; // import { registerRollupSearchStrategy } from './server/lib/search_strategies'; -// import { -// registerIndicesRoute, -// registerFieldsForWildcardRoute, -// registerSearchRoute, -// registerJobsRoute, -// } from './server/routes/api'; -// import { registerRollupUsageCollector } from './server/usage'; export type ServerFacade = Legacy.Server; @@ -55,7 +49,17 @@ export function rollup(kibana: any) { search: ['plugins/rollup/search'], }, init(server: ServerFacade) { - plugin({} as any).setup(server.newPlatform.setup.core, { + const { core, plugins } = server.newPlatform.setup; + const { usageCollection } = plugins; + + const rollupSetup = (plugins.rollup as unknown) as RollupSetup; + + const initContext = ({ + config: rollupSetup.__legacy.config, + } as unknown) as PluginInitializerContext; + + plugin(initContext).setup(core, { + usageCollection, __LEGACY: { route: server.route.bind(server), plugins: { @@ -65,20 +69,13 @@ export function rollup(kibana: any) { }, }); - // const { usageCollection } = server.newPlatform.setup.plugins; - // registerLicenseChecker(server); - // registerIndicesRoute(server); // registerFieldsForWildcardRoute(server); - // registerSearchRoute(server); - // registerJobsRoute(server); - // registerRollupUsageCollector(usageCollection, server); // if ( // server.plugins.index_management && // server.plugins.index_management.addIndexManagementDataEnricher // ) { // server.plugins.index_management.addIndexManagementDataEnricher(rollupDataEnricher); // } - // registerRollupSearchStrategy(this.kbnServer, server); }, }); } diff --git a/x-pack/legacy/plugins/rollup/kibana.json b/x-pack/legacy/plugins/rollup/kibana.json index e9e999a341ae71..8ed31ebe5ad8b5 100644 --- a/x-pack/legacy/plugins/rollup/kibana.json +++ b/x-pack/legacy/plugins/rollup/kibana.json @@ -4,6 +4,9 @@ "requiredPlugins": [ "home" ], + "optionalPlugins": [ + "usageCollection" + ], "server": true, "ui": false } diff --git a/x-pack/legacy/plugins/rollup/server/usage/index.ts b/x-pack/legacy/plugins/rollup/server/collectors/index.ts similarity index 80% rename from x-pack/legacy/plugins/rollup/server/usage/index.ts rename to x-pack/legacy/plugins/rollup/server/collectors/index.ts index 9304b35aeb6c76..47c1bcb6c72489 100644 --- a/x-pack/legacy/plugins/rollup/server/usage/index.ts +++ b/x-pack/legacy/plugins/rollup/server/collectors/index.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { registerRollupUsageCollector } from './collector'; +export { registerRollupUsageCollector } from './register'; diff --git a/x-pack/legacy/plugins/rollup/server/usage/collector.ts b/x-pack/legacy/plugins/rollup/server/collectors/register.ts similarity index 83% rename from x-pack/legacy/plugins/rollup/server/usage/collector.ts rename to x-pack/legacy/plugins/rollup/server/collectors/register.ts index 21c4de62c8fdcb..02ad5dc92fd136 100644 --- a/x-pack/legacy/plugins/rollup/server/usage/collector.ts +++ b/x-pack/legacy/plugins/rollup/server/collectors/register.ts @@ -5,25 +5,31 @@ */ import { get } from 'lodash'; +import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; +import { CallCluster } from 'src/legacy/core_plugins/elasticsearch'; + +interface IdToFlagMap { + [key: string]: boolean; +} const ROLLUP_USAGE_TYPE = 'rollups'; // elasticsearch index.max_result_window default value const ES_MAX_RESULT_WINDOW_DEFAULT_VALUE = 1000; -function getIdFromSavedObjectId(savedObjectId) { +function getIdFromSavedObjectId(savedObjectId: string) { // The saved object ID is formatted `{TYPE}:{ID}`. return savedObjectId.split(':')[1]; } -function createIdToFlagMap(ids) { +function createIdToFlagMap(ids: string[]) { return ids.reduce((map, id) => { map[id] = true; return map; - }, {}); + }, {} as any); } -async function fetchRollupIndexPatterns(kibanaIndex, callCluster) { +async function fetchRollupIndexPatterns(kibanaIndex: string, callCluster: CallCluster) { const searchParams = { size: ES_MAX_RESULT_WINDOW_DEFAULT_VALUE, index: kibanaIndex, @@ -50,7 +56,11 @@ async function fetchRollupIndexPatterns(kibanaIndex, callCluster) { }); } -async function fetchRollupSavedSearches(kibanaIndex, callCluster, rollupIndexPatternToFlagMap) { +async function fetchRollupSavedSearches( + kibanaIndex: string, + callCluster: CallCluster, + rollupIndexPatternToFlagMap: IdToFlagMap +) { const searchParams = { size: ES_MAX_RESULT_WINDOW_DEFAULT_VALUE, index: kibanaIndex, @@ -86,19 +96,19 @@ async function fetchRollupSavedSearches(kibanaIndex, callCluster, rollupIndexPat const searchSource = JSON.parse(searchSourceJSON); if (rollupIndexPatternToFlagMap[searchSource.index]) { - const id = getIdFromSavedObjectId(savedObjectId); + const id = getIdFromSavedObjectId(savedObjectId) as string; rollupSavedSearches.push(id); } return rollupSavedSearches; - }, []); + }, [] as string[]); } async function fetchRollupVisualizations( - kibanaIndex, - callCluster, - rollupIndexPatternToFlagMap, - rollupSavedSearchesToFlagMap + kibanaIndex: string, + callCluster: CallCluster, + rollupIndexPatternToFlagMap: IdToFlagMap, + rollupSavedSearchesToFlagMap: IdToFlagMap ) { const searchParams = { size: ES_MAX_RESULT_WINDOW_DEFAULT_VALUE, @@ -135,7 +145,7 @@ async function fetchRollupVisualizations( savedSearchRefName, kibanaSavedObjectMeta: { searchSourceJSON }, }, - references = [], + references = [] as any[], }, } = visualization; @@ -164,13 +174,14 @@ async function fetchRollupVisualizations( }; } -export function registerRollupUsageCollector(usageCollection, server) { - const kibanaIndex = server.config().get('kibana.index'); - +export function registerRollupUsageCollector( + usageCollection: UsageCollectionSetup, + kibanaIndex: string +): void { const collector = usageCollection.makeUsageCollector({ type: ROLLUP_USAGE_TYPE, isReady: () => true, - fetch: async callCluster => { + fetch: async (callCluster: CallCluster) => { const rollupIndexPatterns = await fetchRollupIndexPatterns(kibanaIndex, callCluster); const rollupIndexPatternToFlagMap = createIdToFlagMap(rollupIndexPatterns); diff --git a/x-pack/legacy/plugins/rollup/server/index.ts b/x-pack/legacy/plugins/rollup/server/index.ts index 02bf2f30572196..6bbd00ac6576e0 100644 --- a/x-pack/legacy/plugins/rollup/server/index.ts +++ b/x-pack/legacy/plugins/rollup/server/index.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { PluginInitializerContext } from 'kibana/server'; +import { PluginInitializerContext } from 'src/core/server'; import { RollupsServerPlugin } from './plugin'; -export const plugin = (ctx: PluginInitializerContext) => new RollupsServerPlugin(); +export const plugin = (ctx: PluginInitializerContext) => new RollupsServerPlugin(ctx); diff --git a/x-pack/legacy/plugins/rollup/server/plugin.ts b/x-pack/legacy/plugins/rollup/server/plugin.ts index fc8f7a1e50035e..9d8f6c79e33548 100644 --- a/x-pack/legacy/plugins/rollup/server/plugin.ts +++ b/x-pack/legacy/plugins/rollup/server/plugin.ts @@ -3,9 +3,11 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { CoreSetup, Plugin } from 'src/core/server'; +import { CoreSetup, Plugin, PluginInitializerContext } from 'src/core/server'; +import { first } from 'rxjs/operators'; import { i18n } from '@kbn/i18n'; +import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { registerLicenseChecker } from '../../../server/lib/register_license_checker'; import { PLUGIN } from '../common'; import { ServerShim, RouteDependencies } from './types'; @@ -17,10 +19,17 @@ import { registerJobsRoute, } from './routes/api'; +import { registerRollupUsageCollector } from './collectors'; + export class RollupsServerPlugin implements Plugin { + constructor(private readonly initializerContext: PluginInitializerContext) {} + async setup( { http, elasticsearch: elasticsearchService }: CoreSetup, - { __LEGACY: serverShim }: { __LEGACY: ServerShim } + { + __LEGACY: serverShim, + usageCollection, + }: { __LEGACY: ServerShim; usageCollection?: UsageCollectionSetup } ) { const elasticsearch = await elasticsearchService.adminClient; const router = http.createRouter(); @@ -42,6 +51,20 @@ export class RollupsServerPlugin implements Plugin { // registerFieldsForWildcardRoute(routeDependencies); registerSearchRoute(routeDependencies, serverShim); registerJobsRoute(routeDependencies, serverShim); + + if (usageCollection) { + this.initializerContext.config.legacy.globalConfig$ + .pipe(first()) + .toPromise() + .then(config => { + registerRollupUsageCollector(usageCollection, config.kibana.index); + }) + .catch(e => { + this.initializerContext.logger + .get('rollup') + .warn(`Registering Rollup collector failed: ${e}`); + }); + } } start() {} stop() {} diff --git a/x-pack/plugins/rollup/kibana.json b/x-pack/plugins/rollup/kibana.json new file mode 100644 index 00000000000000..6ab2fc8907c0db --- /dev/null +++ b/x-pack/plugins/rollup/kibana.json @@ -0,0 +1,6 @@ +{ + "id": "rollup", + "version": "8.0.0", + "kibanaVersion": "kibana", + "server": true +} diff --git a/x-pack/plugins/rollup/server/index.ts b/x-pack/plugins/rollup/server/index.ts new file mode 100644 index 00000000000000..40568424537765 --- /dev/null +++ b/x-pack/plugins/rollup/server/index.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { PluginInitializerContext } from 'src/core/server'; +import { RollupPlugin } from './plugin'; + +export const plugin = (initContext: PluginInitializerContext) => new RollupPlugin(initContext); + +export { RollupSetup } from './plugin'; diff --git a/x-pack/plugins/rollup/server/plugin.ts b/x-pack/plugins/rollup/server/plugin.ts new file mode 100644 index 00000000000000..ca4b8786c2ca28 --- /dev/null +++ b/x-pack/plugins/rollup/server/plugin.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { Plugin, PluginInitializerContext } from 'src/core/server'; + +export class RollupPlugin implements Plugin { + private readonly initContext: PluginInitializerContext; + + constructor(initContext: PluginInitializerContext) { + this.initContext = initContext; + } + + public setup() { + return { + __legacy: { + config: this.initContext.config, + }, + }; + } + + public start() {} + public stop() {} +} + +export interface RollupSetup { + /** @deprecated */ + __legacy: { + config: PluginInitializerContext['config']; + }; +} From ed8e4e96f0bfbd8c9dc4e12211da17d2174afa3c Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Fri, 24 Jan 2020 12:01:50 -0500 Subject: [PATCH 03/13] added back support for index_patterns route --- src/plugins/data/server/index.ts | 1 + .../data/server/index_patterns/index.ts | 1 + .../index_patterns/lib/fields_for_wildcard.ts | 55 ++++++ .../data/server/index_patterns/routes.ts | 41 +--- .../data/server/index_patterns/utils.ts | 10 + x-pack/legacy/plugins/rollup/index.ts | 1 - .../lib/merge_capabilities_with_fields.ts | 13 +- x-pack/legacy/plugins/rollup/server/plugin.ts | 4 +- .../server/routes/api/index_patterns.ts | 187 ++++++------------ .../plugins/rollup/server/shared_imports.ts | 7 + 10 files changed, 143 insertions(+), 177 deletions(-) create mode 100644 src/plugins/data/server/index_patterns/lib/fields_for_wildcard.ts create mode 100644 x-pack/legacy/plugins/rollup/server/shared_imports.ts diff --git a/src/plugins/data/server/index.ts b/src/plugins/data/server/index.ts index 3cd088744a4391..88711d502fa4be 100644 --- a/src/plugins/data/server/index.ts +++ b/src/plugins/data/server/index.ts @@ -60,6 +60,7 @@ export { FieldDescriptor, shouldReadFieldFromDocValues, indexPatterns, + getFieldsForWildcard, } from './index_patterns'; export * from './search'; export { diff --git a/src/plugins/data/server/index_patterns/index.ts b/src/plugins/data/server/index_patterns/index.ts index b303ae30ea810b..a28b5c9508b9b6 100644 --- a/src/plugins/data/server/index_patterns/index.ts +++ b/src/plugins/data/server/index_patterns/index.ts @@ -20,4 +20,5 @@ import * as indexPatterns from './utils'; export { IndexPatternsFetcher, FieldDescriptor, shouldReadFieldFromDocValues } from './fetcher'; export { IndexPatternsService } from './index_patterns_service'; +export { getFieldsForWildcard } from './lib/fields_for_wildcard'; export { indexPatterns }; diff --git a/src/plugins/data/server/index_patterns/lib/fields_for_wildcard.ts b/src/plugins/data/server/index_patterns/lib/fields_for_wildcard.ts new file mode 100644 index 00000000000000..11c16aebc38a9e --- /dev/null +++ b/src/plugins/data/server/index_patterns/lib/fields_for_wildcard.ts @@ -0,0 +1,55 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { RequestHandler } from 'kibana/server'; +import { IndexPatternsFetcher } from '../fetcher'; +import { parseMetaFields } from '../utils'; + +export const getFieldsForWildcard: RequestHandler = async ( + context, + request, + response +) => { + const { callAsCurrentUser } = context.core.elasticsearch.dataClient; + const indexPatterns = new IndexPatternsFetcher(callAsCurrentUser); + const { pattern, meta_fields: metaFields } = request.query; + + let parsedFields: string[] = []; + try { + parsedFields = parseMetaFields(metaFields); + } catch (error) { + return response.badRequest(); + } + + try { + const fields = await indexPatterns.getFieldsForWildcard({ + pattern, + metaFields: parsedFields, + }); + + return response.ok({ + body: { fields }, + headers: { + 'content-type': 'application/json', + }, + }); + } catch (error) { + return response.notFound(); + } +}; diff --git a/src/plugins/data/server/index_patterns/routes.ts b/src/plugins/data/server/index_patterns/routes.ts index 8f017a73083ecf..0725d4f749fafa 100644 --- a/src/plugins/data/server/index_patterns/routes.ts +++ b/src/plugins/data/server/index_patterns/routes.ts @@ -20,18 +20,10 @@ import { schema } from '@kbn/config-schema'; import { HttpServiceSetup, RequestHandlerContext } from 'kibana/server'; import { IndexPatternsFetcher } from './fetcher'; +import { getFieldsForWildcard } from './lib/fields_for_wildcard'; +import { parseMetaFields } from './utils'; export function registerRoutes(http: HttpServiceSetup) { - const parseMetaFields = (metaFields: string | string[]) => { - let parsedFields: string[] = []; - if (typeof metaFields === 'string') { - parsedFields = JSON.parse(metaFields); - } else { - parsedFields = metaFields; - } - return parsedFields; - }; - const router = http.createRouter(); router.get( { @@ -45,34 +37,7 @@ export function registerRoutes(http: HttpServiceSetup) { }), }, }, - async (context, request, response) => { - const { callAsCurrentUser } = context.core.elasticsearch.dataClient; - const indexPatterns = new IndexPatternsFetcher(callAsCurrentUser); - const { pattern, meta_fields: metaFields } = request.query; - - let parsedFields: string[] = []; - try { - parsedFields = parseMetaFields(metaFields); - } catch (error) { - return response.badRequest(); - } - - try { - const fields = await indexPatterns.getFieldsForWildcard({ - pattern, - metaFields: parsedFields, - }); - - return response.ok({ - body: { fields }, - headers: { - 'content-type': 'application/json', - }, - }); - } catch (error) { - return response.notFound(); - } - } + async (context, request, response) => getFieldsForWildcard(context, request, response) ); router.get( diff --git a/src/plugins/data/server/index_patterns/utils.ts b/src/plugins/data/server/index_patterns/utils.ts index b7adafaeb3e94b..ba299808623ee8 100644 --- a/src/plugins/data/server/index_patterns/utils.ts +++ b/src/plugins/data/server/index_patterns/utils.ts @@ -45,3 +45,13 @@ export const findIndexPatternById = async ( return (savedObjectsResponse.saved_objects[0] as unknown) as IIndexPattern; } }; + +export const parseMetaFields = (metaFields: string | string[]) => { + let parsedFields: string[] = []; + if (typeof metaFields === 'string') { + parsedFields = JSON.parse(metaFields); + } else { + parsedFields = metaFields; + } + return parsedFields; +}; diff --git a/x-pack/legacy/plugins/rollup/index.ts b/x-pack/legacy/plugins/rollup/index.ts index 4636e781accfba..7dda38cc481f18 100644 --- a/x-pack/legacy/plugins/rollup/index.ts +++ b/x-pack/legacy/plugins/rollup/index.ts @@ -69,7 +69,6 @@ export function rollup(kibana: any) { }, }); - // registerFieldsForWildcardRoute(server); // if ( // server.plugins.index_management && // server.plugins.index_management.addIndexManagementDataEnricher diff --git a/x-pack/legacy/plugins/rollup/server/lib/merge_capabilities_with_fields.ts b/x-pack/legacy/plugins/rollup/server/lib/merge_capabilities_with_fields.ts index 76592bf12b2e38..24abe9045aae83 100644 --- a/x-pack/legacy/plugins/rollup/server/lib/merge_capabilities_with_fields.ts +++ b/x-pack/legacy/plugins/rollup/server/lib/merge_capabilities_with_fields.ts @@ -6,13 +6,18 @@ // Merge rollup capabilities information with field information +export interface Field { + name?: string; + [key: string]: any; +} + export const mergeCapabilitiesWithFields = ( - rollupIndexCapabilities, - fieldsFromFieldCapsApi, - previousFields = [] + rollupIndexCapabilities: { [key: string]: any }, + fieldsFromFieldCapsApi: { [key: string]: any }, + previousFields: Field[] = [] ) => { const rollupFields = [...previousFields]; - const rollupFieldNames = []; + const rollupFieldNames: string[] = []; Object.keys(rollupIndexCapabilities).forEach(agg => { // Field names of the aggregation diff --git a/x-pack/legacy/plugins/rollup/server/plugin.ts b/x-pack/legacy/plugins/rollup/server/plugin.ts index 9d8f6c79e33548..c698b58a5c6b19 100644 --- a/x-pack/legacy/plugins/rollup/server/plugin.ts +++ b/x-pack/legacy/plugins/rollup/server/plugin.ts @@ -14,7 +14,7 @@ import { ServerShim, RouteDependencies } from './types'; import { registerIndicesRoute, - // registerFieldsForWildcardRoute, + registerFieldsForWildcardRoute, registerSearchRoute, registerJobsRoute, } from './routes/api'; @@ -48,7 +48,7 @@ export class RollupsServerPlugin implements Plugin { ); registerIndicesRoute(routeDependencies, serverShim); - // registerFieldsForWildcardRoute(routeDependencies); + registerFieldsForWildcardRoute(routeDependencies, serverShim); registerSearchRoute(routeDependencies, serverShim); registerJobsRoute(routeDependencies, serverShim); diff --git a/x-pack/legacy/plugins/rollup/server/routes/api/index_patterns.ts b/x-pack/legacy/plugins/rollup/server/routes/api/index_patterns.ts index c7c3684da86d05..fd4c137c859cc7 100644 --- a/x-pack/legacy/plugins/rollup/server/routes/api/index_patterns.ts +++ b/x-pack/legacy/plugins/rollup/server/routes/api/index_patterns.ts @@ -6,148 +6,71 @@ import { schema } from '@kbn/config-schema'; import { RequestHandler } from 'src/core/server'; -import indexBy from 'lodash/collection/indexBy'; -import querystring from 'querystring'; +import { indexBy } from 'lodash'; +import { getFieldsForWildcard } from '../../shared_imports'; +import { RouteDependencies, ServerShim } from '../../types'; import { callWithRequestFactory } from '../../lib/call_with_request_factory'; import { isEsError } from '../../lib/is_es_error'; import { licensePreRoutingFactory } from '../../lib/license_pre_routing_factory'; import { getCapabilitiesForRollupIndices } from '../../lib/map_capabilities'; -import { mergeCapabilitiesWithFields } from '../../lib/merge_capabilities_with_fields'; +import { mergeCapabilitiesWithFields, Field } from '../../lib/merge_capabilities_with_fields'; /** * Get list of fields for rollup index pattern, in the format of regular index pattern fields */ export function registerFieldsForWildcardRoute(deps: RouteDependencies, legacy: ServerShim) { const handler: RequestHandler = async (ctx, request, response) => { - // const { pattern, meta_fields: metaFields, params } = request.query; - // // Format call to standard index pattern `fields for wildcard` - // const standardRequestQuery = querystring.stringify({ pattern, meta_fields: metaFields }); - // const standardRequest = { - // url: `${request.getBasePath()}/api/index_patterns/_fields_for_wildcard?${standardRequestQuery}`, - // method: 'GET', - // headers: request.headers, - // }; - // try { - // // Make call and use field information from response - // const standardResponse = await server.inject(standardRequest); - // const fields = standardResponse.result && standardResponse.result.fields; - // const rollupIndex = params.rollup_index; - // const callWithRequest = callWithRequestFactory(deps.elasticsearchService, request); - // const rollupFields = []; - // const fieldsFromFieldCapsApi = indexBy(fields, 'name'); - // const rollupIndexCapabilities = getCapabilitiesForRollupIndices( - // await callWithRequest('rollup.rollupIndexCapabilities', { - // indexPattern: rollupIndex, - // }) - // )[rollupIndex].aggs; - // // Keep meta fields - // metaFields.forEach( - // field => fieldsFromFieldCapsApi[field] && rollupFields.push(fieldsFromFieldCapsApi[field]) - // ); - // const mergedRollupFields = mergeCapabilitiesWithFields( - // rollupIndexCapabilities, - // fieldsFromFieldCapsApi, - // rollupFields - // ); - // return { - // fields: mergedRollupFields, - // }; - // } catch (err) { - // if (isEsError(err)) { - // return response.customError({ statusCode: err.statusCode, body: err }); - // } - // return response.internalError({ body: err }); - // } - }; + const { params, meta_fields: metaFields } = request.query; + + try { + // Make call and use field information from response + const { payload } = await getFieldsForWildcard(ctx, request, response); + const fields = payload.fields; + const parsedParams = JSON.parse(params); + const rollupIndex = parsedParams.rollup_index; + const callWithRequest = callWithRequestFactory(deps.elasticsearchService, request); + const rollupFields: Field[] = []; + const fieldsFromFieldCapsApi: { [key: string]: any } = indexBy(fields, 'name'); + const rollupIndexCapabilities = getCapabilitiesForRollupIndices( + await callWithRequest('rollup.rollupIndexCapabilities', { + indexPattern: rollupIndex, + }) + )[rollupIndex].aggs; + + // Keep meta fields + metaFields.forEach( + (field: string) => + fieldsFromFieldCapsApi[field] && rollupFields.push(fieldsFromFieldCapsApi[field]) + ); - // deps.router.get( - // { - // path: '/api/index_patterns/rollup/_fields_for_wildcard', - // // validate: { - // // query: schema - // // .object() - // // .keys({ - // // pattern: schema.string().required(), - // // meta_fields: schema - // // .array() - // // .items(schema.string()) - // // .default([]), - // // params: schema - // // .object() - // // .keys({ - // // rollup_index: schema.string().required(), - // // }) - // // .required(), - // // }) - // // .default(), - // // }, - // }, - // licensePreRoutingFactory(legacy, handler) - // ); + const mergedRollupFields = mergeCapabilitiesWithFields( + rollupIndexCapabilities, + fieldsFromFieldCapsApi, + rollupFields + ); + + return response.ok({ body: { fields: mergedRollupFields } }); + } catch (err) { + if (isEsError(err)) { + return response.customError({ statusCode: err.statusCode, body: err }); + } + return response.internalError({ body: err }); + } + }; - // const isEsError = isEsErrorFactory(server); - // const licensePreRouting = licensePreRoutingFactory(server); - // server.route({ - // path: '/api/index_patterns/rollup/_fields_for_wildcard', - // method: 'GET', - // config: { - // pre: [licensePreRouting], - // validate: { - // query: Joi.object() - // .keys({ - // pattern: Joi.string().required(), - // meta_fields: Joi.array() - // .items(Joi.string()) - // .default([]), - // params: Joi.object() - // .keys({ - // rollup_index: Joi.string().required(), - // }) - // .required(), - // }) - // .default(), - // }, - // }, - // handler: async request => { - // const { pattern, meta_fields: metaFields, params } = request.query; - // // Format call to standard index pattern `fields for wildcard` - // const standardRequestQuery = querystring.stringify({ pattern, meta_fields: metaFields }); - // const standardRequest = { - // url: `${request.getBasePath()}/api/index_patterns/_fields_for_wildcard?${standardRequestQuery}`, - // method: 'GET', - // headers: request.headers, - // }; - // try { - // // Make call and use field information from response - // const standardResponse = await server.inject(standardRequest); - // const fields = standardResponse.result && standardResponse.result.fields; - // const rollupIndex = params.rollup_index; - // const callWithRequest = callWithRequestFactory(server, request); - // const rollupFields = []; - // const fieldsFromFieldCapsApi = indexBy(fields, 'name'); - // const rollupIndexCapabilities = getCapabilitiesForRollupIndices( - // await callWithRequest('rollup.rollupIndexCapabilities', { - // indexPattern: rollupIndex, - // }) - // )[rollupIndex].aggs; - // // Keep meta fields - // metaFields.forEach( - // field => fieldsFromFieldCapsApi[field] && rollupFields.push(fieldsFromFieldCapsApi[field]) - // ); - // const mergedRollupFields = mergeCapabilitiesWithFields( - // rollupIndexCapabilities, - // fieldsFromFieldCapsApi, - // rollupFields - // ); - // return { - // fields: mergedRollupFields, - // }; - // } catch (err) { - // if (isEsError(err)) { - // return wrapEsError(err); - // } - // return wrapUnknownError(err); - // } - // }, - // }); + deps.router.get( + { + path: '/api/index_patterns/rollup/_fields_for_wildcard', + validate: { + query: schema.object({ + pattern: schema.string(), + meta_fields: schema.oneOf([schema.string(), schema.arrayOf(schema.string())], { + defaultValue: [], + }), + params: schema.string(), + }), + }, + }, + licensePreRoutingFactory(legacy, handler) + ); } diff --git a/x-pack/legacy/plugins/rollup/server/shared_imports.ts b/x-pack/legacy/plugins/rollup/server/shared_imports.ts new file mode 100644 index 00000000000000..f9bd2bcf207d7c --- /dev/null +++ b/x-pack/legacy/plugins/rollup/server/shared_imports.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { getFieldsForWildcard } from '../../../../../src/plugins/data/server'; From 323927a5df63cd62bd0d212d84111266d5b1f38f Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Wed, 29 Jan 2020 15:02:40 -0500 Subject: [PATCH 04/13] add back support for index management data enricher --- x-pack/legacy/plugins/rollup/index.ts | 18 +++--------------- x-pack/legacy/plugins/rollup/kibana.json | 3 ++- x-pack/legacy/plugins/rollup/server/plugin.ts | 9 +++++++++ .../{ => server}/rollup_data_enricher.ts | 9 ++++++++- x-pack/legacy/plugins/rollup/server/types.ts | 1 + 5 files changed, 23 insertions(+), 17 deletions(-) rename x-pack/legacy/plugins/rollup/{ => server}/rollup_data_enricher.ts (82%) diff --git a/x-pack/legacy/plugins/rollup/index.ts b/x-pack/legacy/plugins/rollup/index.ts index 7dda38cc481f18..450e75b7a932d5 100644 --- a/x-pack/legacy/plugins/rollup/index.ts +++ b/x-pack/legacy/plugins/rollup/index.ts @@ -6,16 +6,10 @@ import { resolve } from 'path'; import { i18n } from '@kbn/i18n'; -import { Legacy } from 'kibana'; +import { PluginInitializerContext } from 'src/core/server'; import { RollupSetup } from '../../../plugins/rollup/server'; import { PLUGIN, CONFIG_ROLLUPS } from './common'; import { plugin } from './server'; -import { PluginInitializerContext } from '../siem/public/plugin'; - -// import { rollupDataEnricher } from './rollup_data_enricher'; -// import { registerRollupSearchStrategy } from './server/lib/search_strategies'; - -export type ServerFacade = Legacy.Server; export function rollup(kibana: any) { return new kibana.Plugin({ @@ -48,7 +42,7 @@ export function rollup(kibana: any) { visualize: ['plugins/rollup/visualize'], search: ['plugins/rollup/search'], }, - init(server: ServerFacade) { + init(server: any) { const { core, plugins } = server.newPlatform.setup; const { usageCollection } = plugins; @@ -65,16 +59,10 @@ export function rollup(kibana: any) { plugins: { xpack_main: server.plugins.xpack_main, rollup: server.plugins[PLUGIN.ID], + index_management: server.plugins.index_management, }, }, }); - - // if ( - // server.plugins.index_management && - // server.plugins.index_management.addIndexManagementDataEnricher - // ) { - // server.plugins.index_management.addIndexManagementDataEnricher(rollupDataEnricher); - // } }, }); } diff --git a/x-pack/legacy/plugins/rollup/kibana.json b/x-pack/legacy/plugins/rollup/kibana.json index 8ed31ebe5ad8b5..5eda7c883897db 100644 --- a/x-pack/legacy/plugins/rollup/kibana.json +++ b/x-pack/legacy/plugins/rollup/kibana.json @@ -2,7 +2,8 @@ "id": "rollup", "version": "kibana", "requiredPlugins": [ - "home" + "home", + "index_management" ], "optionalPlugins": [ "usageCollection" diff --git a/x-pack/legacy/plugins/rollup/server/plugin.ts b/x-pack/legacy/plugins/rollup/server/plugin.ts index c698b58a5c6b19..2f48ea5745d38b 100644 --- a/x-pack/legacy/plugins/rollup/server/plugin.ts +++ b/x-pack/legacy/plugins/rollup/server/plugin.ts @@ -21,6 +21,8 @@ import { import { registerRollupUsageCollector } from './collectors'; +import { rollupDataEnricher } from './rollup_data_enricher'; + export class RollupsServerPlugin implements Plugin { constructor(private readonly initializerContext: PluginInitializerContext) {} @@ -65,6 +67,13 @@ export class RollupsServerPlugin implements Plugin { .warn(`Registering Rollup collector failed: ${e}`); }); } + + if ( + serverShim.plugins.index_management && + serverShim.plugins.index_management.addIndexManagementDataEnricher + ) { + serverShim.plugins.index_management.addIndexManagementDataEnricher(rollupDataEnricher); + } } start() {} stop() {} diff --git a/x-pack/legacy/plugins/rollup/rollup_data_enricher.ts b/x-pack/legacy/plugins/rollup/server/rollup_data_enricher.ts similarity index 82% rename from x-pack/legacy/plugins/rollup/rollup_data_enricher.ts rename to x-pack/legacy/plugins/rollup/server/rollup_data_enricher.ts index 4768468f481b5d..7c5e160c54a31a 100644 --- a/x-pack/legacy/plugins/rollup/rollup_data_enricher.ts +++ b/x-pack/legacy/plugins/rollup/server/rollup_data_enricher.ts @@ -4,14 +4,21 @@ * you may not use this file except in compliance with the Elastic License. */ -export const rollupDataEnricher = async (indicesList, callWithRequest) => { +interface Index { + name: string; + [key: string]: unknown; +} + +export const rollupDataEnricher = async (indicesList: Index[], callWithRequest: any) => { if (!indicesList || !indicesList.length) { return indicesList; } + const params = { path: '/_all/_rollup/data', method: 'GET', }; + try { const rollupJobData = await callWithRequest('transport.request', params); return indicesList.map(index => { diff --git a/x-pack/legacy/plugins/rollup/server/types.ts b/x-pack/legacy/plugins/rollup/server/types.ts index 0d85bcddac653f..4261b15d0b1fbf 100644 --- a/x-pack/legacy/plugins/rollup/server/types.ts +++ b/x-pack/legacy/plugins/rollup/server/types.ts @@ -12,6 +12,7 @@ export interface ServerShim { plugins: { xpack_main: XPackMainPlugin; rollup: any; + index_management: any; }; } From 186c901b15ee9a732d60ebf76b626c3fe2e89d37 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Fri, 31 Jan 2020 09:39:56 -0500 Subject: [PATCH 05/13] rework integration with index_patterns --- src/plugins/data/server/index.ts | 1 - .../data/server/index_patterns/index.ts | 1 - .../index_patterns/lib/fields_for_wildcard.ts | 55 ------------------- .../data/server/index_patterns/routes.ts | 41 +++++++++++++- .../data/server/index_patterns/utils.ts | 10 ---- .../server/routes/api/index_patterns.ts | 46 ++++++++++++++-- .../plugins/rollup/server/shared_imports.ts | 2 +- 7 files changed, 80 insertions(+), 76 deletions(-) delete mode 100644 src/plugins/data/server/index_patterns/lib/fields_for_wildcard.ts diff --git a/src/plugins/data/server/index.ts b/src/plugins/data/server/index.ts index 88711d502fa4be..3cd088744a4391 100644 --- a/src/plugins/data/server/index.ts +++ b/src/plugins/data/server/index.ts @@ -60,7 +60,6 @@ export { FieldDescriptor, shouldReadFieldFromDocValues, indexPatterns, - getFieldsForWildcard, } from './index_patterns'; export * from './search'; export { diff --git a/src/plugins/data/server/index_patterns/index.ts b/src/plugins/data/server/index_patterns/index.ts index a28b5c9508b9b6..b303ae30ea810b 100644 --- a/src/plugins/data/server/index_patterns/index.ts +++ b/src/plugins/data/server/index_patterns/index.ts @@ -20,5 +20,4 @@ import * as indexPatterns from './utils'; export { IndexPatternsFetcher, FieldDescriptor, shouldReadFieldFromDocValues } from './fetcher'; export { IndexPatternsService } from './index_patterns_service'; -export { getFieldsForWildcard } from './lib/fields_for_wildcard'; export { indexPatterns }; diff --git a/src/plugins/data/server/index_patterns/lib/fields_for_wildcard.ts b/src/plugins/data/server/index_patterns/lib/fields_for_wildcard.ts deleted file mode 100644 index 11c16aebc38a9e..00000000000000 --- a/src/plugins/data/server/index_patterns/lib/fields_for_wildcard.ts +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { RequestHandler } from 'kibana/server'; -import { IndexPatternsFetcher } from '../fetcher'; -import { parseMetaFields } from '../utils'; - -export const getFieldsForWildcard: RequestHandler = async ( - context, - request, - response -) => { - const { callAsCurrentUser } = context.core.elasticsearch.dataClient; - const indexPatterns = new IndexPatternsFetcher(callAsCurrentUser); - const { pattern, meta_fields: metaFields } = request.query; - - let parsedFields: string[] = []; - try { - parsedFields = parseMetaFields(metaFields); - } catch (error) { - return response.badRequest(); - } - - try { - const fields = await indexPatterns.getFieldsForWildcard({ - pattern, - metaFields: parsedFields, - }); - - return response.ok({ - body: { fields }, - headers: { - 'content-type': 'application/json', - }, - }); - } catch (error) { - return response.notFound(); - } -}; diff --git a/src/plugins/data/server/index_patterns/routes.ts b/src/plugins/data/server/index_patterns/routes.ts index 0725d4f749fafa..8f017a73083ecf 100644 --- a/src/plugins/data/server/index_patterns/routes.ts +++ b/src/plugins/data/server/index_patterns/routes.ts @@ -20,10 +20,18 @@ import { schema } from '@kbn/config-schema'; import { HttpServiceSetup, RequestHandlerContext } from 'kibana/server'; import { IndexPatternsFetcher } from './fetcher'; -import { getFieldsForWildcard } from './lib/fields_for_wildcard'; -import { parseMetaFields } from './utils'; export function registerRoutes(http: HttpServiceSetup) { + const parseMetaFields = (metaFields: string | string[]) => { + let parsedFields: string[] = []; + if (typeof metaFields === 'string') { + parsedFields = JSON.parse(metaFields); + } else { + parsedFields = metaFields; + } + return parsedFields; + }; + const router = http.createRouter(); router.get( { @@ -37,7 +45,34 @@ export function registerRoutes(http: HttpServiceSetup) { }), }, }, - async (context, request, response) => getFieldsForWildcard(context, request, response) + async (context, request, response) => { + const { callAsCurrentUser } = context.core.elasticsearch.dataClient; + const indexPatterns = new IndexPatternsFetcher(callAsCurrentUser); + const { pattern, meta_fields: metaFields } = request.query; + + let parsedFields: string[] = []; + try { + parsedFields = parseMetaFields(metaFields); + } catch (error) { + return response.badRequest(); + } + + try { + const fields = await indexPatterns.getFieldsForWildcard({ + pattern, + metaFields: parsedFields, + }); + + return response.ok({ + body: { fields }, + headers: { + 'content-type': 'application/json', + }, + }); + } catch (error) { + return response.notFound(); + } + } ); router.get( diff --git a/src/plugins/data/server/index_patterns/utils.ts b/src/plugins/data/server/index_patterns/utils.ts index ba299808623ee8..b7adafaeb3e94b 100644 --- a/src/plugins/data/server/index_patterns/utils.ts +++ b/src/plugins/data/server/index_patterns/utils.ts @@ -45,13 +45,3 @@ export const findIndexPatternById = async ( return (savedObjectsResponse.saved_objects[0] as unknown) as IIndexPattern; } }; - -export const parseMetaFields = (metaFields: string | string[]) => { - let parsedFields: string[] = []; - if (typeof metaFields === 'string') { - parsedFields = JSON.parse(metaFields); - } else { - parsedFields = metaFields; - } - return parsedFields; -}; diff --git a/x-pack/legacy/plugins/rollup/server/routes/api/index_patterns.ts b/x-pack/legacy/plugins/rollup/server/routes/api/index_patterns.ts index fd4c137c859cc7..64a40f92802725 100644 --- a/x-pack/legacy/plugins/rollup/server/routes/api/index_patterns.ts +++ b/x-pack/legacy/plugins/rollup/server/routes/api/index_patterns.ts @@ -7,7 +7,7 @@ import { schema } from '@kbn/config-schema'; import { RequestHandler } from 'src/core/server'; import { indexBy } from 'lodash'; -import { getFieldsForWildcard } from '../../shared_imports'; +import { IndexPatternsFetcher } from '../../shared_imports'; import { RouteDependencies, ServerShim } from '../../types'; import { callWithRequestFactory } from '../../lib/call_with_request_factory'; import { isEsError } from '../../lib/is_es_error'; @@ -15,6 +15,45 @@ import { licensePreRoutingFactory } from '../../lib/license_pre_routing_factory' import { getCapabilitiesForRollupIndices } from '../../lib/map_capabilities'; import { mergeCapabilitiesWithFields, Field } from '../../lib/merge_capabilities_with_fields'; +const parseMetaFields = (metaFields: string | string[]) => { + let parsedFields: string[] = []; + if (typeof metaFields === 'string') { + parsedFields = JSON.parse(metaFields); + } else { + parsedFields = metaFields; + } + return parsedFields; +}; + +const getFieldsForWildcardRequest = async (context: any, request: any, response: any) => { + const { callAsCurrentUser } = context.core.elasticsearch.dataClient; + const indexPatterns = new IndexPatternsFetcher(callAsCurrentUser); + const { pattern, meta_fields: metaFields } = request.query; + + let parsedFields: string[] = []; + try { + parsedFields = parseMetaFields(metaFields); + } catch (error) { + return response.badRequest(); + } + + try { + const fields = await indexPatterns.getFieldsForWildcard({ + pattern, + metaFields: parsedFields, + }); + + return response.ok({ + body: { fields }, + headers: { + 'content-type': 'application/json', + }, + }); + } catch (error) { + return response.notFound(); + } +}; + /** * Get list of fields for rollup index pattern, in the format of regular index pattern fields */ @@ -24,7 +63,7 @@ export function registerFieldsForWildcardRoute(deps: RouteDependencies, legacy: try { // Make call and use field information from response - const { payload } = await getFieldsForWildcard(ctx, request, response); + const { payload } = await getFieldsForWildcardRequest(ctx, request, response); const fields = payload.fields; const parsedParams = JSON.parse(params); const rollupIndex = parsedParams.rollup_index; @@ -36,19 +75,16 @@ export function registerFieldsForWildcardRoute(deps: RouteDependencies, legacy: indexPattern: rollupIndex, }) )[rollupIndex].aggs; - // Keep meta fields metaFields.forEach( (field: string) => fieldsFromFieldCapsApi[field] && rollupFields.push(fieldsFromFieldCapsApi[field]) ); - const mergedRollupFields = mergeCapabilitiesWithFields( rollupIndexCapabilities, fieldsFromFieldCapsApi, rollupFields ); - return response.ok({ body: { fields: mergedRollupFields } }); } catch (err) { if (isEsError(err)) { diff --git a/x-pack/legacy/plugins/rollup/server/shared_imports.ts b/x-pack/legacy/plugins/rollup/server/shared_imports.ts index f9bd2bcf207d7c..941610b97707f8 100644 --- a/x-pack/legacy/plugins/rollup/server/shared_imports.ts +++ b/x-pack/legacy/plugins/rollup/server/shared_imports.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { getFieldsForWildcard } from '../../../../../src/plugins/data/server'; +export { IndexPatternsFetcher } from '../../../../../src/plugins/data/server'; From 57a3a8f80f27036c6fb364b04dbd346d6adfa034 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Fri, 31 Jan 2020 15:15:11 -0500 Subject: [PATCH 06/13] add back support for search_strategy --- x-pack/legacy/plugins/rollup/index.ts | 9 ++++-- x-pack/legacy/plugins/rollup/kibana.json | 3 +- .../register_rollup_search_strategy.ts | 31 +++++++++---------- .../rollup_search_capabilities.ts | 25 +++++++++------ .../rollup_search_request.ts | 11 +++++-- .../rollup_search_strategy.ts | 28 +++++++++++------ x-pack/legacy/plugins/rollup/server/plugin.ts | 17 ++++++++-- 7 files changed, 79 insertions(+), 45 deletions(-) diff --git a/x-pack/legacy/plugins/rollup/index.ts b/x-pack/legacy/plugins/rollup/index.ts index 88c9bf57097074..c0179957e0d1b9 100644 --- a/x-pack/legacy/plugins/rollup/index.ts +++ b/x-pack/legacy/plugins/rollup/index.ts @@ -39,8 +39,8 @@ export function rollup(kibana: any) { search: ['plugins/rollup/legacy'], }, init(server: any) { - const { core, plugins } = server.newPlatform.setup; - const { usageCollection } = plugins; + const { core: coreSetup, plugins } = server.newPlatform.setup; + const { usageCollection, metrics } = plugins; const rollupSetup = (plugins.rollup as unknown) as RollupSetup; @@ -48,8 +48,11 @@ export function rollup(kibana: any) { config: rollupSetup.__legacy.config, } as unknown) as PluginInitializerContext; - plugin(initContext).setup(core, { + const rollupPluginInstance = plugin(initContext); + + rollupPluginInstance.setup(coreSetup, { usageCollection, + metrics, __LEGACY: { route: server.route.bind(server), plugins: { diff --git a/x-pack/legacy/plugins/rollup/kibana.json b/x-pack/legacy/plugins/rollup/kibana.json index 5eda7c883897db..3781d59d8c0f36 100644 --- a/x-pack/legacy/plugins/rollup/kibana.json +++ b/x-pack/legacy/plugins/rollup/kibana.json @@ -3,7 +3,8 @@ "version": "kibana", "requiredPlugins": [ "home", - "index_management" + "index_management", + "metrics" ], "optionalPlugins": [ "usageCollection" diff --git a/x-pack/legacy/plugins/rollup/server/lib/search_strategies/register_rollup_search_strategy.ts b/x-pack/legacy/plugins/rollup/server/lib/search_strategies/register_rollup_search_strategy.ts index fe65a7f1f30e90..93c4c1b52140b2 100644 --- a/x-pack/legacy/plugins/rollup/server/lib/search_strategies/register_rollup_search_strategy.ts +++ b/x-pack/legacy/plugins/rollup/server/lib/search_strategies/register_rollup_search_strategy.ts @@ -11,22 +11,19 @@ import { DefaultSearchCapabilities, AbstractSearchStrategy, } from '../../../../../../../src/plugins/vis_type_timeseries/server'; +import { RouteDependencies } from '../../types'; -export const registerRollupSearchStrategy = kbnServer => - kbnServer.afterPluginsInit(() => { - if (!kbnServer.newPlatform.setup.plugins.metrics) { - return; - } +export const registerRollupSearchStrategy = ( + { elasticsearchService }: RouteDependencies, + addSearchStrategy: (searchStrategy: any) => void +) => { + const RollupSearchRequest = getRollupSearchRequest(AbstractSearchRequest); + const RollupSearchCapabilities = getRollupSearchCapabilities(DefaultSearchCapabilities); + const RollupSearchStrategy = getRollupSearchStrategy( + AbstractSearchStrategy, + RollupSearchRequest, + RollupSearchCapabilities + ); - const { addSearchStrategy } = kbnServer.newPlatform.setup.plugins.metrics; - - const RollupSearchRequest = getRollupSearchRequest(AbstractSearchRequest); - const RollupSearchCapabilities = getRollupSearchCapabilities(DefaultSearchCapabilities); - const RollupSearchStrategy = getRollupSearchStrategy( - AbstractSearchStrategy, - RollupSearchRequest, - RollupSearchCapabilities - ); - - addSearchStrategy(new RollupSearchStrategy(kbnServer)); - }); + addSearchStrategy(new RollupSearchStrategy(elasticsearchService)); +}; diff --git a/x-pack/legacy/plugins/rollup/server/lib/search_strategies/rollup_search_capabilities.ts b/x-pack/legacy/plugins/rollup/server/lib/search_strategies/rollup_search_capabilities.ts index b84664c765dc64..5a57129aa60395 100644 --- a/x-pack/legacy/plugins/rollup/server/lib/search_strategies/rollup_search_capabilities.ts +++ b/x-pack/legacy/plugins/rollup/server/lib/search_strategies/rollup_search_capabilities.ts @@ -4,24 +4,29 @@ * you may not use this file except in compliance with the Elastic License. */ import { get, has } from 'lodash'; +import { KibanaRequest } from 'kibana/server'; import { leastCommonInterval, isCalendarInterval } from './lib/interval_helper'; -export const getRollupSearchCapabilities = DefaultSearchCapabilities => +export const getRollupSearchCapabilities = (DefaultSearchCapabilities: any) => class RollupSearchCapabilities extends DefaultSearchCapabilities { - constructor(req, fieldsCapabilities, rollupIndex) { + constructor( + req: KibanaRequest, + fieldsCapabilities: { [key: string]: any }, + rollupIndex: string + ) { super(req, fieldsCapabilities); this.rollupIndex = rollupIndex; this.availableMetrics = get(fieldsCapabilities, `${rollupIndex}.aggs`, {}); } - get dateHistogram() { + public get dateHistogram() { const [dateHistogram] = Object.values(this.availableMetrics.date_histogram); return dateHistogram; } - get defaultTimeInterval() { + public get defaultTimeInterval() { return ( this.dateHistogram.fixed_interval || this.dateHistogram.calendar_interval || @@ -34,16 +39,16 @@ export const getRollupSearchCapabilities = DefaultSearchCapabilities => ); } - get searchTimezone() { + public get searchTimezone() { return get(this.dateHistogram, 'time_zone', null); } - get whiteListedMetrics() { + public get whiteListedMetrics() { const baseRestrictions = this.createUiRestriction({ count: this.createUiRestriction(), }); - const getFields = fields => + const getFields = (fields: { [key: string]: any }) => Object.keys(fields).reduce( (acc, item) => ({ ...acc, @@ -61,20 +66,20 @@ export const getRollupSearchCapabilities = DefaultSearchCapabilities => ); } - get whiteListedGroupByFields() { + public get whiteListedGroupByFields() { return this.createUiRestriction({ everything: true, terms: has(this.availableMetrics, 'terms'), }); } - get whiteListedTimerangeModes() { + public get whiteListedTimerangeModes() { return this.createUiRestriction({ last_value: true, }); } - getValidTimeInterval(userIntervalString) { + getValidTimeInterval(userIntervalString: string) { const parsedRollupJobInterval = this.parseInterval(this.defaultTimeInterval); const inRollupJobUnit = this.convertIntervalToUnit( userIntervalString, diff --git a/x-pack/legacy/plugins/rollup/server/lib/search_strategies/rollup_search_request.ts b/x-pack/legacy/plugins/rollup/server/lib/search_strategies/rollup_search_request.ts index ee8e5553c89631..7e12d5286f34c5 100644 --- a/x-pack/legacy/plugins/rollup/server/lib/search_strategies/rollup_search_request.ts +++ b/x-pack/legacy/plugins/rollup/server/lib/search_strategies/rollup_search_request.ts @@ -5,9 +5,16 @@ */ const SEARCH_METHOD = 'rollup.search'; -export const getRollupSearchRequest = AbstractSearchRequest => +interface Search { + index: string; + body: { + [key: string]: any; + }; +} + +export const getRollupSearchRequest = (AbstractSearchRequest: any) => class RollupSearchRequest extends AbstractSearchRequest { - async search(searches) { + async search(searches: Search[]) { const requests = searches.map(({ body, index }) => this.callWithRequest(SEARCH_METHOD, { body, diff --git a/x-pack/legacy/plugins/rollup/server/lib/search_strategies/rollup_search_strategy.ts b/x-pack/legacy/plugins/rollup/server/lib/search_strategies/rollup_search_strategy.ts index 5cf7a3c8fd9417..cbd78e7c718959 100644 --- a/x-pack/legacy/plugins/rollup/server/lib/search_strategies/rollup_search_strategy.ts +++ b/x-pack/legacy/plugins/rollup/server/lib/search_strategies/rollup_search_strategy.ts @@ -4,31 +4,32 @@ * you may not use this file except in compliance with the Elastic License. */ import { indexBy, isString } from 'lodash'; +import { ElasticsearchServiceSetup, KibanaRequest } from 'kibana/server'; import { callWithRequestFactory } from '../call_with_request_factory'; import { mergeCapabilitiesWithFields } from '../merge_capabilities_with_fields'; import { getCapabilitiesForRollupIndices } from '../map_capabilities'; const ROLLUP_INDEX_CAPABILITIES_METHOD = 'rollup.rollupIndexCapabilities'; -const getRollupIndices = rollupData => Object.keys(rollupData); +const getRollupIndices = (rollupData: { [key: string]: any[] }) => Object.keys(rollupData); -const isIndexPatternContainsWildcard = indexPattern => indexPattern.includes('*'); -const isIndexPatternValid = indexPattern => +const isIndexPatternContainsWildcard = (indexPattern: string) => indexPattern.includes('*'); +const isIndexPatternValid = (indexPattern: string) => indexPattern && isString(indexPattern) && !isIndexPatternContainsWildcard(indexPattern); export const getRollupSearchStrategy = ( - AbstractSearchStrategy, - RollupSearchRequest, - RollupSearchCapabilities + AbstractSearchStrategy: any, + RollupSearchRequest: any, + RollupSearchCapabilities: any ) => class RollupSearchStrategy extends AbstractSearchStrategy { name = 'rollup'; - constructor(server) { + constructor(server: ElasticsearchServiceSetup) { super(server, callWithRequestFactory, RollupSearchRequest); } - getRollupData(req, indexPattern) { + getRollupData(req: KibanaRequest, indexPattern: string) { const callWithRequest = this.getCallWithRequestInstance(req); return callWithRequest(ROLLUP_INDEX_CAPABILITIES_METHOD, { @@ -36,7 +37,7 @@ export const getRollupSearchStrategy = ( }).catch(() => Promise.resolve({})); } - async checkForViability(req, indexPattern) { + async checkForViability(req: KibanaRequest, indexPattern: string) { let isViable = false; let capabilities = null; @@ -60,7 +61,14 @@ export const getRollupSearchStrategy = ( }; } - async getFieldsForWildcard(req, indexPattern, { fieldsCapabilities, rollupIndex }) { + async getFieldsForWildcard( + req: KibanaRequest, + indexPattern: string, + { + fieldsCapabilities, + rollupIndex, + }: { fieldsCapabilities: { [key: string]: any }; rollupIndex: string } + ) { const fields = await super.getFieldsForWildcard(req, indexPattern); const fieldsFromFieldCapsApi = indexBy(fields, 'name'); const rollupIndexCapabilities = fieldsCapabilities[rollupIndex].aggs; diff --git a/x-pack/legacy/plugins/rollup/server/plugin.ts b/x-pack/legacy/plugins/rollup/server/plugin.ts index 2f48ea5745d38b..d8fcc120eb6be7 100644 --- a/x-pack/legacy/plugins/rollup/server/plugin.ts +++ b/x-pack/legacy/plugins/rollup/server/plugin.ts @@ -8,6 +8,7 @@ import { first } from 'rxjs/operators'; import { i18n } from '@kbn/i18n'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; +import { VisTypeTimeseriesSetup } from 'src/plugins/vis_type_timeseries/server'; import { registerLicenseChecker } from '../../../server/lib/register_license_checker'; import { PLUGIN } from '../common'; import { ServerShim, RouteDependencies } from './types'; @@ -22,6 +23,7 @@ import { import { registerRollupUsageCollector } from './collectors'; import { rollupDataEnricher } from './rollup_data_enricher'; +import { registerRollupSearchStrategy } from './lib/search_strategies'; export class RollupsServerPlugin implements Plugin { constructor(private readonly initializerContext: PluginInitializerContext) {} @@ -31,7 +33,12 @@ export class RollupsServerPlugin implements Plugin { { __LEGACY: serverShim, usageCollection, - }: { __LEGACY: ServerShim; usageCollection?: UsageCollectionSetup } + metrics, + }: { + __LEGACY: ServerShim; + usageCollection?: UsageCollectionSetup; + metrics?: VisTypeTimeseriesSetup; + } ) { const elasticsearch = await elasticsearchService.adminClient; const router = http.createRouter(); @@ -41,7 +48,6 @@ export class RollupsServerPlugin implements Plugin { router, }; - // Register license checker registerLicenseChecker( serverShim as any, PLUGIN.ID, @@ -74,7 +80,14 @@ export class RollupsServerPlugin implements Plugin { ) { serverShim.plugins.index_management.addIndexManagementDataEnricher(rollupDataEnricher); } + + if (metrics) { + const { addSearchStrategy } = metrics; + registerRollupSearchStrategy(routeDependencies, addSearchStrategy); + } } + start() {} + stop() {} } From b2432e14ce5939342e6727b0ded878f62cd4a97d Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Mon, 3 Feb 2020 08:50:35 -0500 Subject: [PATCH 07/13] fix TS --- .../plugins/rollup/server/lib/jobs_compatibility.ts | 6 +++--- .../lib/search_strategies/lib/interval_helper.ts | 11 ++++++++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/x-pack/legacy/plugins/rollup/server/lib/jobs_compatibility.ts b/x-pack/legacy/plugins/rollup/server/lib/jobs_compatibility.ts index 9423e7befb557d..f93641e5962b7b 100644 --- a/x-pack/legacy/plugins/rollup/server/lib/jobs_compatibility.ts +++ b/x-pack/legacy/plugins/rollup/server/lib/jobs_compatibility.ts @@ -37,10 +37,10 @@ export function mergeJobConfigurations(jobs = []) { throw new Error('No capabilities available'); } - const allAggs = {}; + const allAggs: { [key: string]: any } = {}; // For each job, look through all of its fields - jobs.forEach(job => { + jobs.forEach((job: { fields: { [key: string]: any } }) => { const fields = job.fields; const fieldNames = Object.keys(fields); @@ -49,7 +49,7 @@ export function mergeJobConfigurations(jobs = []) { const fieldAggs = fields[fieldName]; // Look through each field's capabilities (aggregations) - fieldAggs.forEach(agg => { + fieldAggs.forEach((agg: { agg: string; interval: string }) => { const aggName = agg.agg; const aggDoesntExist = !allAggs[aggName]; const fieldDoesntExist = allAggs[aggName] && !allAggs[aggName][fieldName]; diff --git a/x-pack/legacy/plugins/rollup/server/lib/search_strategies/lib/interval_helper.ts b/x-pack/legacy/plugins/rollup/server/lib/search_strategies/lib/interval_helper.ts index 8fc17252f9943a..91d73cecdf4011 100644 --- a/x-pack/legacy/plugins/rollup/server/lib/search_strategies/lib/interval_helper.ts +++ b/x-pack/legacy/plugins/rollup/server/lib/search_strategies/lib/interval_helper.ts @@ -4,9 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { unitsMap } from '@elastic/datemath'; +import dateMath from '@elastic/datemath'; + +export type Unit = 'ms' | 's' | 'm' | 'h' | 'd' | 'w' | 'M' | 'y'; export const leastCommonInterval = (num = 0, base = 0) => Math.max(Math.ceil(num / base) * base, base); -export const isCalendarInterval = ({ unit, value }) => - value === 1 && ['calendar', 'mixed'].includes(unitsMap[unit].type); + +export const isCalendarInterval = ({ unit, value }: { unit: Unit; value: number }) => { + const { unitsMap } = dateMath; + return value === 1 && ['calendar', 'mixed'].includes(unitsMap[unit].type); +}; From 7cb95c37b5b7c140a1c1d0d86812e4e48f2b66dc Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Mon, 3 Feb 2020 10:16:36 -0500 Subject: [PATCH 08/13] update tests + index pattern route validation --- .../register_rollup_search_strategy.test.js | 43 +++++-------------- .../server/routes/api/index_patterns.ts | 21 ++++++++- .../rollup/index_patterns_extensions.js | 36 +++++++++++----- 3 files changed, 55 insertions(+), 45 deletions(-) diff --git a/x-pack/legacy/plugins/rollup/server/lib/search_strategies/register_rollup_search_strategy.test.js b/x-pack/legacy/plugins/rollup/server/lib/search_strategies/register_rollup_search_strategy.test.js index acd016d75f97ed..d466ebd69737ee 100644 --- a/x-pack/legacy/plugins/rollup/server/lib/search_strategies/register_rollup_search_strategy.test.js +++ b/x-pack/legacy/plugins/rollup/server/lib/search_strategies/register_rollup_search_strategy.test.js @@ -6,45 +6,22 @@ import { registerRollupSearchStrategy } from './register_rollup_search_strategy'; describe('Register Rollup Search Strategy', () => { - let kbnServer; - let metrics; + let routeDependencies; + let addSearchStrategy; beforeEach(() => { - const afterPluginsInit = jest.fn(callback => callback()); - - kbnServer = { - afterPluginsInit, - newPlatform: { - setup: { plugins: {} }, - }, - }; - - metrics = { - addSearchStrategy: jest.fn().mockName('addSearchStrategy'), - AbstractSearchRequest: jest.fn().mockName('AbstractSearchRequest'), - AbstractSearchStrategy: jest.fn().mockName('AbstractSearchStrategy'), - DefaultSearchCapabilities: jest.fn().mockName('DefaultSearchCapabilities'), + routeDependencies = { + router: jest.fn().mockName('router'), + elasticsearchService: jest.fn().mockName('elasticsearchService'), + elasticsearch: jest.fn().mockName('elasticsearch'), }; - }); - - test('should run initialization on "afterPluginsInit" hook', () => { - registerRollupSearchStrategy(kbnServer); - - expect(kbnServer.afterPluginsInit).toHaveBeenCalled(); - }); - - test('should run initialization if metrics plugin available', () => { - registerRollupSearchStrategy({ - ...kbnServer, - newPlatform: { setup: { plugins: { metrics } } }, - }); - expect(metrics.addSearchStrategy).toHaveBeenCalled(); + addSearchStrategy = jest.fn().mockName('addSearchStrategy'); }); - test('should not run initialization if metrics plugin unavailable', () => { - registerRollupSearchStrategy(kbnServer); + test('should run initialization', () => { + registerRollupSearchStrategy(routeDependencies, addSearchStrategy); - expect(metrics.addSearchStrategy).not.toHaveBeenCalled(); + expect(addSearchStrategy).toHaveBeenCalled(); }); }); diff --git a/x-pack/legacy/plugins/rollup/server/routes/api/index_patterns.ts b/x-pack/legacy/plugins/rollup/server/routes/api/index_patterns.ts index 64a40f92802725..91e46ee53087d5 100644 --- a/x-pack/legacy/plugins/rollup/server/routes/api/index_patterns.ts +++ b/x-pack/legacy/plugins/rollup/server/routes/api/index_patterns.ts @@ -100,10 +100,27 @@ export function registerFieldsForWildcardRoute(deps: RouteDependencies, legacy: validate: { query: schema.object({ pattern: schema.string(), - meta_fields: schema.oneOf([schema.string(), schema.arrayOf(schema.string())], { + meta_fields: schema.arrayOf(schema.string(), { defaultValue: [], }), - params: schema.string(), + params: schema.string({ + validate(value) { + try { + const params = JSON.parse(value); + const keys = Object.keys(params); + const { rollup_index: rollupIndex } = params; + + if (!rollupIndex) { + return '[request query.params]: "rollup_index" is required'; + } else if (keys.length > 1) { + const invalidParams = keys.filter(key => key !== 'rollup_index'); + return `[request query.params]: ${invalidParams.join(', ')} is not allowed`; + } + } catch (err) { + return '[request query.params]: expected JSON string'; + } + }, + }), }), }, }, diff --git a/x-pack/test/api_integration/apis/management/rollup/index_patterns_extensions.js b/x-pack/test/api_integration/apis/management/rollup/index_patterns_extensions.js index 8eb084f24c52f9..be2af7cb76fd54 100644 --- a/x-pack/test/api_integration/apis/management/rollup/index_patterns_extensions.js +++ b/x-pack/test/api_integration/apis/management/rollup/index_patterns_extensions.js @@ -32,28 +32,42 @@ export default function({ getService }) { it('"pattern" is required', async () => { uri = `${BASE_URI}`; ({ body } = await supertest.get(uri).expect(400)); - expect(body.message).to.contain('"pattern" is required'); + expect(body.message).to.contain( + '[request query.pattern]: expected value of type [string]' + ); }); it('"params" is required', async () => { params = { pattern: 'foo' }; uri = `${BASE_URI}?${querystring.stringify(params)}`; ({ body } = await supertest.get(uri).expect(400)); - expect(body.message).to.contain('"params" is required'); + expect(body.message).to.contain( + '[request query.params]: expected value of type [string]' + ); }); - it('"params" must be an object', async () => { - params = { pattern: 'foo', params: 'bar' }; + it('"params" must be a valid JSON string', async () => { + params = { pattern: 'foo', params: 'foobarbaz' }; uri = `${BASE_URI}?${querystring.stringify(params)}`; ({ body } = await supertest.get(uri).expect(400)); - expect(body.message).to.contain('"params" must be an object'); + expect(body.message).to.contain('[request query.params]: expected JSON string'); }); - it('"params" must be an object that only accepts a "rollup_index" property', async () => { - params = { pattern: 'foo', params: JSON.stringify({ someProp: 'bar' }) }; + it('"params" requires a "rollup_index" property', async () => { + params = { pattern: 'foo', params: JSON.stringify({}) }; uri = `${BASE_URI}?${querystring.stringify(params)}`; ({ body } = await supertest.get(uri).expect(400)); - expect(body.message).to.contain('"someProp" is not allowed'); + expect(body.message).to.contain('[request query.params]: "rollup_index" is required'); + }); + + it('"params" only accepts a "rollup_index" property', async () => { + params = { + pattern: 'foo', + params: JSON.stringify({ rollup_index: 'my_index', someProp: 'bar' }), + }; + uri = `${BASE_URI}?${querystring.stringify(params)}`; + ({ body } = await supertest.get(uri).expect(400)); + expect(body.message).to.contain('[request query.params]: someProp is not allowed'); }); it('"meta_fields" must be an Array', async () => { @@ -64,7 +78,9 @@ export default function({ getService }) { }; uri = `${BASE_URI}?${querystring.stringify(params)}`; ({ body } = await supertest.get(uri).expect(400)); - expect(body.message).to.contain('"meta_fields" must be an array'); + expect(body.message).to.contain( + '[request query.meta_fields]: expected value of type [array]' + ); }); it('should return 404 the rollup index to query does not exist', async () => { @@ -73,7 +89,7 @@ export default function({ getService }) { params: JSON.stringify({ rollup_index: 'bar' }), })}`; ({ body } = await supertest.get(uri).expect(404)); - expect(body.message).to.contain('no such index [bar]'); + expect(body.message).to.contain('[index_not_found_exception] no such index [bar]'); }); }); From d0ba3bf7540de35d34e0ec0aa2fe12fa690f0c4d Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Mon, 3 Feb 2020 10:20:48 -0500 Subject: [PATCH 09/13] fix i18n --- x-pack/plugins/translations/translations/ja-JP.json | 5 +---- x-pack/plugins/translations/translations/zh-CN.json | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 47e11817ffa5d4..4883d849de3a9a 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -10257,9 +10257,6 @@ "xpack.reporting.shareContextMenu.csvReportsButtonLabel": "CSV レポート", "xpack.reporting.shareContextMenu.pdfReportsButtonLabel": "PDF レポート", "xpack.rollupJobs.appTitle": "ロールアップジョブ", - "xpack.rollupJobs.checkLicense.errorExpiredMessage": "{licenseType} ライセンスが期限切れのため {pluginName} を使用できません", - "xpack.rollupJobs.checkLicense.errorUnavailableMessage": "現在ライセンス情報が利用できないため {pluginName} を使用できません。", - "xpack.rollupJobs.checkLicense.errorUnsupportedMessage": "ご使用の {licenseType} ライセンスは {pluginName} をサポートしていません。ライセンスをアップグレードしてください。", "xpack.rollupJobs.create.backButton.label": "戻る", "xpack.rollupJobs.create.dateTypeField": "日付", "xpack.rollupJobs.create.errors.dateHistogramFieldMissing": "日付フィールドが必要です。", @@ -13201,4 +13198,4 @@ "xpack.watcher.watchEdit.thresholdWatchExpression.aggType.fieldIsRequiredValidationMessage": "フィールドを選択してください。", "xpack.watcher.watcherDescription": "アラートの作成、管理、監視によりデータへの変更を検知します。" } -} +} \ No newline at end of file diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 86d9a69dc0900b..785ce91cc54fd6 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -10256,9 +10256,6 @@ "xpack.reporting.shareContextMenu.csvReportsButtonLabel": "CSV 报告", "xpack.reporting.shareContextMenu.pdfReportsButtonLabel": "PDF 报告", "xpack.rollupJobs.appTitle": "汇总/打包作业", - "xpack.rollupJobs.checkLicense.errorExpiredMessage": "您不能使用 {pluginName},因为您的 {licenseType} 许可证已过期", - "xpack.rollupJobs.checkLicense.errorUnavailableMessage": "您不能使用 {pluginName},因为许可证信息当前不可用。", - "xpack.rollupJobs.checkLicense.errorUnsupportedMessage": "您的 {licenseType} 许可证不支持 {pluginName}。请升级您的许可。", "xpack.rollupJobs.create.backButton.label": "上一步", "xpack.rollupJobs.create.dateTypeField": "日期", "xpack.rollupJobs.create.errors.dateHistogramFieldMissing": "“日期”字段必填。", @@ -13200,4 +13197,4 @@ "xpack.watcher.watchEdit.thresholdWatchExpression.aggType.fieldIsRequiredValidationMessage": "此字段必填。", "xpack.watcher.watcherDescription": "通过创建、管理和监测警报来检测数据中的更改。" } -} +} \ No newline at end of file From 2c99bebc68a544b2827bfbc8adf0ac6023782b52 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Mon, 3 Feb 2020 11:58:32 -0500 Subject: [PATCH 10/13] fix logger --- x-pack/legacy/plugins/rollup/index.ts | 1 + x-pack/legacy/plugins/rollup/server/plugin.ts | 12 +++++++----- x-pack/plugins/rollup/server/plugin.ts | 2 ++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/x-pack/legacy/plugins/rollup/index.ts b/x-pack/legacy/plugins/rollup/index.ts index c0179957e0d1b9..98095d478bca10 100644 --- a/x-pack/legacy/plugins/rollup/index.ts +++ b/x-pack/legacy/plugins/rollup/index.ts @@ -46,6 +46,7 @@ export function rollup(kibana: any) { const initContext = ({ config: rollupSetup.__legacy.config, + logger: rollupSetup.__legacy.logger, } as unknown) as PluginInitializerContext; const rollupPluginInstance = plugin(initContext); diff --git a/x-pack/legacy/plugins/rollup/server/plugin.ts b/x-pack/legacy/plugins/rollup/server/plugin.ts index d8fcc120eb6be7..52b1e31af4eb22 100644 --- a/x-pack/legacy/plugins/rollup/server/plugin.ts +++ b/x-pack/legacy/plugins/rollup/server/plugin.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { CoreSetup, Plugin, PluginInitializerContext } from 'src/core/server'; +import { CoreSetup, Plugin, PluginInitializerContext, Logger } from 'src/core/server'; import { first } from 'rxjs/operators'; import { i18n } from '@kbn/i18n'; @@ -26,7 +26,11 @@ import { rollupDataEnricher } from './rollup_data_enricher'; import { registerRollupSearchStrategy } from './lib/search_strategies'; export class RollupsServerPlugin implements Plugin { - constructor(private readonly initializerContext: PluginInitializerContext) {} + log: Logger; + + constructor(private readonly initializerContext: PluginInitializerContext) { + this.log = initializerContext.logger.get(); + } async setup( { http, elasticsearch: elasticsearchService }: CoreSetup, @@ -68,9 +72,7 @@ export class RollupsServerPlugin implements Plugin { registerRollupUsageCollector(usageCollection, config.kibana.index); }) .catch(e => { - this.initializerContext.logger - .get('rollup') - .warn(`Registering Rollup collector failed: ${e}`); + this.log.warn(`Registering Rollup collector failed: ${e}`); }); } diff --git a/x-pack/plugins/rollup/server/plugin.ts b/x-pack/plugins/rollup/server/plugin.ts index ca4b8786c2ca28..fa05b8d1307d61 100644 --- a/x-pack/plugins/rollup/server/plugin.ts +++ b/x-pack/plugins/rollup/server/plugin.ts @@ -17,6 +17,7 @@ export class RollupPlugin implements Plugin { return { __legacy: { config: this.initContext.config, + logger: this.initContext.logger, }, }; } @@ -29,5 +30,6 @@ export interface RollupSetup { /** @deprecated */ __legacy: { config: PluginInitializerContext['config']; + logger: PluginInitializerContext['logger']; }; } From 9dfe043da8a725a98432371061f0afdf7d879271 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Mon, 3 Feb 2020 12:50:48 -0500 Subject: [PATCH 11/13] fix license_pre_routing_factory tests --- .../__tests__/license_pre_routing_factory.js | 66 ------------------- .../license_pre_routing_factory.test.js | 62 +++++++++++++++++ 2 files changed, 62 insertions(+), 66 deletions(-) delete mode 100644 x-pack/legacy/plugins/rollup/server/lib/license_pre_routing_factory/__tests__/license_pre_routing_factory.js create mode 100644 x-pack/legacy/plugins/rollup/server/lib/license_pre_routing_factory/license_pre_routing_factory.test.js diff --git a/x-pack/legacy/plugins/rollup/server/lib/license_pre_routing_factory/__tests__/license_pre_routing_factory.js b/x-pack/legacy/plugins/rollup/server/lib/license_pre_routing_factory/__tests__/license_pre_routing_factory.js deleted file mode 100644 index a73aa96209c262..00000000000000 --- a/x-pack/legacy/plugins/rollup/server/lib/license_pre_routing_factory/__tests__/license_pre_routing_factory.js +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import expect from '@kbn/expect'; -import { licensePreRoutingFactory } from '../license_pre_routing_factory'; - -describe('license_pre_routing_factory', () => { - describe('#reportingFeaturePreRoutingFactory', () => { - let mockServer; - let mockLicenseCheckResults; - - beforeEach(() => { - mockServer = { - plugins: { - xpack_main: { - info: { - feature: () => ({ - getLicenseCheckResults: () => mockLicenseCheckResults, - }), - }, - }, - }, - }; - }); - - it('only instantiates one instance per server', () => { - const firstInstance = licensePreRoutingFactory(mockServer); - const secondInstance = licensePreRoutingFactory(mockServer); - - expect(firstInstance).to.be(secondInstance); - }); - - describe('isAvailable is false', () => { - beforeEach(() => { - mockLicenseCheckResults = { - isAvailable: false, - }; - }); - - it('replies with 403', () => { - const licensePreRouting = licensePreRoutingFactory(mockServer); - const response = licensePreRouting(); - expect(response).to.be.an(Error); - expect(response.isBoom).to.be(true); - expect(response.output.statusCode).to.be(403); - }); - }); - - describe('isAvailable is true', () => { - beforeEach(() => { - mockLicenseCheckResults = { - isAvailable: true, - }; - }); - - it('replies with nothing', () => { - const licensePreRouting = licensePreRoutingFactory(mockServer); - const response = licensePreRouting(); - expect(response).to.be(null); - }); - }); - }); -}); diff --git a/x-pack/legacy/plugins/rollup/server/lib/license_pre_routing_factory/license_pre_routing_factory.test.js b/x-pack/legacy/plugins/rollup/server/lib/license_pre_routing_factory/license_pre_routing_factory.test.js new file mode 100644 index 00000000000000..b6cea09e0ea3c1 --- /dev/null +++ b/x-pack/legacy/plugins/rollup/server/lib/license_pre_routing_factory/license_pre_routing_factory.test.js @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; +import { licensePreRoutingFactory } from '.'; +import { + LICENSE_STATUS_VALID, + LICENSE_STATUS_INVALID, +} from '../../../../../common/constants/license_status'; +import { kibanaResponseFactory } from '../../../../../../../src/core/server'; + +describe('licensePreRoutingFactory()', () => { + let mockServer; + let mockLicenseCheckResults; + + beforeEach(() => { + mockServer = { + plugins: { + xpack_main: { + info: { + feature: () => ({ + getLicenseCheckResults: () => mockLicenseCheckResults, + }), + }, + }, + }, + }; + }); + + describe('status is invalid', () => { + beforeEach(() => { + mockLicenseCheckResults = { + status: LICENSE_STATUS_INVALID, + }; + }); + + it('replies with 403', () => { + const routeWithLicenseCheck = licensePreRoutingFactory(mockServer, () => {}); + const stubRequest = {}; + const response = routeWithLicenseCheck({}, stubRequest, kibanaResponseFactory); + expect(response.status).to.be(403); + }); + }); + + describe('status is valid', () => { + beforeEach(() => { + mockLicenseCheckResults = { + status: LICENSE_STATUS_VALID, + }; + }); + + it('replies with nothing', () => { + const routeWithLicenseCheck = licensePreRoutingFactory(mockServer, () => null); + const stubRequest = {}; + const response = routeWithLicenseCheck({}, stubRequest, kibanaResponseFactory); + expect(response).to.be(null); + }); + }); +}); From b90d0a91a7d019a2589f4cb02d4b7df56a897cf0 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Thu, 6 Feb 2020 09:19:18 -0500 Subject: [PATCH 12/13] address review feedback --- x-pack/legacy/plugins/rollup/index.ts | 1 - .../server/lib/search_strategies/rollup_search_strategy.ts | 4 ++-- x-pack/legacy/plugins/rollup/server/types.ts | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/x-pack/legacy/plugins/rollup/index.ts b/x-pack/legacy/plugins/rollup/index.ts index 98095d478bca10..7548af23b3aae9 100644 --- a/x-pack/legacy/plugins/rollup/index.ts +++ b/x-pack/legacy/plugins/rollup/index.ts @@ -55,7 +55,6 @@ export function rollup(kibana: any) { usageCollection, metrics, __LEGACY: { - route: server.route.bind(server), plugins: { xpack_main: server.plugins.xpack_main, rollup: server.plugins[PLUGIN.ID], diff --git a/x-pack/legacy/plugins/rollup/server/lib/search_strategies/rollup_search_strategy.ts b/x-pack/legacy/plugins/rollup/server/lib/search_strategies/rollup_search_strategy.ts index cbd78e7c718959..9d5aad2c2d3bca 100644 --- a/x-pack/legacy/plugins/rollup/server/lib/search_strategies/rollup_search_strategy.ts +++ b/x-pack/legacy/plugins/rollup/server/lib/search_strategies/rollup_search_strategy.ts @@ -25,8 +25,8 @@ export const getRollupSearchStrategy = ( class RollupSearchStrategy extends AbstractSearchStrategy { name = 'rollup'; - constructor(server: ElasticsearchServiceSetup) { - super(server, callWithRequestFactory, RollupSearchRequest); + constructor(elasticsearchService: ElasticsearchServiceSetup) { + super(elasticsearchService, callWithRequestFactory, RollupSearchRequest); } getRollupData(req: KibanaRequest, indexPattern: string) { diff --git a/x-pack/legacy/plugins/rollup/server/types.ts b/x-pack/legacy/plugins/rollup/server/types.ts index 4261b15d0b1fbf..62a4841133cffb 100644 --- a/x-pack/legacy/plugins/rollup/server/types.ts +++ b/x-pack/legacy/plugins/rollup/server/types.ts @@ -8,7 +8,6 @@ import { IRouter, ElasticsearchServiceSetup, IClusterClient } from 'src/core/ser import { XPackMainPlugin } from '../../xpack_main/server/xpack_main'; export interface ServerShim { - route: any; plugins: { xpack_main: XPackMainPlugin; rollup: any; From 941ccd76cfae66c8e10298d566f7bf520f30376c Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Thu, 6 Feb 2020 11:08:38 -0500 Subject: [PATCH 13/13] address feedback --- .../legacy/plugins/rollup/server/routes/api/index_patterns.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/rollup/server/routes/api/index_patterns.ts b/x-pack/legacy/plugins/rollup/server/routes/api/index_patterns.ts index 91e46ee53087d5..2516840bd95375 100644 --- a/x-pack/legacy/plugins/rollup/server/routes/api/index_patterns.ts +++ b/x-pack/legacy/plugins/rollup/server/routes/api/index_patterns.ts @@ -34,7 +34,9 @@ const getFieldsForWildcardRequest = async (context: any, request: any, response: try { parsedFields = parseMetaFields(metaFields); } catch (error) { - return response.badRequest(); + return response.badRequest({ + body: error, + }); } try {