From cfd69b5fe29570ce94801a05a7cbed3721051581 Mon Sep 17 00:00:00 2001 From: cauemarcondes Date: Tue, 22 Feb 2022 13:14:04 -0500 Subject: [PATCH 01/10] new apm indices saved object --- .../apm/common/apm_saved_object_constants.ts | 14 +- x-pack/plugins/apm/server/plugin.ts | 11 +- .../settings/apm_indices/get_apm_indices.ts | 8 +- .../settings/apm_indices/save_apm_indices.ts | 8 +- .../server/saved_objects/apm_indices_space.ts | 35 ++++ .../plugins/apm/server/saved_objects/index.ts | 1 + ..._legacy_apm_indices_to_space_aware.test.ts | 180 ++++++++++++++++++ ...grate_legacy_apm_indices_to_space_aware.ts | 51 +++++ 8 files changed, 298 insertions(+), 10 deletions(-) create mode 100644 x-pack/plugins/apm/server/saved_objects/apm_indices_space.ts create mode 100644 x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.test.ts create mode 100644 x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.ts diff --git a/x-pack/plugins/apm/common/apm_saved_object_constants.ts b/x-pack/plugins/apm/common/apm_saved_object_constants.ts index 7d9e571242afe..f6dcfeef68f9f 100644 --- a/x-pack/plugins/apm/common/apm_saved_object_constants.ts +++ b/x-pack/plugins/apm/common/apm_saved_object_constants.ts @@ -8,10 +8,22 @@ // the types have to match the names of the saved object mappings // in /x-pack/plugins/apm/mappings.json -// APM indices +// APM indices (legacy) +/** + * Should use APM_INDICES_SPACE_SAVED_OBJECT_TYPE instead + * @deprecated + * */ export const APM_INDICES_SAVED_OBJECT_TYPE = 'apm-indices'; +/** + * Should use APM_INDICES_SPACE_SAVED_OBJECT_ID instead + * @deprecated + * */ export const APM_INDICES_SAVED_OBJECT_ID = 'apm-indices'; +// APM indices (space aware) +export const APM_INDICES_SPACE_SAVED_OBJECT_TYPE = 'apm-indices-space'; +export const APM_INDICES_SPACE_SAVED_OBJECT_ID = 'apm-indices-space'; + // APM telemetry export const APM_TELEMETRY_SAVED_OBJECT_TYPE = 'apm-telemetry'; export const APM_TELEMETRY_SAVED_OBJECT_ID = 'apm-telemetry'; diff --git a/x-pack/plugins/apm/server/plugin.ts b/x-pack/plugins/apm/server/plugin.ts index e5ad2cb6c6c1f..aa4153d5351d7 100644 --- a/x-pack/plugins/apm/server/plugin.ts +++ b/x-pack/plugins/apm/server/plugin.ts @@ -29,7 +29,12 @@ import { getInternalSavedObjectsClient } from './lib/helpers/get_internal_saved_ import { createApmAgentConfigurationIndex } from './routes/settings/agent_configuration/create_agent_config_index'; import { getApmIndices } from './routes/settings/apm_indices/get_apm_indices'; import { createApmCustomLinkIndex } from './routes/settings/custom_link/create_custom_link_index'; -import { apmIndices, apmTelemetry, apmServerSettings } from './saved_objects'; +import { + apmIndices, + apmTelemetry, + apmServerSettings, + apmIndicesSpace, +} from './saved_objects'; import type { ApmPluginRequestHandlerContext, APMRouteHandlerResources, @@ -48,6 +53,7 @@ import { TRANSACTION_TYPE, } from '../common/elasticsearch_fieldnames'; import { tutorialProvider } from './tutorial'; +import { migrateLegacyAPMIndicesToSpaceAware } from './saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware'; export class APMPlugin implements @@ -72,6 +78,7 @@ export class APMPlugin const config$ = this.initContext.config.create(); core.savedObjects.registerType(apmIndices); + core.savedObjects.registerType(apmIndicesSpace); core.savedObjects.registerType(apmTelemetry); core.savedObjects.registerType(apmServerSettings); @@ -247,6 +254,8 @@ export class APMPlugin config: this.currentConfig, logger: this.logger, }); + + migrateLegacyAPMIndicesToSpaceAware({ coreStart: core }); } public stop() {} diff --git a/x-pack/plugins/apm/server/routes/settings/apm_indices/get_apm_indices.ts b/x-pack/plugins/apm/server/routes/settings/apm_indices/get_apm_indices.ts index 450ce3fa18dad..79889724f32c3 100644 --- a/x-pack/plugins/apm/server/routes/settings/apm_indices/get_apm_indices.ts +++ b/x-pack/plugins/apm/server/routes/settings/apm_indices/get_apm_indices.ts @@ -7,8 +7,8 @@ import { SavedObjectsClient } from 'src/core/server'; import { - APM_INDICES_SAVED_OBJECT_TYPE, - APM_INDICES_SAVED_OBJECT_ID, + APM_INDICES_SPACE_SAVED_OBJECT_TYPE, + APM_INDICES_SPACE_SAVED_OBJECT_ID, } from '../../../../common/apm_saved_object_constants'; import { APMConfig } from '../../..'; import { APMRouteHandlerResources } from '../../typings'; @@ -24,8 +24,8 @@ async function getApmIndicesSavedObject( ) { const apmIndices = await withApmSpan('get_apm_indices_saved_object', () => savedObjectsClient.get>( - APM_INDICES_SAVED_OBJECT_TYPE, - APM_INDICES_SAVED_OBJECT_ID + APM_INDICES_SPACE_SAVED_OBJECT_TYPE, + APM_INDICES_SPACE_SAVED_OBJECT_ID ) ); return apmIndices.attributes; diff --git a/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.ts b/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.ts index 14a5830d8246c..03e951ddf8419 100644 --- a/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.ts +++ b/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.ts @@ -7,8 +7,8 @@ import { SavedObjectsClientContract } from '../../../../../../../src/core/server'; import { - APM_INDICES_SAVED_OBJECT_TYPE, - APM_INDICES_SAVED_OBJECT_ID, + APM_INDICES_SPACE_SAVED_OBJECT_TYPE, + APM_INDICES_SPACE_SAVED_OBJECT_ID, } from '../../../../common/apm_saved_object_constants'; import { withApmSpan } from '../../../utils/with_apm_span'; import { ApmIndicesConfig } from './get_apm_indices'; @@ -19,10 +19,10 @@ export function saveApmIndices( ) { return withApmSpan('save_apm_indices', () => savedObjectsClient.create( - APM_INDICES_SAVED_OBJECT_TYPE, + APM_INDICES_SPACE_SAVED_OBJECT_TYPE, removeEmpty(apmIndices), { - id: APM_INDICES_SAVED_OBJECT_ID, + id: APM_INDICES_SPACE_SAVED_OBJECT_ID, overwrite: true, } ) diff --git a/x-pack/plugins/apm/server/saved_objects/apm_indices_space.ts b/x-pack/plugins/apm/server/saved_objects/apm_indices_space.ts new file mode 100644 index 0000000000000..f2d9d09f67d2a --- /dev/null +++ b/x-pack/plugins/apm/server/saved_objects/apm_indices_space.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { SavedObjectsType } from 'src/core/server'; +import { i18n } from '@kbn/i18n'; +import { ApmIndicesConfigName } from '..'; + +const properties: { [Property in ApmIndicesConfigName]: { type: 'keyword' } } = + { + sourcemap: { type: 'keyword' }, + error: { type: 'keyword' }, + onboarding: { type: 'keyword' }, + span: { type: 'keyword' }, + transaction: { type: 'keyword' }, + metric: { type: 'keyword' }, + }; + +export const apmIndicesSpace: SavedObjectsType = { + name: 'apm-indices-space', + hidden: false, + namespaceType: 'single', + mappings: { properties }, + management: { + importableAndExportable: true, + icon: 'apmApp', + getTitle: () => + i18n.translate('xpack.apm.apmSettings.index', { + defaultMessage: 'APM Settings - Index', + }), + }, +}; diff --git a/x-pack/plugins/apm/server/saved_objects/index.ts b/x-pack/plugins/apm/server/saved_objects/index.ts index ba4285a238968..8bc705061f208 100644 --- a/x-pack/plugins/apm/server/saved_objects/index.ts +++ b/x-pack/plugins/apm/server/saved_objects/index.ts @@ -8,3 +8,4 @@ export { apmIndices } from './apm_indices'; export { apmTelemetry } from './apm_telemetry'; export { apmServerSettings } from './apm_server_settings'; +export { apmIndicesSpace } from './apm_indices_space'; diff --git a/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.test.ts b/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.test.ts new file mode 100644 index 0000000000000..b86727554d9af --- /dev/null +++ b/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.test.ts @@ -0,0 +1,180 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { CoreStart } from 'src/core/server'; +import { + APM_INDICES_SPACE_SAVED_OBJECT_ID, + APM_INDICES_SPACE_SAVED_OBJECT_TYPE, +} from '../../../common/apm_saved_object_constants'; +import { migrateLegacyAPMIndicesToSpaceAware } from './migrate_legacy_apm_indices_to_space_aware'; + +describe('migrateLegacyAPMIndicesToSpaceAware', () => { + describe('when legacy APM indices is not found', () => { + const mockBulkCreate = jest.fn(); + const mockFind = jest.fn(); + const core = { + savedObjects: { + createInternalRepository: jest.fn().mockReturnValue({ + get: () => { + throw new Error('BOOM'); + }, + find: mockFind, + bulkCreate: mockBulkCreate, + }), + }, + } as unknown as CoreStart; + + it('does not save any new saved object', () => { + migrateLegacyAPMIndicesToSpaceAware({ coreStart: core }); + expect(mockFind).not.toHaveBeenCalled(); + expect(mockBulkCreate).not.toHaveBeenCalled(); + }); + }); + + describe('when only default space is available', () => { + const mockBulkCreate = jest.fn(); + const mockSpaceFind = jest.fn().mockReturnValue({ + page: 1, + per_page: 10000, + total: 3, + saved_objects: [ + { + type: 'space', + id: 'default', + attributes: { + name: 'Default', + }, + references: [], + migrationVersion: { + space: '6.6.0', + }, + coreMigrationVersion: '8.2.0', + updated_at: '2022-02-22T14:13:28.839Z', + version: 'WzI4OSwxXQ==', + score: 0, + }, + ], + }); + const core = { + savedObjects: { + createInternalRepository: jest.fn().mockReturnValue({ + get: jest.fn().mockReturnValue({ + id: 'apm-indices', + type: 'apm-indices', + namespaces: [], + updated_at: '2022-02-22T14:17:10.584Z', + version: 'WzE1OSwxXQ==', + attributes: { + transaction: 'default-apm-*', + span: 'default-apm-*', + error: 'default-apm-*', + metric: 'default-apm-*', + sourcemap: 'default-apm-*', + onboarding: 'default-apm-*', + }, + references: [], + migrationVersion: { + 'apm-indices': '7.16.0', + }, + coreMigrationVersion: '8.2.0', + }), + find: mockSpaceFind, + bulkCreate: mockBulkCreate, + }), + }, + } as unknown as CoreStart; + it('creates new default saved object with space awareness and delete legacy', async () => { + await migrateLegacyAPMIndicesToSpaceAware({ coreStart: core }); + expect(mockBulkCreate).toBeCalledWith([ + { + type: APM_INDICES_SPACE_SAVED_OBJECT_TYPE, + id: APM_INDICES_SPACE_SAVED_OBJECT_ID, + initialNamespaces: ['default'], + attributes: { + transaction: 'default-apm-*', + span: 'default-apm-*', + error: 'default-apm-*', + metric: 'default-apm-*', + sourcemap: 'default-apm-*', + onboarding: 'default-apm-*', + }, + }, + ]); + }); + }); + + describe('when multiple spaces are found', () => { + const mockBulkCreate = jest.fn(); + const mockDelete = jest.fn(); + const savedObjects = [ + { id: 'default', name: 'Default' }, + { id: 'space-a', name: 'Space A' }, + { id: 'space-b', name: 'Space B' }, + ]; + const mockSpaceFind = jest.fn().mockReturnValue({ + page: 1, + per_page: 10000, + total: 3, + saved_objects: savedObjects.map(({ id, name }) => { + return { + type: 'space', + id, + attributes: { name }, + references: [], + migrationVersion: { space: '6.6.0' }, + coreMigrationVersion: '8.2.0', + updated_at: '2022-02-22T14:13:28.839Z', + version: 'WzI4OSwxXQ==', + score: 0, + }; + }), + }); + const attributes = { + transaction: 'space-apm-*', + span: 'space-apm-*', + error: 'space-apm-*', + metric: 'space-apm-*', + sourcemap: 'space-apm-*', + onboarding: 'space-apm-*', + }; + const core = { + savedObjects: { + createInternalRepository: jest.fn().mockReturnValue({ + get: jest.fn().mockReturnValue({ + id: 'apm-indices', + type: 'apm-indices', + namespaces: [], + updated_at: '2022-02-22T14:17:10.584Z', + version: 'WzE1OSwxXQ==', + attributes, + references: [], + migrationVersion: { + 'apm-indices': '7.16.0', + }, + coreMigrationVersion: '8.2.0', + }), + find: mockSpaceFind, + bulkCreate: mockBulkCreate, + delete: mockDelete, + }), + }, + } as unknown as CoreStart; + it('creates multiple saved objects with space awareness and delete legacies', async () => { + await migrateLegacyAPMIndicesToSpaceAware({ coreStart: core }); + expect(mockBulkCreate).toBeCalledWith( + savedObjects.map(({ id }) => { + return { + type: APM_INDICES_SPACE_SAVED_OBJECT_TYPE, + id: APM_INDICES_SPACE_SAVED_OBJECT_ID, + initialNamespaces: [id], + attributes, + }; + }) + ); + expect(mockDelete).toHaveBeenCalled(); + }); + }); +}); diff --git a/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.ts b/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.ts new file mode 100644 index 0000000000000..b8486e476b84c --- /dev/null +++ b/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.ts @@ -0,0 +1,51 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { CoreStart } from 'src/core/server'; +import { + APM_INDICES_SAVED_OBJECT_ID, + APM_INDICES_SAVED_OBJECT_TYPE, + APM_INDICES_SPACE_SAVED_OBJECT_ID, + APM_INDICES_SPACE_SAVED_OBJECT_TYPE, +} from '../../../common/apm_saved_object_constants'; +import { ApmIndicesConfig } from '../../routes/settings/apm_indices/get_apm_indices'; + +export async function migrateLegacyAPMIndicesToSpaceAware({ + coreStart, +}: { + coreStart: CoreStart; +}) { + const repository = coreStart.savedObjects.createInternalRepository(['space']); + try { + const legacyAPMIndices = await repository.get>( + APM_INDICES_SAVED_OBJECT_TYPE, + APM_INDICES_SAVED_OBJECT_ID + ); + + const spaces = await repository.find({ + type: 'space', + page: 1, + perPage: 10_000, // max number of spaces as of 8.1 + fields: ['name'], // to avoid fetching *all* fields + }); + + await repository.bulkCreate( + spaces.saved_objects.map(({ id: spaceId }) => ({ + id: APM_INDICES_SPACE_SAVED_OBJECT_ID, + type: APM_INDICES_SPACE_SAVED_OBJECT_TYPE, + initialNamespaces: [spaceId], + attributes: legacyAPMIndices.attributes, + })) + ); + + await repository.delete( + APM_INDICES_SAVED_OBJECT_TYPE, + APM_INDICES_SAVED_OBJECT_ID + ); + } catch (e) { + // Does nothing when an exception happens (repository.get throws an exception when an saved object is not found) + } +} From 050c4260b08b1e35fe832c56df019e3ae18ba4e5 Mon Sep 17 00:00:00 2001 From: cauemarcondes Date: Tue, 22 Feb 2022 13:36:24 -0500 Subject: [PATCH 02/10] adding some comments --- .../migrations/migrate_legacy_apm_indices_to_space_aware.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.ts b/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.ts index b8486e476b84c..5d6c4c012af53 100644 --- a/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.ts +++ b/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.ts @@ -20,11 +20,13 @@ export async function migrateLegacyAPMIndicesToSpaceAware({ }) { const repository = coreStart.savedObjects.createInternalRepository(['space']); try { + // Fetch legacy APM indices const legacyAPMIndices = await repository.get>( APM_INDICES_SAVED_OBJECT_TYPE, APM_INDICES_SAVED_OBJECT_ID ); + // Fetch spaces available const spaces = await repository.find({ type: 'space', page: 1, @@ -32,6 +34,7 @@ export async function migrateLegacyAPMIndicesToSpaceAware({ fields: ['name'], // to avoid fetching *all* fields }); + // Create new APM indices space aware for all spaces available await repository.bulkCreate( spaces.saved_objects.map(({ id: spaceId }) => ({ id: APM_INDICES_SPACE_SAVED_OBJECT_ID, @@ -41,6 +44,7 @@ export async function migrateLegacyAPMIndicesToSpaceAware({ })) ); + // Delete legacy APM indices await repository.delete( APM_INDICES_SAVED_OBJECT_TYPE, APM_INDICES_SAVED_OBJECT_ID From 15ae67a13a60fbc4c9a28d1159dd7ca0326108e9 Mon Sep 17 00:00:00 2001 From: cauemarcondes Date: Tue, 22 Feb 2022 13:38:23 -0500 Subject: [PATCH 03/10] fixing typo --- .../migrations/migrate_legacy_apm_indices_to_space_aware.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.ts b/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.ts index 5d6c4c012af53..a5c7401d61bbe 100644 --- a/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.ts +++ b/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.ts @@ -50,6 +50,6 @@ export async function migrateLegacyAPMIndicesToSpaceAware({ APM_INDICES_SAVED_OBJECT_ID ); } catch (e) { - // Does nothing when an exception happens (repository.get throws an exception when an saved object is not found) + // Does nothing when an exception happens (repository.get throws an exception when a saved object is not found) } } From b6d153508250c3e982762de0bf6d2a1b12dcf44a Mon Sep 17 00:00:00 2001 From: cauemarcondes Date: Tue, 22 Feb 2022 15:12:30 -0500 Subject: [PATCH 04/10] addressing PR comments --- .../apm/common/apm_saved_object_constants.ts | 18 +---- x-pack/plugins/apm/server/plugin.ts | 5 +- .../settings/apm_indices/get_apm_indices.ts | 8 +-- .../settings/apm_indices/save_apm_indices.ts | 8 +-- ...grate_legacy_apm_indices_to_space_aware.ts | 71 ++++++++++++++----- 5 files changed, 70 insertions(+), 40 deletions(-) diff --git a/x-pack/plugins/apm/common/apm_saved_object_constants.ts b/x-pack/plugins/apm/common/apm_saved_object_constants.ts index f6dcfeef68f9f..83d7bc72e058d 100644 --- a/x-pack/plugins/apm/common/apm_saved_object_constants.ts +++ b/x-pack/plugins/apm/common/apm_saved_object_constants.ts @@ -8,21 +8,9 @@ // the types have to match the names of the saved object mappings // in /x-pack/plugins/apm/mappings.json -// APM indices (legacy) -/** - * Should use APM_INDICES_SPACE_SAVED_OBJECT_TYPE instead - * @deprecated - * */ -export const APM_INDICES_SAVED_OBJECT_TYPE = 'apm-indices'; -/** - * Should use APM_INDICES_SPACE_SAVED_OBJECT_ID instead - * @deprecated - * */ -export const APM_INDICES_SAVED_OBJECT_ID = 'apm-indices'; - -// APM indices (space aware) -export const APM_INDICES_SPACE_SAVED_OBJECT_TYPE = 'apm-indices-space'; -export const APM_INDICES_SPACE_SAVED_OBJECT_ID = 'apm-indices-space'; +// APM index settings +export const APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE = 'apm-index-settings'; +export const APM_INDEX_SETTINGS_SAVED_OBJECT_ID = 'apm-index-settings'; // APM telemetry export const APM_TELEMETRY_SAVED_OBJECT_TYPE = 'apm-telemetry'; diff --git a/x-pack/plugins/apm/server/plugin.ts b/x-pack/plugins/apm/server/plugin.ts index aa4153d5351d7..37c774189f059 100644 --- a/x-pack/plugins/apm/server/plugin.ts +++ b/x-pack/plugins/apm/server/plugin.ts @@ -255,7 +255,10 @@ export class APMPlugin logger: this.logger, }); - migrateLegacyAPMIndicesToSpaceAware({ coreStart: core }); + migrateLegacyAPMIndicesToSpaceAware({ + coreStart: core, + logger: this.logger, + }); } public stop() {} diff --git a/x-pack/plugins/apm/server/routes/settings/apm_indices/get_apm_indices.ts b/x-pack/plugins/apm/server/routes/settings/apm_indices/get_apm_indices.ts index 79889724f32c3..e0b63ba6a2f8c 100644 --- a/x-pack/plugins/apm/server/routes/settings/apm_indices/get_apm_indices.ts +++ b/x-pack/plugins/apm/server/routes/settings/apm_indices/get_apm_indices.ts @@ -7,8 +7,8 @@ import { SavedObjectsClient } from 'src/core/server'; import { - APM_INDICES_SPACE_SAVED_OBJECT_TYPE, - APM_INDICES_SPACE_SAVED_OBJECT_ID, + APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, + APM_INDEX_SETTINGS_SAVED_OBJECT_ID, } from '../../../../common/apm_saved_object_constants'; import { APMConfig } from '../../..'; import { APMRouteHandlerResources } from '../../typings'; @@ -24,8 +24,8 @@ async function getApmIndicesSavedObject( ) { const apmIndices = await withApmSpan('get_apm_indices_saved_object', () => savedObjectsClient.get>( - APM_INDICES_SPACE_SAVED_OBJECT_TYPE, - APM_INDICES_SPACE_SAVED_OBJECT_ID + APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, + APM_INDEX_SETTINGS_SAVED_OBJECT_ID ) ); return apmIndices.attributes; diff --git a/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.ts b/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.ts index 03e951ddf8419..316bf9910b363 100644 --- a/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.ts +++ b/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.ts @@ -7,8 +7,8 @@ import { SavedObjectsClientContract } from '../../../../../../../src/core/server'; import { - APM_INDICES_SPACE_SAVED_OBJECT_TYPE, - APM_INDICES_SPACE_SAVED_OBJECT_ID, + APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, + APM_INDEX_SETTINGS_SAVED_OBJECT_ID, } from '../../../../common/apm_saved_object_constants'; import { withApmSpan } from '../../../utils/with_apm_span'; import { ApmIndicesConfig } from './get_apm_indices'; @@ -19,10 +19,10 @@ export function saveApmIndices( ) { return withApmSpan('save_apm_indices', () => savedObjectsClient.create( - APM_INDICES_SPACE_SAVED_OBJECT_TYPE, + APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, removeEmpty(apmIndices), { - id: APM_INDICES_SPACE_SAVED_OBJECT_ID, + id: APM_INDEX_SETTINGS_SAVED_OBJECT_ID, overwrite: true, } ) diff --git a/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.ts b/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.ts index a5c7401d61bbe..201cce16547fc 100644 --- a/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.ts +++ b/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.ts @@ -4,41 +4,80 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { CoreStart } from 'src/core/server'; +import type { + CoreStart, + Logger, + ISavedObjectsRepository, +} from 'src/core/server'; +import { SavedObjectsErrorHelpers } from 'src/core/server'; import { - APM_INDICES_SAVED_OBJECT_ID, - APM_INDICES_SAVED_OBJECT_TYPE, - APM_INDICES_SPACE_SAVED_OBJECT_ID, - APM_INDICES_SPACE_SAVED_OBJECT_TYPE, + APM_INDEX_SETTINGS_SAVED_OBJECT_ID, + APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, } from '../../../common/apm_saved_object_constants'; import { ApmIndicesConfig } from '../../routes/settings/apm_indices/get_apm_indices'; +// Legacy APM indices saved objects +const APM_INDICES_LEGACY_SAVED_OBJECT_TYPE = 'apm-indices'; +const APM_INDICES_LEGACY_SAVED_OBJECT_ID = 'apm-indices'; + +/** + * Legacy APM indices config object attributes (pre-8.2). + * We need to keep a snapshot of this interface to guard against any incompatible ApmIndicesConfig interface changes in the future. + */ +interface LegacyApmIndicesConfig { + sourcemap: string; + error: string; + onboarding: string; + span: string; + transaction: string; + metric: string; + apmAgentConfigurationIndex: string; + apmCustomLinkIndex: string; +} + +async function fetchLegacyAPMIndices(repository: ISavedObjectsRepository) { + try { + const legacyAPMIndices = await repository.get< + Partial + >(APM_INDICES_LEGACY_SAVED_OBJECT_TYPE, APM_INDICES_LEGACY_SAVED_OBJECT_ID); + return legacyAPMIndices; + } catch (err) { + if (SavedObjectsErrorHelpers.isNotFoundError(err)) { + // This is expected after the legacy APM indices object has been migrated for the first time. + return null; + } + throw err; + } +} + export async function migrateLegacyAPMIndicesToSpaceAware({ coreStart, + logger, }: { coreStart: CoreStart; + logger: Logger; }) { const repository = coreStart.savedObjects.createInternalRepository(['space']); try { // Fetch legacy APM indices - const legacyAPMIndices = await repository.get>( - APM_INDICES_SAVED_OBJECT_TYPE, - APM_INDICES_SAVED_OBJECT_ID - ); + const legacyAPMIndices = await fetchLegacyAPMIndices(repository); + if (legacyAPMIndices === null) { + return; + } // Fetch spaces available const spaces = await repository.find({ type: 'space', page: 1, - perPage: 10_000, // max number of spaces as of 8.1 + perPage: 10_000, // max number of spaces as of 8.2 fields: ['name'], // to avoid fetching *all* fields }); // Create new APM indices space aware for all spaces available - await repository.bulkCreate( + await repository.bulkCreate>( spaces.saved_objects.map(({ id: spaceId }) => ({ - id: APM_INDICES_SPACE_SAVED_OBJECT_ID, - type: APM_INDICES_SPACE_SAVED_OBJECT_TYPE, + id: APM_INDEX_SETTINGS_SAVED_OBJECT_ID, + type: APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, initialNamespaces: [spaceId], attributes: legacyAPMIndices.attributes, })) @@ -46,10 +85,10 @@ export async function migrateLegacyAPMIndicesToSpaceAware({ // Delete legacy APM indices await repository.delete( - APM_INDICES_SAVED_OBJECT_TYPE, - APM_INDICES_SAVED_OBJECT_ID + APM_INDICES_LEGACY_SAVED_OBJECT_TYPE, + APM_INDICES_LEGACY_SAVED_OBJECT_ID ); } catch (e) { - // Does nothing when an exception happens (repository.get throws an exception when a saved object is not found) + logger.error('Failed to migrate legacy APM indices object: ' + e.message); } } From b1d0f04cbde41f90c31f89fb0be9e92ee800851f Mon Sep 17 00:00:00 2001 From: cauemarcondes Date: Tue, 22 Feb 2022 15:23:03 -0500 Subject: [PATCH 05/10] fixing tests --- ..._legacy_apm_indices_to_space_aware.test.ts | 35 +++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.test.ts b/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.test.ts index b86727554d9af..4358aa4353cd2 100644 --- a/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.test.ts +++ b/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.test.ts @@ -4,13 +4,19 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { CoreStart } from 'src/core/server'; +import type { CoreStart, Logger } from 'src/core/server'; import { - APM_INDICES_SPACE_SAVED_OBJECT_ID, - APM_INDICES_SPACE_SAVED_OBJECT_TYPE, + APM_INDEX_SETTINGS_SAVED_OBJECT_ID, + APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, } from '../../../common/apm_saved_object_constants'; import { migrateLegacyAPMIndicesToSpaceAware } from './migrate_legacy_apm_indices_to_space_aware'; +const loggerMock = { + debug: jest.fn(), + warn: jest.fn(), + error: jest.fn(), +} as unknown as Logger; + describe('migrateLegacyAPMIndicesToSpaceAware', () => { describe('when legacy APM indices is not found', () => { const mockBulkCreate = jest.fn(); @@ -28,7 +34,10 @@ describe('migrateLegacyAPMIndicesToSpaceAware', () => { } as unknown as CoreStart; it('does not save any new saved object', () => { - migrateLegacyAPMIndicesToSpaceAware({ coreStart: core }); + migrateLegacyAPMIndicesToSpaceAware({ + coreStart: core, + logger: loggerMock, + }); expect(mockFind).not.toHaveBeenCalled(); expect(mockBulkCreate).not.toHaveBeenCalled(); }); @@ -87,11 +96,14 @@ describe('migrateLegacyAPMIndicesToSpaceAware', () => { }, } as unknown as CoreStart; it('creates new default saved object with space awareness and delete legacy', async () => { - await migrateLegacyAPMIndicesToSpaceAware({ coreStart: core }); + await migrateLegacyAPMIndicesToSpaceAware({ + coreStart: core, + logger: loggerMock, + }); expect(mockBulkCreate).toBeCalledWith([ { - type: APM_INDICES_SPACE_SAVED_OBJECT_TYPE, - id: APM_INDICES_SPACE_SAVED_OBJECT_ID, + type: APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, + id: APM_INDEX_SETTINGS_SAVED_OBJECT_ID, initialNamespaces: ['default'], attributes: { transaction: 'default-apm-*', @@ -163,12 +175,15 @@ describe('migrateLegacyAPMIndicesToSpaceAware', () => { }, } as unknown as CoreStart; it('creates multiple saved objects with space awareness and delete legacies', async () => { - await migrateLegacyAPMIndicesToSpaceAware({ coreStart: core }); + await migrateLegacyAPMIndicesToSpaceAware({ + coreStart: core, + logger: loggerMock, + }); expect(mockBulkCreate).toBeCalledWith( savedObjects.map(({ id }) => { return { - type: APM_INDICES_SPACE_SAVED_OBJECT_TYPE, - id: APM_INDICES_SPACE_SAVED_OBJECT_ID, + type: APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, + id: APM_INDEX_SETTINGS_SAVED_OBJECT_ID, initialNamespaces: [id], attributes, }; From 5041281b067bd2d0c4da0a37b8fa13c137667148 Mon Sep 17 00:00:00 2001 From: cauemarcondes Date: Wed, 23 Feb 2022 11:19:33 -0500 Subject: [PATCH 06/10] addressing PR comments --- .../apm/common/apm_saved_object_constants.ts | 4 +- x-pack/plugins/apm/server/plugin.ts | 8 +-- .../settings/apm_indices/get_apm_indices.ts | 10 +-- .../settings/apm_indices/save_apm_indices.ts | 7 +- .../apm/server/saved_objects/apm_indices.ts | 24 ++++--- .../server/saved_objects/apm_indices_space.ts | 35 --------- .../plugins/apm/server/saved_objects/index.ts | 1 - ...grate_legacy_apm_indices_to_space_aware.ts | 71 +++++++++---------- 8 files changed, 57 insertions(+), 103 deletions(-) delete mode 100644 x-pack/plugins/apm/server/saved_objects/apm_indices_space.ts diff --git a/x-pack/plugins/apm/common/apm_saved_object_constants.ts b/x-pack/plugins/apm/common/apm_saved_object_constants.ts index 83d7bc72e058d..17c5a802a440a 100644 --- a/x-pack/plugins/apm/common/apm_saved_object_constants.ts +++ b/x-pack/plugins/apm/common/apm_saved_object_constants.ts @@ -9,8 +9,8 @@ // in /x-pack/plugins/apm/mappings.json // APM index settings -export const APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE = 'apm-index-settings'; -export const APM_INDEX_SETTINGS_SAVED_OBJECT_ID = 'apm-index-settings'; +export const APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE = 'apm-indices'; +export const APM_INDEX_SETTINGS_SAVED_OBJECT_ID = 'apm-indices'; // APM telemetry export const APM_TELEMETRY_SAVED_OBJECT_TYPE = 'apm-telemetry'; diff --git a/x-pack/plugins/apm/server/plugin.ts b/x-pack/plugins/apm/server/plugin.ts index 37c774189f059..34a09fe57a05b 100644 --- a/x-pack/plugins/apm/server/plugin.ts +++ b/x-pack/plugins/apm/server/plugin.ts @@ -29,12 +29,7 @@ import { getInternalSavedObjectsClient } from './lib/helpers/get_internal_saved_ import { createApmAgentConfigurationIndex } from './routes/settings/agent_configuration/create_agent_config_index'; import { getApmIndices } from './routes/settings/apm_indices/get_apm_indices'; import { createApmCustomLinkIndex } from './routes/settings/custom_link/create_custom_link_index'; -import { - apmIndices, - apmTelemetry, - apmServerSettings, - apmIndicesSpace, -} from './saved_objects'; +import { apmIndices, apmTelemetry, apmServerSettings } from './saved_objects'; import type { ApmPluginRequestHandlerContext, APMRouteHandlerResources, @@ -78,7 +73,6 @@ export class APMPlugin const config$ = this.initContext.config.create(); core.savedObjects.registerType(apmIndices); - core.savedObjects.registerType(apmIndicesSpace); core.savedObjects.registerType(apmTelemetry); core.savedObjects.registerType(apmServerSettings); diff --git a/x-pack/plugins/apm/server/routes/settings/apm_indices/get_apm_indices.ts b/x-pack/plugins/apm/server/routes/settings/apm_indices/get_apm_indices.ts index e0b63ba6a2f8c..0b10a41b23459 100644 --- a/x-pack/plugins/apm/server/routes/settings/apm_indices/get_apm_indices.ts +++ b/x-pack/plugins/apm/server/routes/settings/apm_indices/get_apm_indices.ts @@ -23,12 +23,12 @@ async function getApmIndicesSavedObject( savedObjectsClient: ISavedObjectsClient ) { const apmIndices = await withApmSpan('get_apm_indices_saved_object', () => - savedObjectsClient.get>( - APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, - APM_INDEX_SETTINGS_SAVED_OBJECT_ID - ) + savedObjectsClient.get< + Partial + >(APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, APM_INDEX_SETTINGS_SAVED_OBJECT_ID) ); - return apmIndices.attributes; + const { isSpaceAware, ...attributes } = apmIndices.attributes; + return attributes; } export function getApmIndicesConfig(config: APMConfig): ApmIndicesConfig { diff --git a/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.ts b/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.ts index 316bf9910b363..2f5db06138f38 100644 --- a/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.ts +++ b/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.ts @@ -20,11 +20,8 @@ export function saveApmIndices( return withApmSpan('save_apm_indices', () => savedObjectsClient.create( APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, - removeEmpty(apmIndices), - { - id: APM_INDEX_SETTINGS_SAVED_OBJECT_ID, - overwrite: true, - } + { ...removeEmpty(apmIndices), isSpaceAware: true }, + { id: APM_INDEX_SETTINGS_SAVED_OBJECT_ID, overwrite: true } ) ); } diff --git a/x-pack/plugins/apm/server/saved_objects/apm_indices.ts b/x-pack/plugins/apm/server/saved_objects/apm_indices.ts index 4aa6c4953056a..c1973243b7d9b 100644 --- a/x-pack/plugins/apm/server/saved_objects/apm_indices.ts +++ b/x-pack/plugins/apm/server/saved_objects/apm_indices.ts @@ -10,20 +10,24 @@ import { i18n } from '@kbn/i18n'; import { updateApmOssIndexPaths } from './migrations/update_apm_oss_index_paths'; import { ApmIndicesConfigName } from '..'; -const properties: { [Property in ApmIndicesConfigName]: { type: 'keyword' } } = - { - sourcemap: { type: 'keyword' }, - error: { type: 'keyword' }, - onboarding: { type: 'keyword' }, - span: { type: 'keyword' }, - transaction: { type: 'keyword' }, - metric: { type: 'keyword' }, - }; +const properties: { + [Property in ApmIndicesConfigName]: { type: 'keyword' }; +} & { + isSpaceAware: { type: 'boolean' }; +} = { + sourcemap: { type: 'keyword' }, + error: { type: 'keyword' }, + onboarding: { type: 'keyword' }, + span: { type: 'keyword' }, + transaction: { type: 'keyword' }, + metric: { type: 'keyword' }, + isSpaceAware: { type: 'boolean' }, +}; export const apmIndices: SavedObjectsType = { name: 'apm-indices', hidden: false, - namespaceType: 'agnostic', + namespaceType: 'single', mappings: { properties }, management: { importableAndExportable: true, diff --git a/x-pack/plugins/apm/server/saved_objects/apm_indices_space.ts b/x-pack/plugins/apm/server/saved_objects/apm_indices_space.ts deleted file mode 100644 index f2d9d09f67d2a..0000000000000 --- a/x-pack/plugins/apm/server/saved_objects/apm_indices_space.ts +++ /dev/null @@ -1,35 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { SavedObjectsType } from 'src/core/server'; -import { i18n } from '@kbn/i18n'; -import { ApmIndicesConfigName } from '..'; - -const properties: { [Property in ApmIndicesConfigName]: { type: 'keyword' } } = - { - sourcemap: { type: 'keyword' }, - error: { type: 'keyword' }, - onboarding: { type: 'keyword' }, - span: { type: 'keyword' }, - transaction: { type: 'keyword' }, - metric: { type: 'keyword' }, - }; - -export const apmIndicesSpace: SavedObjectsType = { - name: 'apm-indices-space', - hidden: false, - namespaceType: 'single', - mappings: { properties }, - management: { - importableAndExportable: true, - icon: 'apmApp', - getTitle: () => - i18n.translate('xpack.apm.apmSettings.index', { - defaultMessage: 'APM Settings - Index', - }), - }, -}; diff --git a/x-pack/plugins/apm/server/saved_objects/index.ts b/x-pack/plugins/apm/server/saved_objects/index.ts index 8bc705061f208..ba4285a238968 100644 --- a/x-pack/plugins/apm/server/saved_objects/index.ts +++ b/x-pack/plugins/apm/server/saved_objects/index.ts @@ -8,4 +8,3 @@ export { apmIndices } from './apm_indices'; export { apmTelemetry } from './apm_telemetry'; export { apmServerSettings } from './apm_server_settings'; -export { apmIndicesSpace } from './apm_indices_space'; diff --git a/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.ts b/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.ts index 201cce16547fc..21b56a1cf23ed 100644 --- a/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.ts +++ b/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.ts @@ -9,41 +9,26 @@ import type { Logger, ISavedObjectsRepository, } from 'src/core/server'; -import { SavedObjectsErrorHelpers } from 'src/core/server'; +import { SavedObjectsErrorHelpers } from '../../../../../../src/core/server'; import { APM_INDEX_SETTINGS_SAVED_OBJECT_ID, APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, } from '../../../common/apm_saved_object_constants'; import { ApmIndicesConfig } from '../../routes/settings/apm_indices/get_apm_indices'; -// Legacy APM indices saved objects -const APM_INDICES_LEGACY_SAVED_OBJECT_TYPE = 'apm-indices'; -const APM_INDICES_LEGACY_SAVED_OBJECT_ID = 'apm-indices'; - -/** - * Legacy APM indices config object attributes (pre-8.2). - * We need to keep a snapshot of this interface to guard against any incompatible ApmIndicesConfig interface changes in the future. - */ -interface LegacyApmIndicesConfig { - sourcemap: string; - error: string; - onboarding: string; - span: string; - transaction: string; - metric: string; - apmAgentConfigurationIndex: string; - apmCustomLinkIndex: string; -} - async function fetchLegacyAPMIndices(repository: ISavedObjectsRepository) { try { - const legacyAPMIndices = await repository.get< - Partial - >(APM_INDICES_LEGACY_SAVED_OBJECT_TYPE, APM_INDICES_LEGACY_SAVED_OBJECT_ID); - return legacyAPMIndices; + const apmIndices = await repository.get< + Partial + >(APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, APM_INDEX_SETTINGS_SAVED_OBJECT_ID); + if (apmIndices.attributes.isSpaceAware) { + // This has already been migrated to become space-aware + return null; + } + return apmIndices; } catch (err) { if (SavedObjectsErrorHelpers.isNotFoundError(err)) { - // This is expected after the legacy APM indices object has been migrated for the first time. + // This can happen if APM is not being used return null; } throw err; @@ -61,10 +46,10 @@ export async function migrateLegacyAPMIndicesToSpaceAware({ try { // Fetch legacy APM indices const legacyAPMIndices = await fetchLegacyAPMIndices(repository); + if (legacyAPMIndices === null) { return; } - // Fetch spaces available const spaces = await repository.find({ type: 'space', @@ -73,20 +58,30 @@ export async function migrateLegacyAPMIndicesToSpaceAware({ fields: ['name'], // to avoid fetching *all* fields }); + const savedObjectAttributes = { + ...legacyAPMIndices.attributes, + isSpaceAware: true, + }; + + // Calls create first to update the default space setting isSpaceAware to true + await repository.create< + Partial + >(APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, savedObjectAttributes, { + id: APM_INDEX_SETTINGS_SAVED_OBJECT_ID, + overwrite: true, + }); + // Create new APM indices space aware for all spaces available await repository.bulkCreate>( - spaces.saved_objects.map(({ id: spaceId }) => ({ - id: APM_INDEX_SETTINGS_SAVED_OBJECT_ID, - type: APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, - initialNamespaces: [spaceId], - attributes: legacyAPMIndices.attributes, - })) - ); - - // Delete legacy APM indices - await repository.delete( - APM_INDICES_LEGACY_SAVED_OBJECT_TYPE, - APM_INDICES_LEGACY_SAVED_OBJECT_ID + spaces.saved_objects + // Skip default space since it was already updated + .filter(({ id: spaceId }) => spaceId !== 'default') + .map(({ id: spaceId }) => ({ + id: APM_INDEX_SETTINGS_SAVED_OBJECT_ID, + type: APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, + initialNamespaces: [spaceId], + attributes: savedObjectAttributes, + })) ); } catch (e) { logger.error('Failed to migrate legacy APM indices object: ' + e.message); From 1ffe65869084069fc6bc6a4610bf8fdbb8d83fd2 Mon Sep 17 00:00:00 2001 From: cauemarcondes Date: Wed, 23 Feb 2022 12:38:51 -0500 Subject: [PATCH 07/10] fixing tests --- .../server/routes/settings/apm_indices/save_apm_indices.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.test.ts b/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.test.ts index bce6857aa4ff2..a0a3381411ca6 100644 --- a/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.test.ts +++ b/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.test.ts @@ -26,7 +26,7 @@ describe('saveApmIndices', () => { await saveApmIndices(savedObjectsClient, apmIndices); expect(savedObjectsClient.create).toHaveBeenCalledWith( expect.any(String), - { settingA: 'aa', settingF: 'ff', settingG: 'gg' }, + { settingA: 'aa', settingF: 'ff', settingG: 'gg', isSpaceAware: true }, expect.any(Object) ); }); From 56cd059cc4c5e08548e978caea9552bc0ef68f3c Mon Sep 17 00:00:00 2001 From: cauemarcondes Date: Wed, 23 Feb 2022 13:50:19 -0500 Subject: [PATCH 08/10] fixing test --- ..._legacy_apm_indices_to_space_aware.test.ts | 57 +++++++++++-------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.test.ts b/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.test.ts index 4358aa4353cd2..f72c3ad9a0fc0 100644 --- a/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.test.ts +++ b/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.test.ts @@ -20,6 +20,7 @@ const loggerMock = { describe('migrateLegacyAPMIndicesToSpaceAware', () => { describe('when legacy APM indices is not found', () => { const mockBulkCreate = jest.fn(); + const mockCreate = jest.fn(); const mockFind = jest.fn(); const core = { savedObjects: { @@ -29,6 +30,7 @@ describe('migrateLegacyAPMIndicesToSpaceAware', () => { }, find: mockFind, bulkCreate: mockBulkCreate, + create: mockCreate, }), }, } as unknown as CoreStart; @@ -40,11 +42,13 @@ describe('migrateLegacyAPMIndicesToSpaceAware', () => { }); expect(mockFind).not.toHaveBeenCalled(); expect(mockBulkCreate).not.toHaveBeenCalled(); + expect(mockCreate).not.toHaveBeenCalled(); }); }); describe('when only default space is available', () => { const mockBulkCreate = jest.fn(); + const mockCreate = jest.fn(); const mockSpaceFind = jest.fn().mockReturnValue({ page: 1, per_page: 10000, @@ -92,6 +96,7 @@ describe('migrateLegacyAPMIndicesToSpaceAware', () => { }), find: mockSpaceFind, bulkCreate: mockBulkCreate, + create: mockCreate, }), }, } as unknown as CoreStart; @@ -100,27 +105,29 @@ describe('migrateLegacyAPMIndicesToSpaceAware', () => { coreStart: core, logger: loggerMock, }); - expect(mockBulkCreate).toBeCalledWith([ + expect(mockCreate).toBeCalledWith( + APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, { - type: APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, - id: APM_INDEX_SETTINGS_SAVED_OBJECT_ID, - initialNamespaces: ['default'], - attributes: { - transaction: 'default-apm-*', - span: 'default-apm-*', - error: 'default-apm-*', - metric: 'default-apm-*', - sourcemap: 'default-apm-*', - onboarding: 'default-apm-*', - }, + transaction: 'default-apm-*', + span: 'default-apm-*', + error: 'default-apm-*', + metric: 'default-apm-*', + sourcemap: 'default-apm-*', + onboarding: 'default-apm-*', + isSpaceAware: true, }, - ]); + { + id: APM_INDEX_SETTINGS_SAVED_OBJECT_ID, + overwrite: true, + } + ); }); }); describe('when multiple spaces are found', () => { const mockBulkCreate = jest.fn(); - const mockDelete = jest.fn(); + const mockCreate = jest.fn(); + const savedObjects = [ { id: 'default', name: 'Default' }, { id: 'space-a', name: 'Space A' }, @@ -170,7 +177,7 @@ describe('migrateLegacyAPMIndicesToSpaceAware', () => { }), find: mockSpaceFind, bulkCreate: mockBulkCreate, - delete: mockDelete, + create: mockCreate, }), }, } as unknown as CoreStart; @@ -179,17 +186,19 @@ describe('migrateLegacyAPMIndicesToSpaceAware', () => { coreStart: core, logger: loggerMock, }); + expect(mockCreate).toBeCalled(); expect(mockBulkCreate).toBeCalledWith( - savedObjects.map(({ id }) => { - return { - type: APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, - id: APM_INDEX_SETTINGS_SAVED_OBJECT_ID, - initialNamespaces: [id], - attributes, - }; - }) + savedObjects + .filter(({ id }) => id !== 'default') + .map(({ id }) => { + return { + type: APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, + id: APM_INDEX_SETTINGS_SAVED_OBJECT_ID, + initialNamespaces: [id], + attributes: { ...attributes, isSpaceAware: true }, + }; + }) ); - expect(mockDelete).toHaveBeenCalled(); }); }); }); From ea6597a706bbdb57de9c14fa50b3a3baaac222df Mon Sep 17 00:00:00 2001 From: cauemarcondes Date: Wed, 23 Feb 2022 17:02:46 -0500 Subject: [PATCH 09/10] showing callout with space name --- .../app/settings/apm_indices/index.tsx | 35 +++++++++++++++++++ x-pack/plugins/apm/public/plugin.ts | 2 ++ 2 files changed, 37 insertions(+) diff --git a/x-pack/plugins/apm/public/components/app/settings/apm_indices/index.tsx b/x-pack/plugins/apm/public/components/app/settings/apm_indices/index.tsx index 1a1654e22eb19..383be90168a10 100644 --- a/x-pack/plugins/apm/public/components/app/settings/apm_indices/index.tsx +++ b/x-pack/plugins/apm/public/components/app/settings/apm_indices/index.tsx @@ -8,6 +8,7 @@ import { EuiButton, EuiButtonEmpty, + EuiCallOut, EuiFieldText, EuiFlexGroup, EuiFlexItem, @@ -19,9 +20,12 @@ import { EuiToolTip, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; import React, { useEffect, useState } from 'react'; +import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public'; import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context'; import { useFetcher } from '../../../../hooks/use_fetcher'; +import { ApmPluginStartDeps } from '../../../../plugin'; import { clearCache } from '../../../../services/rest/call_api'; import { APIReturnType, @@ -93,6 +97,8 @@ const INITIAL_STATE: ApiResponse = { apmIndexSettings: [] }; export function ApmIndices() { const { core } = useApmPluginContext(); + const { services } = useKibana(); + const { notifications, application } = core; const canSave = application.capabilities.apm.save; @@ -108,6 +114,10 @@ export function ApmIndices() { [canSave] ); + const { data: space } = useFetcher(() => { + return services.spaces?.getActiveSpace(); + }, [services.spaces]); + useEffect(() => { setApmIndices( data.apmIndexSettings.reduce( @@ -191,6 +201,31 @@ export function ApmIndices() { + {space?.name && ( + <> + + + + {space?.name}, + }} + /> + + } + /> + + + + + )} + diff --git a/x-pack/plugins/apm/public/plugin.ts b/x-pack/plugins/apm/public/plugin.ts index 952df64da840a..75c3c290512d8 100644 --- a/x-pack/plugins/apm/public/plugin.ts +++ b/x-pack/plugins/apm/public/plugin.ts @@ -53,6 +53,7 @@ import { getLazyAPMPolicyCreateExtension } from './components/fleet_integration/ import { getLazyAPMPolicyEditExtension } from './components/fleet_integration/lazy_apm_policy_edit_extension'; import { featureCatalogueEntry } from './feature_catalogue_entry'; import type { SecurityPluginStart } from '../../security/public'; +import { SpacesPluginStart } from '../../spaces/public'; export type ApmPluginSetup = ReturnType; @@ -82,6 +83,7 @@ export interface ApmPluginStartDeps { observability: ObservabilityPublicStart; fleet?: FleetStart; security?: SecurityPluginStart; + spaces?: SpacesPluginStart; } const servicesTitle = i18n.translate('xpack.apm.navigation.servicesTitle', { From 873e1d4a3ea0d289d967c5dfe6c2bd72d5848434 Mon Sep 17 00:00:00 2001 From: cauemarcondes Date: Thu, 24 Feb 2022 11:27:40 -0500 Subject: [PATCH 10/10] addressing PR changes --- .../app/settings/apm_indices/index.test.tsx | 37 ------------------- .../settings/apm_indices/get_apm_indices.ts | 17 +++++---- .../apm_indices/save_apm_indices.test.ts | 5 ++- .../settings/apm_indices/save_apm_indices.ts | 5 ++- .../apm/server/saved_objects/apm_indices.ts | 35 ++++++++++++++---- ..._legacy_apm_indices_to_space_aware.test.ts | 16 ++++---- ...grate_legacy_apm_indices_to_space_aware.ts | 7 ++-- 7 files changed, 57 insertions(+), 65 deletions(-) delete mode 100644 x-pack/plugins/apm/public/components/app/settings/apm_indices/index.test.tsx diff --git a/x-pack/plugins/apm/public/components/app/settings/apm_indices/index.test.tsx b/x-pack/plugins/apm/public/components/app/settings/apm_indices/index.test.tsx deleted file mode 100644 index 1b19bb5860b2c..0000000000000 --- a/x-pack/plugins/apm/public/components/app/settings/apm_indices/index.test.tsx +++ /dev/null @@ -1,37 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { render } from '@testing-library/react'; -import React from 'react'; -import { ApmIndices } from '.'; -import * as hooks from '../../../../hooks/use_fetcher'; -import { MockApmPluginContextWrapper } from '../../../../context/apm_plugin/mock_apm_plugin_context'; - -describe('ApmIndices', () => { - it('should not get stuck in infinite loop', () => { - const spy = jest.spyOn(hooks, 'useFetcher').mockReturnValue({ - data: undefined, - status: hooks.FETCH_STATUS.LOADING, - refetch: jest.fn(), - }); - const { getByText } = render( - - - - ); - - expect(getByText('Indices')).toMatchInlineSnapshot(` -

