From 06bee6051258009cca6c0c92fa1362c56823e734 Mon Sep 17 00:00:00 2001 From: Dario Gieselaar Date: Thu, 21 Nov 2019 15:46:34 +0100 Subject: [PATCH] [APM] Migrate server routes to NP (#49455) * [APM] Migrate server routes to NP Closes #49238. Pass legacy API to NP plugin in order to use internal SO client Fix issues with agent configuration APIs Update tsconfig template for TS optimization Fix typo * Review feedback * Fix type issues after browser duration changes * Revert changes in getServices due to readability concerns * Review feedback --- src/legacy/core_plugins/apm_oss/index.js | 1 - src/plugins/apm_oss/kibana.json | 11 + src/plugins/apm_oss/server/index.ts | 41 ++ src/plugins/apm_oss/server/plugin.ts | 38 ++ .../plugins/apm/common/projections/errors.ts | 8 +- .../plugins/apm/common/projections/metrics.ts | 8 +- .../apm/common/projections/service_nodes.ts | 8 +- .../apm/common/projections/services.ts | 12 +- .../common/projections/transaction_groups.ts | 8 +- .../apm/common/projections/transactions.ts | 8 +- x-pack/legacy/plugins/apm/index.ts | 20 +- x-pack/legacy/plugins/apm/mappings.json | 3 - .../app/Settings/ApmIndices/index.tsx | 7 - .../apm/public/new-platform/plugin.tsx | 5 +- .../public/services/__test__/callApi.test.ts | 2 +- .../services/__test__/callApmApi.test.ts | 4 +- .../apm/public/services/rest/callApi.ts | 16 +- .../public/services/rest/createCallApmApi.ts | 8 +- .../plugins/apm/public/utils/testHelpers.tsx | 20 +- .../scripts/optimize-tsconfig/tsconfig.json | 1 + .../apm/server/lib/apm_telemetry/index.ts | 26 +- .../__snapshots__/queries.test.ts.snap | 4 +- .../__tests__/get_buckets.test.ts | 13 +- .../lib/errors/distribution/get_buckets.ts | 8 +- .../errors/distribution/get_distribution.ts | 16 +- .../apm/server/lib/errors/get_error_group.ts | 8 +- .../apm/server/lib/errors/get_error_groups.ts | 8 +- .../get_trace_errors_per_transaction.ts | 4 +- .../convert_ui_filters/get_ui_filters_es.ts | 1 - .../apm/server/lib/helpers/es_client.ts | 69 ++-- .../lib/helpers/saved_objects_client.ts | 4 +- .../server/lib/helpers/setup_request.test.ts | 146 ++++--- .../apm/server/lib/helpers/setup_request.ts | 92 +++-- .../create_static_index_pattern.test.ts | 45 ++- .../create_static_index_pattern.ts | 14 +- .../get_dynamic_index_pattern.ts | 10 +- .../server/lib/metrics/by_agent/default.ts | 8 +- .../java/gc/fetchAndTransformGcMetrics.ts | 8 +- .../by_agent/java/gc/getGcRateChart.ts | 8 +- .../by_agent/java/gc/getGcTimeChart.ts | 8 +- .../by_agent/java/heap_memory/index.ts | 8 +- .../server/lib/metrics/by_agent/java/index.ts | 8 +- .../by_agent/java/non_heap_memory/index.ts | 8 +- .../by_agent/java/thread_count/index.ts | 8 +- .../lib/metrics/by_agent/shared/cpu/index.ts | 8 +- .../metrics/by_agent/shared/memory/index.ts | 8 +- .../metrics/fetch_and_transform_metrics.ts | 8 +- .../get_metrics_chart_data_by_agent.ts | 8 +- .../apm/server/lib/service_nodes/index.ts | 8 +- .../lib/services/get_service_agent_name.ts | 7 +- .../lib/services/get_service_node_metadata.ts | 8 +- .../services/get_service_transaction_types.ts | 4 +- .../get_services/get_services_items.ts | 10 +- .../server/lib/services/get_services/index.ts | 27 +- .../create_agent_config_index.ts | 36 +- .../create_or_update_configuration.ts | 2 +- .../delete_configuration.ts | 2 +- .../get_existing_environments_for_service.ts | 2 +- .../list_configurations.ts | 2 +- .../mark_applied_by_agent.ts | 2 +- .../settings/agent_configuration/search.ts | 2 +- .../settings/apm_indices/get_apm_indices.ts | 60 ++- .../settings/apm_indices/save_apm_indices.ts | 7 +- .../apm/server/lib/traces/get_trace.ts | 4 +- .../apm/server/lib/traces/get_trace_items.ts | 9 +- .../lib/transaction_groups/fetcher.test.ts | 13 +- .../server/lib/transaction_groups/fetcher.ts | 13 +- .../server/lib/transaction_groups/index.ts | 11 +- .../avg_duration_by_browser/fetcher.test.ts | 8 +- .../avg_duration_by_browser/index.ts | 8 +- .../avg_duration_by_country/index.ts | 8 +- .../lib/transactions/breakdown/index.test.ts | 13 +- .../lib/transactions/breakdown/index.ts | 8 +- .../charts/get_anomaly_data/fetcher.ts | 4 +- .../get_anomaly_data/get_ml_bucket_size.ts | 4 +- .../charts/get_anomaly_data/index.test.ts | 13 +- .../charts/get_anomaly_data/index.ts | 8 +- .../get_timeseries_data/fetcher.test.ts | 13 +- .../charts/get_timeseries_data/fetcher.ts | 8 +- .../charts/get_timeseries_data/index.ts | 8 +- .../server/lib/transactions/charts/index.ts | 8 +- .../transactions/constants.ts} | 8 +- .../distribution/get_buckets/fetcher.ts | 8 +- .../distribution/get_buckets/index.ts | 8 +- .../distribution/get_distribution_max.ts | 8 +- .../lib/transactions/distribution/index.ts | 21 +- .../lib/transactions/get_transaction/index.ts | 8 +- .../server/lib/ui_filters/get_environments.ts | 7 +- .../get_filter_aggregations.ts | 69 ++-- .../lib/ui_filters/local_ui_filters/index.ts | 2 +- .../plugins/apm/server/new-platform/plugin.ts | 23 -- .../server/routes/create_api/index.test.ts | 359 ++++++++++-------- .../apm/server/routes/create_api/index.ts | 174 ++++++--- .../plugins/apm/server/routes/errors.ts | 24 +- .../apm/server/routes/index_pattern.ts | 14 +- .../plugins/apm/server/routes/metrics.ts | 9 +- .../apm/server/routes/service_nodes.ts | 7 +- .../plugins/apm/server/routes/services.ts | 35 +- .../routes/settings/agent_configuration.ts | 51 +-- .../apm/server/routes/settings/apm_indices.ts | 31 +- .../plugins/apm/server/routes/traces.ts | 11 +- .../apm/server/routes/transaction_groups.ts | 46 +-- .../plugins/apm/server/routes/typings.ts | 58 ++- .../plugins/apm/server/routes/ui_filters.ts | 27 +- x-pack/plugins/apm/kibana.json | 14 + x-pack/plugins/apm/server/index.ts | 43 +++ x-pack/plugins/apm/server/plugin.ts | 69 ++++ 107 files changed, 1399 insertions(+), 868 deletions(-) create mode 100644 src/plugins/apm_oss/kibana.json create mode 100644 src/plugins/apm_oss/server/index.ts create mode 100644 src/plugins/apm_oss/server/plugin.ts rename x-pack/legacy/plugins/apm/server/{new-platform/index.ts => lib/transactions/constants.ts} (55%) delete mode 100644 x-pack/legacy/plugins/apm/server/new-platform/plugin.ts create mode 100644 x-pack/plugins/apm/kibana.json create mode 100644 x-pack/plugins/apm/server/index.ts create mode 100644 x-pack/plugins/apm/server/plugin.ts diff --git a/src/legacy/core_plugins/apm_oss/index.js b/src/legacy/core_plugins/apm_oss/index.js index 0c281ec939bb1..9de571ab7cae9 100644 --- a/src/legacy/core_plugins/apm_oss/index.js +++ b/src/legacy/core_plugins/apm_oss/index.js @@ -38,7 +38,6 @@ export default function apmOss(kibana) { spanIndices: Joi.string().default('apm-*'), metricsIndices: Joi.string().default('apm-*'), onboardingIndices: Joi.string().default('apm-*'), - apmAgentConfigurationIndex: Joi.string().default('.apm-agent-configuration'), }).default(); }, diff --git a/src/plugins/apm_oss/kibana.json b/src/plugins/apm_oss/kibana.json new file mode 100644 index 0000000000000..5853ba198e717 --- /dev/null +++ b/src/plugins/apm_oss/kibana.json @@ -0,0 +1,11 @@ +{ + "id": "apm_oss", + "version": "8.0.0", + "server": true, + "kibanaVersion": "kibana", + "configPath": [ + "apm_oss" + ], + "ui": false, + "requiredPlugins": [] +} diff --git a/src/plugins/apm_oss/server/index.ts b/src/plugins/apm_oss/server/index.ts new file mode 100644 index 0000000000000..801140694c139 --- /dev/null +++ b/src/plugins/apm_oss/server/index.ts @@ -0,0 +1,41 @@ +/* + * 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 { schema, TypeOf } from '@kbn/config-schema'; +import { PluginInitializerContext } from '../../../core/server'; +import { APMOSSPlugin } from './plugin'; + +export const config = { + schema: schema.object({ + transactionIndices: schema.string({ defaultValue: 'apm-*' }), + spanIndices: schema.string({ defaultValue: 'apm-*' }), + errorIndices: schema.string({ defaultValue: 'apm-*' }), + metricsIndices: schema.string({ defaultValue: 'apm-*' }), + sourcemapIndices: schema.string({ defaultValue: 'apm-*' }), + onboardingIndices: schema.string({ defaultValue: 'apm-*' }), + indexPattern: schema.string({ defaultValue: 'apm-*' }), + }), +}; + +export function plugin(initializerContext: PluginInitializerContext) { + return new APMOSSPlugin(initializerContext); +} + +export type APMOSSConfig = TypeOf; + +export { APMOSSPlugin as Plugin }; diff --git a/src/plugins/apm_oss/server/plugin.ts b/src/plugins/apm_oss/server/plugin.ts new file mode 100644 index 0000000000000..2708f7729482b --- /dev/null +++ b/src/plugins/apm_oss/server/plugin.ts @@ -0,0 +1,38 @@ +/* + * 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 { Plugin, CoreSetup, PluginInitializerContext } from 'src/core/server'; +import { Observable } from 'rxjs'; +import { APMOSSConfig } from './'; + +export class APMOSSPlugin implements Plugin<{ config$: Observable }> { + constructor(private readonly initContext: PluginInitializerContext) { + this.initContext = initContext; + } + + public setup(core: CoreSetup) { + const config$ = this.initContext.config.create(); + + return { + config$, + }; + } + + start() {} + stop() {} +} diff --git a/x-pack/legacy/plugins/apm/common/projections/errors.ts b/x-pack/legacy/plugins/apm/common/projections/errors.ts index adbd2eb1d6d27..27e1de43a1a94 100644 --- a/x-pack/legacy/plugins/apm/common/projections/errors.ts +++ b/x-pack/legacy/plugins/apm/common/projections/errors.ts @@ -4,7 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Setup } from '../../server/lib/helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../server/lib/helpers/setup_request'; import { PROCESSOR_EVENT, SERVICE_NAME, @@ -16,7 +20,7 @@ export function getErrorGroupsProjection({ setup, serviceName }: { - setup: Setup; + setup: Setup & SetupTimeRange & SetupUIFilters; serviceName: string; }) { const { start, end, uiFiltersES, indices } = setup; diff --git a/x-pack/legacy/plugins/apm/common/projections/metrics.ts b/x-pack/legacy/plugins/apm/common/projections/metrics.ts index 25d1484624e15..066f5789752a7 100644 --- a/x-pack/legacy/plugins/apm/common/projections/metrics.ts +++ b/x-pack/legacy/plugins/apm/common/projections/metrics.ts @@ -4,7 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Setup } from '../../server/lib/helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../server/lib/helpers/setup_request'; import { SERVICE_NAME, PROCESSOR_EVENT, @@ -30,7 +34,7 @@ export function getMetricsProjection({ serviceName, serviceNodeName }: { - setup: Setup; + setup: Setup & SetupTimeRange & SetupUIFilters; serviceName: string; serviceNodeName?: string; }) { diff --git a/x-pack/legacy/plugins/apm/common/projections/service_nodes.ts b/x-pack/legacy/plugins/apm/common/projections/service_nodes.ts index 10ce75785c3bc..42fcdd38cc9fd 100644 --- a/x-pack/legacy/plugins/apm/common/projections/service_nodes.ts +++ b/x-pack/legacy/plugins/apm/common/projections/service_nodes.ts @@ -4,7 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Setup } from '../../server/lib/helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../server/lib/helpers/setup_request'; import { SERVICE_NODE_NAME } from '../elasticsearch_fieldnames'; import { mergeProjection } from './util/merge_projection'; import { getMetricsProjection } from './metrics'; @@ -14,7 +18,7 @@ export function getServiceNodesProjection({ serviceName, serviceNodeName }: { - setup: Setup; + setup: Setup & SetupTimeRange & SetupUIFilters; serviceName: string; serviceNodeName?: string; }) { diff --git a/x-pack/legacy/plugins/apm/common/projections/services.ts b/x-pack/legacy/plugins/apm/common/projections/services.ts index e889899e11634..3531607d59fc4 100644 --- a/x-pack/legacy/plugins/apm/common/projections/services.ts +++ b/x-pack/legacy/plugins/apm/common/projections/services.ts @@ -4,11 +4,19 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Setup } from '../../server/lib/helpers/setup_request'; +import { + Setup, + SetupUIFilters, + SetupTimeRange +} from '../../server/lib/helpers/setup_request'; import { SERVICE_NAME, PROCESSOR_EVENT } from '../elasticsearch_fieldnames'; import { rangeFilter } from '../../server/lib/helpers/range_filter'; -export function getServicesProjection({ setup }: { setup: Setup }) { +export function getServicesProjection({ + setup +}: { + setup: Setup & SetupTimeRange & SetupUIFilters; +}) { const { start, end, uiFiltersES, indices } = setup; return { diff --git a/x-pack/legacy/plugins/apm/common/projections/transaction_groups.ts b/x-pack/legacy/plugins/apm/common/projections/transaction_groups.ts index 6f7be349b0cba..abda606f69384 100644 --- a/x-pack/legacy/plugins/apm/common/projections/transaction_groups.ts +++ b/x-pack/legacy/plugins/apm/common/projections/transaction_groups.ts @@ -4,7 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ import { omit } from 'lodash'; -import { Setup } from '../../server/lib/helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../server/lib/helpers/setup_request'; import { TRANSACTION_NAME, PARENT_ID } from '../elasticsearch_fieldnames'; import { Options } from '../../server/lib/transaction_groups/fetcher'; import { getTransactionsProjection } from './transactions'; @@ -14,7 +18,7 @@ export function getTransactionGroupsProjection({ setup, options }: { - setup: Setup; + setup: Setup & SetupTimeRange & SetupUIFilters; options: Options; }) { const transactionsProjection = getTransactionsProjection({ diff --git a/x-pack/legacy/plugins/apm/common/projections/transactions.ts b/x-pack/legacy/plugins/apm/common/projections/transactions.ts index fb249340c867c..ecbd0c8bf1a31 100644 --- a/x-pack/legacy/plugins/apm/common/projections/transactions.ts +++ b/x-pack/legacy/plugins/apm/common/projections/transactions.ts @@ -4,7 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Setup } from '../../server/lib/helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../server/lib/helpers/setup_request'; import { SERVICE_NAME, TRANSACTION_TYPE, @@ -19,7 +23,7 @@ export function getTransactionsProjection({ transactionName, transactionType }: { - setup: Setup; + setup: Setup & SetupTimeRange & SetupUIFilters; serviceName?: string; transactionName?: string; transactionType?: string; diff --git a/x-pack/legacy/plugins/apm/index.ts b/x-pack/legacy/plugins/apm/index.ts index e2cf907a61457..0cac20ef340d2 100644 --- a/x-pack/legacy/plugins/apm/index.ts +++ b/x-pack/legacy/plugins/apm/index.ts @@ -7,10 +7,10 @@ import { i18n } from '@kbn/i18n'; import { Server } from 'hapi'; import { resolve } from 'path'; -import { PluginInitializerContext } from '../../../../src/core/server'; +import { APMPluginContract } from '../../../plugins/apm/server/plugin'; import { LegacyPluginInitializer } from '../../../../src/legacy/types'; import mappings from './mappings.json'; -import { plugin } from './server/new-platform'; +import { makeApmUsageCollector } from './server/lib/apm_telemetry'; export const apm: LegacyPluginInitializer = kibana => { return new kibana.Plugin({ @@ -68,10 +68,6 @@ export const apm: LegacyPluginInitializer = kibana => { // enable plugin enabled: Joi.boolean().default(true), - // buckets - minimumBucketSize: Joi.number().default(15), - bucketTargetCount: Joi.number().default(15), - // index patterns autocreateApmIndexPattern: Joi.boolean().default(true), @@ -112,15 +108,11 @@ export const apm: LegacyPluginInitializer = kibana => { } } }); + makeApmUsageCollector(server); + const apmPlugin = server.newPlatform.setup.plugins + .apm as APMPluginContract; - const initializerContext = {} as PluginInitializerContext; - const legacySetup = { - server - }; - plugin(initializerContext).setup( - server.newPlatform.setup.core, - legacySetup - ); + apmPlugin.registerLegacyAPI({ server }); } }); }; diff --git a/x-pack/legacy/plugins/apm/mappings.json b/x-pack/legacy/plugins/apm/mappings.json index 02296606b1c01..61bc90da28756 100644 --- a/x-pack/legacy/plugins/apm/mappings.json +++ b/x-pack/legacy/plugins/apm/mappings.json @@ -61,9 +61,6 @@ }, "apm_oss.metricsIndices": { "type": "keyword" - }, - "apm_oss.apmAgentConfigurationIndex": { - "type": "keyword" } } } diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/ApmIndices/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/Settings/ApmIndices/index.tsx index 67957ae76b1f1..6323599436ca8 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Settings/ApmIndices/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/Settings/ApmIndices/index.tsx @@ -63,13 +63,6 @@ const APM_INDEX_LABELS = [ label: i18n.translate('xpack.apm.settings.apmIndices.metricsIndicesLabel', { defaultMessage: 'Metrics Indices' }) - }, - { - configurationName: 'apm_oss.apmAgentConfigurationIndex', - label: i18n.translate( - 'xpack.apm.settings.apmIndices.apmAgentConfigurationIndexLabel', - { defaultMessage: 'Agent Configuration Index' } - ) } ]; diff --git a/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx b/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx index 637dcbcd52f58..ac4aca4c795b7 100644 --- a/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx +++ b/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx @@ -71,6 +71,9 @@ export class Plugin { ); // create static index pattern and store as saved object. Not needed by APM UI but for legacy reasons in Discover, Dashboard etc. - createStaticIndexPattern(core.http); + createStaticIndexPattern(core.http).catch(e => { + // eslint-disable-next-line no-console + console.log('Error fetching static index pattern', e); + }); } } diff --git a/x-pack/legacy/plugins/apm/public/services/__test__/callApi.test.ts b/x-pack/legacy/plugins/apm/public/services/__test__/callApi.test.ts index cd681e354e2ed..31ba1e8d40aaa 100644 --- a/x-pack/legacy/plugins/apm/public/services/__test__/callApi.test.ts +++ b/x-pack/legacy/plugins/apm/public/services/__test__/callApi.test.ts @@ -48,7 +48,7 @@ describe('callApi', () => { it('should not add debug param for non-APM endpoints', async () => { await callApi(http, { pathname: `/api/kibana` }); - expect(http.get).toHaveBeenCalledWith('/api/kibana', {}); + expect(http.get).toHaveBeenCalledWith('/api/kibana', { query: {} }); }); }); diff --git a/x-pack/legacy/plugins/apm/public/services/__test__/callApmApi.test.ts b/x-pack/legacy/plugins/apm/public/services/__test__/callApmApi.test.ts index 22b37c275596f..e8a9fa74bd1da 100644 --- a/x-pack/legacy/plugins/apm/public/services/__test__/callApmApi.test.ts +++ b/x-pack/legacy/plugins/apm/public/services/__test__/callApmApi.test.ts @@ -81,10 +81,10 @@ describe('callApmApi', () => { expect.objectContaining({ pathname: '/api/apm', method: 'POST', - body: JSON.stringify({ + body: { foo: 'bar', bar: 'foo' - }) + } }) ); }); diff --git a/x-pack/legacy/plugins/apm/public/services/rest/callApi.ts b/x-pack/legacy/plugins/apm/public/services/rest/callApi.ts index 031f21e6e2feb..e1b61d06e3559 100644 --- a/x-pack/legacy/plugins/apm/public/services/rest/callApi.ts +++ b/x-pack/legacy/plugins/apm/public/services/rest/callApi.ts @@ -20,15 +20,23 @@ function fetchOptionsWithDebug(fetchOptions: FetchOptions) { sessionStorage.getItem('apm_debug') === 'true' && startsWith(fetchOptions.pathname, '/api/apm'); - if (!debugEnabled) { - return fetchOptions; - } + const isGet = !fetchOptions.method || fetchOptions.method === 'GET'; + + // Need an empty body to pass route validation + const body = isGet + ? {} + : { + body: JSON.stringify( + fetchOptions.body || ({} as HttpFetchOptions['body']) + ) + }; return { ...fetchOptions, + ...body, query: { ...fetchOptions.query, - _debug: true + ...(debugEnabled ? { _debug: true } : {}) } }; } diff --git a/x-pack/legacy/plugins/apm/public/services/rest/createCallApmApi.ts b/x-pack/legacy/plugins/apm/public/services/rest/createCallApmApi.ts index e2084599a0499..964cc12794075 100644 --- a/x-pack/legacy/plugins/apm/public/services/rest/createCallApmApi.ts +++ b/x-pack/legacy/plugins/apm/public/services/rest/createCallApmApi.ts @@ -22,10 +22,6 @@ export const createCallApmApi = (http: HttpServiceBase) => const { pathname, params = {}, ...opts } = options; const path = (params.path || {}) as Record; - const body = params.body - ? { body: JSON.stringify(params.body) } - : undefined; - const query = params.query ? { query: params.query } : undefined; const formattedPathname = Object.keys(path).reduce((acc, paramName) => { return acc.replace(`{${paramName}}`, path[paramName]); @@ -34,7 +30,7 @@ export const createCallApmApi = (http: HttpServiceBase) => return callApi(http, { ...opts, pathname: formattedPathname, - ...body, - ...query + body: params.body, + query: params.query }); }) as APMClient; diff --git a/x-pack/legacy/plugins/apm/public/utils/testHelpers.tsx b/x-pack/legacy/plugins/apm/public/utils/testHelpers.tsx index 751756146b8fe..321ce761422f0 100644 --- a/x-pack/legacy/plugins/apm/public/utils/testHelpers.tsx +++ b/x-pack/legacy/plugins/apm/public/utils/testHelpers.tsx @@ -14,6 +14,7 @@ import { Moment } from 'moment-timezone'; import React from 'react'; import { render, waitForElement } from 'react-testing-library'; import { MemoryRouter } from 'react-router-dom'; +import { APMConfig } from '../../../../../plugins/apm/server'; import { LocationProvider } from '../context/LocationContext'; import { PromiseReturnType } from '../../typings/common'; import { ESFilter } from '../../typings/elasticsearch'; @@ -98,10 +99,7 @@ interface MockSetup { end: number; client: any; internalClient: any; - config: { - get: any; - has: any; - }; + config: APMConfig; uiFiltersES: ESFilter[]; indices: { 'apm_oss.sourcemapIndices': string; @@ -110,7 +108,7 @@ interface MockSetup { 'apm_oss.spanIndices': string; 'apm_oss.transactionIndices': string; 'apm_oss.metricsIndices': string; - 'apm_oss.apmAgentConfigurationIndex': string; + apmAgentConfigurationIndex: string; }; } @@ -138,10 +136,12 @@ export async function inspectSearchParams( internalClient: { search: internalClientSpy } as any, - config: { - get: () => 'myIndex' as any, - has: () => true - }, + config: new Proxy( + {}, + { + get: () => 'myIndex' + } + ) as APMConfig, uiFiltersES: [ { term: { 'service.environment': 'prod' } @@ -154,7 +154,7 @@ export async function inspectSearchParams( 'apm_oss.spanIndices': 'myIndex', 'apm_oss.transactionIndices': 'myIndex', 'apm_oss.metricsIndices': 'myIndex', - 'apm_oss.apmAgentConfigurationIndex': 'myIndex' + apmAgentConfigurationIndex: 'myIndex' }, dynamicIndexPattern: null as any }; diff --git a/x-pack/legacy/plugins/apm/scripts/optimize-tsconfig/tsconfig.json b/x-pack/legacy/plugins/apm/scripts/optimize-tsconfig/tsconfig.json index e7d9abea65a3a..c2f87503b4548 100644 --- a/x-pack/legacy/plugins/apm/scripts/optimize-tsconfig/tsconfig.json +++ b/x-pack/legacy/plugins/apm/scripts/optimize-tsconfig/tsconfig.json @@ -2,6 +2,7 @@ "extends": "../../../apm.tsconfig.json", "include": [ "./**/*", + "../../../plugins/apm/**/*", "../../../typings/**/*" ], "exclude": [ diff --git a/x-pack/legacy/plugins/apm/server/lib/apm_telemetry/index.ts b/x-pack/legacy/plugins/apm/server/lib/apm_telemetry/index.ts index 640072d6ec4d8..de8846a8f9fb4 100644 --- a/x-pack/legacy/plugins/apm/server/lib/apm_telemetry/index.ts +++ b/x-pack/legacy/plugins/apm/server/lib/apm_telemetry/index.ts @@ -4,17 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Server } from 'hapi'; import { countBy } from 'lodash'; import { SavedObjectAttributes } from 'src/core/server'; -import { CoreSetup } from 'src/core/server'; import { isAgentName } from '../../../common/agent_name'; import { getInternalSavedObjectsClient } from '../helpers/saved_objects_client'; import { APM_SERVICES_TELEMETRY_SAVED_OBJECT_TYPE, APM_SERVICES_TELEMETRY_SAVED_OBJECT_ID } from '../../../common/apm_saved_object_constants'; -import { LegacySetup } from '../../new-platform/plugin'; +import { APMLegacyServer } from '../../routes/typings'; export function createApmTelementry( agentNames: string[] = [] @@ -27,12 +25,12 @@ export function createApmTelementry( } export async function storeApmServicesTelemetry( - server: Server, + server: APMLegacyServer, apmTelemetry: SavedObjectAttributes ) { try { - const internalSavedObjectsClient = getInternalSavedObjectsClient(server); - await internalSavedObjectsClient.create( + const savedObjectsClient = getInternalSavedObjectsClient(server); + await savedObjectsClient.create( APM_SERVICES_TELEMETRY_SAVED_OBJECT_TYPE, apmTelemetry, { @@ -45,21 +43,7 @@ export async function storeApmServicesTelemetry( } } -interface LegacySetupWithUsageCollector extends LegacySetup { - server: LegacySetup['server'] & { - usage: { - collectorSet: { - makeUsageCollector: (options: unknown) => unknown; - register: (options: unknown) => unknown; - }; - }; - }; -} - -export function makeApmUsageCollector( - core: CoreSetup, - { server }: LegacySetupWithUsageCollector -) { +export function makeApmUsageCollector(server: APMLegacyServer) { const apmUsageCollector = server.usage.collectorSet.makeUsageCollector({ type: 'apm', fetch: async () => { diff --git a/x-pack/legacy/plugins/apm/server/lib/errors/distribution/__snapshots__/queries.test.ts.snap b/x-pack/legacy/plugins/apm/server/lib/errors/distribution/__snapshots__/queries.test.ts.snap index e1d7e9843bf69..0065c28f60d2d 100644 --- a/x-pack/legacy/plugins/apm/server/lib/errors/distribution/__snapshots__/queries.test.ts.snap +++ b/x-pack/legacy/plugins/apm/server/lib/errors/distribution/__snapshots__/queries.test.ts.snap @@ -11,7 +11,7 @@ Object { "min": 1528113600000, }, "field": "@timestamp", - "interval": NaN, + "interval": 57600000, "min_doc_count": 0, }, }, @@ -63,7 +63,7 @@ Object { "min": 1528113600000, }, "field": "@timestamp", - "interval": NaN, + "interval": 57600000, "min_doc_count": 0, }, }, diff --git a/x-pack/legacy/plugins/apm/server/lib/errors/distribution/__tests__/get_buckets.test.ts b/x-pack/legacy/plugins/apm/server/lib/errors/distribution/__tests__/get_buckets.test.ts index 18ffb743934c0..cf8798d445f8a 100644 --- a/x-pack/legacy/plugins/apm/server/lib/errors/distribution/__tests__/get_buckets.test.ts +++ b/x-pack/legacy/plugins/apm/server/lib/errors/distribution/__tests__/get_buckets.test.ts @@ -6,6 +6,7 @@ import { PROCESSOR_EVENT } from '../../../../../common/elasticsearch_fieldnames'; import { getBuckets } from '../get_buckets'; +import { APMConfig } from '../../../../../../../../plugins/apm/server'; describe('timeseriesFetcher', () => { let clientSpy: jest.Mock; @@ -34,10 +35,12 @@ describe('timeseriesFetcher', () => { internalClient: { search: clientSpy } as any, - config: { - get: () => 'myIndex' as any, - has: () => true - }, + config: new Proxy( + {}, + { + get: () => 'myIndex' + } + ) as APMConfig, uiFiltersES: [ { term: { 'service.environment': 'prod' } @@ -50,7 +53,7 @@ describe('timeseriesFetcher', () => { 'apm_oss.spanIndices': 'apm-*', 'apm_oss.transactionIndices': 'apm-*', 'apm_oss.metricsIndices': 'apm-*', - 'apm_oss.apmAgentConfigurationIndex': '.apm-agent-configuration' + apmAgentConfigurationIndex: '.apm-agent-configuration' }, dynamicIndexPattern: null as any } diff --git a/x-pack/legacy/plugins/apm/server/lib/errors/distribution/get_buckets.ts b/x-pack/legacy/plugins/apm/server/lib/errors/distribution/get_buckets.ts index 37889e69ad8f2..9274f96d58d83 100644 --- a/x-pack/legacy/plugins/apm/server/lib/errors/distribution/get_buckets.ts +++ b/x-pack/legacy/plugins/apm/server/lib/errors/distribution/get_buckets.ts @@ -11,7 +11,11 @@ import { SERVICE_NAME } from '../../../../common/elasticsearch_fieldnames'; import { rangeFilter } from '../../helpers/range_filter'; -import { Setup } from '../../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../helpers/setup_request'; export async function getBuckets({ serviceName, @@ -22,7 +26,7 @@ export async function getBuckets({ serviceName: string; groupId?: string; bucketSize: number; - setup: Setup; + setup: Setup & SetupTimeRange & SetupUIFilters; }) { const { start, end, uiFiltersES, client, indices } = setup; const filter: ESFilter[] = [ diff --git a/x-pack/legacy/plugins/apm/server/lib/errors/distribution/get_distribution.ts b/x-pack/legacy/plugins/apm/server/lib/errors/distribution/get_distribution.ts index 81019b5261044..6172c71a0ed15 100644 --- a/x-pack/legacy/plugins/apm/server/lib/errors/distribution/get_distribution.ts +++ b/x-pack/legacy/plugins/apm/server/lib/errors/distribution/get_distribution.ts @@ -5,12 +5,16 @@ */ import { PromiseReturnType } from '../../../../typings/common'; -import { Setup } from '../../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../helpers/setup_request'; import { getBuckets } from './get_buckets'; +import { BUCKET_TARGET_COUNT } from '../../transactions/constants'; -function getBucketSize({ start, end, config }: Setup) { - const bucketTargetCount = config.get('xpack.apm.bucketTargetCount'); - return Math.floor((end - start) / bucketTargetCount); +function getBucketSize({ start, end }: SetupTimeRange) { + return Math.floor((end - start) / BUCKET_TARGET_COUNT); } export type ErrorDistributionAPIResponse = PromiseReturnType< @@ -24,9 +28,9 @@ export async function getErrorDistribution({ }: { serviceName: string; groupId?: string; - setup: Setup; + setup: Setup & SetupTimeRange & SetupUIFilters; }) { - const bucketSize = getBucketSize(setup); + const bucketSize = getBucketSize({ start: setup.start, end: setup.end }); const { buckets, noHits } = await getBuckets({ serviceName, groupId, diff --git a/x-pack/legacy/plugins/apm/server/lib/errors/get_error_group.ts b/x-pack/legacy/plugins/apm/server/lib/errors/get_error_group.ts index fd1199d07b95f..8d19455651be3 100644 --- a/x-pack/legacy/plugins/apm/server/lib/errors/get_error_group.ts +++ b/x-pack/legacy/plugins/apm/server/lib/errors/get_error_group.ts @@ -13,7 +13,11 @@ import { import { PromiseReturnType } from '../../../typings/common'; import { APMError } from '../../../typings/es_schemas/ui/APMError'; import { rangeFilter } from '../helpers/range_filter'; -import { Setup } from '../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../helpers/setup_request'; import { getTransaction } from '../transactions/get_transaction'; export type ErrorGroupAPIResponse = PromiseReturnType; @@ -26,7 +30,7 @@ export async function getErrorGroup({ }: { serviceName: string; groupId: string; - setup: Setup; + setup: Setup & SetupTimeRange & SetupUIFilters; }) { const { start, end, uiFiltersES, client, indices } = setup; diff --git a/x-pack/legacy/plugins/apm/server/lib/errors/get_error_groups.ts b/x-pack/legacy/plugins/apm/server/lib/errors/get_error_groups.ts index 24e7114efddee..aaa4ca9fb8223 100644 --- a/x-pack/legacy/plugins/apm/server/lib/errors/get_error_groups.ts +++ b/x-pack/legacy/plugins/apm/server/lib/errors/get_error_groups.ts @@ -13,7 +13,11 @@ import { } from '../../../common/elasticsearch_fieldnames'; import { PromiseReturnType } from '../../../typings/common'; import { APMError } from '../../../typings/es_schemas/ui/APMError'; -import { Setup } from '../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../helpers/setup_request'; import { getErrorGroupsProjection } from '../../../common/projections/errors'; import { mergeProjection } from '../../../common/projections/util/merge_projection'; import { SortOptions } from '../../../typings/elasticsearch/aggregations'; @@ -31,7 +35,7 @@ export async function getErrorGroups({ serviceName: string; sortField?: string; sortDirection?: 'asc' | 'desc'; - setup: Setup; + setup: Setup & SetupTimeRange & SetupUIFilters; }) { const { client } = setup; diff --git a/x-pack/legacy/plugins/apm/server/lib/errors/get_trace_errors_per_transaction.ts b/x-pack/legacy/plugins/apm/server/lib/errors/get_trace_errors_per_transaction.ts index 5074f9315d8ae..acbbeed2a527d 100644 --- a/x-pack/legacy/plugins/apm/server/lib/errors/get_trace_errors_per_transaction.ts +++ b/x-pack/legacy/plugins/apm/server/lib/errors/get_trace_errors_per_transaction.ts @@ -11,7 +11,7 @@ import { TRANSACTION_ID } from '../../../common/elasticsearch_fieldnames'; import { rangeFilter } from '../helpers/range_filter'; -import { Setup } from '../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; export interface ErrorsPerTransaction { [transactionId: string]: number; @@ -21,7 +21,7 @@ const includedLogLevels = ['critical', 'error', 'fatal']; export async function getTraceErrorsPerTransaction( traceId: string, - setup: Setup + setup: Setup & SetupTimeRange ): Promise { const { start, end, client, indices } = setup; diff --git a/x-pack/legacy/plugins/apm/server/lib/helpers/convert_ui_filters/get_ui_filters_es.ts b/x-pack/legacy/plugins/apm/server/lib/helpers/convert_ui_filters/get_ui_filters_es.ts index b9ca268c86beb..cee097d010212 100644 --- a/x-pack/legacy/plugins/apm/server/lib/helpers/convert_ui_filters/get_ui_filters_es.ts +++ b/x-pack/legacy/plugins/apm/server/lib/helpers/convert_ui_filters/get_ui_filters_es.ts @@ -19,7 +19,6 @@ export function getUiFiltersES( uiFilters: UIFilters ) { const { kuery, environment, ...localFilterValues } = uiFilters; - const mappedFilters = localUIFilterNames .filter(name => name in localFilterValues) .map(filterName => { diff --git a/x-pack/legacy/plugins/apm/server/lib/helpers/es_client.ts b/x-pack/legacy/plugins/apm/server/lib/helpers/es_client.ts index 9c111910f16f9..28035ac2f9be2 100644 --- a/x-pack/legacy/plugins/apm/server/lib/helpers/es_client.ts +++ b/x-pack/legacy/plugins/apm/server/lib/helpers/es_client.ts @@ -11,14 +11,17 @@ import { IndicesDeleteParams, IndicesCreateParams } from 'elasticsearch'; -import { Legacy } from 'kibana'; -import { cloneDeep, has, isString, set, pick } from 'lodash'; +import { merge } from 'lodash'; +import { cloneDeep, isString } from 'lodash'; +import { KibanaRequest } from 'src/core/server'; import { OBSERVER_VERSION_MAJOR } from '../../../common/elasticsearch_fieldnames'; -import { getApmIndices } from '../settings/apm_indices/get_apm_indices'; import { ESSearchResponse, ESSearchRequest } from '../../../typings/elasticsearch'; +import { APMRequestHandlerContext } from '../../routes/typings'; +import { pickKeys } from '../../../public/utils/pickKeys'; +import { getApmIndices } from '../settings/apm_indices/get_apm_indices'; // `type` was deprecated in 7.0 export type APMIndexDocumentParams = Omit, 'type'>; @@ -38,7 +41,7 @@ export function isApmIndex( function addFilterForLegacyData( apmIndices: string[], - params: SearchParams, + params: ESSearchRequest, { includeLegacyData = false } = {} ): SearchParams { // search across all data (including data) @@ -46,10 +49,18 @@ function addFilterForLegacyData( return params; } - const nextParams = cloneDeep(params); - if (!has(nextParams, 'body.query.bool.filter')) { - set(nextParams, 'body.query.bool.filter', []); - } + const nextParams = merge( + { + body: { + query: { + bool: { + filter: [] + } + } + } + }, + cloneDeep(params) + ); // add filter for omitting pre-7.x data nextParams.body.query.bool.filter.push({ @@ -61,30 +72,27 @@ function addFilterForLegacyData( // add additional params for search (aka: read) requests async function getParamsForSearchRequest( - req: Legacy.Request, - params: SearchParams, + context: APMRequestHandlerContext, + params: ESSearchRequest, apmOptions?: APMOptions ) { - const uiSettings = req.getUiSettingsService(); - const { server } = req; + const { uiSettings } = context.core; const [indices, includeFrozen] = await Promise.all([ - getApmIndices({ - config: server.config(), - savedObjectsClient: server.savedObjects.getScopedSavedObjectsClient(req) - }), - uiSettings.get('search:includeFrozen') + getApmIndices(context), + uiSettings.client.get('search:includeFrozen') ]); // Get indices for legacy data filter (only those which apply) - const apmIndices: string[] = Object.values( - pick(indices, [ + const apmIndices = Object.values( + pickKeys( + indices, 'apm_oss.sourcemapIndices', 'apm_oss.errorIndices', 'apm_oss.onboardingIndices', 'apm_oss.spanIndices', 'apm_oss.transactionIndices', 'apm_oss.metricsIndices' - ]) + ) ); return { ...addFilterForLegacyData(apmIndices, params, apmOptions), // filter out pre-7.0 data @@ -103,15 +111,18 @@ interface ClientCreateOptions { export type ESClient = ReturnType; export function getESClient( - req: Legacy.Request, + context: APMRequestHandlerContext, + request: KibanaRequest, { clientAsInternalUser = false }: ClientCreateOptions = {} ) { - const cluster = req.server.plugins.elasticsearch.getCluster('data'); - const query = req.query as Record; + const { + callAsCurrentUser, + callAsInternalUser + } = context.core.elasticsearch.dataClient; const callMethod = clientAsInternalUser - ? cluster.callWithInternalUser.bind(cluster) - : cluster.callWithRequest.bind(cluster, req); + ? callAsInternalUser + : callAsCurrentUser; return { search: async < @@ -122,17 +133,15 @@ export function getESClient( apmOptions?: APMOptions ): Promise> => { const nextParams = await getParamsForSearchRequest( - req, + context, params, apmOptions ); - if (query._debug) { + if (context.params.query._debug) { console.log(`--DEBUG ES QUERY--`); console.log( - `${req.method.toUpperCase()} ${req.url.pathname} ${JSON.stringify( - query - )}` + `${request.url.pathname} ${JSON.stringify(context.params.query)}` ); console.log(`GET ${nextParams.index}/_search`); console.log(JSON.stringify(nextParams.body, null, 4)); diff --git a/x-pack/legacy/plugins/apm/server/lib/helpers/saved_objects_client.ts b/x-pack/legacy/plugins/apm/server/lib/helpers/saved_objects_client.ts index 9eada84955d26..ced6f77944b6c 100644 --- a/x-pack/legacy/plugins/apm/server/lib/helpers/saved_objects_client.ts +++ b/x-pack/legacy/plugins/apm/server/lib/helpers/saved_objects_client.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Server } from 'hapi'; +import { APMLegacyServer } from '../../routes/typings'; -export function getInternalSavedObjectsClient(server: Server) { +export function getInternalSavedObjectsClient(server: APMLegacyServer) { const { SavedObjectsClient, getSavedObjectsRepository } = server.savedObjects; const { callWithInternalUser } = server.plugins.elasticsearch.getCluster( 'admin' diff --git a/x-pack/legacy/plugins/apm/server/lib/helpers/setup_request.test.ts b/x-pack/legacy/plugins/apm/server/lib/helpers/setup_request.test.ts index 0745c323c7fd2..f320712d6151f 100644 --- a/x-pack/legacy/plugins/apm/server/lib/helpers/setup_request.test.ts +++ b/x-pack/legacy/plugins/apm/server/lib/helpers/setup_request.test.ts @@ -3,9 +3,10 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { Legacy } from 'kibana'; import { setupRequest } from './setup_request'; -import { uiSettingsServiceMock } from 'src/core/server/mocks'; +import { APMConfig } from '../../../../../../plugins/apm/server'; +import { APMRequestHandlerContext } from '../../routes/typings'; +import { KibanaRequest } from 'src/core/server'; jest.mock('../settings/apm_indices/get_apm_indices', () => ({ getApmIndices: async () => ({ @@ -15,7 +16,7 @@ jest.mock('../settings/apm_indices/get_apm_indices', () => ({ 'apm_oss.spanIndices': 'apm-*', 'apm_oss.transactionIndices': 'apm-*', 'apm_oss.metricsIndices': 'apm-*', - 'apm_oss.apmAgentConfigurationIndex': 'apm-*' + apmAgentConfigurationIndex: 'apm-*' }) })); @@ -26,37 +27,62 @@ jest.mock('../index_pattern/get_dynamic_index_pattern', () => ({ })); function getMockRequest() { - const callWithRequestSpy = jest.fn(); - const callWithInternalUserSpy = jest.fn(); - const mockRequest = ({ - params: {}, - query: {}, - server: { - config: () => ({ get: () => 'apm-*' }), - plugins: { - elasticsearch: { - getCluster: () => ({ - callWithRequest: callWithRequestSpy, - callWithInternalUser: callWithInternalUserSpy - }) + const mockContext = ({ + config: new Proxy( + {}, + { + get: () => 'apm-*' + } + ) as APMConfig, + params: { + query: { + _debug: false + } + }, + core: { + elasticsearch: { + dataClient: { + callAsCurrentUser: jest.fn(), + callAsInternalUser: jest.fn() } }, - savedObjects: { - getScopedSavedObjectsClient: () => ({ get: async () => false }) + uiSettings: { + client: { + get: jest.fn().mockResolvedValue(false) + } } - }, - getUiSettingsService: () => ({ get: async () => false }) - } as any) as Legacy.Request; + } + } as unknown) as APMRequestHandlerContext & { + core: { + elasticsearch: { + dataClient: { + callAsCurrentUser: jest.Mock; + callAsInternalUser: jest.Mock; + }; + }; + uiSettings: { + client: { + get: jest.Mock; + }; + }; + }; + }; + + const mockRequest = ({ + url: '' + } as unknown) as KibanaRequest; - return { callWithRequestSpy, callWithInternalUserSpy, mockRequest }; + return { mockContext, mockRequest }; } describe('setupRequest', () => { it('should call callWithRequest with default args', async () => { - const { mockRequest, callWithRequestSpy } = getMockRequest(); - const { client } = await setupRequest(mockRequest); + const { mockContext, mockRequest } = getMockRequest(); + const { client } = await setupRequest(mockContext, mockRequest); await client.search({ index: 'apm-*', body: { foo: 'bar' } } as any); - expect(callWithRequestSpy).toHaveBeenCalledWith(mockRequest, 'search', { + expect( + mockContext.core.elasticsearch.dataClient.callAsCurrentUser + ).toHaveBeenCalledWith('search', { index: 'apm-*', body: { foo: 'bar', @@ -71,13 +97,15 @@ describe('setupRequest', () => { }); it('should call callWithInternalUser with default args', async () => { - const { mockRequest, callWithInternalUserSpy } = getMockRequest(); - const { internalClient } = await setupRequest(mockRequest); + const { mockContext, mockRequest } = getMockRequest(); + const { internalClient } = await setupRequest(mockContext, mockRequest); await internalClient.search({ index: 'apm-*', body: { foo: 'bar' } } as any); - expect(callWithInternalUserSpy).toHaveBeenCalledWith('search', { + expect( + mockContext.core.elasticsearch.dataClient.callAsInternalUser + ).toHaveBeenCalledWith('search', { index: 'apm-*', body: { foo: 'bar', @@ -94,13 +122,15 @@ describe('setupRequest', () => { describe('observer.version_major filter', () => { describe('if index is apm-*', () => { it('should merge `observer.version_major` filter with existing boolean filters', async () => { - const { mockRequest, callWithRequestSpy } = getMockRequest(); - const { client } = await setupRequest(mockRequest); + const { mockContext, mockRequest } = getMockRequest(); + const { client } = await setupRequest(mockContext, mockRequest); await client.search({ index: 'apm-*', body: { query: { bool: { filter: [{ term: 'someTerm' }] } } } }); - const params = callWithRequestSpy.mock.calls[0][2]; + const params = + mockContext.core.elasticsearch.dataClient.callAsCurrentUser.mock + .calls[0][1]; expect(params.body).toEqual({ query: { bool: { @@ -114,10 +144,12 @@ describe('setupRequest', () => { }); it('should add `observer.version_major` filter if none exists', async () => { - const { mockRequest, callWithRequestSpy } = getMockRequest(); - const { client } = await setupRequest(mockRequest); + const { mockContext, mockRequest } = getMockRequest(); + const { client } = await setupRequest(mockContext, mockRequest); await client.search({ index: 'apm-*' }); - const params = callWithRequestSpy.mock.calls[0][2]; + const params = + mockContext.core.elasticsearch.dataClient.callAsCurrentUser.mock + .calls[0][1]; expect(params.body).toEqual({ query: { bool: { @@ -128,8 +160,8 @@ describe('setupRequest', () => { }); it('should not add `observer.version_major` filter if `includeLegacyData=true`', async () => { - const { mockRequest, callWithRequestSpy } = getMockRequest(); - const { client } = await setupRequest(mockRequest); + const { mockContext, mockRequest } = getMockRequest(); + const { client } = await setupRequest(mockContext, mockRequest); await client.search( { index: 'apm-*', @@ -139,7 +171,9 @@ describe('setupRequest', () => { includeLegacyData: true } ); - const params = callWithRequestSpy.mock.calls[0][2]; + const params = + mockContext.core.elasticsearch.dataClient.callAsCurrentUser.mock + .calls[0][1]; expect(params.body).toEqual({ query: { bool: { filter: [{ term: 'someTerm' }] } } }); @@ -147,15 +181,17 @@ describe('setupRequest', () => { }); it('if index is not an APM index, it should not add `observer.version_major` filter', async () => { - const { mockRequest, callWithRequestSpy } = getMockRequest(); - const { client } = await setupRequest(mockRequest); + const { mockContext, mockRequest } = getMockRequest(); + const { client } = await setupRequest(mockContext, mockRequest); await client.search({ index: '.ml-*', body: { query: { bool: { filter: [{ term: 'someTerm' }] } } } }); - const params = callWithRequestSpy.mock.calls[0][2]; + const params = + mockContext.core.elasticsearch.dataClient.callAsCurrentUser.mock + .calls[0][1]; expect(params.body).toEqual({ query: { bool: { @@ -168,28 +204,34 @@ describe('setupRequest', () => { describe('ignore_throttled', () => { it('should set `ignore_throttled=true` if `includeFrozen=false`', async () => { - const { mockRequest, callWithRequestSpy } = getMockRequest(); + const { mockContext, mockRequest } = getMockRequest(); - const uiSettingsService = uiSettingsServiceMock.createClient(); // mock includeFrozen to return false - uiSettingsService.get.mockResolvedValue(false); - mockRequest.getUiSettingsService = () => uiSettingsService; - const { client } = await setupRequest(mockRequest); + mockContext.core.uiSettings.client.get.mockResolvedValue(false); + + const { client } = await setupRequest(mockContext, mockRequest); + await client.search({}); - const params = callWithRequestSpy.mock.calls[0][2]; + + const params = + mockContext.core.elasticsearch.dataClient.callAsCurrentUser.mock + .calls[0][1]; expect(params.ignore_throttled).toBe(true); }); it('should set `ignore_throttled=false` if `includeFrozen=true`', async () => { - const { mockRequest, callWithRequestSpy } = getMockRequest(); + const { mockContext, mockRequest } = getMockRequest(); - const uiSettingsService = uiSettingsServiceMock.createClient(); // mock includeFrozen to return true - uiSettingsService.get.mockResolvedValue(true); - mockRequest.getUiSettingsService = () => uiSettingsService; - const { client } = await setupRequest(mockRequest); + mockContext.core.uiSettings.client.get.mockResolvedValue(true); + + const { client } = await setupRequest(mockContext, mockRequest); + await client.search({}); - const params = callWithRequestSpy.mock.calls[0][2]; + + const params = + mockContext.core.elasticsearch.dataClient.callAsCurrentUser.mock + .calls[0][1]; expect(params.ignore_throttled).toBe(false); }); }); diff --git a/x-pack/legacy/plugins/apm/server/lib/helpers/setup_request.ts b/x-pack/legacy/plugins/apm/server/lib/helpers/setup_request.ts index c5f76ec51b279..8f19f4baed7ee 100644 --- a/x-pack/legacy/plugins/apm/server/lib/helpers/setup_request.ts +++ b/x-pack/legacy/plugins/apm/server/lib/helpers/setup_request.ts @@ -4,21 +4,22 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Legacy } from 'kibana'; import moment from 'moment'; -import { KibanaConfig } from 'src/legacy/server/kbn_server'; -import { getESClient } from './es_client'; -import { getUiFiltersES } from './convert_ui_filters/get_ui_filters_es'; +import { KibanaRequest } from 'src/core/server'; +import { StaticIndexPattern } from 'ui/index_patterns'; +import { IIndexPattern } from 'src/plugins/data/common'; +import { APMConfig } from '../../../../../../plugins/apm/server'; import { getApmIndices, ApmIndicesConfig } from '../settings/apm_indices/get_apm_indices'; import { ESFilter } from '../../../typings/elasticsearch'; import { ESClient } from './es_client'; -import { StaticIndexPattern } from '../../../../../../../src/legacy/core_plugins/data/public'; -import { getDynamicIndexPattern } from '../index_pattern/get_dynamic_index_pattern'; -import { IIndexPattern } from '../../../../../../../src/plugins/data/common'; +import { getUiFiltersES } from './convert_ui_filters/get_ui_filters_es'; +import { APMRequestHandlerContext } from '../../routes/typings'; +import { getESClient } from './es_client'; import { ProcessorEvent } from '../../../common/processor_event'; +import { getDynamicIndexPattern } from '../index_pattern/get_dynamic_index_pattern'; function decodeUiFilters( indexPattern: StaticIndexPattern | undefined, @@ -30,52 +31,73 @@ function decodeUiFilters( const uiFilters = JSON.parse(uiFiltersEncoded); return getUiFiltersES(indexPattern, uiFilters); } - -export interface APMRequestQuery { - _debug?: string; - start?: string; - end?: string; - uiFilters?: string; - processorEvent?: ProcessorEvent; -} // Explicitly type Setup to prevent TS initialization errors // https://github.com/microsoft/TypeScript/issues/34933 export interface Setup { - start: number; - end: number; - uiFiltersES: ESFilter[]; client: ESClient; internalClient: ESClient; - config: KibanaConfig; + config: APMConfig; indices: ApmIndicesConfig; dynamicIndexPattern?: IIndexPattern; } -export async function setupRequest(req: Legacy.Request): Promise { - const query = (req.query as unknown) as APMRequestQuery; - const { server } = req; - const savedObjectsClient = server.savedObjects.getScopedSavedObjectsClient( - req - ); - const config = server.config(); - const indices = await getApmIndices({ config, savedObjectsClient }); +export interface SetupTimeRange { + start: number; + end: number; +} +export interface SetupUIFilters { + uiFiltersES: ESFilter[]; +} + +interface SetupRequestParams { + query?: { + _debug?: boolean; + start?: string; + end?: string; + uiFilters?: string; + processorEvent?: ProcessorEvent; + }; +} + +type InferSetup = Setup & + (TParams extends { query: { start: string } } ? { start: number } : {}) & + (TParams extends { query: { end: string } } ? { end: number } : {}) & + (TParams extends { query: { uiFilters: string } } + ? { uiFiltersES: ESFilter[] } + : {}); + +export async function setupRequest( + context: APMRequestHandlerContext, + request: KibanaRequest +): Promise> { + const { config } = context; + const { query } = context.params; + + const indices = await getApmIndices(context); const dynamicIndexPattern = await getDynamicIndexPattern({ - request: req, + context, indices, processorEvent: query.processorEvent }); + const uiFiltersES = decodeUiFilters(dynamicIndexPattern, query.uiFilters); - return { - start: moment.utc(query.start).valueOf(), - end: moment.utc(query.end).valueOf(), - uiFiltersES, - client: getESClient(req, { clientAsInternalUser: false }), - internalClient: getESClient(req, { clientAsInternalUser: true }), - config, + const coreSetupRequest = { indices, + client: getESClient(context, request, { clientAsInternalUser: false }), + internalClient: getESClient(context, request, { + clientAsInternalUser: true + }), + config, dynamicIndexPattern }; + + return { + ...('start' in query ? { start: moment.utc(query.start).valueOf() } : {}), + ...('end' in query ? { end: moment.utc(query.end).valueOf() } : {}), + ...('uiFilters' in query ? { uiFiltersES } : {}), + ...coreSetupRequest + } as InferSetup; } diff --git a/x-pack/legacy/plugins/apm/server/lib/index_pattern/create_static_index_pattern.test.ts b/x-pack/legacy/plugins/apm/server/lib/index_pattern/create_static_index_pattern.test.ts index 83294ede080c7..2a31563b53c2c 100644 --- a/x-pack/legacy/plugins/apm/server/lib/index_pattern/create_static_index_pattern.test.ts +++ b/x-pack/legacy/plugins/apm/server/lib/index_pattern/create_static_index_pattern.test.ts @@ -4,14 +4,23 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Server } from 'hapi'; import { createStaticIndexPattern } from './create_static_index_pattern'; import { Setup } from '../helpers/setup_request'; import * as savedObjectsClient from '../helpers/saved_objects_client'; import * as HistoricalAgentData from '../services/get_services/has_historical_agent_data'; +import { APMRequestHandlerContext } from '../../routes/typings'; -function getMockConfig(config: Record) { - return () => ({ get: (key: string) => config[key] }); +function getMockContext(config: Record) { + return ({ + config, + __LEGACY: { + server: { + savedObjects: { + getSavedObjectsRepository: jest.fn() + } + } + } + } as unknown) as APMRequestHandlerContext; } describe('createStaticIndexPattern', () => { @@ -27,46 +36,40 @@ describe('createStaticIndexPattern', () => { it(`should not create index pattern if 'xpack.apm.autocreateApmIndexPattern=false'`, async () => { const setup = {} as Setup; - const server = { - config: getMockConfig({ - 'xpack.apm.autocreateApmIndexPattern': false - }) - } as Server; - await createStaticIndexPattern(setup, server); + const context = getMockContext({ + 'xpack.apm.autocreateApmIndexPattern': false + }); + await createStaticIndexPattern(setup, context); expect(createSavedObject).not.toHaveBeenCalled(); }); it(`should not create index pattern if no APM data is found`, async () => { const setup = {} as Setup; - const server = { - config: getMockConfig({ - 'xpack.apm.autocreateApmIndexPattern': true - }) - } as Server; + const context = getMockContext({ + 'xpack.apm.autocreateApmIndexPattern': true + }); // does not have APM data jest .spyOn(HistoricalAgentData, 'hasHistoricalAgentData') .mockResolvedValue(false); - await createStaticIndexPattern(setup, server); + await createStaticIndexPattern(setup, context); expect(createSavedObject).not.toHaveBeenCalled(); }); it(`should create index pattern`, async () => { const setup = {} as Setup; - const server = { - config: getMockConfig({ - 'xpack.apm.autocreateApmIndexPattern': true - }) - } as Server; + const context = getMockContext({ + 'xpack.apm.autocreateApmIndexPattern': true + }); // does have APM data jest .spyOn(HistoricalAgentData, 'hasHistoricalAgentData') .mockResolvedValue(true); - await createStaticIndexPattern(setup, server); + await createStaticIndexPattern(setup, context); expect(createSavedObject).toHaveBeenCalled(); }); diff --git a/x-pack/legacy/plugins/apm/server/lib/index_pattern/create_static_index_pattern.ts b/x-pack/legacy/plugins/apm/server/lib/index_pattern/create_static_index_pattern.ts index 709d287283932..562eb8850aa0c 100644 --- a/x-pack/legacy/plugins/apm/server/lib/index_pattern/create_static_index_pattern.ts +++ b/x-pack/legacy/plugins/apm/server/lib/index_pattern/create_static_index_pattern.ts @@ -3,7 +3,6 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { Server } from 'hapi'; import { getInternalSavedObjectsClient } from '../helpers/saved_objects_client'; import apmIndexPattern from '../../../../../../../src/legacy/core_plugins/kibana/server/tutorials/apm/index_pattern.json'; import { APM_STATIC_INDEX_PATTERN_ID } from '../../../common/index_pattern_constants'; @@ -11,15 +10,16 @@ import { APM_STATIC_INDEX_PATTERN_ID } from '../../../common/index_pattern_const import { SavedObjectsErrorHelpers } from '../../../../../../../src/core/server/saved_objects'; import { hasHistoricalAgentData } from '../services/get_services/has_historical_agent_data'; import { Setup } from '../helpers/setup_request'; +import { APMRequestHandlerContext } from '../../routes/typings'; export async function createStaticIndexPattern( setup: Setup, - server: Server + context: APMRequestHandlerContext ): Promise { - const config = server.config(); + const { config } = context; // don't autocreate APM index pattern if it's been disabled via the config - if (!config.get('xpack.apm.autocreateApmIndexPattern')) { + if (!config['xpack.apm.autocreateApmIndexPattern']) { return; } @@ -31,8 +31,10 @@ export async function createStaticIndexPattern( } try { - const apmIndexPatternTitle = config.get('apm_oss.indexPattern'); - const internalSavedObjectsClient = getInternalSavedObjectsClient(server); + const apmIndexPatternTitle = config['apm_oss.indexPattern']; + const internalSavedObjectsClient = getInternalSavedObjectsClient( + context.__LEGACY.server + ); await internalSavedObjectsClient.create( 'index-pattern', { diff --git a/x-pack/legacy/plugins/apm/server/lib/index_pattern/get_dynamic_index_pattern.ts b/x-pack/legacy/plugins/apm/server/lib/index_pattern/get_dynamic_index_pattern.ts index b0a6eb7aebe8b..f113e645ed95f 100644 --- a/x-pack/legacy/plugins/apm/server/lib/index_pattern/get_dynamic_index_pattern.ts +++ b/x-pack/legacy/plugins/apm/server/lib/index_pattern/get_dynamic_index_pattern.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Legacy } from 'kibana'; import { StaticIndexPattern } from 'ui/index_patterns'; import { APICaller } from 'src/core/server'; import LRU from 'lru-cache'; @@ -14,6 +13,7 @@ import { } from '../../../../../../../src/plugins/data/server'; import { ApmIndicesConfig } from '../settings/apm_indices/get_apm_indices'; import { ProcessorEvent } from '../../../common/processor_event'; +import { APMRequestHandlerContext } from '../../routes/typings'; const cache = new LRU({ max: 100, @@ -22,11 +22,11 @@ const cache = new LRU({ // TODO: this is currently cached globally. In the future we might want to cache this per user export const getDynamicIndexPattern = async ({ - request, + context, indices, processorEvent }: { - request: Legacy.Request; + context: APMRequestHandlerContext; indices: ApmIndicesConfig; processorEvent?: ProcessorEvent; }) => { @@ -39,9 +39,7 @@ export const getDynamicIndexPattern = async ({ const indexPatternsFetcher = new IndexPatternsFetcher( (...rest: Parameters) => - request.server.plugins.elasticsearch - .getCluster('data') - .callWithRequest(request, ...rest) + context.core.elasticsearch.adminClient.callAsCurrentUser(...rest) ); // Since `getDynamicIndexPattern` is called in setup_request (and thus by every endpoint) diff --git a/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/default.ts b/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/default.ts index f55d3320c7f4e..72aa93d7f6ce3 100644 --- a/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/default.ts +++ b/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/default.ts @@ -4,12 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Setup } from '../../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../helpers/setup_request'; import { getCPUChartData } from './shared/cpu'; import { getMemoryChartData } from './shared/memory'; export async function getDefaultMetricsCharts( - setup: Setup, + setup: Setup & SetupTimeRange & SetupUIFilters, serviceName: string ) { const charts = await Promise.all([ diff --git a/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/java/gc/fetchAndTransformGcMetrics.ts b/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/java/gc/fetchAndTransformGcMetrics.ts index 8cff6e5d3aa80..8ffc115a19348 100644 --- a/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/java/gc/fetchAndTransformGcMetrics.ts +++ b/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/java/gc/fetchAndTransformGcMetrics.ts @@ -11,7 +11,11 @@ import { sum, round } from 'lodash'; import theme from '@elastic/eui/dist/eui_theme_light.json'; -import { Setup } from '../../../../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../../../helpers/setup_request'; import { getMetricsDateHistogramParams } from '../../../../helpers/metrics'; import { ChartBase } from '../../../types'; import { getMetricsProjection } from '../../../../../../common/projections/metrics'; @@ -32,7 +36,7 @@ export async function fetchAndTransformGcMetrics({ chartBase, fieldName }: { - setup: Setup; + setup: Setup & SetupTimeRange & SetupUIFilters; serviceName: string; serviceNodeName?: string; chartBase: ChartBase; diff --git a/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/java/gc/getGcRateChart.ts b/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/java/gc/getGcRateChart.ts index 642c6a901da9d..21417891fa15f 100644 --- a/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/java/gc/getGcRateChart.ts +++ b/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/java/gc/getGcRateChart.ts @@ -7,7 +7,11 @@ import theme from '@elastic/eui/dist/eui_theme_light.json'; import { i18n } from '@kbn/i18n'; import { METRIC_JAVA_GC_COUNT } from '../../../../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../../../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../../../helpers/setup_request'; import { fetchAndTransformGcMetrics } from './fetchAndTransformGcMetrics'; import { ChartBase } from '../../../types'; @@ -31,7 +35,7 @@ const chartBase: ChartBase = { }; const getGcRateChart = ( - setup: Setup, + setup: Setup & SetupTimeRange & SetupUIFilters, serviceName: string, serviceNodeName?: string ) => { diff --git a/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/java/gc/getGcTimeChart.ts b/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/java/gc/getGcTimeChart.ts index b6e992acf62a9..ea7557fabacd0 100644 --- a/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/java/gc/getGcTimeChart.ts +++ b/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/java/gc/getGcTimeChart.ts @@ -7,7 +7,11 @@ import theme from '@elastic/eui/dist/eui_theme_light.json'; import { i18n } from '@kbn/i18n'; import { METRIC_JAVA_GC_TIME } from '../../../../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../../../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../../../helpers/setup_request'; import { fetchAndTransformGcMetrics } from './fetchAndTransformGcMetrics'; import { ChartBase } from '../../../types'; @@ -31,7 +35,7 @@ const chartBase: ChartBase = { }; const getGcTimeChart = ( - setup: Setup, + setup: Setup & SetupTimeRange & SetupUIFilters, serviceName: string, serviceNodeName?: string ) => { diff --git a/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/java/heap_memory/index.ts b/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/java/heap_memory/index.ts index ca98a486b3a58..901812815b3f3 100644 --- a/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/java/heap_memory/index.ts +++ b/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/java/heap_memory/index.ts @@ -12,7 +12,11 @@ import { METRIC_JAVA_HEAP_MEMORY_USED, SERVICE_AGENT_NAME } from '../../../../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../../../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../../../helpers/setup_request'; import { fetchAndTransformMetrics } from '../../../fetch_and_transform_metrics'; import { ChartBase } from '../../../types'; @@ -51,7 +55,7 @@ const chartBase: ChartBase = { }; export async function getHeapMemoryChart( - setup: Setup, + setup: Setup & SetupTimeRange & SetupUIFilters, serviceName: string, serviceNodeName?: string ) { diff --git a/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/java/index.ts b/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/java/index.ts index e8f9e4345d06c..191a7a2c14d23 100644 --- a/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/java/index.ts +++ b/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/java/index.ts @@ -5,7 +5,11 @@ */ import { getHeapMemoryChart } from './heap_memory'; -import { Setup } from '../../../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../../helpers/setup_request'; import { getNonHeapMemoryChart } from './non_heap_memory'; import { getThreadCountChart } from './thread_count'; import { getCPUChartData } from '../shared/cpu'; @@ -14,7 +18,7 @@ import { getGcRateChart } from './gc/getGcRateChart'; import { getGcTimeChart } from './gc/getGcTimeChart'; export async function getJavaMetricsCharts( - setup: Setup, + setup: Setup & SetupTimeRange & SetupUIFilters, serviceName: string, serviceNodeName?: string ) { diff --git a/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/java/non_heap_memory/index.ts b/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/java/non_heap_memory/index.ts index 899852e1d5659..7ff4e073e919b 100644 --- a/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/java/non_heap_memory/index.ts +++ b/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/java/non_heap_memory/index.ts @@ -12,7 +12,11 @@ import { METRIC_JAVA_NON_HEAP_MEMORY_USED, SERVICE_AGENT_NAME } from '../../../../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../../../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../../../helpers/setup_request'; import { ChartBase } from '../../../types'; import { fetchAndTransformMetrics } from '../../../fetch_and_transform_metrics'; @@ -48,7 +52,7 @@ const chartBase: ChartBase = { }; export async function getNonHeapMemoryChart( - setup: Setup, + setup: Setup & SetupUIFilters & SetupTimeRange, serviceName: string, serviceNodeName?: string ) { diff --git a/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/java/thread_count/index.ts b/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/java/thread_count/index.ts index eb0984d7aaf59..cf8e120b00e0d 100644 --- a/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/java/thread_count/index.ts +++ b/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/java/thread_count/index.ts @@ -10,7 +10,11 @@ import { METRIC_JAVA_THREAD_COUNT, SERVICE_AGENT_NAME } from '../../../../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../../../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../../../helpers/setup_request'; import { ChartBase } from '../../../types'; import { fetchAndTransformMetrics } from '../../../fetch_and_transform_metrics'; @@ -40,7 +44,7 @@ const chartBase: ChartBase = { }; export async function getThreadCountChart( - setup: Setup, + setup: Setup & SetupTimeRange & SetupUIFilters, serviceName: string, serviceNodeName?: string ) { diff --git a/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/shared/cpu/index.ts b/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/shared/cpu/index.ts index 5f4ad0af474c1..179ed77eedbb3 100644 --- a/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/shared/cpu/index.ts +++ b/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/shared/cpu/index.ts @@ -10,7 +10,11 @@ import { METRIC_SYSTEM_CPU_PERCENT, METRIC_PROCESS_CPU_PERCENT } from '../../../../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../../../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../../../helpers/setup_request'; import { ChartBase } from '../../../types'; import { fetchAndTransformMetrics } from '../../../fetch_and_transform_metrics'; @@ -52,7 +56,7 @@ const chartBase: ChartBase = { }; export async function getCPUChartData( - setup: Setup, + setup: Setup & SetupTimeRange & SetupUIFilters, serviceName: string, serviceNodeName?: string ) { diff --git a/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/shared/memory/index.ts b/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/shared/memory/index.ts index bf0f21dcb3d42..8c6ed2ebcec75 100644 --- a/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/shared/memory/index.ts +++ b/x-pack/legacy/plugins/apm/server/lib/metrics/by_agent/shared/memory/index.ts @@ -9,7 +9,11 @@ import { METRIC_SYSTEM_FREE_MEMORY, METRIC_SYSTEM_TOTAL_MEMORY } from '../../../../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../../../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../../../helpers/setup_request'; import { ChartBase } from '../../../types'; import { fetchAndTransformMetrics } from '../../../fetch_and_transform_metrics'; @@ -45,7 +49,7 @@ const percentUsedScript = { }; export async function getMemoryChartData( - setup: Setup, + setup: Setup & SetupTimeRange & SetupUIFilters, serviceName: string, serviceNodeName?: string ) { diff --git a/x-pack/legacy/plugins/apm/server/lib/metrics/fetch_and_transform_metrics.ts b/x-pack/legacy/plugins/apm/server/lib/metrics/fetch_and_transform_metrics.ts index 3d425e50bc60a..76460bb40bedb 100644 --- a/x-pack/legacy/plugins/apm/server/lib/metrics/fetch_and_transform_metrics.ts +++ b/x-pack/legacy/plugins/apm/server/lib/metrics/fetch_and_transform_metrics.ts @@ -5,7 +5,11 @@ */ import { Unionize } from 'utility-types'; -import { Setup } from '../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../helpers/setup_request'; import { getMetricsDateHistogramParams } from '../helpers/metrics'; import { ChartBase } from './types'; import { transformDataToMetricsChart } from './transform_metrics_chart'; @@ -39,7 +43,7 @@ export async function fetchAndTransformMetrics({ aggs, additionalFilters = [] }: { - setup: Setup; + setup: Setup & SetupTimeRange & SetupUIFilters; serviceName: string; serviceNodeName?: string; chartBase: ChartBase; diff --git a/x-pack/legacy/plugins/apm/server/lib/metrics/get_metrics_chart_data_by_agent.ts b/x-pack/legacy/plugins/apm/server/lib/metrics/get_metrics_chart_data_by_agent.ts index 34c8b2f867fbb..e0b496754fc9e 100644 --- a/x-pack/legacy/plugins/apm/server/lib/metrics/get_metrics_chart_data_by_agent.ts +++ b/x-pack/legacy/plugins/apm/server/lib/metrics/get_metrics_chart_data_by_agent.ts @@ -3,7 +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 { Setup } from '../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../helpers/setup_request'; import { getJavaMetricsCharts } from './by_agent/java'; import { getDefaultMetricsCharts } from './by_agent/default'; import { GenericMetricsChart } from './transform_metrics_chart'; @@ -18,7 +22,7 @@ export async function getMetricsChartDataByAgent({ serviceNodeName, agentName }: { - setup: Setup; + setup: Setup & SetupTimeRange & SetupUIFilters; serviceName: string; serviceNodeName?: string; agentName: string; diff --git a/x-pack/legacy/plugins/apm/server/lib/service_nodes/index.ts b/x-pack/legacy/plugins/apm/server/lib/service_nodes/index.ts index 1e415252200ce..b674afe635bcd 100644 --- a/x-pack/legacy/plugins/apm/server/lib/service_nodes/index.ts +++ b/x-pack/legacy/plugins/apm/server/lib/service_nodes/index.ts @@ -4,7 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Setup } from '../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../helpers/setup_request'; import { getServiceNodesProjection } from '../../../common/projections/service_nodes'; import { mergeProjection } from '../../../common/projections/util/merge_projection'; import { SERVICE_NODE_NAME_MISSING } from '../../../common/service_nodes'; @@ -19,7 +23,7 @@ const getServiceNodes = async ({ setup, serviceName }: { - setup: Setup; + setup: Setup & SetupTimeRange & SetupUIFilters; serviceName: string; }) => { const { client } = setup; diff --git a/x-pack/legacy/plugins/apm/server/lib/services/get_service_agent_name.ts b/x-pack/legacy/plugins/apm/server/lib/services/get_service_agent_name.ts index 9e070f936a25f..a1a2c1a38b3d4 100644 --- a/x-pack/legacy/plugins/apm/server/lib/services/get_service_agent_name.ts +++ b/x-pack/legacy/plugins/apm/server/lib/services/get_service_agent_name.ts @@ -9,9 +9,12 @@ import { SERVICE_NAME } from '../../../common/elasticsearch_fieldnames'; import { rangeFilter } from '../helpers/range_filter'; -import { Setup } from '../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; -export async function getServiceAgentName(serviceName: string, setup: Setup) { +export async function getServiceAgentName( + serviceName: string, + setup: Setup & SetupTimeRange +) { const { start, end, client, indices } = setup; const params = { diff --git a/x-pack/legacy/plugins/apm/server/lib/services/get_service_node_metadata.ts b/x-pack/legacy/plugins/apm/server/lib/services/get_service_node_metadata.ts index e93f6b4a1c17c..7120d3bca6c25 100644 --- a/x-pack/legacy/plugins/apm/server/lib/services/get_service_node_metadata.ts +++ b/x-pack/legacy/plugins/apm/server/lib/services/get_service_node_metadata.ts @@ -4,7 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Setup } from '../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../helpers/setup_request'; import { HOST_NAME, CONTAINER_ID @@ -20,7 +24,7 @@ export async function getServiceNodeMetadata({ }: { serviceName: string; serviceNodeName: string; - setup: Setup; + setup: Setup & SetupTimeRange & SetupUIFilters; }) { const { client } = setup; diff --git a/x-pack/legacy/plugins/apm/server/lib/services/get_service_transaction_types.ts b/x-pack/legacy/plugins/apm/server/lib/services/get_service_transaction_types.ts index 098342bf0221d..60f6e63bb7b25 100644 --- a/x-pack/legacy/plugins/apm/server/lib/services/get_service_transaction_types.ts +++ b/x-pack/legacy/plugins/apm/server/lib/services/get_service_transaction_types.ts @@ -9,11 +9,11 @@ import { TRANSACTION_TYPE } from '../../../common/elasticsearch_fieldnames'; import { rangeFilter } from '../helpers/range_filter'; -import { Setup } from '../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; export async function getServiceTransactionTypes( serviceName: string, - setup: Setup + setup: Setup & SetupTimeRange ) { const { start, end, client, indices } = setup; diff --git a/x-pack/legacy/plugins/apm/server/lib/services/get_services/get_services_items.ts b/x-pack/legacy/plugins/apm/server/lib/services/get_services/get_services_items.ts index 6611ae76bc339..8e578a839ae56 100644 --- a/x-pack/legacy/plugins/apm/server/lib/services/get_services/get_services_items.ts +++ b/x-pack/legacy/plugins/apm/server/lib/services/get_services/get_services_items.ts @@ -12,11 +12,17 @@ import { TRANSACTION_DURATION } from '../../../../common/elasticsearch_fieldnames'; import { PromiseReturnType } from '../../../../typings/common'; -import { Setup } from '../../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../helpers/setup_request'; import { getServicesProjection } from '../../../../common/projections/services'; export type ServiceListAPIResponse = PromiseReturnType; -export async function getServicesItems(setup: Setup) { +export async function getServicesItems( + setup: Setup & SetupTimeRange & SetupUIFilters +) { const { start, end, client } = setup; const projection = getServicesProjection({ setup }); diff --git a/x-pack/legacy/plugins/apm/server/lib/services/get_services/index.ts b/x-pack/legacy/plugins/apm/server/lib/services/get_services/index.ts index ffa9555c29070..d9fc89062cf88 100644 --- a/x-pack/legacy/plugins/apm/server/lib/services/get_services/index.ts +++ b/x-pack/legacy/plugins/apm/server/lib/services/get_services/index.ts @@ -6,26 +6,33 @@ import { isEmpty } from 'lodash'; import { PromiseReturnType } from '../../../../typings/common'; -import { Setup } from '../../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../helpers/setup_request'; import { hasHistoricalAgentData } from './has_historical_agent_data'; import { getLegacyDataStatus } from './get_legacy_data_status'; import { getServicesItems } from './get_services_items'; export type ServiceListAPIResponse = PromiseReturnType; -export async function getServices(setup: Setup) { - const items = await getServicesItems(setup); - const hasLegacyData = await getLegacyDataStatus(setup); - // conditionally check for historical data if no services were found in the current time range +export async function getServices( + setup: Setup & SetupTimeRange & SetupUIFilters +) { + const [items, hasLegacyData] = await Promise.all([ + getServicesItems(setup), + getLegacyDataStatus(setup) + ]); + const noDataInCurrentTimeRange = isEmpty(items); - let hasHistorialAgentData = true; - if (noDataInCurrentTimeRange) { - hasHistorialAgentData = await hasHistoricalAgentData(setup); - } + const hasHistoricalData = noDataInCurrentTimeRange + ? await hasHistoricalAgentData(setup) + : true; return { items, - hasHistoricalData: hasHistorialAgentData, + hasHistoricalData, hasLegacyData }; } diff --git a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/create_agent_config_index.ts b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/create_agent_config_index.ts index 434eda8c0f46e..52ba22cbc0b99 100644 --- a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/create_agent_config_index.ts +++ b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/create_agent_config_index.ts @@ -4,31 +4,25 @@ * you may not use this file except in compliance with the Elastic License. */ -import { CoreSetup } from 'src/core/server'; +import { IClusterClient } from 'src/core/server'; +import { APMConfig } from '../../../../../../../plugins/apm/server'; import { CallCluster } from '../../../../../../../../src/legacy/core_plugins/elasticsearch'; -import { getApmIndices } from '../apm_indices/get_apm_indices'; -import { LegacySetup } from '../../../new-platform/plugin'; -import { getInternalSavedObjectsClient } from '../../helpers/saved_objects_client'; +import { getApmIndicesConfig } from '../apm_indices/get_apm_indices'; -export async function createApmAgentConfigurationIndex( - core: CoreSetup, - { server }: LegacySetup -) { +export async function createApmAgentConfigurationIndex({ + esClient, + config +}: { + esClient: IClusterClient; + config: APMConfig; +}) { try { - const config = server.config(); - const internalSavedObjectsClient = getInternalSavedObjectsClient(server); - const indices = await getApmIndices({ - savedObjectsClient: internalSavedObjectsClient, - config - }); - const index = indices['apm_oss.apmAgentConfigurationIndex']; - const { callWithInternalUser } = server.plugins.elasticsearch.getCluster( - 'admin' - ); - const indexExists = await callWithInternalUser('indices.exists', { index }); + const index = getApmIndicesConfig(config).apmAgentConfigurationIndex; + const { callAsInternalUser } = esClient; + const indexExists = await callAsInternalUser('indices.exists', { index }); const result = indexExists - ? await updateExistingIndex(index, callWithInternalUser) - : await createNewIndex(index, callWithInternalUser); + ? await updateExistingIndex(index, callAsInternalUser) + : await createNewIndex(index, callAsInternalUser); if (!result.acknowledged) { const resultError = diff --git a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/create_or_update_configuration.ts b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/create_or_update_configuration.ts index 23faa4b74cf8f..5a67f78de6f65 100644 --- a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/create_or_update_configuration.ts +++ b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/create_or_update_configuration.ts @@ -25,7 +25,7 @@ export async function createOrUpdateConfiguration({ const params: APMIndexDocumentParams = { refresh: true, - index: indices['apm_oss.apmAgentConfigurationIndex'], + index: indices.apmAgentConfigurationIndex, body: { agent_name: configuration.agent_name, service: { diff --git a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/delete_configuration.ts b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/delete_configuration.ts index ed20a58b271e1..293c01d4b61d5 100644 --- a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/delete_configuration.ts +++ b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/delete_configuration.ts @@ -17,7 +17,7 @@ export async function deleteConfiguration({ const params = { refresh: 'wait_for', - index: indices['apm_oss.apmAgentConfigurationIndex'], + index: indices.apmAgentConfigurationIndex, id: configurationId }; diff --git a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/get_environments/get_existing_environments_for_service.ts b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/get_environments/get_existing_environments_for_service.ts index fc3b62738f8fe..f54217461510f 100644 --- a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/get_environments/get_existing_environments_for_service.ts +++ b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/get_environments/get_existing_environments_for_service.ts @@ -25,7 +25,7 @@ export async function getExistingEnvironmentsForService({ : { must_not: [{ exists: { field: SERVICE_NAME } }] }; const params = { - index: indices['apm_oss.apmAgentConfigurationIndex'], + index: indices.apmAgentConfigurationIndex, body: { size: 0, query: { bool }, diff --git a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/list_configurations.ts b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/list_configurations.ts index dd4d019ef7263..12faa9fba1074 100644 --- a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/list_configurations.ts +++ b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/list_configurations.ts @@ -15,7 +15,7 @@ export async function listConfigurations({ setup }: { setup: Setup }) { const { internalClient, indices } = setup; const params = { - index: indices['apm_oss.apmAgentConfigurationIndex'] + index: indices.apmAgentConfigurationIndex }; const resp = await internalClient.search(params); diff --git a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/mark_applied_by_agent.ts b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/mark_applied_by_agent.ts index b7b9c21172140..b6aecd1d7f0ca 100644 --- a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/mark_applied_by_agent.ts +++ b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/mark_applied_by_agent.ts @@ -19,7 +19,7 @@ export async function markAppliedByAgent({ const { internalClient, indices } = setup; const params = { - index: indices['apm_oss.apmAgentConfigurationIndex'], + index: indices.apmAgentConfigurationIndex, id, // by specifying the `id` elasticsearch will do an "upsert" body: { ...body, diff --git a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/search.ts b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/search.ts index 969bbc542f8a6..a02dd7af755e0 100644 --- a/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/search.ts +++ b/x-pack/legacy/plugins/apm/server/lib/settings/agent_configuration/search.ts @@ -33,7 +33,7 @@ export async function searchConfigurations({ : []; const params = { - index: indices['apm_oss.apmAgentConfigurationIndex'], + index: indices.apmAgentConfigurationIndex, body: { query: { bool: { diff --git a/x-pack/legacy/plugins/apm/server/lib/settings/apm_indices/get_apm_indices.ts b/x-pack/legacy/plugins/apm/server/lib/settings/apm_indices/get_apm_indices.ts index e942a26da373e..0ed30ec4cdd27 100644 --- a/x-pack/legacy/plugins/apm/server/lib/settings/apm_indices/get_apm_indices.ts +++ b/x-pack/legacy/plugins/apm/server/lib/settings/apm_indices/get_apm_indices.ts @@ -5,13 +5,15 @@ */ import { merge } from 'lodash'; -import { KibanaConfig } from 'src/legacy/server/kbn_server'; import { Server } from 'hapi'; +import { SavedObjectsClientContract } from 'kibana/server'; import { PromiseReturnType } from '../../../../typings/common'; import { APM_INDICES_SAVED_OBJECT_TYPE, APM_INDICES_SAVED_OBJECT_ID } from '../../../../common/apm_saved_object_constants'; +import { APMConfig } from '../../../../../../../plugins/apm/server'; +import { APMRequestHandlerContext } from '../../../routes/typings'; export interface ApmIndicesConfig { 'apm_oss.sourcemapIndices': string; @@ -20,7 +22,7 @@ export interface ApmIndicesConfig { 'apm_oss.spanIndices': string; 'apm_oss.transactionIndices': string; 'apm_oss.metricsIndices': string; - 'apm_oss.apmAgentConfigurationIndex': string; + apmAgentConfigurationIndex: string; } export type ApmIndicesName = keyof ApmIndicesConfig; @@ -30,7 +32,7 @@ export type ScopedSavedObjectsClient = ReturnType< >; async function getApmIndicesSavedObject( - savedObjectsClient: ScopedSavedObjectsClient + savedObjectsClient: SavedObjectsClientContract ) { const apmIndices = await savedObjectsClient.get>( APM_INDICES_SAVED_OBJECT_TYPE, @@ -39,39 +41,28 @@ async function getApmIndicesSavedObject( return apmIndices.attributes; } -function getApmIndicesConfig(config: KibanaConfig): ApmIndicesConfig { +export function getApmIndicesConfig(config: APMConfig): ApmIndicesConfig { return { - 'apm_oss.sourcemapIndices': config.get('apm_oss.sourcemapIndices'), - 'apm_oss.errorIndices': config.get('apm_oss.errorIndices'), - 'apm_oss.onboardingIndices': config.get( - 'apm_oss.onboardingIndices' - ), - 'apm_oss.spanIndices': config.get('apm_oss.spanIndices'), - 'apm_oss.transactionIndices': config.get( - 'apm_oss.transactionIndices' - ), - 'apm_oss.metricsIndices': config.get('apm_oss.metricsIndices'), - 'apm_oss.apmAgentConfigurationIndex': config.get( - 'apm_oss.apmAgentConfigurationIndex' - ) + 'apm_oss.sourcemapIndices': config['apm_oss.sourcemapIndices'], + 'apm_oss.errorIndices': config['apm_oss.errorIndices'], + 'apm_oss.onboardingIndices': config['apm_oss.onboardingIndices'], + 'apm_oss.spanIndices': config['apm_oss.spanIndices'], + 'apm_oss.transactionIndices': config['apm_oss.transactionIndices'], + 'apm_oss.metricsIndices': config['apm_oss.metricsIndices'], + // system indices, not configurable + apmAgentConfigurationIndex: '.apm-agent-configuration' }; } -export async function getApmIndices({ - savedObjectsClient, - config -}: { - savedObjectsClient: ScopedSavedObjectsClient; - config: KibanaConfig; -}) { +export async function getApmIndices(context: APMRequestHandlerContext) { try { const apmIndicesSavedObject = await getApmIndicesSavedObject( - savedObjectsClient + context.core.savedObjects.client ); - const apmIndicesConfig = getApmIndicesConfig(config); + const apmIndicesConfig = getApmIndicesConfig(context.config); return merge({}, apmIndicesConfig, apmIndicesSavedObject); } catch (error) { - return getApmIndicesConfig(config); + return getApmIndicesConfig(context.config); } } @@ -81,20 +72,19 @@ const APM_UI_INDICES: ApmIndicesName[] = [ 'apm_oss.onboardingIndices', 'apm_oss.spanIndices', 'apm_oss.transactionIndices', - 'apm_oss.metricsIndices', - 'apm_oss.apmAgentConfigurationIndex' + 'apm_oss.metricsIndices' ]; export async function getApmIndexSettings({ - config, - savedObjectsClient + context }: { - config: KibanaConfig; - savedObjectsClient: ScopedSavedObjectsClient; + context: APMRequestHandlerContext; }) { let apmIndicesSavedObject: PromiseReturnType; try { - apmIndicesSavedObject = await getApmIndicesSavedObject(savedObjectsClient); + apmIndicesSavedObject = await getApmIndicesSavedObject( + context.core.savedObjects.client + ); } catch (error) { if (error.output && error.output.statusCode === 404) { apmIndicesSavedObject = {}; @@ -102,7 +92,7 @@ export async function getApmIndexSettings({ throw error; } } - const apmIndicesConfig = getApmIndicesConfig(config); + const apmIndicesConfig = getApmIndicesConfig(context.config); return APM_UI_INDICES.map(configurationName => ({ configurationName, diff --git a/x-pack/legacy/plugins/apm/server/lib/settings/apm_indices/save_apm_indices.ts b/x-pack/legacy/plugins/apm/server/lib/settings/apm_indices/save_apm_indices.ts index e57e64942ab89..2fdfd79ce933b 100644 --- a/x-pack/legacy/plugins/apm/server/lib/settings/apm_indices/save_apm_indices.ts +++ b/x-pack/legacy/plugins/apm/server/lib/settings/apm_indices/save_apm_indices.ts @@ -4,17 +4,18 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ApmIndicesConfig, ScopedSavedObjectsClient } from './get_apm_indices'; import { APM_INDICES_SAVED_OBJECT_TYPE, APM_INDICES_SAVED_OBJECT_ID } from '../../../../common/apm_saved_object_constants'; +import { ApmIndicesConfig } from './get_apm_indices'; +import { APMRequestHandlerContext } from '../../../routes/typings'; export async function saveApmIndices( - savedObjectsClient: ScopedSavedObjectsClient, + context: APMRequestHandlerContext, apmIndicesSavedObject: Partial ) { - return await savedObjectsClient.create( + return await context.core.savedObjects.client.create( APM_INDICES_SAVED_OBJECT_TYPE, apmIndicesSavedObject, { diff --git a/x-pack/legacy/plugins/apm/server/lib/traces/get_trace.ts b/x-pack/legacy/plugins/apm/server/lib/traces/get_trace.ts index a296bcbdecccf..e38ce56edde80 100644 --- a/x-pack/legacy/plugins/apm/server/lib/traces/get_trace.ts +++ b/x-pack/legacy/plugins/apm/server/lib/traces/get_trace.ts @@ -6,11 +6,11 @@ import { PromiseReturnType } from '../../../typings/common'; import { getTraceErrorsPerTransaction } from '../errors/get_trace_errors_per_transaction'; -import { Setup } from '../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { getTraceItems } from './get_trace_items'; export type TraceAPIResponse = PromiseReturnType; -export async function getTrace(traceId: string, setup: Setup) { +export async function getTrace(traceId: string, setup: Setup & SetupTimeRange) { const [trace, errorsPerTransaction] = await Promise.all([ getTraceItems(traceId, setup), getTraceErrorsPerTransaction(traceId, setup) diff --git a/x-pack/legacy/plugins/apm/server/lib/traces/get_trace_items.ts b/x-pack/legacy/plugins/apm/server/lib/traces/get_trace_items.ts index 0df5cc016431d..8ea548ab3724b 100644 --- a/x-pack/legacy/plugins/apm/server/lib/traces/get_trace_items.ts +++ b/x-pack/legacy/plugins/apm/server/lib/traces/get_trace_items.ts @@ -14,11 +14,14 @@ import { import { Span } from '../../../typings/es_schemas/ui/Span'; import { Transaction } from '../../../typings/es_schemas/ui/Transaction'; import { rangeFilter } from '../helpers/range_filter'; -import { Setup } from '../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; -export async function getTraceItems(traceId: string, setup: Setup) { +export async function getTraceItems( + traceId: string, + setup: Setup & SetupTimeRange +) { const { start, end, client, config, indices } = setup; - const maxTraceItems = config.get('xpack.apm.ui.maxTraceItems'); + const maxTraceItems = config['xpack.apm.ui.maxTraceItems']; const params = { index: [ diff --git a/x-pack/legacy/plugins/apm/server/lib/transaction_groups/fetcher.test.ts b/x-pack/legacy/plugins/apm/server/lib/transaction_groups/fetcher.test.ts index 1d849fbbaaaf5..4121ff74bfacc 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transaction_groups/fetcher.test.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transaction_groups/fetcher.test.ts @@ -5,6 +5,7 @@ */ import { transactionGroupsFetcher } from './fetcher'; +import { APMConfig } from '../../../../../../plugins/apm/server'; function getSetup() { return { @@ -17,14 +18,8 @@ function getSetup() { search: jest.fn() } as any, config: { - get: jest.fn((key: string) => { - switch (key) { - case 'xpack.apm.ui.transactionGroupBucketSize': - return 100; - } - }), - has: () => true - }, + 'xpack.apm.ui.transactionGroupBucketSize': 100 + } as APMConfig, uiFiltersES: [{ term: { 'service.environment': 'test' } }], indices: { 'apm_oss.sourcemapIndices': 'myIndex', @@ -33,7 +28,7 @@ function getSetup() { 'apm_oss.spanIndices': 'myIndex', 'apm_oss.transactionIndices': 'myIndex', 'apm_oss.metricsIndices': 'myIndex', - 'apm_oss.apmAgentConfigurationIndex': 'myIndex' + apmAgentConfigurationIndex: 'myIndex' }, dynamicIndexPattern: null as any }; diff --git a/x-pack/legacy/plugins/apm/server/lib/transaction_groups/fetcher.ts b/x-pack/legacy/plugins/apm/server/lib/transaction_groups/fetcher.ts index bfa46abcad36f..b08bdc334fc87 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transaction_groups/fetcher.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transaction_groups/fetcher.ts @@ -9,7 +9,11 @@ import { TRANSACTION_SAMPLED } from '../../../common/elasticsearch_fieldnames'; import { PromiseReturnType } from '../../../typings/common'; -import { Setup } from '../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../helpers/setup_request'; import { getTransactionGroupsProjection } from '../../../common/projections/transaction_groups'; import { mergeProjection } from '../../../common/projections/util/merge_projection'; import { SortOptions } from '../../../typings/elasticsearch/aggregations'; @@ -30,7 +34,10 @@ interface TopTraceOptions { export type Options = TopTransactionOptions | TopTraceOptions; export type ESResponse = PromiseReturnType; -export function transactionGroupsFetcher(options: Options, setup: Setup) { +export function transactionGroupsFetcher( + options: Options, + setup: Setup & SetupTimeRange & SetupUIFilters +) { const { client, config } = setup; const projection = getTransactionGroupsProjection({ @@ -57,7 +64,7 @@ export function transactionGroupsFetcher(options: Options, setup: Setup) { terms: { ...projection.body.aggs.transactions.terms, order: { sum: 'desc' as const }, - size: config.get('xpack.apm.ui.transactionGroupBucketSize') + size: config['xpack.apm.ui.transactionGroupBucketSize'] }, aggs: { sample: { diff --git a/x-pack/legacy/plugins/apm/server/lib/transaction_groups/index.ts b/x-pack/legacy/plugins/apm/server/lib/transaction_groups/index.ts index 73e30f28c4206..3656b32c17092 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transaction_groups/index.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transaction_groups/index.ts @@ -4,7 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Setup } from '../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../helpers/setup_request'; import { transactionGroupsFetcher, Options } from './fetcher'; import { transactionGroupsTransformer } from './transform'; import { PromiseReturnType } from '../../../typings/common'; @@ -12,7 +16,10 @@ import { PromiseReturnType } from '../../../typings/common'; export type TransactionGroupListAPIResponse = PromiseReturnType< typeof getTransactionGroupList >; -export async function getTransactionGroupList(options: Options, setup: Setup) { +export async function getTransactionGroupList( + options: Options, + setup: Setup & SetupTimeRange & SetupUIFilters +) { const { start, end } = setup; const response = await transactionGroupsFetcher(options, setup); return transactionGroupsTransformer({ diff --git a/x-pack/legacy/plugins/apm/server/lib/transactions/avg_duration_by_browser/fetcher.test.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/avg_duration_by_browser/fetcher.test.ts index f2227524db081..1a5921e06d0d1 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transactions/avg_duration_by_browser/fetcher.test.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transactions/avg_duration_by_browser/fetcher.test.ts @@ -4,7 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Setup } from '../../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../helpers/setup_request'; import { fetcher } from './fetcher'; describe('fetcher', () => { @@ -14,7 +18,7 @@ describe('fetcher', () => { client: { search }, indices: {}, uiFiltersES: [] - } as unknown) as Setup; + } as unknown) as Setup & SetupTimeRange & SetupUIFilters; await fetcher({ serviceName: 'testServiceName', setup }); diff --git a/x-pack/legacy/plugins/apm/server/lib/transactions/avg_duration_by_browser/index.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/avg_duration_by_browser/index.ts index 57b3c8cbe9f93..07b598a86caa4 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transactions/avg_duration_by_browser/index.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transactions/avg_duration_by_browser/index.ts @@ -5,13 +5,17 @@ */ import { Coordinate } from '../../../../typings/timeseries'; -import { Setup } from '../../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../helpers/setup_request'; import { fetcher } from './fetcher'; import { transformer } from './transformer'; export interface Options { serviceName: string; - setup: Setup; + setup: Setup & SetupTimeRange & SetupUIFilters; } export type AvgDurationByBrowserAPIResponse = Array<{ diff --git a/x-pack/legacy/plugins/apm/server/lib/transactions/avg_duration_by_country/index.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/avg_duration_by_country/index.ts index ed6bdf203f2d4..e2dfb5d0f7a58 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transactions/avg_duration_by_country/index.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transactions/avg_duration_by_country/index.ts @@ -12,7 +12,11 @@ import { TRANSACTION_TYPE, TRANSACTION_NAME } from '../../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../helpers/setup_request'; import { rangeFilter } from '../../helpers/range_filter'; import { TRANSACTION_PAGE_LOAD } from '../../../../common/transaction_types'; @@ -21,7 +25,7 @@ export async function getTransactionAvgDurationByCountry({ serviceName, transactionName }: { - setup: Setup; + setup: Setup & SetupTimeRange & SetupUIFilters; serviceName: string; transactionName?: string; }) { diff --git a/x-pack/legacy/plugins/apm/server/lib/transactions/breakdown/index.test.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/breakdown/index.test.ts index 8254f028923d3..f49c1e022a070 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transactions/breakdown/index.test.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transactions/breakdown/index.test.ts @@ -8,6 +8,7 @@ import { getTransactionBreakdown } from '.'; import * as constants from './constants'; import noDataResponse from './mock-responses/noData.json'; import dataResponse from './mock-responses/data.json'; +import { APMConfig } from '../../../../../../../plugins/apm/server'; const mockIndices = { 'apm_oss.sourcemapIndices': 'myIndex', @@ -16,7 +17,7 @@ const mockIndices = { 'apm_oss.spanIndices': 'myIndex', 'apm_oss.transactionIndices': 'myIndex', 'apm_oss.metricsIndices': 'myIndex', - 'apm_oss.apmAgentConfigurationIndex': 'myIndex' + apmAgentConfigurationIndex: 'myIndex' }; function getMockSetup(esResponse: any) { @@ -26,10 +27,12 @@ function getMockSetup(esResponse: any) { end: 500000, client: { search: clientSpy } as any, internalClient: { search: clientSpy } as any, - config: { - get: () => 'myIndex' as any, - has: () => true - }, + config: new Proxy( + {}, + { + get: () => 'myIndex' + } + ) as APMConfig, uiFiltersES: [], indices: mockIndices, dynamicIndexPattern: null as any diff --git a/x-pack/legacy/plugins/apm/server/lib/transactions/breakdown/index.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/breakdown/index.ts index 12f6694116950..26e62d8902eeb 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transactions/breakdown/index.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transactions/breakdown/index.ts @@ -15,7 +15,11 @@ import { TRANSACTION_BREAKDOWN_COUNT, PROCESSOR_EVENT } from '../../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../helpers/setup_request'; import { rangeFilter } from '../../helpers/range_filter'; import { getMetricsDateHistogramParams } from '../../helpers/metrics'; import { MAX_KPIS } from './constants'; @@ -27,7 +31,7 @@ export async function getTransactionBreakdown({ transactionName, transactionType }: { - setup: Setup; + setup: Setup & SetupTimeRange & SetupUIFilters; serviceName: string; transactionName?: string; transactionType: string; diff --git a/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_anomaly_data/fetcher.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_anomaly_data/fetcher.ts index 9b51d9336d2e6..5f211b1427259 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_anomaly_data/fetcher.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_anomaly_data/fetcher.ts @@ -6,7 +6,7 @@ import { getMlIndex } from '../../../../../common/ml_job_constants'; import { PromiseReturnType } from '../../../../../typings/common'; -import { Setup } from '../../../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../../helpers/setup_request'; export type ESResponse = Exclude< PromiseReturnType, @@ -24,7 +24,7 @@ export async function anomalySeriesFetcher({ transactionType: string; intervalString: string; mlBucketSize: number; - setup: Setup; + setup: Setup & SetupTimeRange; }) { const { client, start, end } = setup; diff --git a/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_anomaly_data/get_ml_bucket_size.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_anomaly_data/get_ml_bucket_size.ts index 4933f1b1ed431..9419fa7a77fb9 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_anomaly_data/get_ml_bucket_size.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_anomaly_data/get_ml_bucket_size.ts @@ -5,12 +5,12 @@ */ import { getMlIndex } from '../../../../../common/ml_job_constants'; -import { Setup } from '../../../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../../helpers/setup_request'; interface IOptions { serviceName: string; transactionType: string; - setup: Setup; + setup: Setup & SetupTimeRange; } interface ESResponse { diff --git a/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_anomaly_data/index.test.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_anomaly_data/index.test.ts index a5008ce10f9f9..2a56f744f2f45 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_anomaly_data/index.test.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_anomaly_data/index.test.ts @@ -8,6 +8,7 @@ import { getAnomalySeries } from '.'; import { mlAnomalyResponse } from './mock-responses/mlAnomalyResponse'; import { mlBucketSpanResponse } from './mock-responses/mlBucketSpanResponse'; import { PromiseReturnType } from '../../../../../typings/common'; +import { APMConfig } from '../../../../../../../../plugins/apm/server'; describe('getAnomalySeries', () => { let avgAnomalies: PromiseReturnType; @@ -27,10 +28,12 @@ describe('getAnomalySeries', () => { end: 500000, client: { search: clientSpy } as any, internalClient: { search: clientSpy } as any, - config: { - get: () => 'myIndex' as any, - has: () => true - }, + config: new Proxy( + {}, + { + get: () => 'myIndex' + } + ) as APMConfig, uiFiltersES: [], indices: { 'apm_oss.sourcemapIndices': 'myIndex', @@ -39,7 +42,7 @@ describe('getAnomalySeries', () => { 'apm_oss.spanIndices': 'myIndex', 'apm_oss.transactionIndices': 'myIndex', 'apm_oss.metricsIndices': 'myIndex', - 'apm_oss.apmAgentConfigurationIndex': 'myIndex' + apmAgentConfigurationIndex: 'myIndex' }, dynamicIndexPattern: null as any } diff --git a/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_anomaly_data/index.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_anomaly_data/index.ts index b55d264cfbbfe..c631772b0e18c 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_anomaly_data/index.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_anomaly_data/index.ts @@ -5,7 +5,11 @@ */ import { getBucketSize } from '../../../helpers/get_bucket_size'; -import { Setup } from '../../../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../../helpers/setup_request'; import { anomalySeriesFetcher } from './fetcher'; import { getMlBucketSize } from './get_ml_bucket_size'; import { anomalySeriesTransform } from './transform'; @@ -21,7 +25,7 @@ export async function getAnomalySeries({ transactionType: string | undefined; transactionName: string | undefined; timeSeriesDates: number[]; - setup: Setup; + setup: Setup & SetupTimeRange & SetupUIFilters; }) { // don't fetch anomalies for transaction details page if (transactionName) { diff --git a/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.test.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.test.ts index 7bdfb17ba17b3..676ad4ded6b69 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.test.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.test.ts @@ -6,6 +6,7 @@ import { PROCESSOR_EVENT } from '../../../../../common/elasticsearch_fieldnames'; import { ESResponse, timeseriesFetcher } from './fetcher'; +import { APMConfig } from '../../../../../../../../plugins/apm/server'; describe('timeseriesFetcher', () => { let res: ESResponse; @@ -22,10 +23,12 @@ describe('timeseriesFetcher', () => { end: 1528977600000, client: { search: clientSpy } as any, internalClient: { search: clientSpy } as any, - config: { - get: () => 'myIndex' as any, - has: () => true - }, + config: new Proxy( + {}, + { + get: () => 'myIndex' + } + ) as APMConfig, uiFiltersES: [ { term: { 'service.environment': 'test' } @@ -38,7 +41,7 @@ describe('timeseriesFetcher', () => { 'apm_oss.spanIndices': 'myIndex', 'apm_oss.transactionIndices': 'myIndex', 'apm_oss.metricsIndices': 'myIndex', - 'apm_oss.apmAgentConfigurationIndex': 'myIndex' + apmAgentConfigurationIndex: 'myIndex' }, dynamicIndexPattern: null as any } diff --git a/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.ts index 0d9cccb3b56d3..8a2e01c9a7891 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.ts @@ -16,7 +16,11 @@ import { import { PromiseReturnType } from '../../../../../typings/common'; import { getBucketSize } from '../../../helpers/get_bucket_size'; import { rangeFilter } from '../../../helpers/range_filter'; -import { Setup } from '../../../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../../helpers/setup_request'; export type ESResponse = PromiseReturnType; export function timeseriesFetcher({ @@ -28,7 +32,7 @@ export function timeseriesFetcher({ serviceName: string; transactionType: string | undefined; transactionName: string | undefined; - setup: Setup; + setup: Setup & SetupTimeRange & SetupUIFilters; }) { const { start, end, uiFiltersES, client, indices } = setup; const { intervalString } = getBucketSize(start, end, 'auto'); diff --git a/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_timeseries_data/index.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_timeseries_data/index.ts index 6c18ab84cdfab..96d06bdd3b0e1 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_timeseries_data/index.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transactions/charts/get_timeseries_data/index.ts @@ -5,7 +5,11 @@ */ import { getBucketSize } from '../../../helpers/get_bucket_size'; -import { Setup } from '../../../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../../helpers/setup_request'; import { timeseriesFetcher } from './fetcher'; import { timeseriesTransformer } from './transform'; @@ -13,7 +17,7 @@ export async function getApmTimeseriesData(options: { serviceName: string; transactionType: string | undefined; transactionName: string | undefined; - setup: Setup; + setup: Setup & SetupTimeRange & SetupUIFilters; }) { const { start, end } = options.setup; const { bucketSize } = getBucketSize(start, end, 'auto'); diff --git a/x-pack/legacy/plugins/apm/server/lib/transactions/charts/index.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/charts/index.ts index c297f3a050f0c..a6a1a76e19664 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transactions/charts/index.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transactions/charts/index.ts @@ -5,7 +5,11 @@ */ import { PromiseReturnType } from '../../../../typings/common'; -import { Setup } from '../../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../helpers/setup_request'; import { getAnomalySeries } from './get_anomaly_data'; import { getApmTimeseriesData } from './get_timeseries_data'; import { ApmTimeSeriesResponse } from './get_timeseries_data/transform'; @@ -21,7 +25,7 @@ export async function getTransactionCharts(options: { serviceName: string; transactionType: string | undefined; transactionName: string | undefined; - setup: Setup; + setup: Setup & SetupTimeRange & SetupUIFilters; }) { const apmTimeseries = await getApmTimeseriesData(options); const anomalyTimeseries = await getAnomalySeries({ diff --git a/x-pack/legacy/plugins/apm/server/new-platform/index.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/constants.ts similarity index 55% rename from x-pack/legacy/plugins/apm/server/new-platform/index.ts rename to x-pack/legacy/plugins/apm/server/lib/transactions/constants.ts index 8ad0cbbb811f3..7fae088048903 100644 --- a/x-pack/legacy/plugins/apm/server/new-platform/index.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transactions/constants.ts @@ -4,9 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -import { PluginInitializerContext } from 'src/core/server'; -import { Plugin } from './plugin'; - -export function plugin(initializerContext: PluginInitializerContext) { - return new Plugin(); -} +export const MINIMUM_BUCKET_SIZE = 15; +export const BUCKET_TARGET_COUNT = 15; diff --git a/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/get_buckets/fetcher.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/get_buckets/fetcher.ts index 90d9a925a1f36..32fa65722869d 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/get_buckets/fetcher.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/get_buckets/fetcher.ts @@ -16,7 +16,11 @@ import { TRANSACTION_TYPE } from '../../../../../common/elasticsearch_fieldnames'; import { rangeFilter } from '../../../helpers/range_filter'; -import { Setup } from '../../../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../../helpers/setup_request'; export async function bucketFetcher( serviceName: string, @@ -26,7 +30,7 @@ export async function bucketFetcher( traceId: string, distributionMax: number, bucketSize: number, - setup: Setup + setup: Setup & SetupTimeRange & SetupUIFilters ) { const { start, end, uiFiltersES, client, indices } = setup; diff --git a/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/get_buckets/index.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/get_buckets/index.ts index 86429986063ed..90b2fa5894665 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/get_buckets/index.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/get_buckets/index.ts @@ -4,7 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Setup } from '../../../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../../helpers/setup_request'; import { bucketFetcher } from './fetcher'; import { bucketTransformer } from './transform'; @@ -16,7 +20,7 @@ export async function getBuckets( traceId: string, distributionMax: number, bucketSize: number, - setup: Setup + setup: Setup & SetupTimeRange & SetupUIFilters ) { const response = await bucketFetcher( serviceName, diff --git a/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/get_distribution_max.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/get_distribution_max.ts index a54fa9c10de13..0dfe769c0bbac 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/get_distribution_max.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/get_distribution_max.ts @@ -11,13 +11,17 @@ import { TRANSACTION_NAME, TRANSACTION_TYPE } from '../../../../common/elasticsearch_fieldnames'; -import { Setup } from '../../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../helpers/setup_request'; export async function getDistributionMax( serviceName: string, transactionName: string, transactionType: string, - setup: Setup + setup: Setup & SetupTimeRange & SetupUIFilters ) { const { start, end, uiFiltersES, client, indices } = setup; diff --git a/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/index.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/index.ts index 3efa996d609d8..9dd29a0664329 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/index.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/index.ts @@ -5,19 +5,20 @@ */ import { PromiseReturnType } from '../../../../typings/common'; -import { Setup } from '../../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../helpers/setup_request'; import { getBuckets } from './get_buckets'; import { getDistributionMax } from './get_distribution_max'; import { roundToNearestFiveOrTen } from '../../helpers/round_to_nearest_five_or_ten'; +import { MINIMUM_BUCKET_SIZE, BUCKET_TARGET_COUNT } from '../constants'; -function getBucketSize(max: number, { config }: Setup) { - const minBucketSize: number = config.get( - 'xpack.apm.minimumBucketSize' - ); - const bucketTargetCount = config.get('xpack.apm.bucketTargetCount'); - const bucketSize = max / bucketTargetCount; +function getBucketSize(max: number) { + const bucketSize = max / BUCKET_TARGET_COUNT; return roundToNearestFiveOrTen( - bucketSize > minBucketSize ? bucketSize : minBucketSize + bucketSize > MINIMUM_BUCKET_SIZE ? bucketSize : MINIMUM_BUCKET_SIZE ); } @@ -37,7 +38,7 @@ export async function getTransactionDistribution({ transactionType: string; transactionId: string; traceId: string; - setup: Setup; + setup: Setup & SetupTimeRange & SetupUIFilters; }) { const distributionMax = await getDistributionMax( serviceName, @@ -50,7 +51,7 @@ export async function getTransactionDistribution({ return { noHits: true, buckets: [], bucketSize: 0 }; } - const bucketSize = getBucketSize(distributionMax, setup); + const bucketSize = getBucketSize(distributionMax); const { buckets, noHits } = await getBuckets( serviceName, transactionName, diff --git a/x-pack/legacy/plugins/apm/server/lib/transactions/get_transaction/index.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/get_transaction/index.ts index 652acf773e2e5..56cee04049bd9 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transactions/get_transaction/index.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transactions/get_transaction/index.ts @@ -11,12 +11,16 @@ import { } from '../../../../common/elasticsearch_fieldnames'; import { Transaction } from '../../../../typings/es_schemas/ui/Transaction'; import { rangeFilter } from '../../helpers/range_filter'; -import { Setup } from '../../helpers/setup_request'; +import { + Setup, + SetupTimeRange, + SetupUIFilters +} from '../../helpers/setup_request'; export async function getTransaction( transactionId: string, traceId: string, - setup: Setup + setup: Setup & SetupTimeRange & SetupUIFilters ) { const { start, end, uiFiltersES, client, indices } = setup; diff --git a/x-pack/legacy/plugins/apm/server/lib/ui_filters/get_environments.ts b/x-pack/legacy/plugins/apm/server/lib/ui_filters/get_environments.ts index 1b9e2ebd2e757..50c1926d1e4a0 100644 --- a/x-pack/legacy/plugins/apm/server/lib/ui_filters/get_environments.ts +++ b/x-pack/legacy/plugins/apm/server/lib/ui_filters/get_environments.ts @@ -10,11 +10,14 @@ import { SERVICE_NAME } from '../../../common/elasticsearch_fieldnames'; import { rangeFilter } from '../helpers/range_filter'; -import { Setup } from '../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { ENVIRONMENT_NOT_DEFINED } from '../../../common/environment_filter_values'; import { ESFilter } from '../../../typings/elasticsearch'; -export async function getEnvironments(setup: Setup, serviceName?: string) { +export async function getEnvironments( + setup: Setup & SetupTimeRange, + serviceName?: string +) { const { start, end, client, indices } = setup; const filter: ESFilter[] = [ diff --git a/x-pack/legacy/plugins/apm/server/lib/ui_filters/local_ui_filters/get_filter_aggregations.ts b/x-pack/legacy/plugins/apm/server/lib/ui_filters/local_ui_filters/get_filter_aggregations.ts index cc1ebf2d51952..0bf89414e2894 100644 --- a/x-pack/legacy/plugins/apm/server/lib/ui_filters/local_ui_filters/get_filter_aggregations.ts +++ b/x-pack/legacy/plugins/apm/server/lib/ui_filters/local_ui_filters/get_filter_aggregations.ts @@ -11,7 +11,7 @@ import { getUiFiltersES } from '../../helpers/convert_ui_filters/get_ui_filters_ import { localUIFilters, LocalUIFilterName } from './config'; import { StaticIndexPattern } from '../../../../../../../../src/legacy/core_plugins/data/public'; -export const getFilterAggregations = async ({ +export const getFilterAggregations = ({ indexPattern, uiFilters, projection, @@ -24,49 +24,44 @@ export const getFilterAggregations = async ({ }) => { const mappedFilters = localFilterNames.map(name => localUIFilters[name]); - const aggs = await Promise.all( - mappedFilters.map(async field => { - const filter = await getUiFiltersES( - indexPattern, - omit(uiFilters, field.name) - ); + const aggs = mappedFilters.map(field => { + const filter = getUiFiltersES(indexPattern, omit(uiFilters, field.name)); - const bucketCountAggregation = projection.body.aggs - ? { - aggs: { - bucket_count: { - cardinality: { - field: - projection.body.aggs[Object.keys(projection.body.aggs)[0]] - .terms.field - } + const bucketCountAggregation = projection.body.aggs + ? { + aggs: { + bucket_count: { + cardinality: { + field: + projection.body.aggs[Object.keys(projection.body.aggs)[0]] + .terms.field } } } - : {}; + } + : {}; - return { - [field.name]: { - filter: { - bool: { - filter - } - }, - aggs: { - by_terms: { - terms: { - field: field.fieldName, - order: { - _count: 'desc' as const - } - }, - ...bucketCountAggregation - } + return { + [field.name]: { + filter: { + bool: { + filter + } + }, + aggs: { + by_terms: { + terms: { + field: field.fieldName, + order: { + _count: 'desc' as const + } + }, + ...bucketCountAggregation } } - }; - }) - ); + } + }; + }); const mergedAggregations = Object.assign({}, ...aggs) as Partial< Record diff --git a/x-pack/legacy/plugins/apm/server/lib/ui_filters/local_ui_filters/index.ts b/x-pack/legacy/plugins/apm/server/lib/ui_filters/local_ui_filters/index.ts index ada41c3aa97c7..524e6ca640f3e 100644 --- a/x-pack/legacy/plugins/apm/server/lib/ui_filters/local_ui_filters/index.ts +++ b/x-pack/legacy/plugins/apm/server/lib/ui_filters/local_ui_filters/index.ts @@ -33,7 +33,7 @@ export async function getLocalUIFilters({ delete projectionWithoutAggs.body.aggs; - const filterAggregations = await getFilterAggregations({ + const filterAggregations = getFilterAggregations({ indexPattern: dynamicIndexPattern, uiFilters, projection, diff --git a/x-pack/legacy/plugins/apm/server/new-platform/plugin.ts b/x-pack/legacy/plugins/apm/server/new-platform/plugin.ts deleted file mode 100644 index e1cb1774469f2..0000000000000 --- a/x-pack/legacy/plugins/apm/server/new-platform/plugin.ts +++ /dev/null @@ -1,23 +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 { Server } from 'hapi'; -import { CoreSetup } from 'src/core/server'; -import { makeApmUsageCollector } from '../lib/apm_telemetry'; -import { createApmAgentConfigurationIndex } from '../lib/settings/agent_configuration/create_agent_config_index'; -import { createApmApi } from '../routes/create_apm_api'; - -export interface LegacySetup { - server: Server; -} - -export class Plugin { - public setup(core: CoreSetup, __LEGACY: LegacySetup) { - createApmApi().init(core, __LEGACY); - createApmAgentConfigurationIndex(core, __LEGACY); - makeApmUsageCollector(core, __LEGACY); - } -} diff --git a/x-pack/legacy/plugins/apm/server/routes/create_api/index.test.ts b/x-pack/legacy/plugins/apm/server/routes/create_api/index.test.ts index 18fe547a34cf0..3a74c4377920a 100644 --- a/x-pack/legacy/plugins/apm/server/routes/create_api/index.test.ts +++ b/x-pack/legacy/plugins/apm/server/routes/create_api/index.test.ts @@ -5,25 +5,49 @@ */ import * as t from 'io-ts'; import { createApi } from './index'; -import { CoreSetup } from 'src/core/server'; +import { CoreSetup, Logger } from 'src/core/server'; import { Params } from '../typings'; -import { LegacySetup } from '../../new-platform/plugin'; - -const getCoreMock = () => (({} as unknown) as CoreSetup); +import { BehaviorSubject } from 'rxjs'; +import { APMConfig } from '../../../../../../plugins/apm/server'; +import { LegacySetup } from '../../../../../../plugins/apm/server/plugin'; + +const getCoreMock = () => { + const get = jest.fn(); + const post = jest.fn(); + const put = jest.fn(); + const createRouter = jest.fn().mockReturnValue({ + get, + post, + put + }); -const getLegacyMock = () => - (({ - server: { - route: jest.fn() + const mock = {} as CoreSetup; + + return { + mock: { + ...mock, + http: { + ...mock.http, + createRouter + } + }, + get, + post, + put, + createRouter, + context: { + config$: new BehaviorSubject({} as APMConfig), + logger: ({ + error: jest.fn() + } as unknown) as Logger, + __LEGACY: {} as LegacySetup } - } as unknown) as LegacySetup & { - server: { route: ReturnType }; - }); + }; +}; describe('createApi', () => { it('registers a route with the server', () => { - const coreMock = getCoreMock(); - const legacySetupMock = getLegacyMock(); + const { mock, context, createRouter, post, get, put } = getCoreMock(); createApi() .add(() => ({ @@ -46,236 +70,249 @@ describe('createApi', () => { }, handler: async () => null })) - .init(coreMock, legacySetupMock); + .init(mock, context); - expect(legacySetupMock.server.route).toHaveBeenCalledTimes(3); + expect(createRouter).toHaveBeenCalledTimes(1); - const firstRoute = legacySetupMock.server.route.mock.calls[0][0]; + expect(get).toHaveBeenCalledTimes(1); + expect(post).toHaveBeenCalledTimes(1); + expect(put).toHaveBeenCalledTimes(1); - expect(firstRoute).toEqual({ - method: 'GET', + expect(get.mock.calls[0][0]).toEqual({ options: { tags: ['access:apm'] }, path: '/foo', - handler: expect.any(Function) + validate: expect.anything() }); - const secondRoute = legacySetupMock.server.route.mock.calls[1][0]; - - expect(secondRoute).toEqual({ - method: 'POST', + expect(post.mock.calls[0][0]).toEqual({ options: { tags: ['access:apm'] }, path: '/bar', - handler: expect.any(Function) + validate: expect.anything() }); - const thirdRoute = legacySetupMock.server.route.mock.calls[2][0]; - - expect(thirdRoute).toEqual({ - method: 'PUT', + expect(put.mock.calls[0][0]).toEqual({ options: { tags: ['access:apm', 'access:apm_write'] }, path: '/baz', - handler: expect.any(Function) + validate: expect.anything() }); }); describe('when validating', () => { const initApi = (params: Params) => { - const core = getCoreMock(); - const legacySetupMock = getLegacyMock(); - const handler = jest.fn(); + const { mock, context, createRouter, get, post } = getCoreMock(); + const handlerMock = jest.fn(); createApi() .add(() => ({ path: '/foo', params, - handler + handler: handlerMock })) - .init(core, legacySetupMock); - - const route = legacySetupMock.server.route.mock.calls[0][0]; - - const routeHandler = route.handler; + .init(mock, context); + + const routeHandler = get.mock.calls[0][1]; + const responseMock = { + ok: jest.fn(), + internalError: jest.fn(), + notFound: jest.fn(), + forbidden: jest.fn(), + badRequest: jest.fn() + }; - route.handler = (requestMock: any) => { - return routeHandler({ - // stub hapi's default values - params: {}, - query: {}, - payload: null, - ...requestMock - }); + const simulate = (requestMock: any) => { + return routeHandler( + {}, + { + // stub default values + params: {}, + query: {}, + body: {}, + ...requestMock + }, + responseMock + ); }; - return { route, handler }; + return { simulate, handlerMock, createRouter, get, post, responseMock }; }; - it('adds a _debug query parameter by default', () => { - const { handler, route } = initApi({}); + it('adds a _debug query parameter by default', async () => { + const { simulate, handlerMock, responseMock } = initApi({}); - expect(() => - route.handler({ - query: { - _debug: 'true' - } - }) - ).not.toThrow(); + await simulate({ query: { _debug: true } }); - expect(handler).toHaveBeenCalledTimes(1); + expect(handlerMock).toHaveBeenCalledTimes(1); - const params = handler.mock.calls[0][1]; + expect(responseMock.ok).toHaveBeenCalled(); - expect(params).toEqual({}); + expect(responseMock.badRequest).not.toHaveBeenCalled(); - expect(() => - route.handler({ - query: { - _debug: 1 - } - }) - ).toThrow(); + const params = handlerMock.mock.calls[0][0].context.params; + + expect(params).toEqual({ + query: { + _debug: true + } + }); + + await simulate({ + query: { + _debug: 1 + } + }); + + expect(responseMock.badRequest).toHaveBeenCalled(); }); - it('throws if any parameters are used but no types are defined', () => { - const { route } = initApi({}); + it('throws if any parameters are used but no types are defined', async () => { + const { simulate, responseMock } = initApi({}); - expect(() => - route.handler({ - query: { - _debug: 'true', - extra: '' - } - }) - ).toThrow(); + await simulate({ + query: { + _debug: true, + extra: '' + } + }); - expect(() => - route.handler({ - payload: { foo: 'bar' } - }) - ).toThrow(); + expect(responseMock.badRequest).toHaveBeenCalledTimes(1); - expect(() => - route.handler({ - params: { - foo: 'bar' - } - }) - ).toThrow(); - }); + await simulate({ + body: { foo: 'bar' } + }); - it('validates path parameters', () => { - const { handler, route } = initApi({ path: t.type({ foo: t.string }) }); + expect(responseMock.badRequest).toHaveBeenCalledTimes(2); - expect(() => - route.handler({ - params: { - foo: 'bar' - } + await simulate({ + params: { + foo: 'bar' + } + }); + + expect(responseMock.badRequest).toHaveBeenCalledTimes(3); + }); + + it('validates path parameters', async () => { + const { simulate, handlerMock, responseMock } = initApi({ + path: t.type({ + foo: t.string }) - ).not.toThrow(); + }); + + await simulate({ + params: { + foo: 'bar' + } + }); - expect(handler).toHaveBeenCalledTimes(1); + expect(handlerMock).toHaveBeenCalledTimes(1); - const params = handler.mock.calls[0][1]; + expect(responseMock.ok).toHaveBeenCalledTimes(1); + expect(responseMock.badRequest).not.toHaveBeenCalled(); + + const params = handlerMock.mock.calls[0][0].context.params; expect(params).toEqual({ path: { foo: 'bar' + }, + query: { + _debug: false } }); - handler.mockClear(); + await simulate({ + params: { + bar: 'foo' + } + }); - expect(() => - route.handler({ - params: { - bar: 'foo' - } - }) - ).toThrow(); + expect(responseMock.badRequest).toHaveBeenCalledTimes(1); - expect(() => - route.handler({ - params: { - foo: 9 - } - }) - ).toThrow(); - - expect(() => - route.handler({ - params: { - foo: 'bar', - extra: '' - } - }) - ).toThrow(); + await simulate({ + params: { + foo: 9 + } + }); + + expect(responseMock.badRequest).toHaveBeenCalledTimes(2); + + await simulate({ + params: { + foo: 'bar', + extra: '' + } + }); + + expect(responseMock.badRequest).toHaveBeenCalledTimes(3); }); - it('validates body parameters', () => { - const { handler, route } = initApi({ body: t.string }); + it('validates body parameters', async () => { + const { simulate, handlerMock, responseMock } = initApi({ + body: t.string + }); - expect(() => - route.handler({ - payload: '' - }) - ).not.toThrow(); + await simulate({ + body: '' + }); - expect(handler).toHaveBeenCalledTimes(1); + expect(handlerMock).toHaveBeenCalledTimes(1); + expect(responseMock.ok).toHaveBeenCalledTimes(1); + expect(responseMock.badRequest).not.toHaveBeenCalled(); - const params = handler.mock.calls[0][1]; + const params = handlerMock.mock.calls[0][0].context.params; expect(params).toEqual({ - body: '' + body: '', + query: { + _debug: false + } }); - handler.mockClear(); + await simulate({ + body: null + }); - expect(() => - route.handler({ - payload: null - }) - ).toThrow(); + expect(responseMock.badRequest).toHaveBeenCalledTimes(1); }); - it('validates query parameters', () => { - const { handler, route } = initApi({ + it('validates query parameters', async () => { + const { simulate, handlerMock, responseMock } = initApi({ query: t.type({ bar: t.string }) }); - expect(() => - route.handler({ - query: { - bar: '', - _debug: 'true' - } - }) - ).not.toThrow(); + await simulate({ + query: { + bar: '', + _debug: true + } + }); - expect(handler).toHaveBeenCalledTimes(1); + expect(handlerMock).toHaveBeenCalledTimes(1); + expect(responseMock.ok).toHaveBeenCalledTimes(1); + expect(responseMock.badRequest).not.toHaveBeenCalled(); - const params = handler.mock.calls[0][1]; + const params = handlerMock.mock.calls[0][0].context.params; expect(params).toEqual({ query: { - bar: '' + bar: '', + _debug: true } }); - handler.mockClear(); + await simulate({ + query: { + bar: '', + foo: '' + } + }); - expect(() => - route.handler({ - query: { - bar: '', - foo: '' - } - }) - ).toThrow(); + expect(responseMock.badRequest).toHaveBeenCalledTimes(1); }); }); }); diff --git a/x-pack/legacy/plugins/apm/server/routes/create_api/index.ts b/x-pack/legacy/plugins/apm/server/routes/create_api/index.ts index 66f28a9bf6d44..2e97b01d0d108 100644 --- a/x-pack/legacy/plugins/apm/server/routes/create_api/index.ts +++ b/x-pack/legacy/plugins/apm/server/routes/create_api/index.ts @@ -3,13 +3,14 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { merge, pick, omit, difference } from 'lodash'; +import { pick, difference } from 'lodash'; import Boom from 'boom'; -import { CoreSetup } from 'src/core/server'; -import { Request, ResponseToolkit } from 'hapi'; +import { schema } from '@kbn/config-schema'; import * as t from 'io-ts'; import { PathReporter } from 'io-ts/lib/PathReporter'; import { isLeft } from 'fp-ts/lib/Either'; +import { KibanaResponseFactory } from 'src/core/server'; +import { APMConfig } from '../../../../../../plugins/apm/server'; import { ServerAPI, RouteFactoryFn, @@ -17,10 +18,8 @@ import { Route, Params } from '../typings'; -import { jsonRt } from '../../../common/runtime_types/json_rt'; -import { LegacySetup } from '../../new-platform/plugin'; -const debugRt = t.partial({ _debug: jsonRt.pipe(t.boolean) }); +const debugRt = t.partial({ _debug: t.boolean }); export function createApi() { const factoryFns: Array> = []; @@ -30,17 +29,32 @@ export function createApi() { factoryFns.push(fn); return this as any; }, - init(core: CoreSetup, __LEGACY: LegacySetup) { - const { server } = __LEGACY; + init(core, { config$, logger, __LEGACY }) { + const router = core.http.createRouter(); + + let config = {} as APMConfig; + + config$.subscribe(val => { + config = val; + }); + factoryFns.forEach(fn => { const { params = {}, + path, options = { tags: ['access:apm'] }, - ...route - } = fn(core, __LEGACY) as Route; + method, + handler + } = fn(core) as Route; + + const routerMethod = (method || 'GET').toLowerCase() as + | 'post' + | 'put' + | 'get' + | 'delete'; const bodyRt = params.body; - const fallbackBodyRt = bodyRt || t.null; + const fallbackBodyRt = bodyRt || t.strict({}); const rts = { // add _debug query parameter to all routes @@ -51,65 +65,80 @@ export function createApi() { body: bodyRt && 'props' in bodyRt ? t.exact(bodyRt) : fallbackBodyRt }; - server.route( - merge( - { - options, - method: 'GET' - }, - route, - { - handler: (request: Request, h: ResponseToolkit) => { - const paramMap = { - path: request.params, - body: request.payload, - query: request.query - }; + router[routerMethod]( + { + path, + options, + validate: { + ...(routerMethod === 'get' + ? {} + : { body: schema.object({}, { allowUnknowns: true }) }), + params: schema.object({}, { allowUnknowns: true }), + query: schema.object({}, { allowUnknowns: true }) + } + }, + async (context, request, response) => { + try { + const paramMap = { + path: request.params, + body: request.body, + query: { + _debug: false, + ...request.query + } + }; - const parsedParams = (Object.keys(rts) as Array< - keyof typeof rts - >).reduce((acc, key) => { - const codec = rts[key]; - const value = paramMap[key]; + const parsedParams = (Object.keys(rts) as Array< + keyof typeof rts + >).reduce((acc, key) => { + const codec = rts[key]; + const value = paramMap[key]; - const result = codec.decode(value); + const result = codec.decode(value); - if (isLeft(result)) { - throw Boom.badRequest(PathReporter.report(result)[0]); - } + if (isLeft(result)) { + throw Boom.badRequest(PathReporter.report(result)[0]); + } - const strippedKeys = difference( - Object.keys(value || {}), - Object.keys(result.right || {}) + const strippedKeys = difference( + Object.keys(value || {}), + Object.keys(result.right || {}) + ); + + if (strippedKeys.length) { + throw Boom.badRequest( + `Unknown keys specified: ${strippedKeys}` ); + } + + const parsedValue = result.right; - if (strippedKeys.length) { - throw Boom.badRequest( - `Unknown keys specified: ${strippedKeys}` - ); - } - - // hide _debug from route handlers - const parsedValue = - key === 'query' - ? omit(result.right, '_debug') - : result.right; - - return { - ...acc, - [key]: parsedValue - }; - }, {} as Record); - - return route.handler( - request, + return { + ...acc, + [key]: parsedValue + }; + }, {} as Record); + + const data = await handler({ + request, + context: { + ...context, + __LEGACY, // only return values for parameters that have runtime types - pick(parsedParams, Object.keys(params)), - h - ); + params: pick(parsedParams, ...Object.keys(params), 'query'), + config, + logger + } + }); + + return response.ok({ body: data }); + } catch (error) { + if (Boom.isBoom(error)) { + return convertBoomToKibanaResponse(error, response); } + throw error; } - ) + } ); }); } @@ -117,3 +146,26 @@ export function createApi() { return api; } + +function convertBoomToKibanaResponse( + error: Boom, + response: KibanaResponseFactory +) { + const opts = { body: error.message }; + switch (error.output.statusCode) { + case 404: + return response.notFound(opts); + + case 400: + return response.badRequest(opts); + + case 403: + return response.forbidden(opts); + + default: + return response.custom({ + statusCode: error.output.statusCode, + ...opts + }); + } +} diff --git a/x-pack/legacy/plugins/apm/server/routes/errors.ts b/x-pack/legacy/plugins/apm/server/routes/errors.ts index a315dd10023dc..0c363b6f8ee72 100644 --- a/x-pack/legacy/plugins/apm/server/routes/errors.ts +++ b/x-pack/legacy/plugins/apm/server/routes/errors.ts @@ -27,10 +27,11 @@ export const errorsRoute = createRoute(core => ({ rangeRt ]) }, - handler: async (req, { query, path }) => { - const setup = await setupRequest(req); - const { serviceName } = path; - const { sortField, sortDirection } = query; + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + const { params } = context; + const { serviceName } = params.path; + const { sortField, sortDirection } = params.query; return getErrorGroups({ serviceName, @@ -50,9 +51,9 @@ export const errorGroupsRoute = createRoute(() => ({ }), query: t.intersection([uiFiltersRt, rangeRt]) }, - handler: async (req, { path }) => { - const setup = await setupRequest(req); - const { serviceName, groupId } = path; + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + const { serviceName, groupId } = context.params.path; return getErrorGroup({ serviceName, groupId, setup }); } })); @@ -71,10 +72,11 @@ export const errorDistributionRoute = createRoute(() => ({ rangeRt ]) }, - handler: async (req, { path, query }) => { - const setup = await setupRequest(req); - const { serviceName } = path; - const { groupId } = query; + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + const { params } = context; + const { serviceName } = params.path; + const { groupId } = params.query; return getErrorDistribution({ serviceName, groupId, setup }); } })); diff --git a/x-pack/legacy/plugins/apm/server/routes/index_pattern.ts b/x-pack/legacy/plugins/apm/server/routes/index_pattern.ts index 5e2b7a378f2bc..539846430c7f8 100644 --- a/x-pack/legacy/plugins/apm/server/routes/index_pattern.ts +++ b/x-pack/legacy/plugins/apm/server/routes/index_pattern.ts @@ -8,15 +8,15 @@ import { createStaticIndexPattern } from '../lib/index_pattern/create_static_ind import { createRoute } from './create_route'; import { setupRequest } from '../lib/helpers/setup_request'; -export const staticIndexPatternRoute = createRoute((core, { server }) => ({ +export const staticIndexPatternRoute = createRoute(() => ({ method: 'POST', path: '/api/apm/index_pattern/static', - handler: async (req, params, h) => { - const setup = await setupRequest(req); - await createStaticIndexPattern(setup, server); + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + await createStaticIndexPattern(setup, context); // send empty response regardless of outcome - return h.response().code(204); + return undefined; } })); @@ -31,8 +31,8 @@ export const dynamicIndexPatternRoute = createRoute(() => ({ ]) }) }, - handler: async request => { - const { dynamicIndexPattern } = await setupRequest(request); + handler: async ({ context, request }) => { + const { dynamicIndexPattern } = await setupRequest(context, request); return { dynamicIndexPattern }; } })); diff --git a/x-pack/legacy/plugins/apm/server/routes/metrics.ts b/x-pack/legacy/plugins/apm/server/routes/metrics.ts index ef9145b3dcd4a..74fa625af8802 100644 --- a/x-pack/legacy/plugins/apm/server/routes/metrics.ts +++ b/x-pack/legacy/plugins/apm/server/routes/metrics.ts @@ -27,10 +27,11 @@ export const metricsChartsRoute = createRoute(() => ({ rangeRt ]) }, - handler: async (req, { path, query }) => { - const setup = await setupRequest(req); - const { serviceName } = path; - const { agentName, serviceNodeName } = query; + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + const { params } = context; + const { serviceName } = params.path; + const { agentName, serviceNodeName } = params.query; return await getMetricsChartDataByAgent({ setup, serviceName, diff --git a/x-pack/legacy/plugins/apm/server/routes/service_nodes.ts b/x-pack/legacy/plugins/apm/server/routes/service_nodes.ts index 285dd5b1f10f5..33ecbb316d415 100644 --- a/x-pack/legacy/plugins/apm/server/routes/service_nodes.ts +++ b/x-pack/legacy/plugins/apm/server/routes/service_nodes.ts @@ -17,9 +17,10 @@ export const serviceNodesRoute = createRoute(core => ({ }), query: t.intersection([rangeRt, uiFiltersRt]) }, - handler: async (req, { path }) => { - const setup = await setupRequest(req); - const { serviceName } = path; + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + const { params } = context; + const { serviceName } = params.path; return getServiceNodes({ setup, diff --git a/x-pack/legacy/plugins/apm/server/routes/services.ts b/x-pack/legacy/plugins/apm/server/routes/services.ts index 4b955c7a6e981..ea9fdaa2a4aa4 100644 --- a/x-pack/legacy/plugins/apm/server/routes/services.ts +++ b/x-pack/legacy/plugins/apm/server/routes/services.ts @@ -5,6 +5,7 @@ */ import * as t from 'io-ts'; +import Boom from 'boom'; import { AgentName } from '../../typings/es_schemas/ui/fields/Agent'; import { createApmTelementry, @@ -19,13 +20,13 @@ import { createRoute } from './create_route'; import { uiFiltersRt, rangeRt } from './default_api_types'; import { getServiceMap } from '../lib/services/map'; -export const servicesRoute = createRoute((core, { server }) => ({ +export const servicesRoute = createRoute(() => ({ path: '/api/apm/services', params: { query: t.intersection([uiFiltersRt, rangeRt]) }, - handler: async req => { - const setup = await setupRequest(req); + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); const services = await getServices(setup); // Store telemetry data derived from services @@ -33,7 +34,7 @@ export const servicesRoute = createRoute((core, { server }) => ({ ({ agentName }) => agentName as AgentName ); const apmTelemetry = createApmTelementry(agentNames); - storeApmServicesTelemetry(server, apmTelemetry); + storeApmServicesTelemetry(context.__LEGACY.server, apmTelemetry); return services; } @@ -47,9 +48,9 @@ export const serviceAgentNameRoute = createRoute(() => ({ }), query: rangeRt }, - handler: async (req, { path }) => { - const setup = await setupRequest(req); - const { serviceName } = path; + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + const { serviceName } = context.params.path; return getServiceAgentName(serviceName, setup); } })); @@ -62,9 +63,9 @@ export const serviceTransactionTypesRoute = createRoute(() => ({ }), query: rangeRt }, - handler: async (req, { path }) => { - const setup = await setupRequest(req); - const { serviceName } = path; + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + const { serviceName } = context.params.path; return getServiceTransactionTypes(serviceName, setup); } })); @@ -78,9 +79,9 @@ export const serviceNodeMetadataRoute = createRoute(() => ({ }), query: t.intersection([uiFiltersRt, rangeRt]) }, - handler: async (req, { path }) => { - const setup = await setupRequest(req); - const { serviceName, serviceNodeName } = path; + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + const { serviceName, serviceNodeName } = context.params.path; return getServiceNodeMetadata({ setup, serviceName, serviceNodeName }); } })); @@ -90,12 +91,10 @@ export const serviceMapRoute = createRoute(() => ({ params: { query: rangeRt }, - handler: async (request, _response, hapi) => { - const setup = await setupRequest(request); - if (setup.config.get('xpack.apm.serviceMapEnabled')) { + handler: async ({ context }) => { + if (context.config['xpack.apm.servicemapEnabled']) { return getServiceMap(); - } else { - return hapi.response().code(404); } + return new Boom('Not found', { statusCode: 404 }); } })); diff --git a/x-pack/legacy/plugins/apm/server/routes/settings/agent_configuration.ts b/x-pack/legacy/plugins/apm/server/routes/settings/agent_configuration.ts index 2867cef28d952..b897dfb4b9123 100644 --- a/x-pack/legacy/plugins/apm/server/routes/settings/agent_configuration.ts +++ b/x-pack/legacy/plugins/apm/server/routes/settings/agent_configuration.ts @@ -5,6 +5,7 @@ */ import * as t from 'io-ts'; +import Boom from 'boom'; import { setupRequest } from '../../lib/helpers/setup_request'; import { getServiceNames } from '../../lib/settings/agent_configuration/get_service_names'; import { createOrUpdateConfiguration } from '../../lib/settings/agent_configuration/create_or_update_configuration'; @@ -21,8 +22,8 @@ import { markAppliedByAgent } from '../../lib/settings/agent_configuration/mark_ // get list of configurations export const agentConfigurationRoute = createRoute(core => ({ path: '/api/apm/settings/agent-configuration', - handler: async req => { - const setup = await setupRequest(req); + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); return await listConfigurations({ setup }); } })); @@ -39,9 +40,9 @@ export const deleteAgentConfigurationRoute = createRoute(() => ({ configurationId: t.string }) }, - handler: async (req, { path }) => { - const setup = await setupRequest(req); - const { configurationId } = path; + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + const { configurationId } = context.params.path; return await deleteConfiguration({ configurationId, setup @@ -53,8 +54,8 @@ export const deleteAgentConfigurationRoute = createRoute(() => ({ export const listAgentConfigurationServicesRoute = createRoute(() => ({ method: 'GET', path: '/api/apm/settings/agent-configuration/services', - handler: async req => { - const setup = await setupRequest(req); + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); return await getServiceNames({ setup }); @@ -84,9 +85,9 @@ export const listAgentConfigurationEnvironmentsRoute = createRoute(() => ({ params: { query: t.partial({ serviceName: t.string }) }, - handler: async (req, { query }) => { - const setup = await setupRequest(req); - const { serviceName } = query; + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + const { serviceName } = context.params.query; return await getEnvironments({ serviceName, setup }); } })); @@ -97,9 +98,9 @@ export const agentConfigurationAgentNameRoute = createRoute(() => ({ params: { query: t.type({ serviceName: t.string }) }, - handler: async (req, { query }) => { - const setup = await setupRequest(req); - const { serviceName } = query; + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + const { serviceName } = context.params.query; const agentName = await getAgentNameByService({ serviceName, setup }); return agentName; } @@ -114,9 +115,12 @@ export const createAgentConfigurationRoute = createRoute(() => ({ options: { tags: ['access:apm', 'access:apm_write'] }, - handler: async (req, { body }) => { - const setup = await setupRequest(req); - return await createOrUpdateConfiguration({ configuration: body, setup }); + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + return await createOrUpdateConfiguration({ + configuration: context.params.body, + setup + }); } })); @@ -132,12 +136,12 @@ export const updateAgentConfigurationRoute = createRoute(() => ({ }), body: agentPayloadRt }, - handler: async (req, { path, body }) => { - const setup = await setupRequest(req); - const { configurationId } = path; + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + const { configurationId } = context.params.path; return await createOrUpdateConfiguration({ configurationId, - configuration: body, + configuration: context.params.body, setup }); } @@ -156,8 +160,9 @@ export const agentConfigurationSearchRoute = createRoute(core => ({ etag: t.string }) }, - handler: async (req, { body }, h) => { - const setup = await setupRequest(req); + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + const { body } = context.params; const config = await searchConfigurations({ serviceName: body.service.name, environment: body.service.environment, @@ -165,7 +170,7 @@ export const agentConfigurationSearchRoute = createRoute(core => ({ }); if (!config) { - return h.response().code(404); + throw new Boom('Not found', { statusCode: 404 }); } // update `applied_by_agent` field if etags match diff --git a/x-pack/legacy/plugins/apm/server/routes/settings/apm_indices.ts b/x-pack/legacy/plugins/apm/server/routes/settings/apm_indices.ts index 4afcf135a1a76..b66eb05f6eda5 100644 --- a/x-pack/legacy/plugins/apm/server/routes/settings/apm_indices.ts +++ b/x-pack/legacy/plugins/apm/server/routes/settings/apm_indices.ts @@ -13,28 +13,20 @@ import { import { saveApmIndices } from '../../lib/settings/apm_indices/save_apm_indices'; // get list of apm indices and values -export const apmIndexSettingsRoute = createRoute((core, { server }) => ({ +export const apmIndexSettingsRoute = createRoute(() => ({ method: 'GET', path: '/api/apm/settings/apm-index-settings', - handler: async req => { - const config = server.config(); - const savedObjectsClient = req.server.savedObjects.getScopedSavedObjectsClient( - req - ); - return await getApmIndexSettings({ config, savedObjectsClient }); + handler: async ({ context }) => { + return await getApmIndexSettings({ context }); } })); // get apm indices configuration object -export const apmIndicesRoute = createRoute((core, { server }) => ({ +export const apmIndicesRoute = createRoute(() => ({ method: 'GET', path: '/api/apm/settings/apm-indices', - handler: async req => { - const config = server.config(); - const savedObjectsClient = req.server.savedObjects.getScopedSavedObjectsClient( - req - ); - return await getApmIndices({ config, savedObjectsClient }); + handler: async ({ context }) => { + return await getApmIndices(context); } })); @@ -49,14 +41,11 @@ export const saveApmIndicesRoute = createRoute(() => ({ 'apm_oss.onboardingIndices': t.string, 'apm_oss.spanIndices': t.string, 'apm_oss.transactionIndices': t.string, - 'apm_oss.metricsIndices': t.string, - 'apm_oss.apmAgentConfigurationIndex': t.string + 'apm_oss.metricsIndices': t.string }) }, - handler: async (req, { body }) => { - const savedObjectsClient = req.server.savedObjects.getScopedSavedObjectsClient( - req - ); - return await saveApmIndices(savedObjectsClient, body); + handler: async ({ context, request }) => { + const { body } = context.params; + return await saveApmIndices(context, body); } })); diff --git a/x-pack/legacy/plugins/apm/server/routes/traces.ts b/x-pack/legacy/plugins/apm/server/routes/traces.ts index cd2c86a5c9ca3..089408a03afe9 100644 --- a/x-pack/legacy/plugins/apm/server/routes/traces.ts +++ b/x-pack/legacy/plugins/apm/server/routes/traces.ts @@ -16,8 +16,8 @@ export const tracesRoute = createRoute(() => ({ params: { query: t.intersection([rangeRt, uiFiltersRt]) }, - handler: async req => { - const setup = await setupRequest(req); + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); return getTransactionGroupList({ type: 'top_traces' }, setup); } })); @@ -30,9 +30,8 @@ export const tracesByIdRoute = createRoute(() => ({ }), query: rangeRt }, - handler: async (req, { path }) => { - const { traceId } = path; - const setup = await setupRequest(req); - return getTrace(traceId, setup); + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + return getTrace(context.params.path.traceId, setup); } })); diff --git a/x-pack/legacy/plugins/apm/server/routes/transaction_groups.ts b/x-pack/legacy/plugins/apm/server/routes/transaction_groups.ts index 269f5fee9738c..2170a8fbb9692 100644 --- a/x-pack/legacy/plugins/apm/server/routes/transaction_groups.ts +++ b/x-pack/legacy/plugins/apm/server/routes/transaction_groups.ts @@ -29,10 +29,10 @@ export const transactionGroupsRoute = createRoute(() => ({ rangeRt ]) }, - handler: async (req, { path, query }) => { - const { serviceName } = path; - const { transactionType } = query; - const setup = await setupRequest(req); + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + const { serviceName } = context.params.path; + const { transactionType } = context.params.query; return getTransactionGroupList( { @@ -60,10 +60,10 @@ export const transactionGroupsChartsRoute = createRoute(() => ({ rangeRt ]) }, - handler: async (req, { path, query }) => { - const setup = await setupRequest(req); - const { serviceName } = path; - const { transactionType, transactionName } = query; + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + const { serviceName } = context.params.path; + const { transactionType, transactionName } = context.params.query; return getTransactionCharts({ serviceName, @@ -93,15 +93,15 @@ export const transactionGroupsDistributionRoute = createRoute(() => ({ rangeRt ]) }, - handler: async (req, { path, query }) => { - const setup = await setupRequest(req); - const { serviceName } = path; + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + const { serviceName } = context.params.path; const { transactionType, transactionName, transactionId = '', traceId = '' - } = query; + } = context.params.query; return getTransactionDistribution({ serviceName, @@ -131,10 +131,10 @@ export const transactionGroupsBreakdownRoute = createRoute(() => ({ rangeRt ]) }, - handler: async (req, { path, query }) => { - const setup = await setupRequest(req); - const { serviceName } = path; - const { transactionName, transactionType } = query; + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + const { serviceName } = context.params.path; + const { transactionName, transactionType } = context.params.query; return getTransactionBreakdown({ serviceName, @@ -160,9 +160,9 @@ export const transactionGroupsAvgDurationByBrowser = createRoute(() => ({ rangeRt ]) }, - handler: async (req, { path }) => { - const setup = await setupRequest(req); - const { serviceName } = path; + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + const { serviceName } = context.params.path; return getTransactionAvgDurationByBrowser({ serviceName, @@ -183,10 +183,10 @@ export const transactionGroupsAvgDurationByCountry = createRoute(() => ({ t.partial({ transactionName: t.string }) ]) }, - handler: async (req, { path, query }) => { - const setup = await setupRequest(req); - const { serviceName } = path; - const { transactionName } = query; + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + const { serviceName } = context.params.path; + const { transactionName } = context.params.query; return getTransactionAvgDurationByCountry({ serviceName, diff --git a/x-pack/legacy/plugins/apm/server/routes/typings.ts b/x-pack/legacy/plugins/apm/server/routes/typings.ts index 77d96d3677494..207fe7fe5da33 100644 --- a/x-pack/legacy/plugins/apm/server/routes/typings.ts +++ b/x-pack/legacy/plugins/apm/server/routes/typings.ts @@ -5,11 +5,17 @@ */ import t from 'io-ts'; -import { Request, ResponseToolkit } from 'hapi'; -import { CoreSetup } from 'src/core/server'; +import { + CoreSetup, + KibanaRequest, + RequestHandlerContext, + Logger +} from 'src/core/server'; import { PickByValue, Optional } from 'utility-types'; +import { Observable } from 'rxjs'; +import { Server } from 'hapi'; import { FetchOptions } from '../../public/services/rest/callApi'; -import { LegacySetup } from '../new-platform/plugin'; +import { APMConfig } from '../../../../../plugins/apm/server'; export interface Params { query?: t.HasProps; @@ -37,22 +43,41 @@ export interface Route< options?: { tags: Array<'access:apm' | 'access:apm_write'>; }; - handler: ( - req: Request, - params: DecodeParams, - h: ResponseToolkit - ) => Promise; + handler: (kibanaContext: { + context: APMRequestHandlerContext>; + request: KibanaRequest; + }) => Promise; } +export type APMLegacyServer = Pick & { + usage: { + collectorSet: { + makeUsageCollector: (options: unknown) => unknown; + register: (options: unknown) => unknown; + }; + }; + plugins: { + elasticsearch: Server['plugins']['elasticsearch']; + }; +}; + +export type APMRequestHandlerContext< + TDecodedParams extends { [key in keyof Params]: any } = {} +> = RequestHandlerContext & { + params: { query: { _debug: boolean } } & TDecodedParams; + config: APMConfig; + logger: Logger; + __LEGACY: { + server: APMLegacyServer; + }; +}; + export type RouteFactoryFn< TPath extends string, TMethod extends HttpMethod | undefined, TParams extends Params, TReturn -> = ( - core: CoreSetup, - __LEGACY: LegacySetup -) => Route; +> = (core: CoreSetup) => Route; export interface RouteState { [key: string]: { @@ -83,7 +108,14 @@ export interface ServerAPI { }; } >; - init: (core: CoreSetup, __LEGACY: LegacySetup) => void; + init: ( + core: CoreSetup, + context: { + config$: Observable; + logger: Logger; + __LEGACY: { server: Server }; + } + ) => void; } // without this, TS does not recognize possible existence of `params` in `options` below diff --git a/x-pack/legacy/plugins/apm/server/routes/ui_filters.ts b/x-pack/legacy/plugins/apm/server/routes/ui_filters.ts index d04b49cfe921d..dcca41c7e00df 100644 --- a/x-pack/legacy/plugins/apm/server/routes/ui_filters.ts +++ b/x-pack/legacy/plugins/apm/server/routes/ui_filters.ts @@ -6,7 +6,12 @@ import * as t from 'io-ts'; import { omit } from 'lodash'; -import { setupRequest, Setup } from '../lib/helpers/setup_request'; +import { + setupRequest, + Setup, + SetupUIFilters, + SetupTimeRange +} from '../lib/helpers/setup_request'; import { getEnvironments } from '../lib/ui_filters/get_environments'; import { Projection } from '../../common/projections/typings'; import { @@ -35,9 +40,9 @@ export const uiFiltersEnvironmentsRoute = createRoute(() => ({ rangeRt ]) }, - handler: async (req, { query }) => { - const setup = await setupRequest(req); - const { serviceName } = query; + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + const { serviceName } = context.params.query; return getEnvironments(setup, serviceName); } })); @@ -76,19 +81,19 @@ function createLocalFiltersRoute< return createRoute(() => ({ path, params: { - query: queryRt - ? t.intersection([queryRt, localUiBaseQueryRt]) - : localUiBaseQueryRt + query: t.intersection([localUiBaseQueryRt, queryRt]) }, - handler: async (request, { query }: { query: t.TypeOf }) => { - const setup = await setupRequest(request); + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + const { query } = context.params; + const { uiFilters, filterNames } = query; const parsedUiFilters = JSON.parse(uiFilters); const projection = getProjection({ query, setup: { ...setup, - uiFiltersES: await getUiFiltersES( + uiFiltersES: getUiFiltersES( setup.dynamicIndexPattern, omit(parsedUiFilters, filterNames) ) @@ -222,5 +227,5 @@ type GetProjection< setup }: { query: t.TypeOf; - setup: Setup; + setup: Setup & SetupUIFilters & SetupTimeRange; }) => TProjection; diff --git a/x-pack/plugins/apm/kibana.json b/x-pack/plugins/apm/kibana.json new file mode 100644 index 0000000000000..8161f6ee06bf8 --- /dev/null +++ b/x-pack/plugins/apm/kibana.json @@ -0,0 +1,14 @@ +{ + "id": "apm", + "server": true, + "version": "8.0.0", + "kibanaVersion": "kibana", + "configPath": [ + "xpack", + "apm" + ], + "ui": false, + "requiredPlugins": [ + "apm_oss" + ] +} diff --git a/x-pack/plugins/apm/server/index.ts b/x-pack/plugins/apm/server/index.ts new file mode 100644 index 0000000000000..6e1257bc4d1c4 --- /dev/null +++ b/x-pack/plugins/apm/server/index.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 { schema, TypeOf } from '@kbn/config-schema'; +import { PluginInitializerContext } from 'src/core/server'; +import { APMOSSConfig } from 'src/plugins/apm_oss/server'; +import { APMPlugin } from './plugin'; + +export const config = { + schema: schema.object({ + servicemapEnabled: schema.boolean({ defaultValue: false }), + autocreateApmIndexPattern: schema.boolean({ defaultValue: true }), + 'ui.transactionGroupBucketSize': schema.number({ defaultValue: 100 }), + 'ui.maxTraceItems': schema.number({ defaultValue: 1000 }), + }), +}; + +export type APMXPackConfig = TypeOf; + +export function mergeConfigs(apmOssConfig: APMOSSConfig, apmConfig: APMXPackConfig) { + return { + 'apm_oss.transactionIndices': apmOssConfig.transactionIndices, + 'apm_oss.spanIndices': apmOssConfig.spanIndices, + 'apm_oss.errorIndices': apmOssConfig.errorIndices, + 'apm_oss.metricsIndices': apmOssConfig.metricsIndices, + 'apm_oss.sourcemapIndices': apmOssConfig.sourcemapIndices, + 'apm_oss.onboardingIndices': apmOssConfig.onboardingIndices, + 'apm_oss.indexPattern': apmOssConfig.indexPattern, + 'xpack.apm.servicemapEnabled': apmConfig.servicemapEnabled, + 'xpack.apm.ui.maxTraceItems': apmConfig['ui.maxTraceItems'], + 'xpack.apm.ui.transactionGroupBucketSize': apmConfig['ui.transactionGroupBucketSize'], + 'xpack.apm.autocreateApmIndexPattern': apmConfig.autocreateApmIndexPattern, + }; +} + +export type APMConfig = ReturnType; + +export const plugin = (initContext: PluginInitializerContext) => new APMPlugin(initContext); + +export { APMPlugin } from './plugin'; diff --git a/x-pack/plugins/apm/server/plugin.ts b/x-pack/plugins/apm/server/plugin.ts new file mode 100644 index 0000000000000..b28e00adcc6d1 --- /dev/null +++ b/x-pack/plugins/apm/server/plugin.ts @@ -0,0 +1,69 @@ +/* + * 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, Plugin, CoreSetup } from 'src/core/server'; +import { Observable, combineLatest, AsyncSubject } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { Server } from 'hapi'; +import { once } from 'lodash'; +import { Plugin as APMOSSPlugin } from '../../../../src/plugins/apm_oss/server'; +import { createApmAgentConfigurationIndex } from '../../../legacy/plugins/apm/server/lib/settings/agent_configuration/create_agent_config_index'; +import { createApmApi } from '../../../legacy/plugins/apm/server/routes/create_apm_api'; +import { APMConfig, mergeConfigs, APMXPackConfig } from '.'; + +export interface LegacySetup { + server: Server; +} + +export interface APMPluginContract { + config$: Observable; + registerLegacyAPI: (__LEGACY: LegacySetup) => void; +} + +export class APMPlugin implements Plugin { + legacySetup$: AsyncSubject; + constructor(private readonly initContext: PluginInitializerContext) { + this.initContext = initContext; + this.legacySetup$ = new AsyncSubject(); + } + + public setup( + core: CoreSetup, + plugins: { + apm_oss: APMOSSPlugin extends Plugin ? TSetup : never; + } + ) { + const config$ = this.initContext.config.create(); + const logger = this.initContext.logger.get('apm'); + + const mergedConfig$ = combineLatest(plugins.apm_oss.config$, config$).pipe( + map(([apmOssConfig, apmConfig]) => mergeConfigs(apmOssConfig, apmConfig)) + ); + + this.legacySetup$.subscribe(__LEGACY => { + createApmApi().init(core, { config$: mergedConfig$, logger, __LEGACY }); + }); + + combineLatest(mergedConfig$, core.elasticsearch.dataClient$).subscribe( + ([config, dataClient]) => { + createApmAgentConfigurationIndex({ + esClient: dataClient, + config, + }); + } + ); + + return { + config$: mergedConfig$, + registerLegacyAPI: once((__LEGACY: LegacySetup) => { + this.legacySetup$.next(__LEGACY); + this.legacySetup$.complete(); + }), + }; + } + + public start() {} + public stop() {} +}