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);