Resets Upgrades Assistant in preperation for 9.0 (#30334)
**Removes APM reindexing**: Since indices created in 6.x will be required to re-index in 7.x there is no longer a need to support migrating APM indices to the ECS format since ECS is shipped starting in 7.0 Signed-off-by: Tyler Smalley <tyler.smalley@elastic.co>
This commit is contained in:
parent
afdb0509e4
commit
f741137c99
|
@ -54,6 +54,8 @@ export enum ReindexWarning {
|
|||
|
||||
// 7.0 -> 8.0 warnings
|
||||
apmReindex,
|
||||
|
||||
// 8.0 -> 9.0 warnings
|
||||
}
|
||||
|
||||
export enum IndexGroup {
|
||||
|
|
|
@ -15,7 +15,7 @@ exports[`CheckupTab render with deprecations 1`] = `
|
|||
id="xpack.upgradeAssistant.checkupTab.tabDetail"
|
||||
values={
|
||||
Object {
|
||||
"nextEsVersion": "8.x",
|
||||
"nextEsVersion": "9.x",
|
||||
"strongCheckupLabel": <strong>
|
||||
index
|
||||
</strong>,
|
||||
|
@ -311,7 +311,7 @@ exports[`CheckupTab render with error 1`] = `
|
|||
id="xpack.upgradeAssistant.checkupTab.tabDetail"
|
||||
values={
|
||||
Object {
|
||||
"nextEsVersion": "8.x",
|
||||
"nextEsVersion": "9.x",
|
||||
"strongCheckupLabel": <strong>
|
||||
index
|
||||
</strong>,
|
||||
|
@ -388,7 +388,7 @@ exports[`CheckupTab render without deprecations 1`] = `
|
|||
id="xpack.upgradeAssistant.checkupTab.tabDetail"
|
||||
values={
|
||||
Object {
|
||||
"nextEsVersion": "8.x",
|
||||
"nextEsVersion": "9.x",
|
||||
"strongCheckupLabel": <strong>
|
||||
index
|
||||
</strong>,
|
||||
|
|
|
@ -1,117 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { 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);
|
||||
});
|
||||
});
|
|
@ -1,362 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { 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<EnrichedDeprecationInfo[]> {
|
||||
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];
|
||||
}
|
||||
}
|
||||
`;
|
File diff suppressed because it is too large
Load diff
|
@ -28,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',
|
||||
|
@ -36,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();
|
||||
});
|
||||
|
||||
|
@ -49,7 +49,7 @@ describe('getUpgradeAssistantStatus', () => {
|
|||
};
|
||||
|
||||
await expect(
|
||||
getUpgradeAssistantStatus(callWithRequest, {} as any, false, [])
|
||||
getUpgradeAssistantStatus(callWithRequest, {} as any, false)
|
||||
).resolves.toHaveProperty('readyForUpgrade', false);
|
||||
});
|
||||
|
||||
|
@ -62,7 +62,7 @@ describe('getUpgradeAssistantStatus', () => {
|
|||
};
|
||||
|
||||
await expect(
|
||||
getUpgradeAssistantStatus(callWithRequest, {} as any, false, [])
|
||||
getUpgradeAssistantStatus(callWithRequest, {} as any, false)
|
||||
).resolves.toHaveProperty('readyForUpgrade', true);
|
||||
});
|
||||
|
||||
|
@ -80,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', []);
|
||||
|
|
|
@ -13,8 +13,6 @@ import {
|
|||
DeprecationInfo,
|
||||
} from 'src/legacy/core_plugins/elasticsearch';
|
||||
|
||||
import { getDeprecatedApmIndices } from './apm';
|
||||
|
||||
export interface EnrichedDeprecationInfo extends DeprecationInfo {
|
||||
index?: string;
|
||||
node?: string;
|
||||
|
@ -30,19 +28,15 @@ export interface UpgradeAssistantStatus {
|
|||
export async function getUpgradeAssistantStatus(
|
||||
callWithRequest: CallClusterWithRequest,
|
||||
req: Request,
|
||||
isCloudEnabled: boolean,
|
||||
apmIndices: string[]
|
||||
isCloudEnabled: boolean
|
||||
): Promise<UpgradeAssistantStatus> {
|
||||
const [deprecations, apmIndexDeprecations] = await Promise.all([
|
||||
(await callWithRequest(req, 'transport.request', {
|
||||
path: '/_migration/deprecations',
|
||||
method: 'GET',
|
||||
})) as DeprecationAPIResponse,
|
||||
getDeprecatedApmIndices(callWithRequest, req, apmIndices),
|
||||
]);
|
||||
const deprecations = await callWithRequest(req, 'transport.request', {
|
||||
path: '/_migration/deprecations',
|
||||
method: 'GET',
|
||||
});
|
||||
|
||||
const cluster = getClusterDeprecations(deprecations, isCloudEnabled);
|
||||
const indices = getCombinedIndexInfos(deprecations, apmIndexDeprecations);
|
||||
const indices = getCombinedIndexInfos(deprecations);
|
||||
|
||||
const criticalWarnings = cluster.concat(indices).filter(d => d.level === 'critical');
|
||||
|
||||
|
@ -54,35 +48,22 @@ export async function getUpgradeAssistantStatus(
|
|||
}
|
||||
|
||||
// Reformats the index deprecations to an array of deprecation warnings extended with an index field.
|
||||
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 getCombinedIndexInfos = (deprecations: DeprecationAPIResponse) =>
|
||||
Object.keys(deprecations.index_settings).reduce(
|
||||
(indexDeprecations, indexName) => {
|
||||
return indexDeprecations.concat(
|
||||
deprecations.index_settings[indexName].map(
|
||||
d =>
|
||||
({
|
||||
...d,
|
||||
index: indexName,
|
||||
reindex: /Index created before/.test(d.message),
|
||||
} as EnrichedDeprecationInfo)
|
||||
)
|
||||
);
|
||||
},
|
||||
[] as EnrichedDeprecationInfo[]
|
||||
);
|
||||
|
||||
const getClusterDeprecations = (deprecations: DeprecationAPIResponse, isCloudEnabled: boolean) => {
|
||||
const combined = deprecations.cluster_settings
|
||||
|
|
|
@ -10,7 +10,6 @@ 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 {
|
||||
|
@ -60,16 +59,10 @@ 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,
|
||||
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]
|
||||
>;
|
||||
export const getReindexWarnings = (flatSettings: FlatSettings): ReindexWarning[] => {
|
||||
const warnings = [
|
||||
// No warnings yet for 8.0 -> 9.0
|
||||
] as Array<[ReindexWarning, boolean]>;
|
||||
|
||||
return warnings.filter(([_, applies]) => applies).map(([warning, _]) => warning);
|
||||
};
|
||||
|
|
|
@ -16,8 +16,6 @@ import {
|
|||
ReindexStatus,
|
||||
ReindexStep,
|
||||
} from '../../../common/types';
|
||||
import { apmReindexScript } from '../apm';
|
||||
import apmMappings from '../apm/mapping.json';
|
||||
import { ReindexService, reindexServiceFactory } from './reindex_service';
|
||||
|
||||
describe('reindexService', () => {
|
||||
|
@ -60,7 +58,7 @@ describe('reindexService', () => {
|
|||
},
|
||||
})),
|
||||
};
|
||||
service = reindexServiceFactory(callCluster, xpackInfo as any, actions, ['apm-*']);
|
||||
service = reindexServiceFactory(callCluster, xpackInfo as any, actions);
|
||||
});
|
||||
|
||||
describe('hasRequiredPrivileges', () => {
|
||||
|
@ -732,43 +730,6 @@ 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 })
|
||||
|
@ -826,43 +787,6 @@ 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);
|
||||
|
|
|
@ -15,8 +15,6 @@ 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';
|
||||
|
||||
|
@ -93,8 +91,7 @@ export interface ReindexService {
|
|||
export const reindexServiceFactory = (
|
||||
callCluster: CallCluster,
|
||||
xpackInfo: XPackInfo,
|
||||
actions: ReindexActions,
|
||||
apmIndexPatterns: string[] = []
|
||||
actions: ReindexActions
|
||||
): ReindexService => {
|
||||
// ------ Utility functions
|
||||
|
||||
|
@ -282,13 +279,12 @@ 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: legacyApmIndex ? apmMappings : mappings,
|
||||
mappings,
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -308,28 +304,13 @@ 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: reindexBody,
|
||||
body: {
|
||||
source: { index: indexName },
|
||||
dest: { index: reindexOp.attributes.newIndexName },
|
||||
},
|
||||
})) as any;
|
||||
|
||||
return actions.updateReindexOp(reindexOp, {
|
||||
|
@ -507,7 +488,7 @@ export const reindexServiceFactory = (
|
|||
if (!flatSettings) {
|
||||
return null;
|
||||
} else {
|
||||
return getReindexWarnings(flatSettings, apmIndexPatterns);
|
||||
return getReindexWarnings(flatSettings);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -48,20 +48,16 @@ export class ReindexWorker {
|
|||
private callWithRequest: CallClusterWithRequest,
|
||||
private callWithInternalUser: CallCluster,
|
||||
private xpackInfo: XPackInfo,
|
||||
private readonly log: Server['log'],
|
||||
private apmIndexPatterns: string[]
|
||||
private readonly log: Server['log']
|
||||
) {
|
||||
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),
|
||||
apmIndexPatterns
|
||||
reindexActionsFactory(this.client, this.callWithInternalUser)
|
||||
);
|
||||
|
||||
ReindexWorker.workerSingleton = this;
|
||||
|
@ -165,12 +161,7 @@ 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,
|
||||
this.apmIndexPatterns
|
||||
);
|
||||
const service = reindexServiceFactory(callCluster, this.xpackInfo, actions);
|
||||
reindexOp = await swallowExceptions(service.processNextStep, this.log)(reindexOp);
|
||||
|
||||
// Update credential store with most recent state.
|
||||
|
|
|
@ -23,9 +23,6 @@ describe('cluster checkup API', () => {
|
|||
elasticsearch: {
|
||||
getCluster: () => ({ callWithRequest: jest.fn() } as any),
|
||||
} as any,
|
||||
apm_oss: {
|
||||
indexPatterns: ['apm-*'],
|
||||
},
|
||||
cloud: {
|
||||
isCloudEnabled: false,
|
||||
},
|
||||
|
|
|
@ -18,14 +18,7 @@ export function registerClusterCheckupRoutes(server: Legacy.Server) {
|
|||
method: 'GET',
|
||||
async handler(request) {
|
||||
try {
|
||||
const apmIndexPatterns = server.plugins.apm_oss.indexPatterns;
|
||||
|
||||
return await getUpgradeAssistantStatus(
|
||||
callWithRequest,
|
||||
request,
|
||||
isCloudEnabled,
|
||||
apmIndexPatterns
|
||||
);
|
||||
return await getUpgradeAssistantStatus(callWithRequest, request, isCloudEnabled);
|
||||
} catch (e) {
|
||||
if (e.status === 403) {
|
||||
return Boom.forbidden(e.message);
|
||||
|
|
|
@ -42,9 +42,6 @@ describe('reindex API', () => {
|
|||
xpack_main: {
|
||||
info: {},
|
||||
},
|
||||
apm_oss: {
|
||||
indexPatterns: ['apm-*'],
|
||||
},
|
||||
} as any;
|
||||
server.config = () => ({ get: () => '' } as any);
|
||||
server.decorate('request', 'getSavedObjectsClient', () => jest.fn());
|
||||
|
|
|
@ -40,8 +40,7 @@ export function registerReindexWorker(server: Server, credentialStore: Credentia
|
|||
callWithRequest,
|
||||
callWithInternalUser,
|
||||
xpackInfo,
|
||||
log,
|
||||
server.plugins.apm_oss.indexPatterns
|
||||
log
|
||||
);
|
||||
|
||||
// Wait for ES connection before starting the polling loop.
|
||||
|
@ -60,7 +59,6 @@ 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
|
||||
|
@ -72,12 +70,7 @@ 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,
|
||||
apmIndexPatterns
|
||||
);
|
||||
const reindexService = reindexServiceFactory(callCluster, xpackInfo, reindexActions);
|
||||
|
||||
try {
|
||||
if (!(await reindexService.hasRequiredPrivileges(indexName))) {
|
||||
|
@ -118,12 +111,7 @@ 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,
|
||||
apmIndexPatterns
|
||||
);
|
||||
const reindexService = reindexServiceFactory(callCluster, xpackInfo, reindexActions);
|
||||
|
||||
try {
|
||||
const hasRequiredPrivileges = await reindexService.hasRequiredPrivileges(indexName);
|
||||
|
|
Loading…
Reference in a new issue