kibana/test/api_integration/apis/saved_objects/migrations.ts
Mikhail Shustov 100394cfb6
[7.x] Update @elastic/elasticsearch to 8.0.0-canary13 (#98266) (#101595)
* Update @elastic/elasticsearch to 8.0.0-canary13 (#98266)

* bump @elastic/elasticsearch to canary.7

* address errors in core

* address errors in data plugin

* address errors in Alerting team plugins

* remove outdated messages in Lens

* remove unnecessary comments in ML

* address errors in Observability plugin

* address errors in reporting plugin

* address errors in Rule registry plugin

* fix errors in Security plugins

* fix errors in ES-UI plugin

* remove unnecessary union.

* update core tests

* fix kbn-es-archiver

* update to canary 8

* bump to v9

* use new typings

* fix new errors in core

* fix errors in core typeings

* fix type errors in data plugin

* fix type errors in telemetray plugin

* fix data plugin tests

* fix search examples type error

* fix errors in discover plugin

* fix errors in index_pattern_management

* fix type errors in vis_type_*

* fix errors in typings/elasticsearch

* fix type errors in actions plugin

* fix type errors in alerting and apm plugins

* fix type errors in canvas and cases

* fix errors in event_log

* fix type errors in ILM and ingest_pipelines

* fix errors in lens plugin

* fix errors in lists plugin

* fix errors in logstash

* fix errors in metrics_entities

* fix errors in o11y

* fix errors in watcher

* fix errors in uptime

* fix errors in upgrade_assistant

* fix errors in task_manager

* fix errors in stack_alerts

* fix errors in security_solution

* fix errors in rule_registry

* fix errors in snapshot_restore

* fix remaining errors

* fix search intergration tests

* adjust assetion

* bump version to canary.10

* adapt code to new naming schema

* use mapping types provided by the client library

* Revert "adjust assetion"

This reverts commit 19b8fe0464.

* fix so intergration tests

* fix http integration tests

* bump version to canary 11

* fix login test

* fix http integration test

* fix apm test

* update docs

* fixing some ml types

* fix new errors in data plugin

* fix new errors in alerting plugin

* fix new errors in lists plugin

* fix new errors in reporting

* fix or mute errors in rule_registry plugin

* more ML type fixes

* bump to canary 12

* fix errors after merge conflict

* additional ML fixes

* bump to canary 13

* fix errors in apm plugin

* fix errors in fleet plugin

* fix errors in infra plugin

* fix errors in monitoring plugin

* fix errors in osquery plugin

* fix errors in security solution plugins

* fix errors in transform plugin

* Update type imports for ES

* fix errors in x-pack plugins

* fix errors in tests

* update docs

* fix errors in x-pack/test

* update error description

* fix errors after master merge

* update comment in infra plugin

* fix new errors on xpack tests/

Co-authored-by: James Gowdy <jgowdy@elastic.co>
Co-authored-by: Dario Gieselaar <dario.gieselaar@elastic.co>
# Conflicts:
#	package.json
#	src/core/server/saved_objects/migrationsv2/integration_tests/migration.test.ts
#	test/common/services/saved_object_info.ts
#	x-pack/plugins/snapshot_restore/server/routes/api/repositories.ts
#	x-pack/plugins/snapshot_restore/server/routes/api/snapshots.ts
#	yarn.lock

* revert  @ts-expect-error changes in infra plugin

* update docs
2021-06-08 12:21:59 -04:00

762 lines
23 KiB
TypeScript

/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
/*
* Smokescreen tests for core migration logic
*/
import uuidv5 from 'uuid/v5';
import { set } from '@elastic/safer-lodash-set';
import _ from 'lodash';
import expect from '@kbn/expect';
import { ElasticsearchClient, SavedObjectsType } from 'src/core/server';
import {
DocumentMigrator,
IndexMigrator,
createMigrationEsClient,
} from '../../../../src/core/server/saved_objects/migrations/core';
import { SavedObjectsTypeMappingDefinitions } from '../../../../src/core/server/saved_objects/mappings';
import {
SavedObjectsSerializer,
SavedObjectTypeRegistry,
} from '../../../../src/core/server/saved_objects';
import { FtrProviderContext } from '../../ftr_provider_context';
const KIBANA_VERSION = '99.9.9';
const FOO_TYPE: SavedObjectsType = {
name: 'foo',
hidden: false,
namespaceType: 'single',
mappings: { properties: {} },
};
const BAR_TYPE: SavedObjectsType = {
name: 'bar',
hidden: false,
namespaceType: 'single',
mappings: { properties: {} },
};
const BAZ_TYPE: SavedObjectsType = {
name: 'baz',
hidden: false,
namespaceType: 'single',
mappings: { properties: {} },
};
const FLEET_AGENT_EVENT_TYPE: SavedObjectsType = {
name: 'fleet-agent-event',
hidden: false,
namespaceType: 'single',
mappings: { properties: {} },
};
function getLogMock() {
return {
debug() {},
error() {},
fatal() {},
info() {},
log() {},
trace() {},
warn() {},
get: getLogMock,
};
}
export default ({ getService }: FtrProviderContext) => {
const esClient = getService('es');
const esDeleteAllIndices = getService('esDeleteAllIndices');
describe('Kibana index migration', () => {
before(() => esDeleteAllIndices('.migrate-*'));
it('Migrates an existing index that has never been migrated before', async () => {
const index = '.migration-a';
const originalDocs = [
{ id: 'foo:a', type: 'foo', foo: { name: 'Foo A' } },
{ id: 'foo:e', type: 'foo', foo: { name: 'Fooey' } },
{ id: 'bar:i', type: 'bar', bar: { nomnom: 33 } },
{ id: 'bar:o', type: 'bar', bar: { nomnom: 2 } },
{ id: 'baz:u', type: 'baz', baz: { title: 'Terrific!' } },
];
const mappingProperties = {
foo: { properties: { name: { type: 'text' } } },
bar: { properties: { mynum: { type: 'integer' } } },
} as const;
const savedObjectTypes: SavedObjectsType[] = [
{
...FOO_TYPE,
migrations: {
'1.0.0': (doc) => set(doc, 'attributes.name', doc.attributes.name.toUpperCase()),
},
},
{
...BAR_TYPE,
migrations: {
'1.0.0': (doc) => set(doc, 'attributes.nomnom', doc.attributes.nomnom + 1),
'1.3.0': (doc) => set(doc, 'attributes', { mynum: doc.attributes.nomnom }),
'1.9.0': (doc) => set(doc, 'attributes.mynum', doc.attributes.mynum * 2),
},
},
];
await createIndex({ esClient, index, esDeleteAllIndices });
await createDocs({ esClient, index, docs: originalDocs });
// Test that unrelated index templates are unaffected
await esClient.indices.putTemplate({
name: 'migration_test_a_template',
body: {
index_patterns: ['migration_test_a'],
mappings: {
dynamic: 'strict',
properties: { baz: { type: 'text' } },
},
},
});
// Test that obsolete index templates get removed
await esClient.indices.putTemplate({
name: 'migration_a_template',
body: {
index_patterns: [index],
mappings: {
dynamic: 'strict',
properties: { baz: { type: 'text' } },
},
},
});
const migrationATemplate = await esClient.indices.existsTemplate({
name: 'migration_a_template',
});
expect(migrationATemplate.body).to.be.ok();
const result = await migrateIndex({
esClient,
index,
savedObjectTypes,
mappingProperties,
obsoleteIndexTemplatePattern: 'migration_a*',
});
const migrationATemplateAfter = await esClient.indices.existsTemplate({
name: 'migration_a_template',
});
expect(migrationATemplateAfter.body).not.to.be.ok();
const migrationTestATemplateAfter = await esClient.indices.existsTemplate({
name: 'migration_test_a_template',
});
expect(migrationTestATemplateAfter.body).to.be.ok();
expect(_.omit(result, 'elapsedMs')).to.eql({
destIndex: '.migration-a_2',
sourceIndex: '.migration-a_1',
status: 'migrated',
});
// The docs in the original index are unchanged
expect(await fetchDocs(esClient, `${index}_1`)).to.eql(originalDocs.sort(sortByTypeAndId));
// The docs in the alias have been migrated
expect(await fetchDocs(esClient, index)).to.eql([
{
id: 'bar:i',
type: 'bar',
migrationVersion: { bar: '1.9.0' },
bar: { mynum: 68 },
references: [],
coreMigrationVersion: KIBANA_VERSION,
},
{
id: 'bar:o',
type: 'bar',
migrationVersion: { bar: '1.9.0' },
bar: { mynum: 6 },
references: [],
coreMigrationVersion: KIBANA_VERSION,
},
{
id: 'baz:u',
type: 'baz',
baz: { title: 'Terrific!' },
references: [],
coreMigrationVersion: KIBANA_VERSION,
},
{
id: 'foo:a',
type: 'foo',
migrationVersion: { foo: '1.0.0' },
foo: { name: 'FOO A' },
references: [],
coreMigrationVersion: KIBANA_VERSION,
},
{
id: 'foo:e',
type: 'foo',
migrationVersion: { foo: '1.0.0' },
foo: { name: 'FOOEY' },
references: [],
coreMigrationVersion: KIBANA_VERSION,
},
]);
});
it('migrates a previously migrated index, if migrations change', async () => {
const index = '.migration-b';
const originalDocs = [
{ id: 'foo:a', type: 'foo', foo: { name: 'Foo A' } },
{ id: 'foo:e', type: 'foo', foo: { name: 'Fooey' } },
{ id: 'bar:i', type: 'bar', bar: { nomnom: 33 } },
{ id: 'bar:o', type: 'bar', bar: { nomnom: 2 } },
];
const mappingProperties = {
foo: { properties: { name: { type: 'text' } } },
bar: { properties: { mynum: { type: 'integer' } } },
} as const;
let savedObjectTypes: SavedObjectsType[] = [
{
...FOO_TYPE,
migrations: {
'1.0.0': (doc) => set(doc, 'attributes.name', doc.attributes.name.toUpperCase()),
},
},
{
...BAR_TYPE,
migrations: {
'1.0.0': (doc) => set(doc, 'attributes.nomnom', doc.attributes.nomnom + 1),
'1.3.0': (doc) => set(doc, 'attributes', { mynum: doc.attributes.nomnom }),
'1.9.0': (doc) => set(doc, 'attributes.mynum', doc.attributes.mynum * 2),
},
},
];
await createIndex({ esClient, index, esDeleteAllIndices });
await createDocs({ esClient, index, docs: originalDocs });
await migrateIndex({ esClient, index, savedObjectTypes, mappingProperties });
// @ts-expect-error name doesn't exist on mynum type
mappingProperties.bar.properties.name = { type: 'keyword' };
savedObjectTypes = [
{
...FOO_TYPE,
migrations: {
'2.0.1': (doc) => set(doc, 'attributes.name', `${doc.attributes.name}v2`),
},
},
{
...BAR_TYPE,
migrations: {
'2.3.4': (doc) => set(doc, 'attributes.name', `NAME ${doc.id}`),
},
},
];
await migrateIndex({ esClient, index, savedObjectTypes, mappingProperties });
// The index for the initial migration has not been destroyed...
expect(await fetchDocs(esClient, `${index}_2`)).to.eql([
{
id: 'bar:i',
type: 'bar',
migrationVersion: { bar: '1.9.0' },
bar: { mynum: 68 },
references: [],
coreMigrationVersion: KIBANA_VERSION,
},
{
id: 'bar:o',
type: 'bar',
migrationVersion: { bar: '1.9.0' },
bar: { mynum: 6 },
references: [],
coreMigrationVersion: KIBANA_VERSION,
},
{
id: 'foo:a',
type: 'foo',
migrationVersion: { foo: '1.0.0' },
foo: { name: 'FOO A' },
references: [],
coreMigrationVersion: KIBANA_VERSION,
},
{
id: 'foo:e',
type: 'foo',
migrationVersion: { foo: '1.0.0' },
foo: { name: 'FOOEY' },
references: [],
coreMigrationVersion: KIBANA_VERSION,
},
]);
// The docs were migrated again...
expect(await fetchDocs(esClient, index)).to.eql([
{
id: 'bar:i',
type: 'bar',
migrationVersion: { bar: '2.3.4' },
bar: { mynum: 68, name: 'NAME i' },
references: [],
coreMigrationVersion: KIBANA_VERSION,
},
{
id: 'bar:o',
type: 'bar',
migrationVersion: { bar: '2.3.4' },
bar: { mynum: 6, name: 'NAME o' },
references: [],
coreMigrationVersion: KIBANA_VERSION,
},
{
id: 'foo:a',
type: 'foo',
migrationVersion: { foo: '2.0.1' },
foo: { name: 'FOO Av2' },
references: [],
coreMigrationVersion: KIBANA_VERSION,
},
{
id: 'foo:e',
type: 'foo',
migrationVersion: { foo: '2.0.1' },
foo: { name: 'FOOEYv2' },
references: [],
coreMigrationVersion: KIBANA_VERSION,
},
]);
});
it('drops fleet-agent-event saved object types when doing a migration', async () => {
const index = '.migration-b';
const originalDocs = [
{
id: 'fleet-agent-event:a',
type: 'fleet-agent-event',
'fleet-agent-event': { name: 'Foo A' },
},
{
id: 'fleet-agent-event:e',
type: 'fleet-agent-event',
'fleet-agent-event': { name: 'Fooey' },
},
{ id: 'bar:i', type: 'bar', bar: { nomnom: 33 } },
{ id: 'bar:o', type: 'bar', bar: { nomnom: 2 } },
];
const mappingProperties = {
'fleet-agent-event': { properties: { name: { type: 'text' } } },
bar: { properties: { mynum: { type: 'integer' } } },
} as const;
let savedObjectTypes: SavedObjectsType[] = [
FLEET_AGENT_EVENT_TYPE,
{
...BAR_TYPE,
migrations: {
'1.0.0': (doc) => set(doc, 'attributes.nomnom', doc.attributes.nomnom + 1),
'1.3.0': (doc) => set(doc, 'attributes', { mynum: doc.attributes.nomnom }),
'1.9.0': (doc) => set(doc, 'attributes.mynum', doc.attributes.mynum * 2),
},
},
];
await createIndex({ esClient, index, esDeleteAllIndices });
await createDocs({ esClient, index, docs: originalDocs });
await migrateIndex({ esClient, index, savedObjectTypes, mappingProperties });
// @ts-expect-error name doesn't exist on mynum type
mappingProperties.bar.properties.name = { type: 'keyword' };
savedObjectTypes = [
FLEET_AGENT_EVENT_TYPE,
{
...BAR_TYPE,
migrations: {
'2.3.4': (doc) => set(doc, 'attributes.name', `NAME ${doc.id}`),
},
},
];
await migrateIndex({ esClient, index, savedObjectTypes, mappingProperties });
// Assert that fleet-agent-events were dropped
expect(await fetchDocs(esClient, index)).to.eql([
{
id: 'bar:i',
type: 'bar',
migrationVersion: { bar: '2.3.4' },
bar: { mynum: 68, name: 'NAME i' },
references: [],
coreMigrationVersion: KIBANA_VERSION,
},
{
id: 'bar:o',
type: 'bar',
migrationVersion: { bar: '2.3.4' },
bar: { mynum: 6, name: 'NAME o' },
references: [],
coreMigrationVersion: KIBANA_VERSION,
},
]);
});
it('Coordinates migrations across the Kibana cluster', async () => {
const index = '.migration-c';
const originalDocs = [{ id: 'foo:lotr', type: 'foo', foo: { name: 'Lord of the Rings' } }];
const mappingProperties = {
foo: { properties: { name: { type: 'text' } } },
} as const;
const savedObjectTypes: SavedObjectsType[] = [
{
...FOO_TYPE,
migrations: {
'1.0.0': (doc) => set(doc, 'attributes.name', 'LOTR'),
},
},
];
await createIndex({ esClient, index, esDeleteAllIndices });
await createDocs({ esClient, index, docs: originalDocs });
const result = await Promise.all([
migrateIndex({ esClient, index, savedObjectTypes, mappingProperties }),
migrateIndex({ esClient, index, savedObjectTypes, mappingProperties }),
]);
// The polling instance and the migrating instance should both
// return a similar migration result.
expect(
result
// @ts-expect-error destIndex exists only on MigrationResult status: 'migrated';
.map(({ status, destIndex }) => ({ status, destIndex }))
.sort(({ destIndex: a }, { destIndex: b }) =>
// sort by destIndex in ascending order, keeping falsy values at the end
(a && !b) || a < b ? -1 : (!a && b) || a > b ? 1 : 0
)
).to.eql([
{ status: 'migrated', destIndex: '.migration-c_2' },
{ status: 'skipped', destIndex: undefined },
]);
const { body } = await esClient.cat.indices({ index: '.migration-c*', format: 'json' });
// It only created the original and the dest
expect(_.map(body, 'index').sort()).to.eql(['.migration-c_1', '.migration-c_2']);
// The docs in the original index are unchanged
expect(await fetchDocs(esClient, `${index}_1`)).to.eql([
{ id: 'foo:lotr', type: 'foo', foo: { name: 'Lord of the Rings' } },
]);
// The docs in the alias have been migrated
expect(await fetchDocs(esClient, index)).to.eql([
{
id: 'foo:lotr',
type: 'foo',
migrationVersion: { foo: '1.0.0' },
foo: { name: 'LOTR' },
references: [],
coreMigrationVersion: KIBANA_VERSION,
},
]);
});
it('Correctly applies reference transforms and conversion transforms', async () => {
const index = '.migration-d';
const originalDocs = [
{ id: 'foo:1', type: 'foo', foo: { name: 'Foo 1 default' } },
{ id: 'spacex:foo:1', type: 'foo', foo: { name: 'Foo 1 spacex' }, namespace: 'spacex' },
{
id: 'bar:1',
type: 'bar',
bar: { nomnom: 1 },
references: [{ type: 'foo', id: '1', name: 'Foo 1 default' }],
},
{
id: 'spacex:bar:1',
type: 'bar',
bar: { nomnom: 2 },
references: [{ type: 'foo', id: '1', name: 'Foo 1 spacex' }],
namespace: 'spacex',
},
{
id: 'baz:1',
type: 'baz',
baz: { title: 'Baz 1 default' },
references: [{ type: 'bar', id: '1', name: 'Bar 1 default' }],
},
{
id: 'spacex:baz:1',
type: 'baz',
baz: { title: 'Baz 1 spacex' },
references: [{ type: 'bar', id: '1', name: 'Bar 1 spacex' }],
namespace: 'spacex',
},
];
const mappingProperties = {
foo: { properties: { name: { type: 'text' } } },
bar: { properties: { nomnom: { type: 'integer' } } },
baz: { properties: { title: { type: 'keyword' } } },
} as const;
const savedObjectTypes: SavedObjectsType[] = [
{
...FOO_TYPE,
namespaceType: 'multiple',
convertToMultiNamespaceTypeVersion: '1.0.0',
},
{
...BAR_TYPE,
namespaceType: 'multiple-isolated',
convertToMultiNamespaceTypeVersion: '2.0.0',
},
BAZ_TYPE, // must be registered for reference transforms to be applied to objects of this type
];
await createIndex({ esClient, index, esDeleteAllIndices });
await createDocs({ esClient, index, docs: originalDocs });
await migrateIndex({
esClient,
index,
savedObjectTypes,
mappingProperties,
obsoleteIndexTemplatePattern: 'migration_a*',
});
// The docs in the original index are unchanged
expect(await fetchDocs(esClient, `${index}_1`)).to.eql(originalDocs.sort(sortByTypeAndId));
// The docs in the alias have been migrated
const migratedDocs = await fetchDocs(esClient, index);
// each newly converted multi-namespace object in a non-default space has its ID deterministically regenerated, and a legacy-url-alias
// object is created which links the old ID to the new ID
const newFooId = uuidv5('spacex:foo:1', uuidv5.DNS);
const newBarId = uuidv5('spacex:bar:1', uuidv5.DNS);
expect(migratedDocs).to.eql(
[
{
id: 'foo:1',
type: 'foo',
foo: { name: 'Foo 1 default' },
references: [],
namespaces: ['default'],
migrationVersion: { foo: '1.0.0' },
coreMigrationVersion: KIBANA_VERSION,
},
{
id: `foo:${newFooId}`,
type: 'foo',
foo: { name: 'Foo 1 spacex' },
references: [],
namespaces: ['spacex'],
originId: '1',
migrationVersion: { foo: '1.0.0' },
coreMigrationVersion: KIBANA_VERSION,
},
{
// new object
id: 'legacy-url-alias:spacex:foo:1',
type: 'legacy-url-alias',
'legacy-url-alias': {
sourceId: '1',
targetId: newFooId,
targetNamespace: 'spacex',
targetType: 'foo',
},
migrationVersion: {},
references: [],
coreMigrationVersion: KIBANA_VERSION,
},
{
id: 'bar:1',
type: 'bar',
bar: { nomnom: 1 },
references: [{ type: 'foo', id: '1', name: 'Foo 1 default' }],
namespaces: ['default'],
migrationVersion: { bar: '2.0.0' },
coreMigrationVersion: KIBANA_VERSION,
},
{
id: `bar:${newBarId}`,
type: 'bar',
bar: { nomnom: 2 },
references: [{ type: 'foo', id: newFooId, name: 'Foo 1 spacex' }],
namespaces: ['spacex'],
originId: '1',
migrationVersion: { bar: '2.0.0' },
coreMigrationVersion: KIBANA_VERSION,
},
{
// new object
id: 'legacy-url-alias:spacex:bar:1',
type: 'legacy-url-alias',
'legacy-url-alias': {
sourceId: '1',
targetId: newBarId,
targetNamespace: 'spacex',
targetType: 'bar',
},
migrationVersion: {},
references: [],
coreMigrationVersion: KIBANA_VERSION,
},
{
id: 'baz:1',
type: 'baz',
baz: { title: 'Baz 1 default' },
references: [{ type: 'bar', id: '1', name: 'Bar 1 default' }],
coreMigrationVersion: KIBANA_VERSION,
},
{
id: 'spacex:baz:1',
type: 'baz',
baz: { title: 'Baz 1 spacex' },
references: [{ type: 'bar', id: newBarId, name: 'Bar 1 spacex' }],
namespace: 'spacex',
coreMigrationVersion: KIBANA_VERSION,
},
].sort(sortByTypeAndId)
);
});
});
};
async function createIndex({
esClient,
index,
esDeleteAllIndices,
}: {
esClient: ElasticsearchClient;
index: string;
esDeleteAllIndices: (pattern: string) => Promise<void>;
}) {
await esDeleteAllIndices(`${index}*`);
const properties = {
type: { type: 'keyword' },
foo: { properties: { name: { type: 'keyword' } } },
bar: { properties: { nomnom: { type: 'integer' } } },
baz: { properties: { title: { type: 'keyword' } } },
'legacy-url-alias': {
properties: {
targetNamespace: { type: 'text' },
targetType: { type: 'text' },
targetId: { type: 'text' },
lastResolved: { type: 'date' },
resolveCounter: { type: 'integer' },
disabled: { type: 'boolean' },
},
},
namespace: { type: 'keyword' },
namespaces: { type: 'keyword' },
originId: { type: 'keyword' },
references: {
type: 'nested',
properties: {
name: { type: 'keyword' },
type: { type: 'keyword' },
id: { type: 'keyword' },
},
},
coreMigrationVersion: {
type: 'keyword',
},
} as const;
await esClient.indices.create({
index,
body: { mappings: { dynamic: 'strict', properties } },
});
}
async function createDocs({
esClient,
index,
docs,
}: {
esClient: ElasticsearchClient;
index: string;
docs: any[];
}) {
await esClient.bulk({
body: docs.reduce((acc, doc) => {
acc.push({ index: { _id: doc.id, _index: index } });
acc.push(_.omit(doc, 'id'));
return acc;
}, []),
});
await esClient.indices.refresh({ index });
}
async function migrateIndex({
esClient,
index,
savedObjectTypes,
mappingProperties,
obsoleteIndexTemplatePattern,
}: {
esClient: ElasticsearchClient;
index: string;
savedObjectTypes: SavedObjectsType[];
mappingProperties: SavedObjectsTypeMappingDefinitions;
obsoleteIndexTemplatePattern?: string;
}) {
const typeRegistry = new SavedObjectTypeRegistry();
savedObjectTypes.forEach((type) => typeRegistry.registerType(type));
const documentMigrator = new DocumentMigrator({
kibanaVersion: KIBANA_VERSION,
typeRegistry,
minimumConvertVersion: '0.0.0', // bypass the restriction of a minimum version of 8.0.0 for these integration tests
log: getLogMock(),
});
documentMigrator.prepareMigrations();
const migrator = new IndexMigrator({
client: createMigrationEsClient(esClient, getLogMock()),
documentMigrator,
index,
kibanaVersion: KIBANA_VERSION,
obsoleteIndexTemplatePattern,
mappingProperties,
batchSize: 10,
log: getLogMock(),
setStatus: () => {},
pollInterval: 50,
scrollDuration: '5m',
serializer: new SavedObjectsSerializer(typeRegistry),
});
return await migrator.migrate();
}
async function fetchDocs(esClient: ElasticsearchClient, index: string) {
const { body } = await esClient.search<any>({ index });
return body.hits.hits
.map((h) => ({
...h._source,
id: h._id,
}))
.sort(sortByTypeAndId);
}
function sortByTypeAndId(a: { type: string; id: string }, b: { type: string; id: string }) {
return a.type.localeCompare(b.type) || a.id.localeCompare(b.id);
}