diff --git a/src/legacy/core_plugins/apm_oss/index.d.ts b/src/legacy/core_plugins/apm_oss/index.d.ts new file mode 100644 index 0000000000000..86fe4e0350dce --- /dev/null +++ b/src/legacy/core_plugins/apm_oss/index.d.ts @@ -0,0 +1,22 @@ +/* + * 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. + */ + +export interface ApmOssPlugin { + indexPatterns: string[]; +} diff --git a/src/legacy/core_plugins/apm_oss/index.js b/src/legacy/core_plugins/apm_oss/index.js index 72683bed8970e..2c404b6197f5a 100644 --- a/src/legacy/core_plugins/apm_oss/index.js +++ b/src/legacy/core_plugins/apm_oss/index.js @@ -17,6 +17,8 @@ * under the License. */ +import _ from 'lodash'; + export default function apmOss(kibana) { return new kibana.Plugin({ id: 'apm_oss', @@ -30,12 +32,24 @@ export default function apmOss(kibana) { indexPattern: Joi.string().default('apm-*'), // ES Indices + sourcemapIndices: Joi.string().default('apm-*'), errorIndices: Joi.string().default('apm-*'), - onboardingIndices: Joi.string().default('apm-*'), - spanIndices: Joi.string().default('apm-*'), transactionIndices: Joi.string().default('apm-*'), + spanIndices: Joi.string().default('apm-*'), metricsIndices: Joi.string().default('apm-*'), + onboardingIndices: Joi.string().default('apm-*'), }).default(); }, + + init(server) { + server.expose('indexPatterns', _.uniq([ + 'sourcemapIndices', + 'errorIndices', + 'transactionIndices', + 'spanIndices', + 'metricsIndices', + 'onboardingIndices' + ].map(type => server.config().get(`apm_oss.${type}`)))); + } }); } diff --git a/src/legacy/core_plugins/elasticsearch/index.d.ts b/src/legacy/core_plugins/elasticsearch/index.d.ts index d1ac84cad6986..7ab4700d379d2 100644 --- a/src/legacy/core_plugins/elasticsearch/index.d.ts +++ b/src/legacy/core_plugins/elasticsearch/index.d.ts @@ -202,13 +202,15 @@ export interface DeprecationInfo { details?: string; } +export interface IndexSettingsDeprecationInfo { + [indexName: string]: DeprecationInfo[]; +} + export interface DeprecationAPIResponse { cluster_settings: DeprecationInfo[]; ml_settings: DeprecationInfo[]; node_settings: DeprecationInfo[]; - index_settings: { - [indexName: string]: DeprecationInfo[]; - }; + index_settings: IndexSettingsDeprecationInfo; } export interface CallClusterOptions { diff --git a/src/server/kbn_server.d.ts b/src/server/kbn_server.d.ts index 9ec8a6349045d..5bf7657dcafd8 100644 --- a/src/server/kbn_server.d.ts +++ b/src/server/kbn_server.d.ts @@ -19,7 +19,9 @@ import { Server } from 'hapi'; +import { ApmOssPlugin } from '../legacy/core_plugins/apm_oss'; import { CallClusterWithRequest, ElasticsearchPlugin } from '../legacy/core_plugins/elasticsearch'; + import { IndexPatternsServiceFactory } from './index_patterns'; import { SavedObjectsClient, SavedObjectsService } from './saved_objects'; @@ -33,6 +35,7 @@ declare module 'hapi' { elasticsearch: ElasticsearchPlugin; kibana: any; spaces: any; + apm_oss: ApmOssPlugin; // add new plugin types here } diff --git a/x-pack/plugins/upgrade_assistant/common/types.ts b/x-pack/plugins/upgrade_assistant/common/types.ts index e634e49f99cf8..6b628181bdf29 100644 --- a/x-pack/plugins/upgrade_assistant/common/types.ts +++ b/x-pack/plugins/upgrade_assistant/common/types.ts @@ -53,6 +53,7 @@ export enum ReindexWarning { booleanFields = 1, // 7.0 -> 8.0 warnings + apmReindex, } export enum IndexGroup { diff --git a/x-pack/plugins/upgrade_assistant/index.ts b/x-pack/plugins/upgrade_assistant/index.ts index 6c327a93ee360..7c38fbf02a564 100644 --- a/x-pack/plugins/upgrade_assistant/index.ts +++ b/x-pack/plugins/upgrade_assistant/index.ts @@ -3,8 +3,8 @@ * 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 Joi from 'joi'; +import { Legacy } from 'kibana'; import { resolve } from 'path'; import mappings from './mappings.json'; import { initServer } from './server'; @@ -35,7 +35,7 @@ export function upgradeAssistant(kibana: any) { }).default(); }, - init(server: Server) { + init(server: Legacy.Server) { // Add server routes and initialize the plugin here initServer(server); }, diff --git a/x-pack/plugins/upgrade_assistant/public/components/tabs/checkup/deprecations/index_table.tsx b/x-pack/plugins/upgrade_assistant/public/components/tabs/checkup/deprecations/index_table.tsx index 5deed2523e215..5a1deb59c270e 100644 --- a/x-pack/plugins/upgrade_assistant/public/components/tabs/checkup/deprecations/index_table.tsx +++ b/x-pack/plugins/upgrade_assistant/public/components/tabs/checkup/deprecations/index_table.tsx @@ -135,7 +135,7 @@ export class IndexDeprecationTableUI extends React.Component< // NOTE: this naive implementation assumes all indices in the table are // should show the reindex button. This should work for known usecases. const { indices } = this.props; - if (!indices.find(i => i.reindex)) { + if (!indices.find(i => i.reindex === true)) { return null; } @@ -143,7 +143,7 @@ export class IndexDeprecationTableUI extends React.Component< actions: [ { render(indexDep: IndexDeprecationDetails) { - return ; + return ; }, }, ], diff --git a/x-pack/plugins/upgrade_assistant/public/components/tabs/checkup/deprecations/list.tsx b/x-pack/plugins/upgrade_assistant/public/components/tabs/checkup/deprecations/list.tsx index 0783802b6c0c6..cb38b848b3bd7 100644 --- a/x-pack/plugins/upgrade_assistant/public/components/tabs/checkup/deprecations/list.tsx +++ b/x-pack/plugins/upgrade_assistant/public/components/tabs/checkup/deprecations/list.tsx @@ -10,13 +10,10 @@ import { DeprecationInfo } from 'src/legacy/core_plugins/elasticsearch'; import { EnrichedDeprecationInfo } from '../../../../../server/lib/es_migration_apis'; import { GroupByOption } from '../../../types'; -import { CURRENT_MAJOR_VERSION } from 'x-pack/plugins/upgrade_assistant/common/version'; import { COLOR_MAP, LEVEL_MAP } from '../constants'; import { DeprecationCell } from './cell'; import { IndexDeprecationDetails, IndexDeprecationTable } from './index_table'; -const OLD_INDEX_MESSAGE = `Index created before ${CURRENT_MAJOR_VERSION}.0`; - const sortByLevelDesc = (a: DeprecationInfo, b: DeprecationInfo) => { return -1 * (LEVEL_MAP[a.level] - LEVEL_MAP[b.level]); }; @@ -37,7 +34,7 @@ const MessageDeprecation: StatelessComponent<{ deprecation: EnrichedDeprecationI @@ -91,9 +88,8 @@ export const DeprecationList: StatelessComponent<{ const indices = deprecations.map(dep => ({ index: dep.index!, details: dep.details, - reindex: dep.message === OLD_INDEX_MESSAGE, + reindex: dep.reindex === true, })); - return ; } else if (currentGroupBy === GroupByOption.index) { return ( diff --git a/x-pack/plugins/upgrade_assistant/public/components/tabs/checkup/deprecations/reindex/flyout/__snapshots__/warning_step.test.tsx.snap b/x-pack/plugins/upgrade_assistant/public/components/tabs/checkup/deprecations/reindex/flyout/__snapshots__/warning_step.test.tsx.snap index bd06a5e6b82d3..c1e7e58813425 100644 --- a/x-pack/plugins/upgrade_assistant/public/components/tabs/checkup/deprecations/reindex/flyout/__snapshots__/warning_step.test.tsx.snap +++ b/x-pack/plugins/upgrade_assistant/public/components/tabs/checkup/deprecations/reindex/flyout/__snapshots__/warning_step.test.tsx.snap @@ -108,8 +108,7 @@ exports[`WarningsFlyoutStep renders 1`] = ` 1 - ), reindexing converts these fields to - + ), reindexing converts these fields to true @@ -129,6 +128,9 @@ exports[`WarningsFlyoutStep renders 1`] = `

+ {warnings.includes(ReindexWarning.allField) && ( - - - _all field will be removed - - } - checked={checkedIds[idForWarning(ReindexWarning.allField)]} - onChange={this.onChange} - /> -

- The _all meta field is no longer supported in 7.0. Reindexing - removes the _all field in the new index. Ensure that no - application code or scripts reply on this field. -
- - Documentation - -

-
+ + + + _all field will be removed + + } + checked={checkedIds[idForWarning(ReindexWarning.allField)]} + onChange={this.onChange} + /> +

+ The _all meta field is no longer supported in 7.0. Reindexing + removes the _all field in the new index. Ensure that no + application code or scripts reply on this field. +
+ + Documentation + +

+
+ + +
)} - + {warnings.includes(ReindexWarning.apmReindex) && ( + + + This index will be converted to ECS format} + checked={checkedIds[idForWarning(ReindexWarning.apmReindex)]} + onChange={this.onChange} + /> +

+ Starting in version 7.0.0, APM data will be represented in the Elastic Common + Schema. Historical APM data will not visible until it's reindexed. +
+ + Documentation + +

+
+ + +
+ )} {warnings.includes(ReindexWarning.booleanFields) && ( - - - Boolean data in _source might change - - } - checked={checkedIds[idForWarning(ReindexWarning.booleanFields)]} - onChange={this.onChange} - /> -

- If a documents contain a boolean field that is neither true or{' '} - false (for example, "yes",{' '} - "on", 1), reindexing converts these fields to{' '} - true or false. Ensure that no application code - or scripts rely on boolean fields in the deprecated format. -
- - Documentation - -

-
+ + + + Boolean data in _source might change + + } + checked={checkedIds[idForWarning(ReindexWarning.booleanFields)]} + onChange={this.onChange} + /> +

+ If a documents contain a boolean field that is neither true or{' '} + false (for example, "yes",{' '} + "on", 1), reindexing converts these fields + to true or false. Ensure that no application + code or scripts rely on boolean fields in the deprecated format. +
+ + Documentation + +

+
+ + +
)} diff --git a/x-pack/plugins/upgrade_assistant/server/lib/__snapshots__/es_migration_apis.test.ts.snap b/x-pack/plugins/upgrade_assistant/server/lib/__snapshots__/es_migration_apis.test.ts.snap index ac5c5994344eb..10f66fd1fc01a 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/__snapshots__/es_migration_apis.test.ts.snap +++ b/x-pack/plugins/upgrade_assistant/server/lib/__snapshots__/es_migration_apis.test.ts.snap @@ -34,6 +34,7 @@ Object { "index": ".monitoring-es-6-2018.11.07", "level": "warning", "message": "Coercion of boolean fields", + "reindex": false, "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", }, Object { @@ -41,6 +42,7 @@ Object { "index": "twitter", "level": "warning", "message": "Coercion of boolean fields", + "reindex": false, "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", }, Object { @@ -48,6 +50,7 @@ Object { "index": ".kibana", "level": "warning", "message": "Coercion of boolean fields", + "reindex": false, "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", }, Object { @@ -55,6 +58,7 @@ Object { "index": ".watcher-history-6-2018.11.07", "level": "warning", "message": "Coercion of boolean fields", + "reindex": false, "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", }, Object { @@ -62,6 +66,7 @@ Object { "index": ".monitoring-kibana-6-2018.11.07", "level": "warning", "message": "Coercion of boolean fields", + "reindex": false, "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", }, Object { @@ -69,6 +74,7 @@ Object { "index": "twitter2", "level": "warning", "message": "Coercion of boolean fields", + "reindex": false, "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", }, ], diff --git a/x-pack/plugins/upgrade_assistant/server/lib/apm/index.test.ts b/x-pack/plugins/upgrade_assistant/server/lib/apm/index.test.ts new file mode 100644 index 0000000000000..4263fec5cff11 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/server/lib/apm/index.test.ts @@ -0,0 +1,117 @@ +/* + * 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 { getDeprecatedApmIndices, isLegacyApmIndex } from './'; + +function mockedCallWithRequest() { + return jest.fn().mockImplementation(async () => { + return { + 'foo-1': { + mappings: {}, + }, + 'foo-2': { + mappings: { + _meta: { + version: '6.7.0', + }, + }, + }, + 'foo-3': { + mappings: { + _meta: { + version: '7.0.0', + }, + }, + }, + 'foo-4': { + mappings: { + _meta: { + version: '7.1.0', + }, + }, + }, + }; + }); +} + +describe('getDeprecatedApmIndices', () => { + it('calls indices.getMapping', async () => { + const callWithRequest = mockedCallWithRequest(); + await getDeprecatedApmIndices(callWithRequest, {} as any, ['foo-*', 'bar-*']); + + expect(callWithRequest).toHaveBeenCalledWith({}, 'indices.getMapping', { + index: 'foo-*,bar-*', + filterPath: '*.mappings._meta.version,*.mappings.properties.@timestamp', + }); + }); + + it('includes mappings not yet at 7.0.0', async () => { + const callWithRequest = mockedCallWithRequest(); + const deprecations = await getDeprecatedApmIndices(callWithRequest, {} as any, ['foo-*']); + + expect(deprecations).toHaveLength(2); + expect(deprecations[0].index).toEqual('foo-1'); + expect(deprecations[1].index).toEqual('foo-2'); + }); + + it('formats the deprecations', async () => { + const callWithRequest = mockedCallWithRequest(); + // @ts-ignore + const [deprecation, _] = await getDeprecatedApmIndices(callWithRequest, {} as any, ['foo-*']); + + expect(deprecation.level).toEqual('warning'); + expect(deprecation.message).toEqual('APM index needs converted to 7.x format'); + expect(deprecation.url).toEqual( + 'https://www.elastic.co/guide/en/apm/get-started/master/apm-release-notes.html' + ); + expect(deprecation.details).toEqual('This index was created prior to 7.0'); + expect(deprecation.reindex).toBe(true); + }); +}); + +describe('isLegacyApmIndex', () => { + it('is true when for no version', () => { + expect(isLegacyApmIndex('foo-1', ['foo-*'], {})).toEqual(true); + }); + + it('is true when version is less than 7.0.0', () => { + expect( + isLegacyApmIndex('foo-1', ['foo-*'], { + _meta: { version: '6.7.0' }, + }) + ).toEqual(true); + }); + + it('is false when version is 7.0.0', () => { + expect( + isLegacyApmIndex('foo-1', ['foo-*'], { + _meta: { version: '7.0.0' }, + }) + ).toEqual(false); + }); + + it('is false when version is greater than 7.0.0', () => { + expect( + isLegacyApmIndex('foo-1', ['foo-*'], { + _meta: { version: '7.1.0' }, + }) + ).toEqual(false); + }); + + it('handles multiple index patterns', () => { + expect( + isLegacyApmIndex('bar-1', ['foo-*', 'bar-*'], { + _meta: { version: '6.7.0' }, + }) + ).toEqual(true); + + expect( + isLegacyApmIndex('bar-1', ['foo-*', 'bar-*'], { + _meta: { version: '7.0.0' }, + }) + ).toEqual(false); + }); +}); diff --git a/x-pack/plugins/upgrade_assistant/server/lib/apm/index.ts b/x-pack/plugins/upgrade_assistant/server/lib/apm/index.ts new file mode 100644 index 0000000000000..ee5dd5a0562b1 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/server/lib/apm/index.ts @@ -0,0 +1,362 @@ +/* + * 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 { Request } from 'hapi'; +import { get } from 'lodash'; +import minimatch from 'minimatch'; +import semver from 'semver'; +import { CallClusterWithRequest } from 'src/legacy/core_plugins/elasticsearch'; +import pkg from '../../../../../package.json'; + +import { EnrichedDeprecationInfo } from '../es_migration_apis'; +import { FlatSettings } from '../reindexing/types'; + +export async function getDeprecatedApmIndices( + callWithRequest: CallClusterWithRequest, + request: Request, + indexPatterns: string[] = [] +): Promise { + const indices = await callWithRequest(request, 'indices.getMapping', { + index: indexPatterns.join(','), + // we include @timestamp to prevent filtering mappings without a version + // since @timestamp is expected to always exist + filterPath: '*.mappings._meta.version,*.mappings.properties.@timestamp', + }); + + return Object.keys(indices).reduce((deprecations: EnrichedDeprecationInfo[], index) => { + if (semver.lt(get(indices[index], 'mappings._meta.version', '0.0.0'), pkg.version)) { + deprecations.push({ + level: 'warning', + message: 'APM index needs converted to 7.x format', + url: 'https://www.elastic.co/guide/en/apm/get-started/master/apm-release-notes.html', + details: 'This index was created prior to 7.0', + reindex: true, + index, + }); + } + + return deprecations; + }, []); +} + +export const isLegacyApmIndex = ( + indexName: string, + apmIndexPatterns: string[] = [], + mappings: FlatSettings['mappings'] +) => { + const clientVersion = get(mappings, '_meta.version', '0.0.0'); + + const find = apmIndexPatterns.find(pattern => { + return minimatch(indexName, pattern) && semver.lt(clientVersion, pkg.version); // no client version or version < 7.0 + }); + + return Boolean(find); +}; + +// source: https://github.com/elastic/apm-integration-testing/blob/master/tests/server/test_upgrade.py +export const apmReindexScript = ` + // add ecs version + ctx._source.ecs = ['version': '1.0.0-beta2']; + + // beat -> observer + def beat = ctx._source.remove("beat"); + if (beat != null) { + beat.remove("name"); + ctx._source.observer = beat; + ctx._source.observer.type = "apm-server"; + } + + if (! ctx._source.containsKey("observer")) { + ctx._source.observer = new HashMap(); + } + + // observer.major_version + ctx._source.observer.version_major = 7; + + def listening = ctx._source.remove("listening"); + if (listening != null) { + ctx._source.observer.listening = listening; + } + + // remove host[.name] + // clarify if we can simply delete this or it will be set somewhere else in 7.0 + ctx._source.remove("host"); + + // docker.container -> container + def docker = ctx._source.remove("docker"); + if (docker != null && docker.containsKey("container")) { + ctx._source.container = docker.container; + } + + // rip up context + HashMap context = ctx._source.remove("context"); + if (context != null) { + // context.process -> process + if (context.containsKey("process")) { + ctx._source.process = context.remove("process"); + ctx._source.process.args = ctx._source.process.remove("argv"); + } + + // context.response -> http.response + HashMap resp = context.remove("response"); + if (resp != null) { + if (! ctx._source.containsKey("http")) { + ctx._source.http = new HashMap(); + } + ctx._source.http.response = resp; + } + + // context.request -> http & url + HashMap request = context.remove("request"); + if (request != null) { + if (! ctx._source.containsKey("http")) { + ctx._source.http = new HashMap(); + } + + // context.request.http_version -> http.version + def http_version = request.remove("http_version"); + if (http_version != null) { + ctx._source.http.version = http_version; + } + + ctx._source.http.request = new HashMap(); + + + // context.request.url -> url + HashMap url = request.remove("url"); + def fragment = url.remove("hash"); + if (fragment != null) { + url.fragment = fragment; + } + def domain = url.remove("hostname"); + if (domain != null) { + url.domain = domain; + } + def path = url.remove("pathname"); + if (path != null) { + url.path = path; + } + def scheme = url.remove("protocol"); + if (scheme != null) { + def end = scheme.lastIndexOf(":"); + if (end > -1) { + scheme = scheme.substring(0, end); + } + url.scheme = scheme + } + def original = url.remove("raw"); + if (original != null) { + url.original = original; + } + def port = url.remove("port"); + if (port != null) { + try { + int portNum = Integer.parseInt(port); + url.port = portNum; + } catch (Exception e) { + // toss port + } + } + def query = url.remove("search"); + if (query != null) { + url.query = query; + } + ctx._source.url = url; + + // restore what is left of request, under http + + def body = request.remove("body"); + + ctx._source.http.request = request; + ctx._source.http.request.method = ctx._source.http.request.method?.toLowerCase(); + + // context.request.body -> http.request.body.original + if (body != null) { + ctx._source.http.request.body = new HashMap(); + ctx._source.http.request.body.original = body; + } + + } + + // context.service.agent -> agent + HashMap service = context.remove("service"); + ctx._source.agent = service.remove("agent"); + + // context.service -> service + ctx._source.service = service; + + // context.system -> host + def system = context.remove("system"); + if (system != null) { + system.os = new HashMap(); + system.os.platform = system.remove("platform"); + ctx._source.host = system; + } + + // context.tags -> labels + def tags = context.remove("tags"); + if (tags != null) { + ctx._source.labels = tags; + } + + // context.user -> user & user_agent + if (context.containsKey("user")) { + HashMap user = context.remove("user"); + // user.username -> user.name + def username = user.remove("username"); + if (username != null) { + user.name = username; + } + + // context.user.ip -> client.ip + if (user.containsKey("ip")) { + ctx._source.client = new HashMap(); + ctx._source.client.ip = user.remove("ip"); + } + + def ua = user.remove("user-agent"); + if (ua != null) { + ctx._source.user_agent = new HashMap(); + // setting original and original.text is not possible in painless + // as original is a keyword in ES template we cannot set it to a HashMap here, + // so the following is the only possible solution: + ctx._source.user_agent.original = ua.substring(0, Integer.min(1024, ua.length())); + } + + def pua = user.remove("user_agent"); + if (pua != null) { + if (ctx._source.user_agent == null){ + ctx._source.user_agent = new HashMap(); + } + def os = pua.remove("os"); + def osminor = pua.remove("os_minor"); + def osmajor = pua.remove("os_major"); + def osname = pua.remove("os_name"); + if (osminor != null || osmajor != null || osname != null){ + ctx._source.user_agent.os = new HashMap(); + ctx._source.user_agent.os.full = os; + ctx._source.user_agent.os.version = osmajor + "." + osminor; + ctx._source.user_agent.os.name = osname; + } + + def device = pua.remove("device"); + if (device != null){ + ctx._source.user_agent.device = new HashMap(); + ctx._source.user_agent.device.name = device; + } + // not exactly reflecting 7.0, but the closes we can get + def patch = pua.remove("patch"); + def minor = pua.remove("minor"); + def major = pua.remove("major"); + if (patch != null || minor != null || major != null){ + ctx._source.user_agent.version = major + "." + minor + "." + patch; + } + } + + ctx._source.user = user; + } + + // context.custom -> error,transaction,span.custom + def custom = context.remove("custom"); + if (custom != null) { + if (ctx._source.processor.event == "span") { + ctx._source.span.custom = custom; + } else if (ctx._source.processor.event == "transaction") { + ctx._source.transaction.custom = custom; + } else if (ctx._source.processor.event == "error") { + ctx._source.error.custom = custom; + } + } + + // context.db -> span.db + def db = context.remove("db"); + if (db != null) { + ctx._source.span.db = db; + } + + // context.http -> span.http + def http = context.remove("http"); + if (http != null) { + // context.http.url -> span.http.url.original + def url = http.remove("url"); + if (url != null) { + http.url = ["original": url]; + } + // context.http.status_code -> span.http.response.status_code + def status_code = http.remove("status_code"); + if (status_code != null) { + http.response = ["status_code": status_code]; + } + ctx._source.span.http = http; + } + } + + if (ctx._source.processor.event == "span") { + // bump timestamp.us by span.start.us for spans + // shouldn't @timestamp this already be a Date? + def ts = ctx._source.get("@timestamp"); + if (ts != null && !ctx._source.containsKey("timestamp")) { + // add span.start to @timestamp for rum documents v1 + if (ctx._source.context.service.agent.name == "js-base" && ctx._source.span.start.containsKey("us")) { + ts += ctx._source.span.start.us/1000; + } + } + if (ctx._source.span.containsKey("hex_id")) { + ctx._source.span.id = ctx._source.span.remove("hex_id"); + } + def parent = ctx._source.span.remove("parent"); + if (parent != null && ctx._source.parent == null) { + ctx._source.parent = ["id": parent]; + } + } + + // create trace.id + if (ctx._source.processor.event == "transaction" || ctx._source.processor.event == "span" || ctx._source.processor.event == "error") { + if (ctx._source.containsKey("transaction")) { + def tr_id = ctx._source.transaction.get("id"); + if (ctx._source.trace == null && tr_id != null) { + // create a trace id from the transaction.id + // v1 transaction.id was a UUID, should have 122 random bits or so + ctx._source.trace = new HashMap(); + ctx._source.trace.id = tr_id.replace("-", ""); + } + } + + // create timestamp.us from @timestamp + def ts = ctx._source.get("@timestamp"); + if (ts != null && !ctx._source.containsKey("timestamp")) { + //set timestamp.microseconds to @timestamp + ctx._source.timestamp = new HashMap(); + ctx._source.timestamp.us = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").parse(ts).getTime()*1000; + } + + } + + // transaction.span_count.dropped.total -> transaction.span_count.dropped + if (ctx._source.processor.event == "transaction") { + // transaction.span_count.dropped.total -> transaction.span_count.dropped + if (ctx._source.transaction.containsKey("span_count")) { + def dropped = ctx._source.transaction.span_count.remove("dropped"); + if (dropped != null) { + ctx._source.transaction.span_count.dropped = dropped.total; + } + } + } + + if (ctx._source.processor.event == "error") { + // culprit is now a keyword, so trim it down to 1024 chars + def culprit = ctx._source.error.remove("culprit"); + if (culprit != null) { + ctx._source.error.culprit = culprit.substring(0, Integer.min(1024, culprit.length())); + } + + // error.exception is now a list (exception chain) + def exception = ctx._source.error.remove("exception"); + if (exception != null) { + ctx._source.error.exception = [exception]; + } + } +`; diff --git a/x-pack/plugins/upgrade_assistant/server/lib/apm/mapping.json b/x-pack/plugins/upgrade_assistant/server/lib/apm/mapping.json new file mode 100644 index 0000000000000..f518b824f1108 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/server/lib/apm/mapping.json @@ -0,0 +1,1598 @@ +{ + "_meta": { + "beat": "apm", + "version": "7.0.0" + }, + "date_detection": false, + "dynamic_templates": [ + { + "container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "container.labels.*" + } + }, + { + "fields": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "fields.*" + } + }, + { + "docker.container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "docker.container.labels.*" + } + }, + { + "labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "labels": { + "mapping": { + "type": "boolean" + }, + "match_mapping_type": "boolean", + "path_match": "labels.*" + } + }, + { + "labels": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "match_mapping_type": "*", + "path_match": "labels.*" + } + }, + { + "transaction.marks": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "transaction.marks.*" + } + }, + { + "transaction.marks.*.*": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "match_mapping_type": "*", + "path_match": "transaction.marks.*.*" + } + }, + { + "strings_as_keyword": { + "mapping": { + "ignore_above": 1024, + "type": "keyword" + }, + "match_mapping_type": "string" + } + } + ], + "properties": { + "@timestamp": { + "type": "date" + }, + "agent": { + "dynamic": false, + "properties": { + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "client": { + "dynamic": false, + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + } + } + }, + "cloud": { + "properties": { + "account": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "availability_zone": { + "ignore_above": 1024, + "type": "keyword" + }, + "instance": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "machine": { + "properties": { + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "project": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "region": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "container": { + "dynamic": false, + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "tag": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "type": "object" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "runtime": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "destination": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + } + } + }, + "docker": { + "properties": { + "container": { + "properties": { + "labels": { + "type": "object" + } + } + } + } + }, + "ecs": { + "properties": { + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "error": { + "dynamic": false, + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "culprit": { + "ignore_above": 1024, + "type": "keyword" + }, + "exception": { + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "handled": { + "type": "boolean" + }, + "message": { + "norms": false, + "type": "text" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "grouping_key": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "norms": false, + "type": "text" + }, + "param_message": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "event": { + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "created": { + "type": "date" + }, + "dataset": { + "ignore_above": 1024, + "type": "keyword" + }, + "duration": { + "type": "long" + }, + "end": { + "type": "date" + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "kind": { + "ignore_above": 1024, + "type": "keyword" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "doc_values": false, + "ignore_above": 1024, + "index": false, + "type": "keyword" + }, + "outcome": { + "ignore_above": 1024, + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "risk_score_norm": { + "type": "float" + }, + "severity": { + "type": "long" + }, + "start": { + "type": "date" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "fields": { + "type": "object" + }, + "file": { + "properties": { + "ctime": { + "type": "date" + }, + "device": { + "ignore_above": 1024, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "gid": { + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "ignore_above": 1024, + "type": "keyword" + }, + "inode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mtime": { + "type": "date" + }, + "owner": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "size": { + "type": "long" + }, + "target_path": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "host": { + "dynamic": false, + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "http": { + "dynamic": false, + "properties": { + "request": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "method": { + "ignore_above": 1024, + "type": "keyword" + }, + "referrer": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "response": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "finished": { + "type": "boolean" + }, + "status_code": { + "type": "long" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "kubernetes": { + "dynamic": false, + "properties": { + "annotations": { + "type": "object" + }, + "container": { + "properties": { + "image": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "type": "object" + }, + "namespace": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pod": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "labels": { + "dynamic": true, + "type": "object" + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "doc_values": false, + "ignore_above": 1024, + "index": false, + "type": "keyword" + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "network": { + "properties": { + "application": { + "ignore_above": 1024, + "type": "keyword" + }, + "bytes": { + "type": "long" + }, + "community_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "direction": { + "ignore_above": 1024, + "type": "keyword" + }, + "forwarded_ip": { + "type": "ip" + }, + "iana_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "packets": { + "type": "long" + }, + "protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "transport": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "observer": { + "dynamic": false, + "properties": { + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "listening": { + "ignore_above": 1024, + "type": "keyword" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vendor": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_major": { + "type": "byte" + } + } + }, + "organization": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "parent": { + "dynamic": false, + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "process": { + "dynamic": false, + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + } + } + }, + "title": { + "ignore_above": 1024, + "type": "keyword" + }, + "working_directory": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "processor": { + "properties": { + "event": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "related": { + "properties": { + "ip": { + "type": "ip" + } + } + }, + "server": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + } + } + }, + "service": { + "dynamic": false, + "properties": { + "environment": { + "ignore_above": 1024, + "type": "keyword" + }, + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "framework": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "language": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "runtime": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "state": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "source": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + } + } + }, + "sourcemap": { + "dynamic": false, + "properties": { + "bundle_filepath": { + "ignore_above": 1024, + "type": "keyword" + }, + "service": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "span": { + "dynamic": false, + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "duration": { + "properties": { + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "start": { + "properties": { + "us": { + "type": "long" + } + } + }, + "subtype": { + "ignore_above": 1024, + "type": "keyword" + }, + "sync": { + "type": "boolean" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "system": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "actual": { + "properties": { + "free": { + "type": "long" + } + } + }, + "total": { + "type": "long" + } + } + }, + "process": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "rss": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "size": { + "type": "long" + } + } + } + } + } + } + }, + "tags": { + "ignore_above": 1024, + "type": "keyword" + }, + "timestamp": { + "properties": { + "us": { + "type": "long" + } + } + }, + "trace": { + "dynamic": false, + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "transaction": { + "dynamic": false, + "properties": { + "duration": { + "properties": { + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "marks": { + "dynamic": true, + "properties": { + "*": { + "properties": { + "*": { + "dynamic": true, + "type": "object" + } + } + } + }, + "type": "object" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "result": { + "ignore_above": 1024, + "type": "keyword" + }, + "sampled": { + "type": "boolean" + }, + "span_count": { + "properties": { + "dropped": { + "type": "long" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "url": { + "dynamic": false, + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "fragment": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "password": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "port": { + "type": "long" + }, + "query": { + "ignore_above": 1024, + "type": "keyword" + }, + "scheme": { + "ignore_above": 1024, + "type": "keyword" + }, + "username": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user": { + "dynamic": false, + "properties": { + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user_agent": { + "dynamic": false, + "properties": { + "device": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "view spans": { + "ignore_above": 1024, + "type": "keyword" + } + } +} diff --git a/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.test.ts b/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.test.ts index 52b8267f0ec7d..a3c5a33a6c2de 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.test.ts @@ -16,6 +16,8 @@ describe('getUpgradeAssistantStatus', () => { const callWithRequest = jest.fn().mockImplementation(async (req, api, { path }) => { if (path === '/_migration/deprecations') { return deprecationsResponse; + } else if (api === 'indices.getMapping') { + return {}; } else { throw new Error(`Unexpected API call: ${path}`); } @@ -26,7 +28,7 @@ describe('getUpgradeAssistantStatus', () => { }); it('calls /_migration/deprecations', async () => { - await getUpgradeAssistantStatus(callWithRequest, {} as any, false); + await getUpgradeAssistantStatus(callWithRequest, {} as any, false, []); expect(callWithRequest).toHaveBeenCalledWith({}, 'transport.request', { path: '/_migration/deprecations', method: 'GET', @@ -34,7 +36,7 @@ describe('getUpgradeAssistantStatus', () => { }); it('returns the correct shape of data', async () => { - const resp = await getUpgradeAssistantStatus(callWithRequest, {} as any, false); + const resp = await getUpgradeAssistantStatus(callWithRequest, {} as any, false, []); expect(resp).toMatchSnapshot(); }); @@ -47,7 +49,7 @@ describe('getUpgradeAssistantStatus', () => { }; await expect( - getUpgradeAssistantStatus(callWithRequest, {} as any, false) + getUpgradeAssistantStatus(callWithRequest, {} as any, false, []) ).resolves.toHaveProperty('readyForUpgrade', false); }); @@ -60,7 +62,7 @@ describe('getUpgradeAssistantStatus', () => { }; await expect( - getUpgradeAssistantStatus(callWithRequest, {} as any, false) + getUpgradeAssistantStatus(callWithRequest, {} as any, false, []) ).resolves.toHaveProperty('readyForUpgrade', true); }); @@ -78,7 +80,7 @@ describe('getUpgradeAssistantStatus', () => { index_settings: {}, }; - const result = await getUpgradeAssistantStatus(callWithRequest, {} as any, true); + const result = await getUpgradeAssistantStatus(callWithRequest, {} as any, true, []); expect(result).toHaveProperty('readyForUpgrade', true); expect(result).toHaveProperty('cluster', []); diff --git a/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.ts b/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.ts index 1144dbd214a6b..8990a57c87559 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.ts @@ -13,9 +13,12 @@ import { DeprecationInfo, } from 'src/legacy/core_plugins/elasticsearch'; +import { getDeprecatedApmIndices } from './apm'; + export interface EnrichedDeprecationInfo extends DeprecationInfo { index?: string; node?: string; + reindex?: boolean; } export interface UpgradeAssistantStatus { @@ -27,15 +30,19 @@ export interface UpgradeAssistantStatus { export async function getUpgradeAssistantStatus( callWithRequest: CallClusterWithRequest, req: Request, - isCloudEnabled: boolean + isCloudEnabled: boolean, + apmIndices: string[] ): Promise { - const deprecations = await callWithRequest(req, 'transport.request', { - path: '/_migration/deprecations', - method: 'GET', - }); + const [deprecations, apmIndexDeprecations] = await Promise.all([ + (await callWithRequest(req, 'transport.request', { + path: '/_migration/deprecations', + method: 'GET', + })) as DeprecationAPIResponse, + getDeprecatedApmIndices(callWithRequest, req, apmIndices), + ]); const cluster = getClusterDeprecations(deprecations, isCloudEnabled); - const indices = getCombinedIndexInfos(deprecations); + const indices = getCombinedIndexInfos(deprecations, apmIndexDeprecations); const criticalWarnings = cluster.concat(indices).filter(d => d.level === 'critical'); @@ -47,17 +54,35 @@ export async function getUpgradeAssistantStatus( } // Reformats the index deprecations to an array of deprecation warnings extended with an index field. -const getCombinedIndexInfos = (deprecations: DeprecationAPIResponse) => - Object.keys(deprecations.index_settings).reduce( - (indexDeprecations, indexName) => { - return indexDeprecations.concat( - deprecations.index_settings[indexName].map( - d => ({ ...d, index: indexName } as EnrichedDeprecationInfo) - ) - ); - }, - [] as EnrichedDeprecationInfo[] - ); +const getCombinedIndexInfos = ( + deprecations: DeprecationAPIResponse, + apmIndexDeprecations: EnrichedDeprecationInfo[] +) => { + const apmIndices = apmIndexDeprecations.reduce((acc, dep) => acc.add(dep.index), new Set()); + + return Object.keys(deprecations.index_settings) + .reduce( + (indexDeprecations, indexName) => { + // prevent APM indices from showing up for general re-indexing + if (apmIndices.has(indexName)) { + return indexDeprecations; + } + + return indexDeprecations.concat( + deprecations.index_settings[indexName].map( + d => + ({ + ...d, + index: indexName, + reindex: /Index created before/.test(d.message), + } as EnrichedDeprecationInfo) + ) + ); + }, + [] as EnrichedDeprecationInfo[] + ) + .concat(apmIndexDeprecations); +}; const getClusterDeprecations = (deprecations: DeprecationAPIResponse, isCloudEnabled: boolean) => { const combined = deprecations.cluster_settings diff --git a/x-pack/plugins/upgrade_assistant/server/lib/reindexing/index_settings.ts b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/index_settings.ts index 8a89efe49173a..6681add4ec405 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/reindexing/index_settings.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/index_settings.ts @@ -10,6 +10,7 @@ import { PREV_MAJOR_VERSION, } from 'x-pack/plugins/upgrade_assistant/common/version'; import { ReindexWarning } from '../../../common/types'; +import { isLegacyApmIndex } from '../apm'; import { FlatSettings } from './types'; export interface ParsedIndexName { @@ -59,10 +60,16 @@ export const parseIndexName = (indexName: string): ParsedIndexName => { * Returns an array of warnings that should be displayed to user before reindexing begins. * @param flatSettings */ -export const getReindexWarnings = (flatSettings: FlatSettings): ReindexWarning[] => { - const warnings = [ - // No warnings yet for 7.0 -> 8.0 - ] as Array<[ReindexWarning, boolean]>; +export const getReindexWarnings = ( + flatSettings: FlatSettings, + apmIndexPatterns: string[] = [] +): ReindexWarning[] => { + const indexName = flatSettings.settings['index.provided_name']; + const apmReindexWarning = isLegacyApmIndex(indexName, apmIndexPatterns, flatSettings.mappings); + + const warnings = [[ReindexWarning.apmReindex, apmReindexWarning]] as Array< + [ReindexWarning, boolean] + >; return warnings.filter(([_, applies]) => applies).map(([warning, _]) => warning); }; diff --git a/x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.test.ts b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.test.ts index 8371eacd6b02f..6480e9bfc793b 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.test.ts @@ -16,6 +16,8 @@ import { ReindexStatus, ReindexStep, } from '../../../common/types'; +import { apmReindexScript } from '../apm'; +import apmMappings from '../apm/mapping.json'; import { ReindexService, reindexServiceFactory } from './reindex_service'; describe('reindexService', () => { @@ -58,7 +60,7 @@ describe('reindexService', () => { }, })), }; - service = reindexServiceFactory(callCluster, xpackInfo as any, actions); + service = reindexServiceFactory(callCluster, xpackInfo as any, actions, ['apm-*']); }); describe('hasRequiredPrivileges', () => { @@ -179,14 +181,17 @@ describe('reindexService', () => { describe('detectReindexWarnings', () => { it('fetches reindex warnings from flat settings', async () => { + const indexName = 'myIndex'; actions.getFlatSettings.mockResolvedValueOnce({ - settings: {}, + settings: { + 'index.provided_name': indexName, + }, mappings: { properties: { https: { type: 'boolean' } }, }, }); - const reindexWarnings = await service.detectReindexWarnings('myIndex'); + const reindexWarnings = await service.detectReindexWarnings(indexName); expect(reindexWarnings).toEqual([]); }); @@ -727,6 +732,43 @@ describe('reindexService', () => { }); }); + it('used APM mapping for legacy APM index', async () => { + const indexName = 'apm-1'; + const newIndexName = 'apm-1-reindexed'; + + actions.getFlatSettings.mockResolvedValueOnce({ + settings: { + 'index.number_of_replicas': 5, + }, + mappings: { + _meta: { + version: '6.7.0', + }, + }, + }); + + callCluster.mockResolvedValueOnce({ acknowledged: true }); // indices.create + await service.processNextStep({ + id: '1', + attributes: { + ...defaultAttributes, + indexName, + newIndexName, + lastCompletedStep: ReindexStep.readonly, + }, + } as ReindexSavedObject); + + expect(callCluster).toHaveBeenCalledWith('indices.create', { + index: newIndexName, + body: { + mappings: apmMappings, + settings: { + 'index.number_of_replicas': 5, + }, + }, + }); + }); + it('fails if create index is not acknowledged', async () => { callCluster .mockResolvedValueOnce({ myIndex: settingsMappings }) @@ -761,6 +803,13 @@ describe('reindexService', () => { attributes: { ...defaultAttributes, lastCompletedStep: ReindexStep.newIndexCreated }, } as ReindexSavedObject; + beforeEach(() => { + actions.getFlatSettings.mockResolvedValueOnce({ + settings: {}, + mappings: {}, + }); + }); + it('starts reindex, saves taskId, and updates lastCompletedStep', async () => { callCluster.mockResolvedValueOnce({ task: 'xyz' }); // reindex const updatedOp = await service.processNextStep(reindexOp); @@ -777,6 +826,43 @@ describe('reindexService', () => { }); }); + it('uses APM script for legacy APM index', async () => { + const indexName = 'apm-1'; + const newIndexName = 'apm-1-reindexed'; + + callCluster.mockResolvedValueOnce({ task: 'xyz' }); // reindex + actions.getFlatSettings.mockResolvedValueOnce({ + settings: {}, + mappings: { + _meta: { + version: '6.7.0', + }, + }, + }); + + await service.processNextStep({ + id: '1', + attributes: { + ...defaultAttributes, + indexName, + newIndexName, + lastCompletedStep: ReindexStep.newIndexCreated, + }, + } as ReindexSavedObject); + expect(callCluster).toHaveBeenLastCalledWith('reindex', { + refresh: true, + waitForCompletion: false, + body: { + source: { index: indexName }, + dest: { index: newIndexName }, + script: { + lang: 'painless', + source: apmReindexScript, + }, + }, + }); + }); + it('fails if starting reindex fails', async () => { callCluster.mockRejectedValueOnce(new Error('blah!')).mockResolvedValueOnce({}); const updatedOp = await service.processNextStep(reindexOp); diff --git a/x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.ts b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.ts index 1e657c9225b47..bd28d43da146e 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.ts @@ -15,6 +15,8 @@ import { ReindexStep, ReindexWarning, } from '../../../common/types'; +import { apmReindexScript, isLegacyApmIndex } from '../apm'; +import apmMappings from '../apm/mapping.json'; import { getReindexWarnings, parseIndexName, transformFlatSettings } from './index_settings'; import { ReindexActions } from './reindex_actions'; @@ -91,7 +93,8 @@ export interface ReindexService { export const reindexServiceFactory = ( callCluster: CallCluster, xpackInfo: XPackInfo, - actions: ReindexActions + actions: ReindexActions, + apmIndexPatterns: string[] = [] ): ReindexService => { // ------ Utility functions @@ -279,11 +282,13 @@ export const reindexServiceFactory = ( } const { settings, mappings } = transformFlatSettings(flatSettings); + const legacyApmIndex = isLegacyApmIndex(indexName, apmIndexPatterns, flatSettings.mappings); + const createIndex = await callCluster('indices.create', { index: newIndexName, body: { settings, - mappings, + mappings: legacyApmIndex ? apmMappings : mappings, }, }); @@ -302,13 +307,29 @@ export const reindexServiceFactory = ( */ const startReindexing = async (reindexOp: ReindexSavedObject) => { const { indexName } = reindexOp.attributes; + + const reindexBody = { + source: { index: indexName }, + dest: { index: reindexOp.attributes.newIndexName }, + } as any; + + const flatSettings = await actions.getFlatSettings(indexName); + if (!flatSettings) { + throw Boom.notFound(`Index ${indexName} does not exist.`); + } + + const legacyApmIndex = isLegacyApmIndex(indexName, apmIndexPatterns, flatSettings.mappings); + if (legacyApmIndex) { + reindexBody.script = { + lang: 'painless', + source: apmReindexScript, + }; + } + const startReindex = (await callCluster('reindex', { refresh: true, waitForCompletion: false, - body: { - source: { index: indexName }, - dest: { index: reindexOp.attributes.newIndexName }, - }, + body: reindexBody, })) as any; return actions.updateReindexOp(reindexOp, { @@ -486,7 +507,7 @@ export const reindexServiceFactory = ( if (!flatSettings) { return null; } else { - return getReindexWarnings(flatSettings); + return getReindexWarnings(flatSettings, apmIndexPatterns); } }, diff --git a/x-pack/plugins/upgrade_assistant/server/lib/reindexing/types.ts b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/types.ts index 72243de7c013c..077400e7567fe 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/reindexing/types.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/types.ts @@ -13,11 +13,16 @@ export interface MappingProperties { [key: string]: Mapping; } +interface MetaProperties { + [key: string]: string; +} + export interface FlatSettings { settings: { [key: string]: string; }; mappings: { properties?: MappingProperties; + _meta?: MetaProperties; }; } diff --git a/x-pack/plugins/upgrade_assistant/server/lib/reindexing/worker.ts b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/worker.ts index 202646f121ce5..d2b001a77ed0d 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/reindexing/worker.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/worker.ts @@ -48,16 +48,20 @@ export class ReindexWorker { private callWithRequest: CallClusterWithRequest, private callWithInternalUser: CallCluster, private xpackInfo: XPackInfo, - private readonly log: Server['log'] + private readonly log: Server['log'], + private apmIndexPatterns: string[] ) { if (ReindexWorker.workerSingleton) { throw new Error(`More than one ReindexWorker cannot be created.`); } + this.apmIndexPatterns = apmIndexPatterns; + this.reindexService = reindexServiceFactory( this.callWithInternalUser, this.xpackInfo, - reindexActionsFactory(this.client, this.callWithInternalUser) + reindexActionsFactory(this.client, this.callWithInternalUser), + apmIndexPatterns ); ReindexWorker.workerSingleton = this; @@ -161,7 +165,12 @@ export class ReindexWorker { const fakeRequest = { headers: credential } as Request; const callCluster = this.callWithRequest.bind(null, fakeRequest) as CallCluster; const actions = reindexActionsFactory(this.client, callCluster); - const service = reindexServiceFactory(callCluster, this.xpackInfo, actions); + const service = reindexServiceFactory( + callCluster, + this.xpackInfo, + actions, + this.apmIndexPatterns + ); reindexOp = await swallowExceptions(service.processNextStep, this.log)(reindexOp); // Update credential store with most recent state. diff --git a/x-pack/plugins/upgrade_assistant/server/routes/cluster_checkup.test.ts b/x-pack/plugins/upgrade_assistant/server/routes/cluster_checkup.test.ts index 32261cba70b99..d8088d873147d 100644 --- a/x-pack/plugins/upgrade_assistant/server/routes/cluster_checkup.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/routes/cluster_checkup.test.ts @@ -23,6 +23,9 @@ describe('cluster checkup API', () => { elasticsearch: { getCluster: () => ({ callWithRequest: jest.fn() } as any), } as any, + apm_oss: { + indexPatterns: ['apm-*'], + }, cloud: { isCloudEnabled: false, }, diff --git a/x-pack/plugins/upgrade_assistant/server/routes/cluster_checkup.ts b/x-pack/plugins/upgrade_assistant/server/routes/cluster_checkup.ts index 9a9a50ff9b78e..2ea0c6bba9106 100644 --- a/x-pack/plugins/upgrade_assistant/server/routes/cluster_checkup.ts +++ b/x-pack/plugins/upgrade_assistant/server/routes/cluster_checkup.ts @@ -18,7 +18,14 @@ export function registerClusterCheckupRoutes(server: Legacy.Server) { method: 'GET', async handler(request) { try { - return await getUpgradeAssistantStatus(callWithRequest, request, isCloudEnabled); + const apmIndexPatterns = server.plugins.apm_oss.indexPatterns; + + return await getUpgradeAssistantStatus( + callWithRequest, + request, + isCloudEnabled, + apmIndexPatterns + ); } catch (e) { if (e.status === 403) { return Boom.forbidden(e.message); diff --git a/x-pack/plugins/upgrade_assistant/server/routes/reindex_indices.test.ts b/x-pack/plugins/upgrade_assistant/server/routes/reindex_indices.test.ts index 7802b5b28bf8d..63e8f83e20ff6 100644 --- a/x-pack/plugins/upgrade_assistant/server/routes/reindex_indices.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/routes/reindex_indices.test.ts @@ -42,6 +42,9 @@ describe('reindex API', () => { xpack_main: { info: {}, }, + apm_oss: { + indexPatterns: ['apm-*'], + }, } as any; server.config = () => ({ get: () => '' } as any); server.decorate('request', 'getSavedObjectsClient', () => jest.fn()); diff --git a/x-pack/plugins/upgrade_assistant/server/routes/reindex_indices.ts b/x-pack/plugins/upgrade_assistant/server/routes/reindex_indices.ts index 14041bdf00e3c..a4d53aa59f096 100644 --- a/x-pack/plugins/upgrade_assistant/server/routes/reindex_indices.ts +++ b/x-pack/plugins/upgrade_assistant/server/routes/reindex_indices.ts @@ -40,7 +40,8 @@ export function registerReindexWorker(server: Server, credentialStore: Credentia callWithRequest, callWithInternalUser, xpackInfo, - log + log, + server.plugins.apm_oss.indexPatterns ); // Wait for ES connection before starting the polling loop. @@ -59,6 +60,7 @@ export function registerReindexIndicesRoutes( ) { const { callWithRequest } = server.plugins.elasticsearch.getCluster('admin'); const xpackInfo = server.plugins.xpack_main.info; + const apmIndexPatterns = server.plugins.apm_oss.indexPatterns; const BASE_PATH = '/api/upgrade_assistant/reindex'; // Start reindex for an index @@ -70,7 +72,12 @@ export function registerReindexIndicesRoutes( const { indexName } = request.params; const callCluster = callWithRequest.bind(null, request) as CallCluster; const reindexActions = reindexActionsFactory(client, callCluster); - const reindexService = reindexServiceFactory(callCluster, xpackInfo, reindexActions); + const reindexService = reindexServiceFactory( + callCluster, + xpackInfo, + reindexActions, + apmIndexPatterns + ); try { if (!(await reindexService.hasRequiredPrivileges(indexName))) { @@ -111,7 +118,12 @@ export function registerReindexIndicesRoutes( const { indexName } = request.params; const callCluster = callWithRequest.bind(null, request) as CallCluster; const reindexActions = reindexActionsFactory(client, callCluster); - const reindexService = reindexServiceFactory(callCluster, xpackInfo, reindexActions); + const reindexService = reindexServiceFactory( + callCluster, + xpackInfo, + reindexActions, + apmIndexPatterns + ); try { const hasRequiredPrivileges = await reindexService.hasRequiredPrivileges(indexName);