- Indices -

- `); - - expect(spy).toHaveBeenCalledTimes(2); - }); -}); diff --git a/x-pack/plugins/apm/server/routes/settings/apm_indices/get_apm_indices.ts b/x-pack/plugins/apm/server/routes/settings/apm_indices/get_apm_indices.ts index 0b10a41b23459..7d98502ee5d93 100644 --- a/x-pack/plugins/apm/server/routes/settings/apm_indices/get_apm_indices.ts +++ b/x-pack/plugins/apm/server/routes/settings/apm_indices/get_apm_indices.ts @@ -14,6 +14,7 @@ import { APMConfig } from '../../..'; import { APMRouteHandlerResources } from '../../typings'; import { withApmSpan } from '../../../utils/with_apm_span'; import { ApmIndicesConfig } from '../../../../../observability/common/typings'; +import { APMIndices } from '../../../saved_objects/apm_indices'; export type { ApmIndicesConfig }; @@ -22,13 +23,15 @@ type ISavedObjectsClient = Pick; async function getApmIndicesSavedObject( savedObjectsClient: ISavedObjectsClient ) { - const apmIndices = await withApmSpan('get_apm_indices_saved_object', () => - savedObjectsClient.get< - Partial - >(APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, APM_INDEX_SETTINGS_SAVED_OBJECT_ID) + const apmIndicesSavedObject = await withApmSpan( + 'get_apm_indices_saved_object', + () => + savedObjectsClient.get>( + APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, + APM_INDEX_SETTINGS_SAVED_OBJECT_ID + ) ); - const { isSpaceAware, ...attributes } = apmIndices.attributes; - return attributes; + return apmIndicesSavedObject.attributes.apmIndices; } export function getApmIndicesConfig(config: APMConfig): ApmIndicesConfig { @@ -90,6 +93,6 @@ export async function getApmIndexSettings({ return apmIndices.map((configurationName) => ({ configurationName, defaultValue: apmIndicesConfig[configurationName], // value defined in kibana[.dev].yml - savedValue: apmIndicesSavedObject[configurationName], // value saved via Saved Objects service + savedValue: apmIndicesSavedObject?.[configurationName], // value saved via Saved Objects service })); } diff --git a/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.test.ts b/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.test.ts index a0a3381411ca6..0c91bccb42999 100644 --- a/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.test.ts +++ b/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.test.ts @@ -26,7 +26,10 @@ describe('saveApmIndices', () => { await saveApmIndices(savedObjectsClient, apmIndices); expect(savedObjectsClient.create).toHaveBeenCalledWith( expect.any(String), - { settingA: 'aa', settingF: 'ff', settingG: 'gg', isSpaceAware: true }, + { + apmIndices: { settingA: 'aa', settingF: 'ff', settingG: 'gg' }, + isSpaceAware: true, + }, expect.any(Object) ); }); diff --git a/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.ts b/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.ts index 2f5db06138f38..2bd4273910bbf 100644 --- a/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.ts +++ b/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.ts @@ -10,6 +10,7 @@ import { APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, APM_INDEX_SETTINGS_SAVED_OBJECT_ID, } from '../../../../common/apm_saved_object_constants'; +import { APMIndices } from '../../../saved_objects/apm_indices'; import { withApmSpan } from '../../../utils/with_apm_span'; import { ApmIndicesConfig } from './get_apm_indices'; @@ -18,9 +19,9 @@ export function saveApmIndices( apmIndices: Partial ) { return withApmSpan('save_apm_indices', () => - savedObjectsClient.create( + savedObjectsClient.create( APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, - { ...removeEmpty(apmIndices), isSpaceAware: true }, + { apmIndices: removeEmpty(apmIndices), isSpaceAware: true }, { id: APM_INDEX_SETTINGS_SAVED_OBJECT_ID, overwrite: true } ) ); diff --git a/x-pack/plugins/apm/server/saved_objects/apm_indices.ts b/x-pack/plugins/apm/server/saved_objects/apm_indices.ts index c1973243b7d9b..4a3b0d32e9667 100644 --- a/x-pack/plugins/apm/server/saved_objects/apm_indices.ts +++ b/x-pack/plugins/apm/server/saved_objects/apm_indices.ts @@ -10,17 +10,36 @@ import { i18n } from '@kbn/i18n'; import { updateApmOssIndexPaths } from './migrations/update_apm_oss_index_paths'; import { ApmIndicesConfigName } from '..'; +export interface APMIndices { + apmIndices?: { + sourcemap?: string; + error?: string; + onboarding?: string; + span?: string; + transaction?: string; + metric?: string; + }; + isSpaceAware?: boolean; +} + const properties: { - [Property in ApmIndicesConfigName]: { type: 'keyword' }; -} & { + apmIndices: { + properties: { + [Property in ApmIndicesConfigName]: { type: 'keyword' }; + }; + }; isSpaceAware: { type: 'boolean' }; } = { - sourcemap: { type: 'keyword' }, - error: { type: 'keyword' }, - onboarding: { type: 'keyword' }, - span: { type: 'keyword' }, - transaction: { type: 'keyword' }, - metric: { type: 'keyword' }, + apmIndices: { + properties: { + sourcemap: { type: 'keyword' }, + error: { type: 'keyword' }, + onboarding: { type: 'keyword' }, + span: { type: 'keyword' }, + transaction: { type: 'keyword' }, + metric: { type: 'keyword' }, + }, + }, isSpaceAware: { type: 'boolean' }, }; diff --git a/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.test.ts b/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.test.ts index f72c3ad9a0fc0..404e08a6b112b 100644 --- a/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.test.ts +++ b/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.test.ts @@ -108,12 +108,14 @@ describe('migrateLegacyAPMIndicesToSpaceAware', () => { expect(mockCreate).toBeCalledWith( APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, { - transaction: 'default-apm-*', - span: 'default-apm-*', - error: 'default-apm-*', - metric: 'default-apm-*', - sourcemap: 'default-apm-*', - onboarding: 'default-apm-*', + apmIndices: { + transaction: 'default-apm-*', + span: 'default-apm-*', + error: 'default-apm-*', + metric: 'default-apm-*', + sourcemap: 'default-apm-*', + onboarding: 'default-apm-*', + }, isSpaceAware: true, }, { @@ -195,7 +197,7 @@ describe('migrateLegacyAPMIndicesToSpaceAware', () => { type: APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, id: APM_INDEX_SETTINGS_SAVED_OBJECT_ID, initialNamespaces: [id], - attributes: { ...attributes, isSpaceAware: true }, + attributes: { apmIndices: attributes, isSpaceAware: true }, }; }) ); diff --git a/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.ts b/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.ts index 21b56a1cf23ed..130070b80ff14 100644 --- a/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.ts +++ b/x-pack/plugins/apm/server/saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware.ts @@ -15,6 +15,7 @@ import { APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, } from '../../../common/apm_saved_object_constants'; import { ApmIndicesConfig } from '../../routes/settings/apm_indices/get_apm_indices'; +import { APMIndices } from '../apm_indices'; async function fetchLegacyAPMIndices(repository: ISavedObjectsRepository) { try { @@ -58,8 +59,8 @@ export async function migrateLegacyAPMIndicesToSpaceAware({ fields: ['name'], // to avoid fetching *all* fields }); - const savedObjectAttributes = { - ...legacyAPMIndices.attributes, + const savedObjectAttributes: APMIndices = { + apmIndices: legacyAPMIndices.attributes, isSpaceAware: true, }; @@ -72,7 +73,7 @@ export async function migrateLegacyAPMIndicesToSpaceAware({ }); // Create new APM indices space aware for all spaces available - await repository.bulkCreate>( + await repository.bulkCreate>( spaces.saved_objects // Skip default space since it was already updated .filter(({ id: spaceId }) => spaceId !== 'default')