mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
Add deprecation warning when unknown SO types are present (#111268)
* Add deprecation warning when unknown types are present * fix and add service tests * remove export * plug deprecation route * add integration test for new route * add unit test for getIndexForType * add unit tests * improve deprecation messages * add FTR test * fix things due to merge * change the name of the deprecation provider * improve message * improve message again
This commit is contained in:
parent
b74f154903
commit
138371e50c
20 changed files with 1561 additions and 12 deletions
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import type { RegisterDeprecationsConfig } from '../../deprecations';
|
||||
import type { ISavedObjectTypeRegistry } from '../saved_objects_type_registry';
|
||||
import type { SavedObjectConfig } from '../saved_objects_config';
|
||||
import type { KibanaConfigType } from '../../kibana_config';
|
||||
import { getUnknownTypesDeprecations } from './unknown_object_types';
|
||||
|
||||
interface GetDeprecationProviderOptions {
|
||||
typeRegistry: ISavedObjectTypeRegistry;
|
||||
savedObjectsConfig: SavedObjectConfig;
|
||||
kibanaConfig: KibanaConfigType;
|
||||
kibanaVersion: string;
|
||||
}
|
||||
|
||||
export const getSavedObjectsDeprecationsProvider = (
|
||||
config: GetDeprecationProviderOptions
|
||||
): RegisterDeprecationsConfig => {
|
||||
return {
|
||||
getDeprecations: async (context) => {
|
||||
return [
|
||||
...(await getUnknownTypesDeprecations({
|
||||
...config,
|
||||
esClient: context.esClient,
|
||||
})),
|
||||
];
|
||||
},
|
||||
};
|
||||
};
|
10
src/core/server/saved_objects/deprecations/index.ts
Normal file
10
src/core/server/saved_objects/deprecations/index.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { getSavedObjectsDeprecationsProvider } from './deprecation_factory';
|
||||
export { deleteUnknownTypeObjects } from './unknown_object_types';
|
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export const getIndexForTypeMock = jest.fn();
|
||||
|
||||
jest.doMock('../service/lib/get_index_for_type', () => ({
|
||||
getIndexForType: getIndexForTypeMock,
|
||||
}));
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { getIndexForTypeMock } from './unknown_object_types.test.mocks';
|
||||
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import { deleteUnknownTypeObjects, getUnknownTypesDeprecations } from './unknown_object_types';
|
||||
import { typeRegistryMock } from '../saved_objects_type_registry.mock';
|
||||
import { elasticsearchClientMock } from '../../elasticsearch/client/mocks';
|
||||
import type { KibanaConfigType } from '../../kibana_config';
|
||||
import type { SavedObjectConfig } from '../saved_objects_config';
|
||||
import { SavedObjectsType } from 'kibana/server';
|
||||
|
||||
const createSearchResponse = (count: number): estypes.SearchResponse => {
|
||||
return {
|
||||
hits: {
|
||||
total: count,
|
||||
max_score: 0,
|
||||
hits: new Array(count).fill({}),
|
||||
},
|
||||
} as estypes.SearchResponse;
|
||||
};
|
||||
|
||||
describe('unknown saved object types deprecation', () => {
|
||||
const kibanaVersion = '8.0.0';
|
||||
|
||||
let typeRegistry: ReturnType<typeof typeRegistryMock.create>;
|
||||
let esClient: ReturnType<typeof elasticsearchClientMock.createScopedClusterClient>;
|
||||
let kibanaConfig: KibanaConfigType;
|
||||
let savedObjectsConfig: SavedObjectConfig;
|
||||
|
||||
beforeEach(() => {
|
||||
typeRegistry = typeRegistryMock.create();
|
||||
esClient = elasticsearchClientMock.createScopedClusterClient();
|
||||
|
||||
typeRegistry.getAllTypes.mockReturnValue([
|
||||
{ name: 'foo' },
|
||||
{ name: 'bar' },
|
||||
] as SavedObjectsType[]);
|
||||
getIndexForTypeMock.mockImplementation(({ type }: { type: string }) => `${type}-index`);
|
||||
|
||||
kibanaConfig = {
|
||||
index: '.kibana',
|
||||
enabled: true,
|
||||
};
|
||||
|
||||
savedObjectsConfig = {
|
||||
migration: {
|
||||
enableV2: true,
|
||||
},
|
||||
} as SavedObjectConfig;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
getIndexForTypeMock.mockReset();
|
||||
});
|
||||
|
||||
describe('getUnknownTypesDeprecations', () => {
|
||||
beforeEach(() => {
|
||||
esClient.asInternalUser.search.mockReturnValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise(createSearchResponse(0))
|
||||
);
|
||||
});
|
||||
|
||||
it('calls `esClient.asInternalUser.search` with the correct parameters', async () => {
|
||||
await getUnknownTypesDeprecations({
|
||||
savedObjectsConfig,
|
||||
esClient,
|
||||
typeRegistry,
|
||||
kibanaConfig,
|
||||
kibanaVersion,
|
||||
});
|
||||
|
||||
expect(esClient.asInternalUser.search).toHaveBeenCalledTimes(1);
|
||||
expect(esClient.asInternalUser.search).toHaveBeenCalledWith({
|
||||
index: ['foo-index', 'bar-index'],
|
||||
body: {
|
||||
size: 10000,
|
||||
query: {
|
||||
bool: {
|
||||
must_not: [{ term: { type: 'foo' } }, { term: { type: 'bar' } }],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('returns no deprecation if no unknown type docs are found', async () => {
|
||||
esClient.asInternalUser.search.mockReturnValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise(createSearchResponse(0))
|
||||
);
|
||||
|
||||
const deprecations = await getUnknownTypesDeprecations({
|
||||
savedObjectsConfig,
|
||||
esClient,
|
||||
typeRegistry,
|
||||
kibanaConfig,
|
||||
kibanaVersion,
|
||||
});
|
||||
|
||||
expect(deprecations.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('returns a deprecation if any unknown type docs are found', async () => {
|
||||
esClient.asInternalUser.search.mockReturnValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise(createSearchResponse(1))
|
||||
);
|
||||
|
||||
const deprecations = await getUnknownTypesDeprecations({
|
||||
savedObjectsConfig,
|
||||
esClient,
|
||||
typeRegistry,
|
||||
kibanaConfig,
|
||||
kibanaVersion,
|
||||
});
|
||||
|
||||
expect(deprecations.length).toEqual(1);
|
||||
expect(deprecations[0]).toEqual({
|
||||
title: expect.any(String),
|
||||
message: expect.any(String),
|
||||
level: 'critical',
|
||||
requireRestart: false,
|
||||
deprecationType: undefined,
|
||||
correctiveActions: {
|
||||
manualSteps: expect.any(Array),
|
||||
api: {
|
||||
path: '/internal/saved_objects/deprecations/_delete_unknown_types',
|
||||
method: 'POST',
|
||||
body: {},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteUnknownTypeObjects', () => {
|
||||
it('calls `esClient.asInternalUser.search` with the correct parameters', async () => {
|
||||
await deleteUnknownTypeObjects({
|
||||
savedObjectsConfig,
|
||||
esClient,
|
||||
typeRegistry,
|
||||
kibanaConfig,
|
||||
kibanaVersion,
|
||||
});
|
||||
|
||||
expect(esClient.asInternalUser.deleteByQuery).toHaveBeenCalledTimes(1);
|
||||
expect(esClient.asInternalUser.deleteByQuery).toHaveBeenCalledWith({
|
||||
index: ['foo-index', 'bar-index'],
|
||||
wait_for_completion: false,
|
||||
body: {
|
||||
query: {
|
||||
bool: {
|
||||
must_not: [{ term: { type: 'foo' } }, { term: { type: 'bar' } }],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { DeprecationsDetails } from '../../deprecations';
|
||||
import { IScopedClusterClient } from '../../elasticsearch';
|
||||
import { ISavedObjectTypeRegistry } from '../saved_objects_type_registry';
|
||||
import { SavedObjectsRawDocSource } from '../serialization';
|
||||
import type { KibanaConfigType } from '../../kibana_config';
|
||||
import type { SavedObjectConfig } from '../saved_objects_config';
|
||||
import { getIndexForType } from '../service/lib';
|
||||
|
||||
interface UnknownTypesDeprecationOptions {
|
||||
typeRegistry: ISavedObjectTypeRegistry;
|
||||
esClient: IScopedClusterClient;
|
||||
kibanaConfig: KibanaConfigType;
|
||||
savedObjectsConfig: SavedObjectConfig;
|
||||
kibanaVersion: string;
|
||||
}
|
||||
|
||||
const getKnownTypes = (typeRegistry: ISavedObjectTypeRegistry) =>
|
||||
typeRegistry.getAllTypes().map((type) => type.name);
|
||||
|
||||
const getTargetIndices = ({
|
||||
types,
|
||||
typeRegistry,
|
||||
kibanaVersion,
|
||||
kibanaConfig,
|
||||
savedObjectsConfig,
|
||||
}: {
|
||||
types: string[];
|
||||
typeRegistry: ISavedObjectTypeRegistry;
|
||||
savedObjectsConfig: SavedObjectConfig;
|
||||
kibanaConfig: KibanaConfigType;
|
||||
kibanaVersion: string;
|
||||
}) => {
|
||||
return [
|
||||
...new Set(
|
||||
types.map((type) =>
|
||||
getIndexForType({
|
||||
type,
|
||||
typeRegistry,
|
||||
migV2Enabled: savedObjectsConfig.migration.enableV2,
|
||||
kibanaVersion,
|
||||
defaultIndex: kibanaConfig.index,
|
||||
})
|
||||
)
|
||||
),
|
||||
];
|
||||
};
|
||||
|
||||
const getUnknownTypesQuery = (knownTypes: string[]): estypes.QueryDslQueryContainer => {
|
||||
return {
|
||||
bool: {
|
||||
must_not: knownTypes.map((type) => ({
|
||||
term: { type },
|
||||
})),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const getUnknownSavedObjects = async ({
|
||||
typeRegistry,
|
||||
esClient,
|
||||
kibanaConfig,
|
||||
savedObjectsConfig,
|
||||
kibanaVersion,
|
||||
}: UnknownTypesDeprecationOptions) => {
|
||||
const knownTypes = getKnownTypes(typeRegistry);
|
||||
const targetIndices = getTargetIndices({
|
||||
types: knownTypes,
|
||||
typeRegistry,
|
||||
kibanaConfig,
|
||||
kibanaVersion,
|
||||
savedObjectsConfig,
|
||||
});
|
||||
const query = getUnknownTypesQuery(knownTypes);
|
||||
|
||||
const { body } = await esClient.asInternalUser.search<SavedObjectsRawDocSource>({
|
||||
index: targetIndices,
|
||||
body: {
|
||||
size: 10000,
|
||||
query,
|
||||
},
|
||||
});
|
||||
const { hits: unknownDocs } = body.hits;
|
||||
|
||||
return unknownDocs.map((doc) => ({ id: doc._id, type: doc._source?.type ?? 'unknown' }));
|
||||
};
|
||||
|
||||
export const getUnknownTypesDeprecations = async (
|
||||
options: UnknownTypesDeprecationOptions
|
||||
): Promise<DeprecationsDetails[]> => {
|
||||
const deprecations: DeprecationsDetails[] = [];
|
||||
const unknownDocs = await getUnknownSavedObjects(options);
|
||||
if (unknownDocs.length) {
|
||||
deprecations.push({
|
||||
title: i18n.translate('core.savedObjects.deprecations.unknownTypes.title', {
|
||||
defaultMessage: 'Saved objects with unknown types are present in Kibana system indices',
|
||||
}),
|
||||
message: i18n.translate('core.savedObjects.deprecations.unknownTypes.message', {
|
||||
defaultMessage:
|
||||
'{objectCount, plural, one {# object} other {# objects}} with unknown types {objectCount, plural, one {was} other {were}} found in Kibana system indices. ' +
|
||||
'Upgrading with unknown savedObject types is no longer supported. ' +
|
||||
`To ensure that upgrades will succeed in the future, either re-enable plugins or delete these documents from the Kibana indices`,
|
||||
values: {
|
||||
objectCount: unknownDocs.length,
|
||||
},
|
||||
}),
|
||||
level: 'critical',
|
||||
requireRestart: false,
|
||||
deprecationType: undefined, // not config nor feature...
|
||||
correctiveActions: {
|
||||
manualSteps: [
|
||||
i18n.translate('core.savedObjects.deprecations.unknownTypes.manualSteps.1', {
|
||||
defaultMessage: 'Enable disabled plugins then restart Kibana.',
|
||||
}),
|
||||
i18n.translate('core.savedObjects.deprecations.unknownTypes.manualSteps.2', {
|
||||
defaultMessage:
|
||||
'If no plugins are disabled, or if enabling them does not fix the issue, delete the documents.',
|
||||
}),
|
||||
],
|
||||
api: {
|
||||
path: '/internal/saved_objects/deprecations/_delete_unknown_types',
|
||||
method: 'POST',
|
||||
body: {},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
return deprecations;
|
||||
};
|
||||
|
||||
interface DeleteUnknownTypesOptions {
|
||||
typeRegistry: ISavedObjectTypeRegistry;
|
||||
esClient: IScopedClusterClient;
|
||||
kibanaConfig: KibanaConfigType;
|
||||
savedObjectsConfig: SavedObjectConfig;
|
||||
kibanaVersion: string;
|
||||
}
|
||||
|
||||
export const deleteUnknownTypeObjects = async ({
|
||||
esClient,
|
||||
typeRegistry,
|
||||
kibanaConfig,
|
||||
savedObjectsConfig,
|
||||
kibanaVersion,
|
||||
}: DeleteUnknownTypesOptions) => {
|
||||
const knownTypes = getKnownTypes(typeRegistry);
|
||||
const targetIndices = getTargetIndices({
|
||||
types: knownTypes,
|
||||
typeRegistry,
|
||||
kibanaConfig,
|
||||
kibanaVersion,
|
||||
savedObjectsConfig,
|
||||
});
|
||||
const query = getUnknownTypesQuery(knownTypes);
|
||||
|
||||
await esClient.asInternalUser.deleteByQuery({
|
||||
index: targetIndices,
|
||||
wait_for_completion: false,
|
||||
body: {
|
||||
query,
|
||||
},
|
||||
});
|
||||
};
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { IRouter } from '../../../http';
|
||||
import { catchAndReturnBoomErrors } from '../utils';
|
||||
import { deleteUnknownTypeObjects } from '../../deprecations';
|
||||
import { SavedObjectConfig } from '../../saved_objects_config';
|
||||
import { KibanaConfigType } from '../../../kibana_config';
|
||||
|
||||
interface RouteDependencies {
|
||||
config: SavedObjectConfig;
|
||||
kibanaConfig: KibanaConfigType;
|
||||
kibanaVersion: string;
|
||||
}
|
||||
|
||||
export const registerDeleteUnknownTypesRoute = (
|
||||
router: IRouter,
|
||||
{ config, kibanaConfig, kibanaVersion }: RouteDependencies
|
||||
) => {
|
||||
router.post(
|
||||
{
|
||||
path: '/deprecations/_delete_unknown_types',
|
||||
validate: false,
|
||||
},
|
||||
catchAndReturnBoomErrors(async (context, req, res) => {
|
||||
await deleteUnknownTypeObjects({
|
||||
esClient: context.core.elasticsearch.client,
|
||||
typeRegistry: context.core.savedObjects.typeRegistry,
|
||||
savedObjectsConfig: config,
|
||||
kibanaConfig,
|
||||
kibanaVersion,
|
||||
});
|
||||
return res.ok({
|
||||
body: {
|
||||
success: true,
|
||||
},
|
||||
});
|
||||
})
|
||||
);
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { registerDeleteUnknownTypesRoute } from './delete_unknown_types';
|
|
@ -26,6 +26,8 @@ import { registerResolveImportErrorsRoute } from './resolve_import_errors';
|
|||
import { registerMigrateRoute } from './migrate';
|
||||
import { registerLegacyImportRoute } from './legacy_import_export/import';
|
||||
import { registerLegacyExportRoute } from './legacy_import_export/export';
|
||||
import { registerDeleteUnknownTypesRoute } from './deprecations';
|
||||
import { KibanaConfigType } from '../../kibana_config';
|
||||
|
||||
export function registerRoutes({
|
||||
http,
|
||||
|
@ -34,6 +36,7 @@ export function registerRoutes({
|
|||
config,
|
||||
migratorPromise,
|
||||
kibanaVersion,
|
||||
kibanaConfig,
|
||||
}: {
|
||||
http: InternalHttpServiceSetup;
|
||||
coreUsageData: InternalCoreUsageDataSetup;
|
||||
|
@ -41,6 +44,7 @@ export function registerRoutes({
|
|||
config: SavedObjectConfig;
|
||||
migratorPromise: Promise<IKibanaMigrator>;
|
||||
kibanaVersion: string;
|
||||
kibanaConfig: KibanaConfigType;
|
||||
}) {
|
||||
const router = http.createRouter('/api/saved_objects/');
|
||||
|
||||
|
@ -68,4 +72,5 @@ export function registerRoutes({
|
|||
const internalRouter = http.createRouter('/internal/saved_objects/');
|
||||
|
||||
registerMigrateRoute(internalRouter, migratorPromise);
|
||||
registerDeleteUnknownTypesRoute(internalRouter, { config, kibanaConfig, kibanaVersion });
|
||||
}
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import supertest from 'supertest';
|
||||
import { UnwrapPromise } from '@kbn/utility-types';
|
||||
import { registerDeleteUnknownTypesRoute } from '../deprecations';
|
||||
import { elasticsearchServiceMock } from '../../../../../core/server/elasticsearch/elasticsearch_service.mock';
|
||||
import { typeRegistryMock } from '../../saved_objects_type_registry.mock';
|
||||
import { setupServer } from '../test_utils';
|
||||
import { KibanaConfigType } from '../../../kibana_config';
|
||||
import { SavedObjectConfig } from '../../saved_objects_config';
|
||||
import { SavedObjectsType } from 'kibana/server';
|
||||
|
||||
type SetupServerReturn = UnwrapPromise<ReturnType<typeof setupServer>>;
|
||||
|
||||
describe('POST /internal/saved_objects/deprecations/_delete_unknown_types', () => {
|
||||
const kibanaVersion = '8.0.0';
|
||||
const kibanaConfig: KibanaConfigType = {
|
||||
enabled: true,
|
||||
index: '.kibana',
|
||||
};
|
||||
const config: SavedObjectConfig = {
|
||||
maxImportExportSize: 10000,
|
||||
maxImportPayloadBytes: 24000000,
|
||||
migration: {
|
||||
enableV2: true,
|
||||
} as SavedObjectConfig['migration'],
|
||||
};
|
||||
|
||||
let server: SetupServerReturn['server'];
|
||||
let httpSetup: SetupServerReturn['httpSetup'];
|
||||
let handlerContext: SetupServerReturn['handlerContext'];
|
||||
let typeRegistry: ReturnType<typeof typeRegistryMock.create>;
|
||||
let elasticsearchClient: ReturnType<typeof elasticsearchServiceMock.createScopedClusterClient>;
|
||||
|
||||
beforeEach(async () => {
|
||||
({ server, httpSetup, handlerContext } = await setupServer());
|
||||
elasticsearchClient = elasticsearchServiceMock.createScopedClusterClient();
|
||||
typeRegistry = typeRegistryMock.create();
|
||||
|
||||
typeRegistry.getAllTypes.mockReturnValue([{ name: 'known-type' } as SavedObjectsType]);
|
||||
typeRegistry.getIndex.mockImplementation((type) => `${type}-index`);
|
||||
|
||||
handlerContext.savedObjects.typeRegistry = typeRegistry;
|
||||
handlerContext.elasticsearch.client.asCurrentUser = elasticsearchClient.asCurrentUser;
|
||||
handlerContext.elasticsearch.client.asInternalUser = elasticsearchClient.asInternalUser;
|
||||
|
||||
const router = httpSetup.createRouter('/internal/saved_objects/');
|
||||
registerDeleteUnknownTypesRoute(router, {
|
||||
kibanaVersion,
|
||||
kibanaConfig,
|
||||
config,
|
||||
});
|
||||
|
||||
await server.start();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await server.stop();
|
||||
});
|
||||
|
||||
it('formats successful response', async () => {
|
||||
const result = await supertest(httpSetup.server.listener)
|
||||
.post('/internal/saved_objects/deprecations/_delete_unknown_types')
|
||||
.expect(200);
|
||||
|
||||
expect(result.body).toEqual({ success: true });
|
||||
});
|
||||
|
||||
it('calls upon esClient.deleteByQuery', async () => {
|
||||
await supertest(httpSetup.server.listener)
|
||||
.post('/internal/saved_objects/deprecations/_delete_unknown_types')
|
||||
.expect(200);
|
||||
|
||||
expect(elasticsearchClient.asInternalUser.deleteByQuery).toHaveBeenCalledTimes(1);
|
||||
expect(elasticsearchClient.asInternalUser.deleteByQuery).toHaveBeenCalledWith({
|
||||
index: ['known-type-index_8.0.0'],
|
||||
wait_for_completion: false,
|
||||
body: {
|
||||
query: {
|
||||
bool: {
|
||||
must_not: expect.any(Array),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
|
@ -20,17 +20,26 @@ import { Env } from '../config';
|
|||
import { configServiceMock } from '../mocks';
|
||||
import { elasticsearchServiceMock } from '../elasticsearch/elasticsearch_service.mock';
|
||||
import { coreUsageDataServiceMock } from '../core_usage_data/core_usage_data_service.mock';
|
||||
import { deprecationsServiceMock } from '../deprecations/deprecations_service.mock';
|
||||
import { httpServiceMock } from '../http/http_service.mock';
|
||||
import { httpServerMock } from '../http/http_server.mocks';
|
||||
import { SavedObjectsClientFactoryProvider } from './service/lib';
|
||||
import { NodesVersionCompatibility } from '../elasticsearch/version_check/ensure_es_version';
|
||||
import { SavedObjectsRepository } from './service/lib/repository';
|
||||
import { registerCoreObjectTypes } from './object_types';
|
||||
import { getSavedObjectsDeprecationsProvider } from './deprecations';
|
||||
|
||||
jest.mock('./service/lib/repository');
|
||||
jest.mock('./object_types');
|
||||
jest.mock('./deprecations');
|
||||
|
||||
describe('SavedObjectsService', () => {
|
||||
let deprecationsSetup: ReturnType<typeof deprecationsServiceMock.createInternalSetupContract>;
|
||||
|
||||
beforeEach(() => {
|
||||
deprecationsSetup = deprecationsServiceMock.createInternalSetupContract();
|
||||
});
|
||||
|
||||
const createCoreContext = ({
|
||||
skipMigration = true,
|
||||
env,
|
||||
|
@ -53,6 +62,7 @@ describe('SavedObjectsService', () => {
|
|||
return {
|
||||
http: httpServiceMock.createInternalSetupContract(),
|
||||
elasticsearch: elasticsearchMock,
|
||||
deprecations: deprecationsSetup,
|
||||
coreUsageData: coreUsageDataServiceMock.createSetupContract(),
|
||||
};
|
||||
};
|
||||
|
@ -79,6 +89,24 @@ describe('SavedObjectsService', () => {
|
|||
expect(mockedRegisterCoreObjectTypes).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('register the deprecation provider', async () => {
|
||||
const coreContext = createCoreContext();
|
||||
const soService = new SavedObjectsService(coreContext);
|
||||
|
||||
const mockRegistry = deprecationsServiceMock.createSetupContract();
|
||||
deprecationsSetup.getRegistry.mockReturnValue(mockRegistry);
|
||||
|
||||
const deprecations = Symbol('deprecations');
|
||||
const mockedGetSavedObjectsDeprecationsProvider = getSavedObjectsDeprecationsProvider as jest.Mock;
|
||||
mockedGetSavedObjectsDeprecationsProvider.mockReturnValue(deprecations);
|
||||
await soService.setup(createSetupDeps());
|
||||
|
||||
expect(deprecationsSetup.getRegistry).toHaveBeenCalledTimes(1);
|
||||
expect(deprecationsSetup.getRegistry).toHaveBeenCalledWith('savedObjects');
|
||||
expect(mockRegistry.registerDeprecations).toHaveBeenCalledTimes(1);
|
||||
expect(mockRegistry.registerDeprecations).toHaveBeenCalledWith(deprecations);
|
||||
});
|
||||
|
||||
describe('#setClientFactoryProvider', () => {
|
||||
it('registers the factory to the clientProvider', async () => {
|
||||
const coreContext = createCoreContext();
|
||||
|
|
|
@ -22,6 +22,7 @@ import {
|
|||
InternalElasticsearchServiceSetup,
|
||||
InternalElasticsearchServiceStart,
|
||||
} from '../elasticsearch';
|
||||
import { InternalDeprecationsServiceSetup } from '../deprecations';
|
||||
import { KibanaConfigType } from '../kibana_config';
|
||||
import {
|
||||
SavedObjectsConfigType,
|
||||
|
@ -44,6 +45,7 @@ import { registerRoutes } from './routes';
|
|||
import { ServiceStatus } from '../status';
|
||||
import { calculateStatus$ } from './status';
|
||||
import { registerCoreObjectTypes } from './object_types';
|
||||
import { getSavedObjectsDeprecationsProvider } from './deprecations';
|
||||
|
||||
/**
|
||||
* Saved Objects is Kibana's data persistence mechanism allowing plugins to
|
||||
|
@ -251,6 +253,7 @@ export interface SavedObjectsSetupDeps {
|
|||
http: InternalHttpServiceSetup;
|
||||
elasticsearch: InternalElasticsearchServiceSetup;
|
||||
coreUsageData: InternalCoreUsageDataSetup;
|
||||
deprecations: InternalDeprecationsServiceSetup;
|
||||
}
|
||||
|
||||
interface WrappedClientFactoryWrapper {
|
||||
|
@ -286,7 +289,7 @@ export class SavedObjectsService
|
|||
this.logger.debug('Setting up SavedObjects service');
|
||||
|
||||
this.setupDeps = setupDeps;
|
||||
const { http, elasticsearch, coreUsageData } = setupDeps;
|
||||
const { http, elasticsearch, coreUsageData, deprecations } = setupDeps;
|
||||
|
||||
const savedObjectsConfig = await this.coreContext.configService
|
||||
.atPath<SavedObjectsConfigType>('savedObjects')
|
||||
|
@ -298,6 +301,20 @@ export class SavedObjectsService
|
|||
.toPromise();
|
||||
this.config = new SavedObjectConfig(savedObjectsConfig, savedObjectsMigrationConfig);
|
||||
|
||||
const kibanaConfig = await this.coreContext.configService
|
||||
.atPath<KibanaConfigType>('kibana')
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
|
||||
deprecations.getRegistry('savedObjects').registerDeprecations(
|
||||
getSavedObjectsDeprecationsProvider({
|
||||
kibanaConfig,
|
||||
savedObjectsConfig: this.config,
|
||||
kibanaVersion: this.coreContext.env.packageInfo.version,
|
||||
typeRegistry: this.typeRegistry,
|
||||
})
|
||||
);
|
||||
|
||||
coreUsageData.registerType(this.typeRegistry);
|
||||
|
||||
registerRoutes({
|
||||
|
@ -306,6 +323,7 @@ export class SavedObjectsService
|
|||
logger: this.logger,
|
||||
config: this.config,
|
||||
migratorPromise: this.migrator$.pipe(first()).toPromise(),
|
||||
kibanaConfig,
|
||||
kibanaVersion: this.coreContext.env.packageInfo.version,
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { getIndexForType } from './get_index_for_type';
|
||||
import { typeRegistryMock } from '../../saved_objects_type_registry.mock';
|
||||
|
||||
describe('getIndexForType', () => {
|
||||
const kibanaVersion = '8.0.0';
|
||||
const defaultIndex = '.kibana';
|
||||
let typeRegistry: ReturnType<typeof typeRegistryMock.create>;
|
||||
|
||||
beforeEach(() => {
|
||||
typeRegistry = typeRegistryMock.create();
|
||||
});
|
||||
|
||||
describe('when migV2 is enabled', () => {
|
||||
const migV2Enabled = true;
|
||||
|
||||
it('returns the correct index for a type specifying a custom index', () => {
|
||||
typeRegistry.getIndex.mockImplementation((type) => `.${type}-index`);
|
||||
expect(
|
||||
getIndexForType({
|
||||
type: 'foo',
|
||||
typeRegistry,
|
||||
defaultIndex,
|
||||
kibanaVersion,
|
||||
migV2Enabled,
|
||||
})
|
||||
).toEqual('.foo-index_8.0.0');
|
||||
});
|
||||
|
||||
it('returns the correct index for a type not specifying a custom index', () => {
|
||||
typeRegistry.getIndex.mockImplementation((type) => undefined);
|
||||
expect(
|
||||
getIndexForType({
|
||||
type: 'foo',
|
||||
typeRegistry,
|
||||
defaultIndex,
|
||||
kibanaVersion,
|
||||
migV2Enabled,
|
||||
})
|
||||
).toEqual('.kibana_8.0.0');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when migV2 is disabled', () => {
|
||||
const migV2Enabled = false;
|
||||
|
||||
it('returns the correct index for a type specifying a custom index', () => {
|
||||
typeRegistry.getIndex.mockImplementation((type) => `.${type}-index`);
|
||||
expect(
|
||||
getIndexForType({
|
||||
type: 'foo',
|
||||
typeRegistry,
|
||||
defaultIndex,
|
||||
kibanaVersion,
|
||||
migV2Enabled,
|
||||
})
|
||||
).toEqual('.foo-index');
|
||||
});
|
||||
|
||||
it('returns the correct index for a type not specifying a custom index', () => {
|
||||
typeRegistry.getIndex.mockImplementation((type) => undefined);
|
||||
expect(
|
||||
getIndexForType({
|
||||
type: 'foo',
|
||||
typeRegistry,
|
||||
defaultIndex,
|
||||
kibanaVersion,
|
||||
migV2Enabled,
|
||||
})
|
||||
).toEqual('.kibana');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { ISavedObjectTypeRegistry } from '../../saved_objects_type_registry';
|
||||
|
||||
interface GetIndexForTypeOptions {
|
||||
type: string;
|
||||
typeRegistry: ISavedObjectTypeRegistry;
|
||||
migV2Enabled: boolean;
|
||||
kibanaVersion: string;
|
||||
defaultIndex: string;
|
||||
}
|
||||
|
||||
export const getIndexForType = ({
|
||||
type,
|
||||
typeRegistry,
|
||||
migV2Enabled,
|
||||
defaultIndex,
|
||||
kibanaVersion,
|
||||
}: GetIndexForTypeOptions): string => {
|
||||
// TODO migrationsV2: Remove once we remove migrations v1
|
||||
// This is a hacky, but it required the least amount of changes to
|
||||
// existing code to support a migrations v2 index. Long term we would
|
||||
// want to always use the type registry to resolve a type's index
|
||||
// (including the default index).
|
||||
if (migV2Enabled) {
|
||||
return `${typeRegistry.getIndex(type) || defaultIndex}_${kibanaVersion}`;
|
||||
} else {
|
||||
return typeRegistry.getIndex(type) || defaultIndex;
|
||||
}
|
||||
};
|
|
@ -41,3 +41,5 @@ export type {
|
|||
SavedObjectsUpdateObjectsSpacesResponse,
|
||||
SavedObjectsUpdateObjectsSpacesResponseObject,
|
||||
} from './update_objects_spaces';
|
||||
|
||||
export { getIndexForType } from './get_index_for_type';
|
||||
|
|
|
@ -92,6 +92,7 @@ import {
|
|||
SavedObjectsUpdateObjectsSpacesObject,
|
||||
SavedObjectsUpdateObjectsSpacesOptions,
|
||||
} from './update_objects_spaces';
|
||||
import { getIndexForType } from './get_index_for_type';
|
||||
|
||||
// BEWARE: The SavedObjectClient depends on the implementation details of the SavedObjectsRepository
|
||||
// so any breaking changes to this repository are considered breaking changes to the SavedObjectsClient.
|
||||
|
@ -2099,16 +2100,13 @@ export class SavedObjectsRepository {
|
|||
* @param type - the type
|
||||
*/
|
||||
private getIndexForType(type: string) {
|
||||
// TODO migrationsV2: Remove once we remove migrations v1
|
||||
// This is a hacky, but it required the least amount of changes to
|
||||
// existing code to support a migrations v2 index. Long term we would
|
||||
// want to always use the type registry to resolve a type's index
|
||||
// (including the default index).
|
||||
if (this._migrator.soMigrationsConfig.enableV2) {
|
||||
return `${this._registry.getIndex(type) || this._index}_${this._migrator.kibanaVersion}`;
|
||||
} else {
|
||||
return this._registry.getIndex(type) || this._index;
|
||||
}
|
||||
return getIndexForType({
|
||||
type,
|
||||
defaultIndex: this._index,
|
||||
typeRegistry: this._registry,
|
||||
kibanaVersion: this._migrator.kibanaVersion,
|
||||
migV2Enabled: this._migrator.soMigrationsConfig.enableV2,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -233,6 +233,7 @@ export class Server {
|
|||
const savedObjectsSetup = await this.savedObjects.setup({
|
||||
http: httpSetup,
|
||||
elasticsearch: elasticsearchServiceSetup,
|
||||
deprecations: deprecationsSetup,
|
||||
coreUsageData: coreUsageDataSetup,
|
||||
});
|
||||
|
||||
|
@ -303,6 +304,7 @@ export class Server {
|
|||
|
||||
const executionContextStart = this.executionContext.start();
|
||||
const elasticsearchStart = await this.elasticsearch.start();
|
||||
const deprecationsStart = this.deprecations.start();
|
||||
const soStartSpan = startTransaction?.startSpan('saved_objects.migration', 'migration');
|
||||
const savedObjectsStart = await this.savedObjects.start({
|
||||
elasticsearch: elasticsearchStart,
|
||||
|
@ -320,7 +322,7 @@ export class Server {
|
|||
savedObjects: savedObjectsStart,
|
||||
exposedConfigsToUsage: this.plugins.getExposedPluginConfigsToUsage(),
|
||||
});
|
||||
const deprecationsStart = this.deprecations.start();
|
||||
|
||||
this.status.start();
|
||||
|
||||
this.coreStart = {
|
||||
|
|
125
test/api_integration/apis/saved_objects/delete_unknown_types.ts
Normal file
125
test/api_integration/apis/saved_objects/delete_unknown_types.ts
Normal file
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
|
||||
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
const supertest = getService('supertest');
|
||||
const esArchiver = getService('esArchiver');
|
||||
const es = getService('es');
|
||||
|
||||
describe('/deprecations/_delete_unknown_types', () => {
|
||||
before(async () => {
|
||||
await esArchiver.emptyKibanaIndex();
|
||||
await esArchiver.load(
|
||||
'test/api_integration/fixtures/es_archiver/saved_objects/delete_unknown_types'
|
||||
);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await esArchiver.unload(
|
||||
'test/api_integration/fixtures/es_archiver/saved_objects/delete_unknown_types'
|
||||
);
|
||||
});
|
||||
|
||||
const fetchIndexContent = async () => {
|
||||
const { body } = await es.search<{ type: string }>({
|
||||
index: '.kibana',
|
||||
body: {
|
||||
size: 100,
|
||||
},
|
||||
});
|
||||
return body.hits.hits
|
||||
.map((hit) => ({
|
||||
type: hit._source!.type,
|
||||
id: hit._id,
|
||||
}))
|
||||
.sort((a, b) => {
|
||||
return a.id > b.id ? 1 : -1;
|
||||
});
|
||||
};
|
||||
|
||||
it('should return 200 with individual responses', async () => {
|
||||
const beforeDelete = await fetchIndexContent();
|
||||
expect(beforeDelete).to.eql([
|
||||
{
|
||||
id: 'dashboard:b70c7ae0-3224-11e8-a572-ffca06da1357',
|
||||
type: 'dashboard',
|
||||
},
|
||||
{
|
||||
id: 'index-pattern:8963ca30-3224-11e8-a572-ffca06da1357',
|
||||
type: 'index-pattern',
|
||||
},
|
||||
{
|
||||
id: 'search:960372e0-3224-11e8-a572-ffca06da1357',
|
||||
type: 'search',
|
||||
},
|
||||
{
|
||||
id: 'space:default',
|
||||
type: 'space',
|
||||
},
|
||||
{
|
||||
id: 'unknown-shareable-doc',
|
||||
type: 'unknown-shareable-type',
|
||||
},
|
||||
{
|
||||
id: 'unknown-type:unknown-doc',
|
||||
type: 'unknown-type',
|
||||
},
|
||||
{
|
||||
id: 'visualization:a42c0580-3224-11e8-a572-ffca06da1357',
|
||||
type: 'visualization',
|
||||
},
|
||||
]);
|
||||
|
||||
await supertest
|
||||
.post(`/internal/saved_objects/deprecations/_delete_unknown_types`)
|
||||
.send({})
|
||||
.expect(200)
|
||||
.then((resp) => {
|
||||
expect(resp.body).to.eql({ success: true });
|
||||
});
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const afterDelete = await fetchIndexContent();
|
||||
// we're deleting with `wait_for_completion: false` and we don't surface
|
||||
// the task ID in the API, so we're forced to use pooling for the FTR tests
|
||||
if (afterDelete.map((obj) => obj.type).includes('unknown-type') && i < 10) {
|
||||
await delay(1000);
|
||||
continue;
|
||||
}
|
||||
expect(afterDelete).to.eql([
|
||||
{
|
||||
id: 'dashboard:b70c7ae0-3224-11e8-a572-ffca06da1357',
|
||||
type: 'dashboard',
|
||||
},
|
||||
{
|
||||
id: 'index-pattern:8963ca30-3224-11e8-a572-ffca06da1357',
|
||||
type: 'index-pattern',
|
||||
},
|
||||
{
|
||||
id: 'search:960372e0-3224-11e8-a572-ffca06da1357',
|
||||
type: 'search',
|
||||
},
|
||||
{
|
||||
id: 'space:default',
|
||||
type: 'space',
|
||||
},
|
||||
{
|
||||
id: 'visualization:a42c0580-3224-11e8-a572-ffca06da1357',
|
||||
type: 'visualization',
|
||||
},
|
||||
]);
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
|
@ -23,5 +23,6 @@ export default function ({ loadTestFile }: FtrProviderContext) {
|
|||
loadTestFile(require.resolve('./resolve'));
|
||||
loadTestFile(require.resolve('./resolve_import_errors'));
|
||||
loadTestFile(require.resolve('./update'));
|
||||
loadTestFile(require.resolve('./delete_unknown_types'));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
{
|
||||
"type": "doc",
|
||||
"value": {
|
||||
"id": "index-pattern:8963ca30-3224-11e8-a572-ffca06da1357",
|
||||
"index": ".kibana",
|
||||
"source": {
|
||||
"coreMigrationVersion": "7.14.0",
|
||||
"index-pattern": {
|
||||
"fields": "[{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true}]",
|
||||
"title": "saved_objects*"
|
||||
},
|
||||
"migrationVersion": {
|
||||
"index-pattern": "7.11.0"
|
||||
},
|
||||
"references": [
|
||||
],
|
||||
"type": "index-pattern",
|
||||
"updated_at": "2018-03-28T01:08:34.290Z"
|
||||
},
|
||||
"type": "_doc"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "doc",
|
||||
"value": {
|
||||
"id": "search:960372e0-3224-11e8-a572-ffca06da1357",
|
||||
"index": ".kibana",
|
||||
"source": {
|
||||
"coreMigrationVersion": "7.14.0",
|
||||
"migrationVersion": {
|
||||
"search": "7.9.3"
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"id": "8963ca30-3224-11e8-a572-ffca06da1357",
|
||||
"name": "kibanaSavedObjectMeta.searchSourceJSON.index",
|
||||
"type": "index-pattern"
|
||||
}
|
||||
],
|
||||
"search": {
|
||||
"columns": [
|
||||
"_source"
|
||||
],
|
||||
"description": "",
|
||||
"hits": 0,
|
||||
"kibanaSavedObjectMeta": {
|
||||
"searchSourceJSON": "{\"highlightAll\":true,\"version\":true,\"query\":{\"query\":\"id:3\",\"language\":\"lucene\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"
|
||||
},
|
||||
"sort": [
|
||||
[
|
||||
"_score",
|
||||
"desc"
|
||||
]
|
||||
],
|
||||
"title": "OneRecord",
|
||||
"version": 1
|
||||
},
|
||||
"type": "search",
|
||||
"updated_at": "2018-03-28T01:08:55.182Z"
|
||||
},
|
||||
"type": "_doc"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "doc",
|
||||
"value": {
|
||||
"id": "visualization:a42c0580-3224-11e8-a572-ffca06da1357",
|
||||
"index": ".kibana",
|
||||
"source": {
|
||||
"coreMigrationVersion": "7.14.0",
|
||||
"migrationVersion": {
|
||||
"visualization": "7.14.0"
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"id": "960372e0-3224-11e8-a572-ffca06da1357",
|
||||
"name": "search_0",
|
||||
"type": "search"
|
||||
}
|
||||
],
|
||||
"type": "visualization",
|
||||
"updated_at": "2018-03-28T01:09:18.936Z",
|
||||
"visualization": {
|
||||
"description": "",
|
||||
"kibanaSavedObjectMeta": {
|
||||
"searchSourceJSON": "{\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}"
|
||||
},
|
||||
"savedSearchRefName": "search_0",
|
||||
"title": "VisualizationFromSavedSearch",
|
||||
"uiStateJSON": "{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}",
|
||||
"version": 1,
|
||||
"visState": "{\"title\":\"VisualizationFromSavedSearch\",\"type\":\"table\",\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMeticsAtAllLevels\":false,\"sort\":{\"columnIndex\":null,\"direction\":null},\"showTotal\":false,\"totalFunc\":\"sum\",\"showToolbar\":true},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}}]}"
|
||||
}
|
||||
},
|
||||
"type": "_doc"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "doc",
|
||||
"value": {
|
||||
"id": "dashboard:b70c7ae0-3224-11e8-a572-ffca06da1357",
|
||||
"index": ".kibana",
|
||||
"source": {
|
||||
"coreMigrationVersion": "7.14.0",
|
||||
"dashboard": {
|
||||
"description": "",
|
||||
"hits": 0,
|
||||
"kibanaSavedObjectMeta": {
|
||||
"searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[],\"highlightAll\":true,\"version\":true}"
|
||||
},
|
||||
"optionsJSON": "{\"darkTheme\":false,\"useMargins\":true,\"hidePanelTitles\":false}",
|
||||
"panelsJSON": "[{\"version\":\"7.0.0-alpha1\",\"gridData\":{\"w\":24,\"h\":15,\"x\":0,\"y\":0,\"i\":\"1\"},\"panelIndex\":\"1\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_0\"},{\"version\":\"7.0.0-alpha1\",\"gridData\":{\"w\":24,\"h\":15,\"x\":24,\"y\":0,\"i\":\"2\"},\"panelIndex\":\"2\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_1\"}]",
|
||||
"timeRestore": false,
|
||||
"title": "Dashboard",
|
||||
"version": 1
|
||||
},
|
||||
"migrationVersion": {
|
||||
"dashboard": "7.14.0"
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"id": "add810b0-3224-11e8-a572-ffca06da1357",
|
||||
"name": "panel_0",
|
||||
"type": "visualization"
|
||||
},
|
||||
{
|
||||
"id": "a42c0580-3224-11e8-a572-ffca06da1357",
|
||||
"name": "panel_1",
|
||||
"type": "visualization"
|
||||
}
|
||||
],
|
||||
"type": "dashboard",
|
||||
"updated_at": "2018-03-28T01:09:50.606Z"
|
||||
},
|
||||
"type": "_doc"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
"type": "doc",
|
||||
"value": {
|
||||
"id": "unknown-type:unknown-doc",
|
||||
"index": ".kibana",
|
||||
"source": {
|
||||
"coreMigrationVersion": "7.14.0",
|
||||
"unknown-type": {
|
||||
"foo": "bar"
|
||||
},
|
||||
"migrationVersion": {},
|
||||
"references": [
|
||||
],
|
||||
"type": "unknown-type",
|
||||
"updated_at": "2018-03-28T01:08:34.290Z"
|
||||
},
|
||||
"type": "_doc"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
"type": "doc",
|
||||
"value": {
|
||||
"id": "unknown-shareable-doc",
|
||||
"index": ".kibana",
|
||||
"source": {
|
||||
"coreMigrationVersion": "7.14.0",
|
||||
"unknown-shareable-type": {
|
||||
"foo": "bar"
|
||||
},
|
||||
"migrationVersion": {},
|
||||
"references": [
|
||||
],
|
||||
"type": "unknown-shareable-type",
|
||||
"updated_at": "2018-03-28T01:08:34.290Z"
|
||||
},
|
||||
"type": "_doc"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,530 @@
|
|||
{
|
||||
"type": "index",
|
||||
"value": {
|
||||
"aliases": {
|
||||
".kibana_$KIBANA_PACKAGE_VERSION": {},
|
||||
".kibana": {}
|
||||
},
|
||||
"index": ".kibana_$KIBANA_PACKAGE_VERSION_001",
|
||||
"mappings": {
|
||||
"_meta": {
|
||||
"migrationMappingPropertyHashes": {
|
||||
"application_usage_daily": "43b8830d5d0df85a6823d290885fc9fd",
|
||||
"application_usage_totals": "3d1b76c39bfb2cc8296b024d73854724",
|
||||
"application_usage_transactional": "3d1b76c39bfb2cc8296b024d73854724",
|
||||
"config": "c63748b75f39d0c54de12d12c1ccbc20",
|
||||
"core-usage-stats": "3d1b76c39bfb2cc8296b024d73854724",
|
||||
"coreMigrationVersion": "2f4316de49999235636386fe51dc06c1",
|
||||
"dashboard": "40554caf09725935e2c02e02563a2d07",
|
||||
"index-pattern": "45915a1ad866812242df474eb0479052",
|
||||
"kql-telemetry": "d12a98a6f19a2d273696597547e064ee",
|
||||
"legacy-url-alias": "6155300fd11a00e23d5cbaa39f0fce0a",
|
||||
"migrationVersion": "4a1746014a75ade3a714e1db5763276f",
|
||||
"namespace": "2f4316de49999235636386fe51dc06c1",
|
||||
"namespaces": "2f4316de49999235636386fe51dc06c1",
|
||||
"originId": "2f4316de49999235636386fe51dc06c1",
|
||||
"query": "11aaeb7f5f7fa5bb43f25e18ce26e7d9",
|
||||
"references": "7997cf5a56cc02bdc9c93361bde732b0",
|
||||
"sample-data-telemetry": "7d3cfeb915303c9641c59681967ffeb4",
|
||||
"search": "db2c00e39b36f40930a3b9fc71c823e1",
|
||||
"search-telemetry": "3d1b76c39bfb2cc8296b024d73854724",
|
||||
"telemetry": "36a616f7026dfa617d6655df850fe16d",
|
||||
"timelion-sheet": "9a2a2748877c7a7b582fef201ab1d4cf",
|
||||
"type": "2f4316de49999235636386fe51dc06c1",
|
||||
"ui-counter": "0d409297dc5ebe1e3a1da691c6ee32e3",
|
||||
"ui-metric": "0d409297dc5ebe1e3a1da691c6ee32e3",
|
||||
"updated_at": "00da57df13e94e9d98437d13ace4bfe0",
|
||||
"url": "c7f66a0df8b1b52f17c28c4adb111105",
|
||||
"usage-counters": "8cc260bdceffec4ffc3ad165c97dc1b4",
|
||||
"visualization": "f819cf6636b75c9e76ba733a0c6ef355"
|
||||
}
|
||||
},
|
||||
"dynamic": "strict",
|
||||
"properties": {
|
||||
"application_usage_daily": {
|
||||
"dynamic": "false",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "date"
|
||||
}
|
||||
}
|
||||
},
|
||||
"application_usage_totals": {
|
||||
"dynamic": "false",
|
||||
"type": "object"
|
||||
},
|
||||
"application_usage_transactional": {
|
||||
"dynamic": "false",
|
||||
"type": "object"
|
||||
},
|
||||
"config": {
|
||||
"dynamic": "false",
|
||||
"properties": {
|
||||
"buildNum": {
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
},
|
||||
"unknown-type": {
|
||||
"dynamic": "false",
|
||||
"properties": {
|
||||
"foo": {
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
},
|
||||
"unknown-shareable-type": {
|
||||
"dynamic": "false",
|
||||
"properties": {
|
||||
"foo": {
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
},
|
||||
"core-usage-stats": {
|
||||
"dynamic": "false",
|
||||
"type": "object"
|
||||
},
|
||||
"coreMigrationVersion": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"dashboard": {
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "text"
|
||||
},
|
||||
"hits": {
|
||||
"doc_values": false,
|
||||
"index": false,
|
||||
"type": "integer"
|
||||
},
|
||||
"kibanaSavedObjectMeta": {
|
||||
"properties": {
|
||||
"searchSourceJSON": {
|
||||
"index": false,
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
},
|
||||
"optionsJSON": {
|
||||
"index": false,
|
||||
"type": "text"
|
||||
},
|
||||
"panelsJSON": {
|
||||
"index": false,
|
||||
"type": "text"
|
||||
},
|
||||
"refreshInterval": {
|
||||
"properties": {
|
||||
"display": {
|
||||
"doc_values": false,
|
||||
"index": false,
|
||||
"type": "keyword"
|
||||
},
|
||||
"pause": {
|
||||
"doc_values": false,
|
||||
"index": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"section": {
|
||||
"doc_values": false,
|
||||
"index": false,
|
||||
"type": "integer"
|
||||
},
|
||||
"value": {
|
||||
"doc_values": false,
|
||||
"index": false,
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"timeFrom": {
|
||||
"doc_values": false,
|
||||
"index": false,
|
||||
"type": "keyword"
|
||||
},
|
||||
"timeRestore": {
|
||||
"doc_values": false,
|
||||
"index": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"timeTo": {
|
||||
"doc_values": false,
|
||||
"index": false,
|
||||
"type": "keyword"
|
||||
},
|
||||
"title": {
|
||||
"type": "text"
|
||||
},
|
||||
"version": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"index-pattern": {
|
||||
"dynamic": "false",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "text"
|
||||
},
|
||||
"type": {
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kql-telemetry": {
|
||||
"properties": {
|
||||
"optInCount": {
|
||||
"type": "long"
|
||||
},
|
||||
"optOutCount": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"legacy-url-alias": {
|
||||
"dynamic": "false",
|
||||
"properties": {
|
||||
"disabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"sourceId": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"targetType": {
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
},
|
||||
"migrationVersion": {
|
||||
"dynamic": "true",
|
||||
"properties": {
|
||||
"config": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 256,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
},
|
||||
"dashboard": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 256,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
},
|
||||
"index-pattern": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 256,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
},
|
||||
"search": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 256,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
},
|
||||
"visualization": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 256,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
},
|
||||
"namespace": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"namespaces": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"originId": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"query": {
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "text"
|
||||
},
|
||||
"filters": {
|
||||
"enabled": false,
|
||||
"type": "object"
|
||||
},
|
||||
"query": {
|
||||
"properties": {
|
||||
"language": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"query": {
|
||||
"index": false,
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
},
|
||||
"timefilter": {
|
||||
"enabled": false,
|
||||
"type": "object"
|
||||
},
|
||||
"title": {
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
},
|
||||
"references": {
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"name": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"type": {
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "nested"
|
||||
},
|
||||
"sample-data-telemetry": {
|
||||
"properties": {
|
||||
"installCount": {
|
||||
"type": "long"
|
||||
},
|
||||
"unInstallCount": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"search": {
|
||||
"properties": {
|
||||
"columns": {
|
||||
"doc_values": false,
|
||||
"index": false,
|
||||
"type": "keyword"
|
||||
},
|
||||
"description": {
|
||||
"type": "text"
|
||||
},
|
||||
"grid": {
|
||||
"enabled": false,
|
||||
"type": "object"
|
||||
},
|
||||
"hideChart": {
|
||||
"doc_values": false,
|
||||
"index": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"hits": {
|
||||
"doc_values": false,
|
||||
"index": false,
|
||||
"type": "integer"
|
||||
},
|
||||
"kibanaSavedObjectMeta": {
|
||||
"properties": {
|
||||
"searchSourceJSON": {
|
||||
"index": false,
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sort": {
|
||||
"doc_values": false,
|
||||
"index": false,
|
||||
"type": "keyword"
|
||||
},
|
||||
"title": {
|
||||
"type": "text"
|
||||
},
|
||||
"version": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"search-telemetry": {
|
||||
"dynamic": "false",
|
||||
"type": "object"
|
||||
},
|
||||
"server": {
|
||||
"dynamic": "false",
|
||||
"type": "object"
|
||||
},
|
||||
"telemetry": {
|
||||
"properties": {
|
||||
"allowChangingOptInStatus": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"lastReported": {
|
||||
"type": "date"
|
||||
},
|
||||
"lastVersionChecked": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"reportFailureCount": {
|
||||
"type": "integer"
|
||||
},
|
||||
"reportFailureVersion": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"sendUsageFrom": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"userHasSeenNotice": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"timelion-sheet": {
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "text"
|
||||
},
|
||||
"hits": {
|
||||
"type": "integer"
|
||||
},
|
||||
"kibanaSavedObjectMeta": {
|
||||
"properties": {
|
||||
"searchSourceJSON": {
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
},
|
||||
"timelion_chart_height": {
|
||||
"type": "integer"
|
||||
},
|
||||
"timelion_columns": {
|
||||
"type": "integer"
|
||||
},
|
||||
"timelion_interval": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"timelion_other_interval": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"timelion_rows": {
|
||||
"type": "integer"
|
||||
},
|
||||
"timelion_sheet": {
|
||||
"type": "text"
|
||||
},
|
||||
"title": {
|
||||
"type": "text"
|
||||
},
|
||||
"version": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"ui-counter": {
|
||||
"properties": {
|
||||
"count": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ui-metric": {
|
||||
"properties": {
|
||||
"count": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "date"
|
||||
},
|
||||
"url": {
|
||||
"properties": {
|
||||
"accessCount": {
|
||||
"type": "long"
|
||||
},
|
||||
"accessDate": {
|
||||
"type": "date"
|
||||
},
|
||||
"createDate": {
|
||||
"type": "date"
|
||||
},
|
||||
"url": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 2048,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
},
|
||||
"usage-counters": {
|
||||
"dynamic": "false",
|
||||
"properties": {
|
||||
"domainId": {
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
},
|
||||
"visualization": {
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "text"
|
||||
},
|
||||
"kibanaSavedObjectMeta": {
|
||||
"properties": {
|
||||
"searchSourceJSON": {
|
||||
"index": false,
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
},
|
||||
"savedSearchRefName": {
|
||||
"doc_values": false,
|
||||
"index": false,
|
||||
"type": "keyword"
|
||||
},
|
||||
"title": {
|
||||
"type": "text"
|
||||
},
|
||||
"uiStateJSON": {
|
||||
"index": false,
|
||||
"type": "text"
|
||||
},
|
||||
"version": {
|
||||
"type": "integer"
|
||||
},
|
||||
"visState": {
|
||||
"index": false,
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"index": {
|
||||
"auto_expand_replicas": "0-1",
|
||||
"number_of_replicas": "0",
|
||||
"number_of_shards": "1",
|
||||
"priority": "10",
|
||||
"refresh_interval": "1s",
|
||||
"routing_partition_size": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue