diff --git a/docs/apm/getting-started.asciidoc b/docs/apm/getting-started.asciidoc index 7c7321dc37e8c8..2b4651a9fce971 100644 --- a/docs/apm/getting-started.asciidoc +++ b/docs/apm/getting-started.asciidoc @@ -41,11 +41,7 @@ Notice something awry? Select a service or trace and dive deeper with: * <> TIP: Want to learn more about the Elastic APM ecosystem? -<<<<<<< HEAD -See the {apm-overview-ref-v}/overview.html[APM Overview]. -======= See the {apm-guide-ref}/apm-overview.html[APM Overview]. ->>>>>>> 2daadc0d74d (docs: update links to APM docs (#115664)) include::services.asciidoc[] diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc index ddf52ccad768d9..09d0c43d6b6c17 100644 --- a/docs/setup/settings.asciidoc +++ b/docs/setup/settings.asciidoc @@ -497,9 +497,6 @@ override this parameter to use their own Tile Map Service. For example: | `migrations.maxBatchSizeBytes:` | Defines the maximum payload size for indexing batches of upgraded saved objects to avoid migrations failing due to a 413 Request Entity Too Large response from Elasticsearch. This value should be lower than or equal to your Elasticsearch cluster's `http.max_content_length` configuration option. *Default: `100mb`* -| `migrations.enableV2:` - | experimental[]. Enables the new Saved Objects migration algorithm. For information about the migration algorithm, refer to <>. When `migrations v2` is stable, the setting will be removed in an upcoming release without any further notice. Setting the value to `false` causes {kib} to use the legacy migration algorithm, which shipped in 7.11 and earlier versions. *Default: `true`* - | `migrations.retryAttempts:` | The number of times migrations retry temporary failures, such as a network timeout, 503 status code, or `snapshot_in_progress_exception`. When upgrade migrations frequently fail after exhausting all retry attempts with a message such as `Unable to complete the [...] step after 15 attempts, terminating.`, increase the setting value. *Default: `15`* diff --git a/src/core/server/saved_objects/deprecations/unknown_object_types.test.ts b/src/core/server/saved_objects/deprecations/unknown_object_types.test.ts index d7ea73456e236a..1f9ca741691d10 100644 --- a/src/core/server/saved_objects/deprecations/unknown_object_types.test.ts +++ b/src/core/server/saved_objects/deprecations/unknown_object_types.test.ts @@ -13,7 +13,6 @@ import { deleteUnknownTypeObjects, getUnknownTypesDeprecations } from './unknown 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 => { @@ -32,7 +31,6 @@ describe('unknown saved object types deprecation', () => { let typeRegistry: ReturnType; let esClient: ReturnType; let kibanaConfig: KibanaConfigType; - let savedObjectsConfig: SavedObjectConfig; beforeEach(() => { typeRegistry = typeRegistryMock.create(); @@ -48,12 +46,6 @@ describe('unknown saved object types deprecation', () => { index: '.kibana', enabled: true, }; - - savedObjectsConfig = { - migration: { - enableV2: true, - }, - } as SavedObjectConfig; }); afterEach(() => { @@ -69,7 +61,6 @@ describe('unknown saved object types deprecation', () => { it('calls `esClient.asInternalUser.search` with the correct parameters', async () => { await getUnknownTypesDeprecations({ - savedObjectsConfig, esClient, typeRegistry, kibanaConfig, @@ -96,7 +87,6 @@ describe('unknown saved object types deprecation', () => { ); const deprecations = await getUnknownTypesDeprecations({ - savedObjectsConfig, esClient, typeRegistry, kibanaConfig, @@ -112,7 +102,6 @@ describe('unknown saved object types deprecation', () => { ); const deprecations = await getUnknownTypesDeprecations({ - savedObjectsConfig, esClient, typeRegistry, kibanaConfig, @@ -141,7 +130,6 @@ describe('unknown saved object types deprecation', () => { describe('deleteUnknownTypeObjects', () => { it('calls `esClient.asInternalUser.search` with the correct parameters', async () => { await deleteUnknownTypeObjects({ - savedObjectsConfig, esClient, typeRegistry, kibanaConfig, diff --git a/src/core/server/saved_objects/deprecations/unknown_object_types.ts b/src/core/server/saved_objects/deprecations/unknown_object_types.ts index c966e621ca6055..8cd650bac8a2d5 100644 --- a/src/core/server/saved_objects/deprecations/unknown_object_types.ts +++ b/src/core/server/saved_objects/deprecations/unknown_object_types.ts @@ -13,14 +13,12 @@ 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; } @@ -32,11 +30,9 @@ const getTargetIndices = ({ typeRegistry, kibanaVersion, kibanaConfig, - savedObjectsConfig, }: { types: string[]; typeRegistry: ISavedObjectTypeRegistry; - savedObjectsConfig: SavedObjectConfig; kibanaConfig: KibanaConfigType; kibanaVersion: string; }) => { @@ -46,7 +42,6 @@ const getTargetIndices = ({ getIndexForType({ type, typeRegistry, - migV2Enabled: savedObjectsConfig.migration.enableV2, kibanaVersion, defaultIndex: kibanaConfig.index, }) @@ -69,7 +64,6 @@ const getUnknownSavedObjects = async ({ typeRegistry, esClient, kibanaConfig, - savedObjectsConfig, kibanaVersion, }: UnknownTypesDeprecationOptions) => { const knownTypes = getKnownTypes(typeRegistry); @@ -78,7 +72,6 @@ const getUnknownSavedObjects = async ({ typeRegistry, kibanaConfig, kibanaVersion, - savedObjectsConfig, }); const query = getUnknownTypesQuery(knownTypes); @@ -141,7 +134,6 @@ interface DeleteUnknownTypesOptions { typeRegistry: ISavedObjectTypeRegistry; esClient: IScopedClusterClient; kibanaConfig: KibanaConfigType; - savedObjectsConfig: SavedObjectConfig; kibanaVersion: string; } @@ -149,7 +141,6 @@ export const deleteUnknownTypeObjects = async ({ esClient, typeRegistry, kibanaConfig, - savedObjectsConfig, kibanaVersion, }: DeleteUnknownTypesOptions) => { const knownTypes = getKnownTypes(typeRegistry); @@ -158,7 +149,6 @@ export const deleteUnknownTypeObjects = async ({ typeRegistry, kibanaConfig, kibanaVersion, - savedObjectsConfig, }); const query = getUnknownTypesQuery(knownTypes); diff --git a/src/core/server/saved_objects/migrations/kibana/kibana_migrator.mock.ts b/src/core/server/saved_objects/migrations/kibana/kibana_migrator.mock.ts index 9471bbc1b87a63..660300ea867ff2 100644 --- a/src/core/server/saved_objects/migrations/kibana/kibana_migrator.mock.ts +++ b/src/core/server/saved_objects/migrations/kibana/kibana_migrator.mock.ts @@ -42,8 +42,6 @@ const createMigrator = ( scrollDuration: '15m', pollInterval: 1500, skip: false, - // TODO migrationsV2: remove/deprecate once we remove migrations v1 - enableV2: false, retryAttempts: 10, }, runMigrations: jest.fn(), diff --git a/src/core/server/saved_objects/migrations/kibana/kibana_migrator.test.ts b/src/core/server/saved_objects/migrations/kibana/kibana_migrator.test.ts index 6e10349f4b57c3..c397559b52570c 100644 --- a/src/core/server/saved_objects/migrations/kibana/kibana_migrator.test.ts +++ b/src/core/server/saved_objects/migrations/kibana/kibana_migrator.test.ts @@ -7,7 +7,7 @@ */ import { take } from 'rxjs/operators'; -import { estypes, errors as esErrors } from '@elastic/elasticsearch'; +import { estypes } from '@elastic/elasticsearch'; import { elasticsearchClientMock } from '../../../elasticsearch/client/mocks'; import { KibanaMigratorOptions, KibanaMigrator } from './kibana_migrator'; @@ -125,13 +125,6 @@ describe('KibanaMigrator', () => { it('only runs migrations once if called multiple times', async () => { const options = mockOptions(); - options.client.cat.templates.mockReturnValue( - elasticsearchClientMock.createSuccessTransportRequestPromise( - // @ts-expect-error - { templates: [] } as CatTemplatesResponse, - { statusCode: 404 } - ) - ); options.client.indices.get.mockReturnValue( elasticsearchClientMock.createSuccessTransportRequestPromise({}, { statusCode: 404 }) ); @@ -144,159 +137,79 @@ describe('KibanaMigrator', () => { migrator.prepareMigrations(); await migrator.runMigrations(); await migrator.runMigrations(); + await migrator.runMigrations(); - expect(options.client.cat.templates).toHaveBeenCalledTimes(1); + // indices.get is called twice during a single migration + expect(options.client.indices.get).toHaveBeenCalledTimes(2); }); - describe('when enableV2 = false', () => { - it('when enableV2 = false creates an IndexMigrator which retries NoLivingConnectionsError errors from ES client', async () => { - const options = mockOptions(); - - options.client.cat.templates.mockReturnValue( - elasticsearchClientMock.createSuccessTransportRequestPromise( - // @ts-expect-error - { templates: [] } as CatTemplatesResponse, - { statusCode: 404 } - ) - ); - options.client.indices.get.mockReturnValue( - elasticsearchClientMock.createSuccessTransportRequestPromise({}, { statusCode: 404 }) - ); - options.client.indices.getAlias.mockReturnValue( - elasticsearchClientMock.createSuccessTransportRequestPromise({}, { statusCode: 404 }) - ); - - options.client.indices.create = jest - .fn() - .mockReturnValueOnce( - elasticsearchClientMock.createErrorTransportRequestPromise( - new esErrors.NoLivingConnectionsError('reason', {} as any) - ) - ) - .mockImplementationOnce(() => - elasticsearchClientMock.createSuccessTransportRequestPromise('success') - ); - - const migrator = new KibanaMigrator(options); - const migratorStatus = migrator.getStatus$().pipe(take(3)).toPromise(); - - migrator.prepareMigrations(); - await migrator.runMigrations(); + it('emits results on getMigratorResult$()', async () => { + const options = mockV2MigrationOptions(); + const migrator = new KibanaMigrator(options); + const migratorStatus = migrator.getStatus$().pipe(take(3)).toPromise(); + migrator.prepareMigrations(); + await migrator.runMigrations(); - expect(options.client.indices.create).toHaveBeenCalledTimes(3); - const { status } = await migratorStatus; - return expect(status).toEqual('completed'); + const { status, result } = await migratorStatus; + expect(status).toEqual('completed'); + expect(result![0]).toMatchObject({ + destIndex: '.my-index_8.2.3_001', + sourceIndex: '.my-index_pre8.2.3_001', + elapsedMs: expect.any(Number), + status: 'migrated', }); - - it('emits results on getMigratorResult$()', async () => { - const options = mockOptions(); - - options.client.cat.templates.mockReturnValue( - elasticsearchClientMock.createSuccessTransportRequestPromise( - // @ts-expect-error - { templates: [] } as CatTemplatesResponse, - { statusCode: 404 } - ) - ); - options.client.indices.get.mockReturnValue( - elasticsearchClientMock.createSuccessTransportRequestPromise({}, { statusCode: 404 }) - ); - options.client.indices.getAlias.mockReturnValue( - elasticsearchClientMock.createSuccessTransportRequestPromise({}, { statusCode: 404 }) - ); - - const migrator = new KibanaMigrator(options); - const migratorStatus = migrator.getStatus$().pipe(take(3)).toPromise(); - migrator.prepareMigrations(); - await migrator.runMigrations(); - const { status, result } = await migratorStatus; - expect(status).toEqual('completed'); - expect(result![0]).toMatchObject({ - destIndex: '.my-index_1', - elapsedMs: expect.any(Number), - sourceIndex: '.my-index', - status: 'migrated', - }); - expect(result![1]).toMatchObject({ - destIndex: 'other-index_1', - elapsedMs: expect.any(Number), - sourceIndex: 'other-index', - status: 'migrated', - }); + expect(result![1]).toMatchObject({ + destIndex: 'other-index_8.2.3_001', + elapsedMs: expect.any(Number), + status: 'patched', }); }); - describe('when enableV2 = true', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('emits results on getMigratorResult$()', async () => { - const options = mockV2MigrationOptions(); - const migrator = new KibanaMigrator(options); - const migratorStatus = migrator.getStatus$().pipe(take(3)).toPromise(); - migrator.prepareMigrations(); - await migrator.runMigrations(); - - const { status, result } = await migratorStatus; - expect(status).toEqual('completed'); - expect(result![0]).toMatchObject({ - destIndex: '.my-index_8.2.3_001', - sourceIndex: '.my-index_pre8.2.3_001', - elapsedMs: expect.any(Number), - status: 'migrated', - }); - expect(result![1]).toMatchObject({ - destIndex: 'other-index_8.2.3_001', - elapsedMs: expect.any(Number), - status: 'patched', - }); - }); - it('rejects when the migration state machine terminates in a FATAL state', () => { - const options = mockV2MigrationOptions(); - options.client.indices.get.mockReturnValue( - elasticsearchClientMock.createSuccessTransportRequestPromise( - { - '.my-index_8.2.4_001': { - aliases: { - '.my-index': {}, - '.my-index_8.2.4': {}, - }, - mappings: { properties: {}, _meta: { migrationMappingPropertyHashes: {} } }, - settings: {}, + it('rejects when the migration state machine terminates in a FATAL state', () => { + const options = mockV2MigrationOptions(); + options.client.indices.get.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise( + { + '.my-index_8.2.4_001': { + aliases: { + '.my-index': {}, + '.my-index_8.2.4': {}, }, + mappings: { properties: {}, _meta: { migrationMappingPropertyHashes: {} } }, + settings: {}, }, - { statusCode: 200 } - ) - ); + }, + { statusCode: 200 } + ) + ); - const migrator = new KibanaMigrator(options); - migrator.prepareMigrations(); - return expect(migrator.runMigrations()).rejects.toMatchInlineSnapshot( - `[Error: Unable to complete saved object migrations for the [.my-index] index: The .my-index alias is pointing to a newer version of Kibana: v8.2.4]` - ); - }); - it('rejects when an unexpected exception occurs in an action', async () => { - const options = mockV2MigrationOptions(); - options.client.tasks.get.mockReturnValue( - elasticsearchClientMock.createSuccessTransportRequestPromise({ - completed: true, - error: { type: 'elasticsearch_exception', reason: 'task failed with an error' }, - failures: [], - task: { description: 'task description' } as any, - }) - ); + const migrator = new KibanaMigrator(options); + migrator.prepareMigrations(); + return expect(migrator.runMigrations()).rejects.toMatchInlineSnapshot( + `[Error: Unable to complete saved object migrations for the [.my-index] index: The .my-index alias is pointing to a newer version of Kibana: v8.2.4]` + ); + }); - const migrator = new KibanaMigrator(options); - migrator.prepareMigrations(); - await expect(migrator.runMigrations()).rejects.toMatchInlineSnapshot(` - [Error: Unable to complete saved object migrations for the [.my-index] index. Error: Reindex failed with the following error: - {"_tag":"Some","value":{"type":"elasticsearch_exception","reason":"task failed with an error"}}] - `); - expect(loggingSystemMock.collect(options.logger).error[0][0]).toMatchInlineSnapshot(` - [Error: Reindex failed with the following error: - {"_tag":"Some","value":{"type":"elasticsearch_exception","reason":"task failed with an error"}}] - `); - }); + it('rejects when an unexpected exception occurs in an action', async () => { + const options = mockV2MigrationOptions(); + options.client.tasks.get.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ + completed: true, + error: { type: 'elasticsearch_exception', reason: 'task failed with an error' }, + failures: [], + task: { description: 'task description' } as any, + }) + ); + + const migrator = new KibanaMigrator(options); + migrator.prepareMigrations(); + await expect(migrator.runMigrations()).rejects.toMatchInlineSnapshot(` + [Error: Unable to complete saved object migrations for the [.my-index] index. Error: Reindex failed with the following error: + {"_tag":"Some","value":{"type":"elasticsearch_exception","reason":"task failed with an error"}}] + `); + expect(loggingSystemMock.collect(options.logger).error[0][0]).toMatchInlineSnapshot(` + [Error: Reindex failed with the following error: + {"_tag":"Some","value":{"type":"elasticsearch_exception","reason":"task failed with an error"}}] + `); }); }); }); @@ -306,7 +219,7 @@ type MockedOptions = KibanaMigratorOptions & { }; const mockV2MigrationOptions = () => { - const options = mockOptions({ enableV2: true }); + const options = mockOptions(); options.client.indices.get.mockReturnValue( elasticsearchClientMock.createSuccessTransportRequestPromise( @@ -362,7 +275,7 @@ const mockV2MigrationOptions = () => { return options; }; -const mockOptions = ({ enableV2 }: { enableV2: boolean } = { enableV2: false }) => { +const mockOptions = () => { const options: MockedOptions = { logger: loggingSystemMock.create().get(), kibanaVersion: '8.2.3', @@ -401,7 +314,6 @@ const mockOptions = ({ enableV2 }: { enableV2: boolean } = { enableV2: false }) pollInterval: 20000, scrollDuration: '10m', skip: false, - enableV2, retryAttempts: 20, }, client: elasticsearchClientMock.createElasticsearchClient(), diff --git a/src/core/server/saved_objects/migrations/kibana/kibana_migrator.ts b/src/core/server/saved_objects/migrations/kibana/kibana_migrator.ts index 572b2934e49b82..d3755f8c7e666c 100644 --- a/src/core/server/saved_objects/migrations/kibana/kibana_migrator.ts +++ b/src/core/server/saved_objects/migrations/kibana/kibana_migrator.ts @@ -22,13 +22,7 @@ import { SavedObjectsSerializer, SavedObjectsRawDoc, } from '../../serialization'; -import { - buildActiveMappings, - createMigrationEsClient, - IndexMigrator, - MigrationResult, - MigrationStatus, -} from '../core'; +import { buildActiveMappings, MigrationResult, MigrationStatus } from '../core'; import { DocumentMigrator, VersionedTransformer } from '../core/document_migrator'; import { createIndexMap } from '../core/build_index_map'; import { SavedObjectsMigrationConfigType } from '../../saved_objects_config'; @@ -71,7 +65,6 @@ export class KibanaMigrator { status: 'waiting_to_start', }); private readonly activeMappings: IndexMapping; - private migrationsRetryDelay?: number; // TODO migrationsV2: make private once we remove migrations v1 public readonly kibanaVersion: string; // TODO migrationsV2: make private once we remove migrations v1 @@ -105,7 +98,6 @@ export class KibanaMigrator { // Building the active mappings (and associated md5sums) is an expensive // operation so we cache the result this.activeMappings = buildActiveMappings(this.mappingProperties); - this.migrationsRetryDelay = migrationsRetryDelay; } /** @@ -173,49 +165,28 @@ export class KibanaMigrator { }); const migrators = Object.keys(indexMap).map((index) => { - // TODO migrationsV2: remove old migrations algorithm - if (this.soMigrationsConfig.enableV2) { - return { - migrate: (): Promise => { - return runResilientMigrator({ - client: this.client, - kibanaVersion: this.kibanaVersion, - targetMappings: buildActiveMappings(indexMap[index].typeMappings), - logger: this.log, - preMigrationScript: indexMap[index].script, - transformRawDocs: (rawDocs: SavedObjectsRawDoc[]) => - migrateRawDocsSafely({ - serializer: this.serializer, - knownTypes: new Set(this.typeRegistry.getAllTypes().map((t) => t.name)), - migrateDoc: this.documentMigrator.migrateAndConvert, - rawDocs, - }), - migrationVersionPerType: this.documentMigrator.migrationVersion, - indexPrefix: index, - migrationsConfig: this.soMigrationsConfig, - typeRegistry: this.typeRegistry, - }); - }, - }; - } else { - return new IndexMigrator({ - batchSize: this.soMigrationsConfig.batchSize, - client: createMigrationEsClient(this.client, this.log, this.migrationsRetryDelay), - documentMigrator: this.documentMigrator, - index, - kibanaVersion: this.kibanaVersion, - log: this.log, - mappingProperties: indexMap[index].typeMappings, - setStatus: (status) => this.status$.next(status), - pollInterval: this.soMigrationsConfig.pollInterval, - scrollDuration: this.soMigrationsConfig.scrollDuration, - serializer: this.serializer, - // Only necessary for the migrator of the kibana index. - obsoleteIndexTemplatePattern: - index === kibanaIndexName ? 'kibana_index_template*' : undefined, - convertToAliasScript: indexMap[index].script, - }); - } + return { + migrate: (): Promise => { + return runResilientMigrator({ + client: this.client, + kibanaVersion: this.kibanaVersion, + targetMappings: buildActiveMappings(indexMap[index].typeMappings), + logger: this.log, + preMigrationScript: indexMap[index].script, + transformRawDocs: (rawDocs: SavedObjectsRawDoc[]) => + migrateRawDocsSafely({ + serializer: this.serializer, + knownTypes: new Set(this.typeRegistry.getAllTypes().map((t) => t.name)), + migrateDoc: this.documentMigrator.migrateAndConvert, + rawDocs, + }), + migrationVersionPerType: this.documentMigrator.migrationVersion, + indexPrefix: index, + migrationsConfig: this.soMigrationsConfig, + typeRegistry: this.typeRegistry, + }); + }, + }; }); return Promise.all(migrators.map((migrator) => migrator.migrate())); diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/7.7.2_xpack_100k.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/7.7.2_xpack_100k.test.ts index d072ccc5c976ed..3dcfb34c47a17b 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/7.7.2_xpack_100k.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/7.7.2_xpack_100k.test.ts @@ -49,7 +49,6 @@ describe('migration from 7.7.2-xpack with 100k objects', () => { { migrations: { skip: false, - enableV2: true, }, logging: { appenders: { diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/7_13_0_failed_action_tasks.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/7_13_0_failed_action_tasks.test.ts index d70e034703158a..a4ce95a9e05843 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/7_13_0_failed_action_tasks.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/7_13_0_failed_action_tasks.test.ts @@ -113,7 +113,6 @@ function createRoot() { { migrations: { skip: false, - enableV2: true, batchSize: 250, }, logging: { diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/7_13_0_transform_failures.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/7_13_0_transform_failures.test.ts index fb40bda81cba59..c8e17a64a3fa3f 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/7_13_0_transform_failures.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/7_13_0_transform_failures.test.ts @@ -155,7 +155,6 @@ function createRoot() { { migrations: { skip: false, - enableV2: true, batchSize: 5, }, logging: { diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/7_13_0_unknown_types.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/7_13_0_unknown_types.test.ts index f15e0c5d684d05..31c802bb561f97 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/7_13_0_unknown_types.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/7_13_0_unknown_types.test.ts @@ -218,7 +218,6 @@ function createRoot() { { migrations: { skip: false, - enableV2: true, batchSize: 5, }, logging: { diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/batch_size_bytes.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/batch_size_bytes.test.ts index ead46627e324db..9daae7eddafe05 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/batch_size_bytes.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/batch_size_bytes.test.ts @@ -118,7 +118,6 @@ function createRoot(options: { maxBatchSizeBytes?: number }) { { migrations: { skip: false, - enableV2: true, batchSize: 1000, maxBatchSizeBytes: options.maxBatchSizeBytes, }, diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/batch_size_bytes_exceeds_es_content_length.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/batch_size_bytes_exceeds_es_content_length.test.ts index 4f456b0bc741f8..d61426d92d390d 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/batch_size_bytes_exceeds_es_content_length.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/batch_size_bytes_exceeds_es_content_length.test.ts @@ -88,7 +88,6 @@ function createRoot(options: { maxBatchSizeBytes?: number }) { { migrations: { skip: false, - enableV2: true, batchSize: 1000, maxBatchSizeBytes: options.maxBatchSizeBytes, }, diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/cleanup.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/cleanup.test.ts index d76bbc786cffca..c84f72b1842618 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/cleanup.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/cleanup.test.ts @@ -28,7 +28,6 @@ function createRoot() { { migrations: { skip: false, - enableV2: true, }, logging: { appenders: { diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/collects_corrupt_docs.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/collects_corrupt_docs.test.ts index 9738650b0db883..0f59d194614954 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/collects_corrupt_docs.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/collects_corrupt_docs.test.ts @@ -150,7 +150,6 @@ function createRoot() { { migrations: { skip: false, - enableV2: true, batchSize: 5, }, logging: { diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/corrupt_outdated_docs.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/corrupt_outdated_docs.test.ts index d19ae51315745b..7e4b52dea185d4 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/corrupt_outdated_docs.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/corrupt_outdated_docs.test.ts @@ -154,7 +154,6 @@ function createRoot() { { migrations: { skip: false, - enableV2: true, batchSize: 5, }, logging: { diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/migration_from_older_v1.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/migration_from_older_v1.test.ts index 8e01e11eaccfb7..12d04d89dee78b 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/migration_from_older_v1.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/migration_from_older_v1.test.ts @@ -77,7 +77,6 @@ describe('migrating from 7.3.0-xpack which used v1 migrations', () => { { migrations: { skip: false, - enableV2: true, // There are 53 docs in fixtures. Batch size configured to enforce 3 migration steps. batchSize: 20, }, diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/multiple_es_nodes.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/multiple_es_nodes.test.ts index 755bb5f946e4fc..6956e53ebc7fae 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/multiple_es_nodes.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/multiple_es_nodes.test.ts @@ -67,7 +67,6 @@ function createRoot({ logFileName, hosts }: RootConfig) { }, migrations: { skip: false, - enableV2: true, batchSize: 100, // fixture contains 5000 docs }, logging: { diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/multiple_kibana_nodes.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/multiple_kibana_nodes.test.ts index 11c5b33c0fd3d9..ef92c823182d8e 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/multiple_kibana_nodes.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/multiple_kibana_nodes.test.ts @@ -67,7 +67,6 @@ async function createRoot({ logFileName }: CreateRootConfig) { }, migrations: { skip: false, - enableV2: true, batchSize: 100, // fixture contains 5000 docs }, logging: { diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/outdated_docs.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/outdated_docs.test.ts index 19d77637902f81..4718b5d1285fe4 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/outdated_docs.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/outdated_docs.test.ts @@ -96,7 +96,6 @@ function createRoot() { { migrations: { skip: false, - enableV2: true, }, logging: { appenders: { diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/rewriting_id.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/rewriting_id.test.ts index 78eec5fe94ef37..84c25fcdef8b42 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/rewriting_id.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/rewriting_id.test.ts @@ -62,7 +62,6 @@ function createRoot() { { migrations: { skip: false, - enableV2: true, }, logging: { appenders: { diff --git a/src/core/server/saved_objects/migrationsv2/migrations_state_action_machine.test.ts b/src/core/server/saved_objects/migrationsv2/migrations_state_action_machine.test.ts index 21468d75523204..338eecf1511747 100644 --- a/src/core/server/saved_objects/migrationsv2/migrations_state_action_machine.test.ts +++ b/src/core/server/saved_objects/migrationsv2/migrations_state_action_machine.test.ts @@ -45,7 +45,6 @@ describe('migrationsStateActionMachine', () => { pollInterval: 0, scrollDuration: '0s', skip: false, - enableV2: true, retryAttempts: 5, }, typeRegistry, diff --git a/src/core/server/saved_objects/routes/deprecations/delete_unknown_types.ts b/src/core/server/saved_objects/routes/deprecations/delete_unknown_types.ts index a9e1a41f01d916..2b6d64bef4f1af 100644 --- a/src/core/server/saved_objects/routes/deprecations/delete_unknown_types.ts +++ b/src/core/server/saved_objects/routes/deprecations/delete_unknown_types.ts @@ -9,18 +9,16 @@ 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 + { kibanaConfig, kibanaVersion }: RouteDependencies ) => { router.post( { @@ -31,7 +29,6 @@ export const registerDeleteUnknownTypesRoute = ( await deleteUnknownTypeObjects({ esClient: context.core.elasticsearch.client, typeRegistry: context.core.savedObjects.typeRegistry, - savedObjectsConfig: config, kibanaConfig, kibanaVersion, }); diff --git a/src/core/server/saved_objects/routes/index.ts b/src/core/server/saved_objects/routes/index.ts index e2698c619b10c5..7aa6711a37c339 100644 --- a/src/core/server/saved_objects/routes/index.ts +++ b/src/core/server/saved_objects/routes/index.ts @@ -76,5 +76,5 @@ export function registerRoutes({ const internalRouter = http.createRouter('/internal/saved_objects/'); registerMigrateRoute(internalRouter, migratorPromise); - registerDeleteUnknownTypesRoute(internalRouter, { config, kibanaConfig, kibanaVersion }); + registerDeleteUnknownTypesRoute(internalRouter, { kibanaConfig, kibanaVersion }); } diff --git a/src/core/server/saved_objects/routes/integration_tests/delete_unknown_types.test.ts b/src/core/server/saved_objects/routes/integration_tests/delete_unknown_types.test.ts index fef2b2d5870e0c..0c7fbdda89fbfe 100644 --- a/src/core/server/saved_objects/routes/integration_tests/delete_unknown_types.test.ts +++ b/src/core/server/saved_objects/routes/integration_tests/delete_unknown_types.test.ts @@ -13,7 +13,6 @@ import { elasticsearchServiceMock } from '../../../../../core/server/elasticsear 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>; @@ -24,13 +23,6 @@ describe('POST /internal/saved_objects/deprecations/_delete_unknown_types', () = 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']; @@ -54,7 +46,6 @@ describe('POST /internal/saved_objects/deprecations/_delete_unknown_types', () = registerDeleteUnknownTypesRoute(router, { kibanaVersion, kibanaConfig, - config, }); await server.start(); diff --git a/src/core/server/saved_objects/saved_objects_config.test.ts b/src/core/server/saved_objects/saved_objects_config.test.ts index 720b28403edf20..06b9e9661b746e 100644 --- a/src/core/server/saved_objects/saved_objects_config.test.ts +++ b/src/core/server/saved_objects/saved_objects_config.test.ts @@ -22,7 +22,7 @@ describe('migrations config', function () { const { messages } = applyMigrationsDeprecations({ enableV2: true }); expect(messages).toMatchInlineSnapshot(` Array [ - "\\"migrations.enableV2\\" is deprecated and will be removed in an upcoming release without any further notice.", + "You no longer need to configure \\"migrations.enableV2\\".", ] `); }); @@ -31,7 +31,7 @@ describe('migrations config', function () { const { messages } = applyMigrationsDeprecations({ enableV2: false }); expect(messages).toMatchInlineSnapshot(` Array [ - "\\"migrations.enableV2\\" is deprecated and will be removed in an upcoming release without any further notice.", + "You no longer need to configure \\"migrations.enableV2\\".", ] `); }); diff --git a/src/core/server/saved_objects/saved_objects_config.ts b/src/core/server/saved_objects/saved_objects_config.ts index c9b4b4499fa808..02fbd974da4ae9 100644 --- a/src/core/server/saved_objects/saved_objects_config.ts +++ b/src/core/server/saved_objects/saved_objects_config.ts @@ -7,8 +7,8 @@ */ import { schema, TypeOf } from '@kbn/config-schema'; +import { ConfigDeprecationProvider } from '../config'; import type { ServiceConfigDescriptor } from '../internal_types'; -import type { ConfigDeprecationProvider } from '../config'; const migrationSchema = schema.object({ batchSize: schema.number({ defaultValue: 1_000 }), @@ -16,29 +16,12 @@ const migrationSchema = schema.object({ scrollDuration: schema.string({ defaultValue: '15m' }), pollInterval: schema.number({ defaultValue: 1_500 }), skip: schema.boolean({ defaultValue: false }), - enableV2: schema.boolean({ defaultValue: true }), retryAttempts: schema.number({ defaultValue: 15 }), }); export type SavedObjectsMigrationConfigType = TypeOf; -const migrationDeprecations: ConfigDeprecationProvider = () => [ - (settings, fromPath, addDeprecation) => { - const migrationsConfig = settings[fromPath]; - if (migrationsConfig?.enableV2 !== undefined) { - addDeprecation({ - configPath: `${fromPath}.enableV2`, - message: - '"migrations.enableV2" is deprecated and will be removed in an upcoming release without any further notice.', - documentationUrl: 'https://ela.st/kbn-so-migration-v2', - correctiveActions: { - manualSteps: [`Remove "migrations.enableV2" from your kibana configs.`], - }, - }); - } - return settings; - }, -]; +const migrationDeprecations: ConfigDeprecationProvider = ({ unused }) => [unused('enableV2')]; export const savedObjectsMigrationConfig: ServiceConfigDescriptor = { diff --git a/src/core/server/saved_objects/service/lib/get_index_for_type.test.ts b/src/core/server/saved_objects/service/lib/get_index_for_type.test.ts index fa065b02b8050a..16e3ba9495f045 100644 --- a/src/core/server/saved_objects/service/lib/get_index_for_type.test.ts +++ b/src/core/server/saved_objects/service/lib/get_index_for_type.test.ts @@ -18,63 +18,27 @@ describe('getIndexForType', () => { 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'); - }); + 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, + }) + ).toEqual('.foo-index_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'); - }); + 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, + }) + ).toEqual('.kibana_8.0.0'); }); }); diff --git a/src/core/server/saved_objects/service/lib/get_index_for_type.ts b/src/core/server/saved_objects/service/lib/get_index_for_type.ts index cef477e6dd8402..ae34e6063e0a56 100644 --- a/src/core/server/saved_objects/service/lib/get_index_for_type.ts +++ b/src/core/server/saved_objects/service/lib/get_index_for_type.ts @@ -11,7 +11,6 @@ import { ISavedObjectTypeRegistry } from '../../saved_objects_type_registry'; interface GetIndexForTypeOptions { type: string; typeRegistry: ISavedObjectTypeRegistry; - migV2Enabled: boolean; kibanaVersion: string; defaultIndex: string; } @@ -19,18 +18,8 @@ interface GetIndexForTypeOptions { 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; - } + return `${typeRegistry.getIndex(type) || defaultIndex}_${kibanaVersion}`; }; diff --git a/src/core/server/saved_objects/service/lib/repository.test.js b/src/core/server/saved_objects/service/lib/repository.test.js index 82a0dd71700f65..45865a2fb988f9 100644 --- a/src/core/server/saved_objects/service/lib/repository.test.js +++ b/src/core/server/saved_objects/service/lib/repository.test.js @@ -612,12 +612,18 @@ describe('SavedObjectsRepository', () => { it(`should use default index`, async () => { await bulkCreateSuccess([obj1, obj2]); - expectClientCallArgsAction([obj1, obj2], { method: 'create', _index: '.kibana-test' }); + expectClientCallArgsAction([obj1, obj2], { + method: 'create', + _index: '.kibana-test_8.0.0-testing', + }); }); it(`should use custom index`, async () => { await bulkCreateSuccess([obj1, obj2].map((x) => ({ ...x, type: CUSTOM_INDEX_TYPE }))); - expectClientCallArgsAction([obj1, obj2], { method: 'create', _index: 'custom' }); + expectClientCallArgsAction([obj1, obj2], { + method: 'create', + _index: 'custom_8.0.0-testing', + }); }); it(`prepends namespace to the id when providing namespace for single-namespace type`, async () => { @@ -2091,7 +2097,7 @@ describe('SavedObjectsRepository', () => { it(`should use default index`, async () => { await createSuccess(type, attributes, { id }); expect(client.create).toHaveBeenCalledWith( - expect.objectContaining({ index: '.kibana-test' }), + expect.objectContaining({ index: '.kibana-test_8.0.0-testing' }), expect.anything() ); }); @@ -2099,7 +2105,7 @@ describe('SavedObjectsRepository', () => { it(`should use custom index`, async () => { await createSuccess(CUSTOM_INDEX_TYPE, attributes, { id }); expect(client.create).toHaveBeenCalledWith( - expect.objectContaining({ index: 'custom' }), + expect.objectContaining({ index: 'custom_8.0.0-testing' }), expect.anything() ); }); @@ -2679,7 +2685,9 @@ describe('SavedObjectsRepository', () => { it(`should use all indices for types that are not namespace-agnostic`, async () => { await deleteByNamespaceSuccess(namespace); expect(client.updateByQuery).toHaveBeenCalledWith( - expect.objectContaining({ index: ['.kibana-test', 'custom'] }), + expect.objectContaining({ + index: ['.kibana-test_8.0.0-testing', 'custom_8.0.0-testing'], + }), expect.anything() ); }); @@ -2769,7 +2777,7 @@ describe('SavedObjectsRepository', () => { await removeReferencesToSuccess(); expect(client.updateByQuery).toHaveBeenCalledWith( expect.objectContaining({ - index: ['.kibana-test', 'custom'], + index: ['.kibana-test_8.0.0-testing', 'custom_8.0.0-testing'], }), expect.anything() ); diff --git a/src/core/server/saved_objects/service/lib/repository.ts b/src/core/server/saved_objects/service/lib/repository.ts index c74092faad96a8..26ebef4d12ea5c 100644 --- a/src/core/server/saved_objects/service/lib/repository.ts +++ b/src/core/server/saved_objects/service/lib/repository.ts @@ -2077,7 +2077,6 @@ export class SavedObjectsRepository { defaultIndex: this._index, typeRegistry: this._registry, kibanaVersion: this._migrator.kibanaVersion, - migV2Enabled: this._migrator.soMigrationsConfig.enableV2, }); } diff --git a/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker b/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker index 7d486e4717e575..73ed445d272a1e 100755 --- a/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker +++ b/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker @@ -109,7 +109,6 @@ kibana_vars=( map.tilemap.url migrations.batchSize migrations.maxBatchSizeBytes - migrations.enableV2 migrations.pollInterval migrations.retryAttempts migrations.scrollDuration diff --git a/x-pack/plugins/apm/public/plugin.ts b/x-pack/plugins/apm/public/plugin.ts index 1e1d9ce5687d10..3a439df245609d 100644 --- a/x-pack/plugins/apm/public/plugin.ts +++ b/x-pack/plugins/apm/public/plugin.ts @@ -367,6 +367,7 @@ export class ApmPlugin implements Plugin { fleet.registerExtension({ package: 'apm', view: 'package-policy-edit', + useLatestPackageVersion: true, Component: getLazyAPMPolicyEditExtension(), }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/suggested_curations_callout.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/suggested_curations_callout.test.tsx index 38e57fa0483e69..58e2cd8cf4c9b0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/suggested_curations_callout.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/suggested_curations_callout.test.tsx @@ -26,6 +26,8 @@ const MOCK_VALUES = { }, }, }, + // LicensingLogic + hasPlatinumLicense: true, }; describe('SuggestedCurationsCallout', () => { @@ -56,4 +58,14 @@ describe('SuggestedCurationsCallout', () => { expect(wrapper.isEmptyRender()).toBe(true); }); + + it('is empty when the user has no platinum license', () => { + // This would happen if the user *had* suggestions and then downgraded from platinum to gold or something + const values = set('hasPlatinumLicense', false, MOCK_VALUES); + setMockValues(values); + + const wrapper = shallow(); + + expect(wrapper.isEmptyRender()).toBe(true); + }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/suggested_curations_callout.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/suggested_curations_callout.tsx index a7155b7d2b161d..046cc2d744b009 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/suggested_curations_callout.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/suggested_curations_callout.tsx @@ -10,6 +10,7 @@ import { useValues } from 'kea'; import { i18n } from '@kbn/i18n'; +import { LicensingLogic } from '../../../../shared/licensing'; import { ENGINE_CURATIONS_PATH } from '../../../routes'; import { SuggestionsCallout } from '../../curations/components/suggestions_callout'; import { EngineLogic, generateEnginePath } from '../../engine'; @@ -18,10 +19,15 @@ export const SuggestedCurationsCallout: React.FC = () => { const { engine: { search_relevance_suggestions: searchRelevanceSuggestions }, } = useValues(EngineLogic); + const { hasPlatinumLicense } = useValues(LicensingLogic); const pendingCount = searchRelevanceSuggestions?.curation.pending; - if (typeof searchRelevanceSuggestions === 'undefined' || pendingCount === 0) { + if ( + typeof searchRelevanceSuggestions === 'undefined' || + pendingCount === 0 || + hasPlatinumLicense === false + ) { return null; } diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/layout.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/layout.tsx index 1de37912b05c9f..3daf7fa545f246 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/layout.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/layout.tsx @@ -61,7 +61,11 @@ export const CreatePackagePolicyPageLayout: React.FunctionComponent<{ const isEdit = useMemo(() => ['edit', 'package-edit'].includes(from), [from]); const isUpgrade = useMemo( () => - ['upgrade-from-fleet-policy-list', 'upgrade-from-integrations-policy-list'].includes(from), + [ + 'upgrade-from-fleet-policy-list', + 'upgrade-from-integrations-policy-list', + 'upgrade-from-extension', + ].includes(from), [from] ); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/step_define_package_policy.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/step_define_package_policy.tsx index 7e4896837013c9..29c226ca64f57e 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/step_define_package_policy.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/step_define_package_policy.tsx @@ -105,11 +105,12 @@ export const StepDefinePackagePolicy: React.FunctionComponent<{ agentPolicy?.id || '', packagePolicy.output_id, packagePolicy.namespace, - `${packageInfo.name}-${ - pkgPoliciesWithMatchingNames.length - ? pkgPoliciesWithMatchingNames[pkgPoliciesWithMatchingNames.length - 1] + 1 - : 1 - }`, + packagePolicy.name || + `${packageInfo.name}-${ + pkgPoliciesWithMatchingNames.length + ? pkgPoliciesWithMatchingNames[pkgPoliciesWithMatchingNames.length - 1] + 1 + : 1 + }`, packagePolicy.description, integrationToEnable ) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/types.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/types.ts index d3b1fb12905963..82c18c34977df8 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/types.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/types.ts @@ -11,7 +11,9 @@ export type EditPackagePolicyFrom = | 'policy' | 'edit' | 'upgrade-from-fleet-policy-list' - | 'upgrade-from-integrations-policy-list'; + | 'upgrade-from-integrations-policy-list' + | 'upgrade-from-extension'; + export type PackagePolicyFormState = | 'VALID' | 'INVALID' diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx index 840a5a71a63c7f..71dfb610a91515 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx @@ -41,10 +41,12 @@ import { sendGetOneAgentPolicy, sendGetOnePackagePolicy, sendGetPackageInfoByKey, - sendUpgradePackagePolicy, sendUpgradePackagePolicyDryRun, } from '../../../hooks'; -import { useBreadcrumbs as useIntegrationsBreadcrumbs } from '../../../../integrations/hooks'; +import { + useBreadcrumbs as useIntegrationsBreadcrumbs, + useGetOnePackagePolicy, +} from '../../../../integrations/hooks'; import { Loading, Error, ExtensionWrapper } from '../../../components'; import { ConfirmDeployAgentPolicyModal } from '../components'; import { CreatePackagePolicyPageLayout } from '../create_package_policy_page/components'; @@ -68,7 +70,23 @@ export const EditPackagePolicyPage = memo(() => { params: { packagePolicyId }, } = useRouteMatch<{ policyId: string; packagePolicyId: string }>(); - return ; + const packagePolicy = useGetOnePackagePolicy(packagePolicyId); + + const extensionView = useUIExtension( + packagePolicy.data?.item?.package?.name ?? '', + 'package-policy-edit' + ); + + return ( + + ); }); export const EditPackagePolicyForm = memo<{ @@ -345,29 +363,6 @@ export const EditPackagePolicyForm = memo<{ const { error } = await savePackagePolicy(); if (!error) { - if (isUpgrade) { - const { error: upgradeError } = await sendUpgradePackagePolicy([packagePolicyId]); - - if (upgradeError) { - notifications.toasts.addError(upgradeError, { - title: i18n.translate('xpack.fleet.upgradePackagePolicy.failedNotificationTitle', { - defaultMessage: 'Error upgrading {packagePolicyName}', - values: { - packagePolicyName: packagePolicy.name, - }, - }), - toastMessage: i18n.translate( - 'xpack.fleet.editPackagePolicy.failedConflictNotificationMessage', - { - defaultMessage: `Data is out of date. Refresh the page to get the latest policy.`, - } - ), - }); - - return; - } - } - application.navigateToUrl(successRedirectPath); notifications.toasts.addSuccess({ title: i18n.translate('xpack.fleet.editPackagePolicy.updatedNotificationTitle', { @@ -426,7 +421,7 @@ export const EditPackagePolicyForm = memo<{ const [selectedTab, setSelectedTab] = useState(0); const layoutProps = { - from, + from: extensionView?.useLatestPackageVersion ? 'upgrade-from-extension' : from, cancelUrl, agentPolicy, packageInfo, diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/policy/index.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/policy/index.tsx index cb95634de4c076..ed8ad166cde9b7 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/policy/index.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/policy/index.tsx @@ -10,11 +10,25 @@ import { useRouteMatch } from 'react-router-dom'; // TODO: Needs to be moved import { EditPackagePolicyForm } from '../../../../../fleet/sections/agent_policy/edit_package_policy_page'; +import { useGetOnePackagePolicy, useUIExtension } from '../../../../hooks'; export const Policy = memo(() => { const { params: { packagePolicyId }, } = useRouteMatch<{ packagePolicyId: string }>(); - return ; + const packagePolicy = useGetOnePackagePolicy(packagePolicyId); + + const extensionView = useUIExtension( + packagePolicy.data?.item?.package?.name ?? '', + 'package-policy-edit' + ); + + return ( + + ); }); diff --git a/x-pack/plugins/fleet/public/hooks/use_request/package_policy.ts b/x-pack/plugins/fleet/public/hooks/use_request/package_policy.ts index f8d14647439b2c..5aa36ba2e8268f 100644 --- a/x-pack/plugins/fleet/public/hooks/use_request/package_policy.ts +++ b/x-pack/plugins/fleet/public/hooks/use_request/package_policy.ts @@ -59,6 +59,13 @@ export function useGetPackagePolicies(query: GetPackagePoliciesRequest['query']) }); } +export const useGetOnePackagePolicy = (packagePolicyId: string) => { + return useRequest({ + path: packagePolicyRouteService.getInfoPath(packagePolicyId), + method: 'get', + }); +}; + export const sendGetOnePackagePolicy = (packagePolicyId: string) => { return sendRequest({ path: packagePolicyRouteService.getInfoPath(packagePolicyId), diff --git a/x-pack/plugins/fleet/public/types/ui_extensions.ts b/x-pack/plugins/fleet/public/types/ui_extensions.ts index d365b798fe83e3..6c959bec1d785e 100644 --- a/x-pack/plugins/fleet/public/types/ui_extensions.ts +++ b/x-pack/plugins/fleet/public/types/ui_extensions.ts @@ -50,6 +50,7 @@ export interface PackagePolicyEditExtensionComponentProps { export interface PackagePolicyEditExtension { package: string; view: 'package-policy-edit'; + useLatestPackageVersion?: boolean; Component: LazyExoticComponent; } diff --git a/x-pack/plugins/fleet/server/errors/index.ts b/x-pack/plugins/fleet/server/errors/index.ts index f31719d6c43645..22f4b8cd6daaba 100644 --- a/x-pack/plugins/fleet/server/errors/index.ts +++ b/x-pack/plugins/fleet/server/errors/index.ts @@ -38,6 +38,8 @@ export class PackageCacheError extends IngestManagerError {} export class PackageOperationNotSupportedError extends IngestManagerError {} export class ConcurrentInstallOperationError extends IngestManagerError {} export class AgentReassignmentError extends IngestManagerError {} +export class PackagePolicyIneligibleForUpgradeError extends IngestManagerError {} +export class PackagePolicyValidationError extends IngestManagerError {} export class HostedAgentPolicyRestrictionRelatedError extends IngestManagerError { constructor(message = 'Cannot perform that action') { super( diff --git a/x-pack/plugins/fleet/server/services/package_policy.ts b/x-pack/plugins/fleet/server/services/package_policy.ts index b0c0b9499c68ec..9928ce3063159d 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.ts @@ -45,6 +45,8 @@ import { HostedAgentPolicyRestrictionRelatedError, IngestManagerError, ingestErrorToResponseOptions, + PackagePolicyIneligibleForUpgradeError, + PackagePolicyValidationError, } from '../errors'; import { NewPackagePolicySchema, UpdatePackagePolicySchema } from '../types'; import type { @@ -528,25 +530,25 @@ class PackagePolicyService { pkgName: packagePolicy.package.name, pkgVersion: installedPackage?.version ?? '', }); + } - const isInstalledVersionLessThanOrEqualToPolicyVersion = semverLte( - installedPackage?.version ?? '', - packagePolicy.package.version - ); + const isInstalledVersionLessThanOrEqualToPolicyVersion = semverLte( + packageInfo?.version ?? '', + packagePolicy.package.version + ); - if (isInstalledVersionLessThanOrEqualToPolicyVersion) { - throw new IngestManagerError( - i18n.translate('xpack.fleet.packagePolicy.ineligibleForUpgradeError', { - defaultMessage: - "Package policy {id}'s package version {version} of package {name} is up to date with the installed package. Please install the latest version of {name}.", - values: { - id: packagePolicy.id, - name: packagePolicy.package.name, - version: packagePolicy.package.version, - }, - }) - ); - } + if (isInstalledVersionLessThanOrEqualToPolicyVersion) { + throw new PackagePolicyIneligibleForUpgradeError( + i18n.translate('xpack.fleet.packagePolicy.ineligibleForUpgradeError', { + defaultMessage: + "Package policy {id}'s package version {version} of package {name} is up to date with the installed package. Please install the latest version of {name}.", + values: { + id: packagePolicy.id, + name: packagePolicy.package.name, + version: packagePolicy.package.version, + }, + }) + ); } return { @@ -600,6 +602,13 @@ class PackagePolicyService { currentVersion: packageInfo.version, }); } catch (error) { + // We only want to specifically handle validation errors for the new package policy. If a more severe or + // general error is thrown elsewhere during the upgrade process, we want to surface that directly in + // order to preserve any status code mappings, etc that might be included w/ the particular error type + if (!(error instanceof PackagePolicyValidationError)) { + throw error; + } + result.push({ id, success: false, @@ -653,6 +662,10 @@ class PackagePolicyService { hasErrors, }; } catch (error) { + if (!(error instanceof PackagePolicyValidationError)) { + throw error; + } + return { hasErrors: true, ...ingestErrorToResponseOptions(error), @@ -1089,7 +1102,7 @@ export function overridePackageInputs( return { ...resultingPackagePolicy, errors: responseFormattedValidationErrors }; } - throw new IngestManagerError( + throw new PackagePolicyValidationError( i18n.translate('xpack.fleet.packagePolicyInvalidError', { defaultMessage: 'Package policy is invalid: {errors}', values: { diff --git a/x-pack/plugins/reporting/server/config/index.test.ts b/x-pack/plugins/reporting/server/config/index.test.ts index 1a75f6dfec3bdb..f77713551592b2 100644 --- a/x-pack/plugins/reporting/server/config/index.test.ts +++ b/x-pack/plugins/reporting/server/config/index.test.ts @@ -49,7 +49,7 @@ describe('deprecations', () => { const { messages } = applyReportingDeprecations({ roles: { enabled: true } }); expect(messages).toMatchInlineSnapshot(` Array [ - "Use Kibana application privileges to grant reporting privileges. Using \\"xpack.reporting.roles.allow\\" to grant reporting privileges prevents users from using API Keys to create reports. The \\"xpack.reporting.roles.enabled\\" setting will default to false in a future release.", + "Use Kibana application privileges to grant reporting privileges. Using \\"xpack.reporting.roles.allow\\" to grant reporting privileges is deprecated. The \\"xpack.reporting.roles.enabled\\" setting will default to false in a future release.", ] `); }); diff --git a/x-pack/plugins/reporting/server/config/index.ts b/x-pack/plugins/reporting/server/config/index.ts index 1eeafb4e0c5130..244a4577813dab 100644 --- a/x-pack/plugins/reporting/server/config/index.ts +++ b/x-pack/plugins/reporting/server/config/index.ts @@ -64,7 +64,7 @@ export const config: PluginConfigDescriptor = { defaultMessage: `Use Kibana application privileges to grant reporting privileges.` + ` Using "{fromPath}.roles.allow" to grant reporting privileges` + - ` prevents users from using API Keys to create reports.` + + ` is deprecated.` + ` The "{fromPath}.roles.enabled" setting will default to false` + ` in a future release.`, values: { fromPath }, @@ -74,6 +74,9 @@ export const config: PluginConfigDescriptor = { i18n.translate('xpack.reporting.deprecations.reportingRoles.manualStepOne', { defaultMessage: `Set "xpack.reporting.roles.enabled" to "false" in kibana.yml.`, }), + i18n.translate('xpack.reporting.deprecations.reportingRoles.manualStepOnePartOne', { + defaultMessage: `Remove "xpack.reporting.roles.allow" to "false" in kibana.yml, if present.`, + }), i18n.translate('xpack.reporting.deprecations.reportingRoles.manualStepTwo', { defaultMessage: `Create one or more roles that grant the Kibana application` + diff --git a/x-pack/plugins/reporting/server/core.ts b/x-pack/plugins/reporting/server/core.ts index e09cee8c3c7c2e..6b00e08c586858 100644 --- a/x-pack/plugins/reporting/server/core.ts +++ b/x-pack/plugins/reporting/server/core.ts @@ -13,6 +13,7 @@ import { BasePath, IClusterClient, KibanaRequest, + PackageInfo, PluginInitializerContext, SavedObjectsClientContract, SavedObjectsServiceStart, @@ -57,7 +58,7 @@ export interface ReportingInternalStart { } export class ReportingCore { - private kibanaVersion: string; + private packageInfo: PackageInfo; private pluginSetupDeps?: ReportingInternalSetup; private pluginStartDeps?: ReportingInternalStart; private readonly pluginSetup$ = new Rx.ReplaySubject(); // observe async background setupDeps and config each are done @@ -72,7 +73,7 @@ export class ReportingCore { public getContract: () => ReportingSetup; constructor(private logger: LevelLogger, context: PluginInitializerContext) { - this.kibanaVersion = context.env.packageInfo.version; + this.packageInfo = context.env.packageInfo; const syncConfig = context.config.get(); this.deprecatedAllowedRoles = syncConfig.roles.enabled ? syncConfig.roles.allow : false; this.executeTask = new ExecuteReportTask(this, syncConfig, this.logger); @@ -85,8 +86,8 @@ export class ReportingCore { this.executing = new Set(); } - public getKibanaVersion() { - return this.kibanaVersion; + public getKibanaPackageInfo() { + return this.packageInfo; } /* diff --git a/x-pack/plugins/reporting/server/deprecations/__snapshots__/reporting_role.test.ts.snap b/x-pack/plugins/reporting/server/deprecations/__snapshots__/reporting_role.test.ts.snap new file mode 100644 index 00000000000000..00a2a63280c9e9 --- /dev/null +++ b/x-pack/plugins/reporting/server/deprecations/__snapshots__/reporting_role.test.ts.snap @@ -0,0 +1,113 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`roles mapped to a deprecated role includes steps to remove the incompatible config, when applicable 1`] = ` +Array [ + Object { + "correctiveActions": Object { + "manualSteps": Array [ + "Set \\"xpack.reporting.roles.enabled: false\\" in kibana.yml.", + "Remove \\"xpack.reporting.roles.allow\\" in kibana.yml, if present.", + "Create a custom role with Kibana privileges to grant access to Reporting.", + "Remove the \\"reporting_user\\" role from all users and add the custom role. The affected users are: reportron[reporting_user].", + ], + }, + "deprecationType": "feature", + "documentationUrl": "https://www.elastic.co/guide/en/kibana/branch/kibana-privileges.html", + "level": "warning", + "message": "Existing users have their Reporting privilege granted by a deprecated setting.", + "title": "The \\"reporting_user\\" role is deprecated: check user roles", + }, +] +`; + +exports[`roles mapped to a deprecated role logs a deprecation when a role was found that maps to a deprecated custom role from the roles.allow setting 1`] = ` +Array [ + Object { + "correctiveActions": Object { + "manualSteps": Array [ + "Create a custom role with Kibana privileges to grant access to Reporting.", + "Remove the \\"reporting_user\\" role from all role mappings and add the custom role. The affected role mappings are: dungeon_master[my_test_reporting_user].", + ], + }, + "deprecationType": "feature", + "documentationUrl": "https://www.elastic.co/guide/en/kibana/branch/kibana-privileges.html", + "level": "warning", + "message": "Existing roles are mapped to a deprecated role for Reporting privileges", + "title": "The \\"reporting_user\\" role is deprecated: check role mappings", + }, +] +`; + +exports[`roles mapped to a deprecated role logs a deprecation when a role was found that maps to the deprecated reporting_user role 1`] = ` +Array [ + Object { + "correctiveActions": Object { + "manualSteps": Array [ + "Create a custom role with Kibana privileges to grant access to Reporting.", + "Remove the \\"reporting_user\\" role from all role mappings and add the custom role. The affected role mappings are: dungeon_master[reporting_user].", + ], + }, + "deprecationType": "feature", + "documentationUrl": "https://www.elastic.co/guide/en/kibana/branch/kibana-privileges.html", + "level": "warning", + "message": "Existing roles are mapped to a deprecated role for Reporting privileges", + "title": "The \\"reporting_user\\" role is deprecated: check role mappings", + }, +] +`; + +exports[`users assigned to a deprecated role includes steps to remove the incompatible config, when applicable 1`] = ` +Array [ + Object { + "correctiveActions": Object { + "manualSteps": Array [ + "Set \\"xpack.reporting.roles.enabled: false\\" in kibana.yml.", + "Remove \\"xpack.reporting.roles.allow\\" in kibana.yml, if present.", + "Create a custom role with Kibana privileges to grant access to Reporting.", + "Remove the \\"reporting_user\\" role from all users and add the custom role. The affected users are: reportron[reporting_user].", + ], + }, + "deprecationType": "feature", + "documentationUrl": "https://www.elastic.co/guide/en/kibana/branch/kibana-privileges.html", + "level": "warning", + "message": "Existing users have their Reporting privilege granted by a deprecated setting.", + "title": "The \\"reporting_user\\" role is deprecated: check user roles", + }, +] +`; + +exports[`users assigned to a deprecated role logs a deprecation when a user was found with a deprecated custom role from the roles.allow setting 1`] = ` +Array [ + Object { + "correctiveActions": Object { + "manualSteps": Array [ + "Create a custom role with Kibana privileges to grant access to Reporting.", + "Remove the \\"reporting_user\\" role from all users and add the custom role. The affected users are: reportron[my_test_reporting_user].", + ], + }, + "deprecationType": "feature", + "documentationUrl": "https://www.elastic.co/guide/en/kibana/branch/kibana-privileges.html", + "level": "warning", + "message": "Existing users have their Reporting privilege granted by a deprecated setting.", + "title": "The \\"reporting_user\\" role is deprecated: check user roles", + }, +] +`; + +exports[`users assigned to a deprecated role logs a deprecation when a user was found with a deprecated reporting_user role 1`] = ` +Array [ + Object { + "correctiveActions": Object { + "manualSteps": Array [ + "Create a custom role with Kibana privileges to grant access to Reporting.", + "Remove the \\"reporting_user\\" role from all users and add the custom role. The affected users are: reportron[reporting_user].", + ], + }, + "deprecationType": "feature", + "documentationUrl": "https://www.elastic.co/guide/en/kibana/branch/kibana-privileges.html", + "level": "warning", + "message": "Existing users have their Reporting privilege granted by a deprecated setting.", + "title": "The \\"reporting_user\\" role is deprecated: check user roles", + }, +] +`; diff --git a/x-pack/plugins/reporting/server/deprecations/reporting_role.test.ts b/x-pack/plugins/reporting/server/deprecations/reporting_role.test.ts index 5b0719bf6e6b6a..2286a9767f0001 100644 --- a/x-pack/plugins/reporting/server/deprecations/reporting_role.test.ts +++ b/x-pack/plugins/reporting/server/deprecations/reporting_role.test.ts @@ -5,19 +5,25 @@ * 2.0. */ +import { GetDeprecationsContext, IScopedClusterClient } from 'kibana/server'; +import { elasticsearchServiceMock } from 'src/core/server/mocks'; import { ReportingCore } from '..'; +import { + createMockConfigSchema, + createMockPluginSetup, + createMockReportingCore, +} from '../test_helpers'; import { getDeprecationsInfo } from './reporting_role'; -import { createMockConfigSchema, createMockReportingCore } from '../test_helpers'; -import { elasticsearchServiceMock } from 'src/core/server/mocks'; -import { GetDeprecationsContext, IScopedClusterClient } from 'kibana/server'; let reportingCore: ReportingCore; let context: GetDeprecationsContext; let esClient: jest.Mocked; beforeEach(async () => { - const mockReportingConfig = createMockConfigSchema({ roles: { enabled: false } }); - reportingCore = await createMockReportingCore(mockReportingConfig); + reportingCore = await createMockReportingCore( + createMockConfigSchema({ roles: { enabled: false } }) + ); + esClient = elasticsearchServiceMock.createScopedClusterClient(); esClient.asCurrentUser.security.getUser = jest.fn().mockResolvedValue({ body: { xyz: { username: 'normal_user', roles: ['data_analyst'] } }, @@ -26,95 +32,132 @@ beforeEach(async () => { }); test('logs no deprecations when setup has no issues', async () => { - expect( - await getDeprecationsInfo(context, { - reportingCore, - }) - ).toMatchInlineSnapshot(`Array []`); + expect(await getDeprecationsInfo(context, { reportingCore })).toMatchInlineSnapshot(`Array []`); }); -test('logs a plain message when only a reporting_user role issue is found', async () => { - esClient.asCurrentUser.security.getUser = jest.fn().mockResolvedValue({ - body: { reportron: { username: 'reportron', roles: ['kibana_admin', 'reporting_user'] } }, +describe('users assigned to a deprecated role', () => { + test('logs a deprecation when a user was found with a deprecated reporting_user role', async () => { + esClient.asCurrentUser.security.getUser = jest.fn().mockResolvedValue({ + body: { reportron: { username: 'reportron', roles: ['kibana_admin', 'reporting_user'] } }, + }); + + reportingCore = await createMockReportingCore(createMockConfigSchema()); + + expect(await getDeprecationsInfo(context, { reportingCore })).toMatchSnapshot(); }); - expect( - await getDeprecationsInfo(context, { - reportingCore, - }) - ).toMatchInlineSnapshot(` - Array [ - Object { - "correctiveActions": Object { - "manualSteps": Array [ - "Create one or more custom roles that provide Kibana application privileges to reporting features in **Management > Security > Roles**.", - "Assign the custom role(s) as desired, and remove the \\"reporting_user\\" role from the user(s).", - ], - }, - "documentationUrl": "https://www.elastic.co/guide/en/kibana/current/secure-reporting.html", - "level": "critical", - "message": "The deprecated \\"reporting_user\\" role has been found for 1 user(s): \\"reportron\\"", - "title": "Found deprecated reporting role", + + test('logs a deprecation when a user was found with a deprecated custom role from the roles.allow setting', async () => { + reportingCore = await createMockReportingCore( + createMockConfigSchema({ roles: { allow: ['my_test_reporting_user'] } }) + ); + esClient.asCurrentUser.security.getUser = jest.fn().mockResolvedValue({ + body: { + reportron: { username: 'reportron', roles: ['kibana_admin', 'my_test_reporting_user'] }, }, - ] - `); + }); + + expect(await getDeprecationsInfo(context, { reportingCore })).toMatchSnapshot(); + }); + + test('includes steps to remove the incompatible config, when applicable', async () => { + esClient.asCurrentUser.security.getUser = jest.fn().mockResolvedValue({ + body: { reportron: { username: 'reportron', roles: ['kibana_admin', 'reporting_user'] } }, + }); + + reportingCore = await createMockReportingCore( + createMockConfigSchema({ roles: { enabled: true } }) + ); + + expect(await getDeprecationsInfo(context, { reportingCore })).toMatchSnapshot(); + }); }); -test('logs multiple entries when multiple reporting_user role issues are found', async () => { - esClient.asCurrentUser.security.getUser = jest.fn().mockResolvedValue({ - body: { - reportron: { username: 'reportron', roles: ['kibana_admin', 'reporting_user'] }, - supercooluser: { username: 'supercooluser', roles: ['kibana_admin', 'reporting_user'] }, - }, +describe('roles mapped to a deprecated role', () => { + test('logs a deprecation when a role was found that maps to the deprecated reporting_user role', async () => { + esClient.asCurrentUser.security.getRoleMapping = jest.fn().mockResolvedValue({ + body: { dungeon_master: { roles: ['reporting_user'] } }, + }); + + reportingCore = await createMockReportingCore(createMockConfigSchema()); + + expect(await getDeprecationsInfo(context, { reportingCore })).toMatchSnapshot(); + }); + + test('logs a deprecation when a role was found that maps to a deprecated custom role from the roles.allow setting', async () => { + reportingCore = await createMockReportingCore( + createMockConfigSchema({ roles: { allow: ['my_test_reporting_user'] } }) + ); + esClient.asCurrentUser.security.getRoleMapping = jest.fn().mockResolvedValue({ + body: { dungeon_master: { roles: ['my_test_reporting_user'] } }, + }); + + expect(await getDeprecationsInfo(context, { reportingCore })).toMatchSnapshot(); }); - expect( - await getDeprecationsInfo(context, { - reportingCore, - }) - ).toMatchInlineSnapshot(` + test('includes steps to remove the incompatible config, when applicable', async () => { + esClient.asCurrentUser.security.getUser = jest.fn().mockResolvedValue({ + body: { reportron: { username: 'reportron', roles: ['kibana_admin', 'reporting_user'] } }, + }); + + reportingCore = await createMockReportingCore( + createMockConfigSchema({ roles: { enabled: true } }) + ); + + expect(await getDeprecationsInfo(context, { reportingCore })).toMatchSnapshot(); + }); +}); + +describe('check deprecations when security is disabled', () => { + test('logs no deprecations: roles not enabled', async () => { + reportingCore = await createMockReportingCore( + createMockConfigSchema({ roles: { enabled: false } }), + createMockPluginSetup({ security: null }) + ); + expect(await getDeprecationsInfo(context, { reportingCore })).toMatchInlineSnapshot(`Array []`); + }); + + test('logs no deprecations: roles enabled', async () => { + const mockReportingConfig = createMockConfigSchema(); // roles.enabled: true is default in 7.x / 8.0 + reportingCore = await createMockReportingCore( + mockReportingConfig, + createMockPluginSetup({ security: null }) + ); + + expect(await getDeprecationsInfo(context, { reportingCore })).toMatchInlineSnapshot(`Array []`); + }); +}); + +it('insufficient permissions', async () => { + const permissionsError = new Error('you shall not pass'); + (permissionsError as unknown as { statusCode: number }).statusCode = 403; + esClient.asCurrentUser.security.getUser = jest.fn().mockRejectedValue(permissionsError); + esClient.asCurrentUser.security.getRoleMapping = jest.fn().mockRejectedValue(permissionsError); + + expect(await getDeprecationsInfo(context, { reportingCore })).toMatchInlineSnapshot(` Array [ Object { "correctiveActions": Object { "manualSteps": Array [ - "Create one or more custom roles that provide Kibana application privileges to reporting features in **Management > Security > Roles**.", - "Assign the custom role(s) as desired, and remove the \\"reporting_user\\" role from the user(s).", + "Make sure you have a \\"manage_security\\" cluster privilege assigned.", ], }, - "documentationUrl": "https://www.elastic.co/guide/en/kibana/current/secure-reporting.html", - "level": "critical", - "message": "The deprecated \\"reporting_user\\" role has been found for 2 user(s): \\"reportron\\", \\"supercooluser\\"", - "title": "Found deprecated reporting role", + "deprecationType": "feature", + "documentationUrl": "https://www.elastic.co/guide/en/kibana/current/xpack-security.html#_required_permissions_7", + "level": "fetch_error", + "message": "You do not have enough permissions to fix this deprecation.", + "title": "The \\"reporting_user\\" role is deprecated: check user roles", }, - ] - `); -}); - -test('logs an expanded message when a config issue and a reporting_user role issue is found', async () => { - esClient.asCurrentUser.security.getUser = jest.fn().mockResolvedValue({ - body: { reportron: { username: 'reportron', roles: ['kibana_admin', 'reporting_user'] } }, - }); - - const mockReportingConfig = createMockConfigSchema({ roles: { enabled: true } }); - reportingCore = await createMockReportingCore(mockReportingConfig); - - expect( - await getDeprecationsInfo(context, { - reportingCore, - }) - ).toMatchInlineSnapshot(` - Array [ Object { "correctiveActions": Object { "manualSteps": Array [ - "Set \\"xpack.reporting.roles.enabled: false\\" in kibana.yml", - "Create one or more custom roles that provide Kibana application privileges to reporting features in **Management > Security > Roles**.", - "Assign the custom role(s) as desired, and remove the \\"reporting_user\\" role from the user(s).", + "Make sure you have a \\"manage_security\\" cluster privilege assigned.", ], }, - "documentationUrl": "https://www.elastic.co/guide/en/kibana/current/secure-reporting.html", - "level": "critical", - "message": "The deprecated \\"reporting_user\\" role has been found for 1 user(s): \\"reportron\\"", - "title": "Found deprecated reporting role", + "deprecationType": "feature", + "documentationUrl": "https://www.elastic.co/guide/en/kibana/current/xpack-security.html#_required_permissions_7", + "level": "fetch_error", + "message": "You do not have enough permissions to fix this deprecation.", + "title": "The \\"reporting_user\\" role is deprecated: check role mappings", }, ] `); diff --git a/x-pack/plugins/reporting/server/deprecations/reporting_role.ts b/x-pack/plugins/reporting/server/deprecations/reporting_role.ts index 6e08169727d1bc..a2a7e9c78726da 100644 --- a/x-pack/plugins/reporting/server/deprecations/reporting_role.ts +++ b/x-pack/plugins/reporting/server/deprecations/reporting_role.ts @@ -5,65 +5,206 @@ * 2.0. */ -import type { GetDeprecationsContext, DeprecationsDetails } from 'src/core/server'; +import { + SecurityGetRoleMappingResponse, + SecurityGetUserResponse, +} from '@elastic/elasticsearch/api/types'; import { i18n } from '@kbn/i18n'; -import { ReportingCore } from '..'; +import type { + DeprecationsDetails, + ElasticsearchClient, + GetDeprecationsContext, +} from 'src/core/server'; +import { ReportingCore } from '../'; +import { deprecations } from '../lib/deprecations'; -const deprecatedRole = 'reporting_user'; -const upgradableConfig = 'xpack.reporting.roles.enabled: false'; +const REPORTING_USER_ROLE_NAME = 'reporting_user'; +const getDocumentationUrl = (branch: string) => + `https://www.elastic.co/guide/en/kibana/${branch}/kibana-privileges.html`; interface ExtraDependencies { reportingCore: ReportingCore; } -export const getDeprecationsInfo = async ( +export async function getDeprecationsInfo( { esClient }: GetDeprecationsContext, { reportingCore }: ExtraDependencies -): Promise => { +): Promise { + const client = esClient.asCurrentUser; + const { security } = reportingCore.getPluginSetupDeps(); + + // Nothing to do if security is disabled + if (!security?.license.isEnabled()) { + return []; + } + + const config = reportingCore.getConfig(); + const deprecatedRoles = config.get('roles', 'allow') || ['reporting_user']; + + return [ + ...(await getUsersDeprecations(client, reportingCore, deprecatedRoles)), + ...(await getRoleMappingsDeprecations(client, reportingCore, deprecatedRoles)), + ]; +} + +async function getUsersDeprecations( + client: ElasticsearchClient, + reportingCore: ReportingCore, + deprecatedRoles: string[] +): Promise { const usingDeprecatedConfig = !reportingCore.getContract().usesUiCapabilities(); - const deprecations: DeprecationsDetails[] = []; - const { body: users } = await esClient.asCurrentUser.security.getUser(); + const strings = { + title: i18n.translate('xpack.reporting.deprecations.reportingRoleUsersTitle', { + defaultMessage: 'The "{reportingUserRoleName}" role is deprecated: check user roles', + values: { reportingUserRoleName: REPORTING_USER_ROLE_NAME }, + }), + message: i18n.translate('xpack.reporting.deprecations.reportingRoleUsersMessage', { + defaultMessage: + 'Existing users have their Reporting privilege granted by a deprecated setting.', + }), + manualSteps: (usersRoles: string) => [ + ...(usingDeprecatedConfig + ? [ + i18n.translate('xpack.reporting.deprecations.reportingRoleUsers.manualStepOne', { + defaultMessage: 'Set "xpack.reporting.roles.enabled: false" in kibana.yml.', + }), + i18n.translate('xpack.reporting.deprecations.reportingRoleUsers.manualStepTwo', { + defaultMessage: 'Remove "xpack.reporting.roles.allow" in kibana.yml, if present.', + }), + ] + : []), + + i18n.translate('xpack.reporting.deprecations.reportingRoleUsers.manualStepThree', { + defaultMessage: 'Create a custom role with Kibana privileges to grant access to Reporting.', + }), + i18n.translate('xpack.reporting.deprecations.reportingRoleUsers.manualStepFour', { + defaultMessage: + 'Remove the "reporting_user" role from all users and add the custom role. The affected users are: {usersRoles}.', + values: { usersRoles }, + }), + ], + }; + + let users: SecurityGetUserResponse; + try { + users = (await client.security.getUser()).body; + } catch (err) { + const { logger } = reportingCore.getPluginSetupDeps(); + if (deprecations.getErrorStatusCode(err) === 403) { + logger.warn( + `Failed to retrieve users when checking for deprecations:` + + ` the "manage_security" cluster privilege is required.` + ); + } else { + logger.error( + `Failed to retrieve users when checking for deprecations,` + + ` unexpected error: ${deprecations.getDetailedErrorMessage(err)}.` + ); + } + return deprecations.deprecationError(strings.title, err); + } + + const reportingUsers = Object.entries(users).reduce((userSet, current) => { + const [userName, user] = current; + const foundRole = user.roles.find((role) => deprecatedRoles.includes(role)); + return foundRole ? [...userSet, `${userName}[${foundRole}]`] : userSet; + }, [] as string[]); - const reportingUsers = Object.entries(users) - .filter(([, user]) => user.roles.includes(deprecatedRole)) - .map(([, user]) => user.username); + if (reportingUsers.length === 0) { + return []; + } + + return [ + { + title: strings.title, + message: strings.message, + correctiveActions: { manualSteps: strings.manualSteps(reportingUsers.join(', ')) }, + level: 'warning', + deprecationType: 'feature', + documentationUrl: getDocumentationUrl(reportingCore.getKibanaPackageInfo().branch), + }, + ]; +} - const numReportingUsers = reportingUsers.length; +async function getRoleMappingsDeprecations( + client: ElasticsearchClient, + reportingCore: ReportingCore, + deprecatedRoles: string[] +): Promise { + const usingDeprecatedConfig = !reportingCore.getContract().usesUiCapabilities(); + const strings = { + title: i18n.translate('xpack.reporting.deprecations.reportingRoleMappingsTitle', { + defaultMessage: 'The "{reportingUserRoleName}" role is deprecated: check role mappings', + values: { reportingUserRoleName: REPORTING_USER_ROLE_NAME }, + }), + message: i18n.translate('xpack.reporting.deprecations.reportingRoleMappingsMessage', { + defaultMessage: 'Existing roles are mapped to a deprecated role for Reporting privileges', + }), + manualSteps: (roleMappings: string) => [ + ...(usingDeprecatedConfig + ? [ + i18n.translate('xpack.reporting.deprecations.reportingRoleMappings.manualStepOne', { + defaultMessage: 'Set "xpack.reporting.roles.enabled: false" in kibana.yml.', + }), + i18n.translate('xpack.reporting.deprecations.reportingRoleMappings.manualStepTwo', { + defaultMessage: 'Remove "xpack.reporting.roles.allow" in kibana.yml, if present.', + }), + ] + : []), - if (numReportingUsers > 0) { - deprecations.push({ - title: i18n.translate('xpack.reporting.deprecations.reportingRoleTitle', { - defaultMessage: 'Found deprecated reporting role', + i18n.translate('xpack.reporting.deprecations.reportingRoleMappings.manualStepThree', { + defaultMessage: 'Create a custom role with Kibana privileges to grant access to Reporting.', }), - message: i18n.translate('xpack.reporting.deprecations.reportingRoleMessage', { + i18n.translate('xpack.reporting.deprecations.reportingRoleMappings.manualStepFour', { defaultMessage: - 'The deprecated "{deprecatedRole}" role has been found for {numReportingUsers} user(s): "{usernames}"', - values: { deprecatedRole, numReportingUsers, usernames: reportingUsers.join('", "') }, + 'Remove the "reporting_user" role from all role mappings and add the custom role. The affected role mappings are: {roleMappings}.', + values: { roleMappings }, }), - documentationUrl: 'https://www.elastic.co/guide/en/kibana/current/secure-reporting.html', - level: 'critical', - correctiveActions: { - manualSteps: [ - ...(usingDeprecatedConfig - ? [ - i18n.translate('xpack.reporting.deprecations.reportingRole.manualStepOneMessage', { - defaultMessage: 'Set "{upgradableConfig}" in kibana.yml', - values: { upgradableConfig }, - }), - ] - : []), - i18n.translate('xpack.reporting.deprecations.reportingRole.manualStepTwoMessage', { - defaultMessage: `Create one or more custom roles that provide Kibana application privileges to reporting features in **Management > Security > Roles**.`, - }), - i18n.translate('xpack.reporting.deprecations.reportingRole.manualStepThreeMessage', { - defaultMessage: - 'Assign the custom role(s) as desired, and remove the "{deprecatedRole}" role from the user(s).', - values: { deprecatedRole }, - }), - ], - }, - }); + ], + }; + + let roleMappings: SecurityGetRoleMappingResponse; + try { + roleMappings = (await client.security.getRoleMapping()).body; + } catch (err) { + const { logger } = reportingCore.getPluginSetupDeps(); + if (deprecations.getErrorStatusCode(err) === 403) { + logger.warn( + `Failed to retrieve role mappings when checking for deprecations:` + + ` the "manage_security" cluster privilege is required.` + ); + } else { + logger.error( + `Failed to retrieve role mappings when checking for deprecations,` + + ` unexpected error: ${deprecations.getDetailedErrorMessage(err)}.` + ); + } + return deprecations.deprecationError(strings.title, err); } - return deprecations; -}; + const roleMappingsWithReportingRole: string[] = Object.entries(roleMappings).reduce( + (roleSet, current) => { + const [roleName, role] = current; + const foundMapping = role.roles.find((roll) => deprecatedRoles.includes(roll)); + return foundMapping ? [...roleSet, `${roleName}[${foundMapping}]`] : roleSet; + }, + [] as string[] + ); + + if (roleMappingsWithReportingRole.length === 0) { + return []; + } + + return [ + { + title: strings.title, + message: strings.message, + correctiveActions: { + manualSteps: strings.manualSteps(roleMappingsWithReportingRole.join(', ')), + }, + level: 'warning', + deprecationType: 'feature', + documentationUrl: getDocumentationUrl(reportingCore.getKibanaPackageInfo().branch), + }, + ]; +} diff --git a/x-pack/plugins/reporting/server/lib/deprecations/index.ts b/x-pack/plugins/reporting/server/lib/deprecations/index.ts index 95594940e07e23..2d55c3b4c22d85 100644 --- a/x-pack/plugins/reporting/server/lib/deprecations/index.ts +++ b/x-pack/plugins/reporting/server/lib/deprecations/index.ts @@ -5,8 +5,82 @@ * 2.0. */ +import { errors } from '@elastic/elasticsearch'; +import Boom from '@hapi/boom'; +import { i18n } from '@kbn/i18n'; +import { DeprecationsDetails } from 'kibana/server'; import { checkIlmMigrationStatus } from './check_ilm_migration_status'; +function deprecationError(title: string, error: Error): DeprecationsDetails[] { + if (getErrorStatusCode(error) === 403) { + return [ + { + title, + level: 'fetch_error', // NOTE: is fetch_error not shown in the Upgrade Assistant UI? + deprecationType: 'feature', + message: i18n.translate( + 'xpack.reporting.deprecations.reportingRole.forbiddenErrorMessage', + { defaultMessage: 'You do not have enough permissions to fix this deprecation.' } + ), + documentationUrl: `https://www.elastic.co/guide/en/kibana/current/xpack-security.html#_required_permissions_7`, + correctiveActions: { + manualSteps: [ + i18n.translate( + 'xpack.reporting.deprecations.reportingRole.forbiddenErrorCorrectiveAction', + { + defaultMessage: + 'Make sure you have a "manage_security" cluster privilege assigned.', + } + ), + ], + }, + }, + ]; + } + + return [ + { + title, + level: 'fetch_error', // NOTE: is fetch_error not shown in the Upgrade Assistant UI? + deprecationType: 'feature', + message: i18n.translate('xpack.reporting.deprecations.reportingRole.unknownErrorMessage', { + defaultMessage: 'Failed to perform deprecation check. Check Kibana logs for more details.', + }), + correctiveActions: { + manualSteps: [ + i18n.translate( + 'xpack.reporting.deprecations.reportingRole.unknownErrorCorrectiveAction', + { defaultMessage: 'Check Kibana logs for more details.' } + ), + ], + }, + }, + ]; +} + +function getErrorStatusCode(error: any): number { + if (error instanceof errors.ResponseError) { + return error.statusCode; + } + + return Boom.isBoom(error) ? error.output.statusCode : error.statusCode || error.status; +} + +function getDetailedErrorMessage(error: any): string { + if (error instanceof errors.ResponseError) { + return JSON.stringify(error.body); + } + + if (Boom.isBoom(error)) { + return JSON.stringify(error.output.payload); + } + + return error.message; +} + export const deprecations = { checkIlmMigrationStatus, + deprecationError, + getDetailedErrorMessage, + getErrorStatusCode, }; diff --git a/x-pack/plugins/reporting/server/routes/diagnostic/browser.test.ts b/x-pack/plugins/reporting/server/routes/diagnostic/browser.test.ts index f32e1b437bc335..7677f37702f0d8 100644 --- a/x-pack/plugins/reporting/server/routes/diagnostic/browser.test.ts +++ b/x-pack/plugins/reporting/server/routes/diagnostic/browser.test.ts @@ -52,11 +52,13 @@ describe('POST /diagnose/browser', () => { () => ({ usesUiCapabilities: () => false }) ); - const mockSetupDeps = createMockPluginSetup({ - router: httpSetup.createRouter(''), - }); - - core = await createMockReportingCore(config, mockSetupDeps); + core = await createMockReportingCore( + config, + createMockPluginSetup({ + router: httpSetup.createRouter(''), + security: null, + }) + ); mockedSpawn.mockImplementation(() => ({ removeAllListeners: jest.fn(), diff --git a/x-pack/plugins/reporting/server/routes/diagnostic/screenshot.test.ts b/x-pack/plugins/reporting/server/routes/diagnostic/screenshot.test.ts index 6d844f9637a0bd..dd543707fe66a0 100644 --- a/x-pack/plugins/reporting/server/routes/diagnostic/screenshot.test.ts +++ b/x-pack/plugins/reporting/server/routes/diagnostic/screenshot.test.ts @@ -50,11 +50,13 @@ describe('POST /diagnose/screenshot', () => { () => ({ usesUiCapabilities: () => false }) ); - const mockSetupDeps = createMockPluginSetup({ - router: httpSetup.createRouter(''), - }); - - core = await createMockReportingCore(config, mockSetupDeps); + core = await createMockReportingCore( + config, + createMockPluginSetup({ + router: httpSetup.createRouter(''), + security: null, + }) + ); }); afterEach(async () => { diff --git a/x-pack/plugins/reporting/server/routes/generate/legacy.ts b/x-pack/plugins/reporting/server/routes/generate/legacy.ts index 92f1784dc8ecad..f262d186d55317 100644 --- a/x-pack/plugins/reporting/server/routes/generate/legacy.ts +++ b/x-pack/plugins/reporting/server/routes/generate/legacy.ts @@ -53,7 +53,7 @@ export function registerLegacy(reporting: ReportingCore, logger: LevelLogger) { savedObjectId, browserTimezone, queryString, - version: reporting.getKibanaVersion(), + version: reporting.getKibanaPackageInfo().version, }); } catch (err) { throw requestHandler.handleError(err); diff --git a/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts b/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts index 9e58d6d4efa41b..d62cc750ccfcc2 100644 --- a/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts +++ b/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts @@ -12,11 +12,13 @@ jest.mock('../browsers'); import _ from 'lodash'; import * as Rx from 'rxjs'; import { coreMock, elasticsearchServiceMock } from 'src/core/server/mocks'; -import { FieldFormatsRegistry } from 'src/plugins/field_formats/common'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { dataPluginMock } from 'src/plugins/data/server/mocks'; +import { FieldFormatsRegistry } from 'src/plugins/field_formats/common'; import { ReportingConfig, ReportingCore } from '../'; import { featuresPluginMock } from '../../../features/server/mocks'; +import { securityMock } from '../../../security/server/mocks'; +import { taskManagerMock } from '../../../task_manager/server/mocks'; import { chromium, HeadlessChromiumDriverFactory, @@ -39,9 +41,9 @@ export const createMockPluginSetup = (setupMock?: any): ReportingInternalSetup = features: featuresPluginMock.createSetup(), basePath: { set: jest.fn() }, router: setupMock.router, - security: setupMock.security, + security: securityMock.createSetup(), licensing: { license$: Rx.of({ isAvailable: true, isActive: true, type: 'basic' }) } as any, - taskManager: { registerTaskDefinitions: jest.fn() } as any, + taskManager: taskManagerMock.createSetup(), logger: createMockLevelLogger(), ...setupMock, }; diff --git a/x-pack/plugins/timelines/public/components/t_grid/event_rendered_view/index.tsx b/x-pack/plugins/timelines/public/components/t_grid/event_rendered_view/index.tsx index 91bb6ad1dac0b8..523460bfd2d013 100644 --- a/x-pack/plugins/timelines/public/components/t_grid/event_rendered_view/index.tsx +++ b/x-pack/plugins/timelines/public/components/t_grid/event_rendered_view/index.tsx @@ -139,7 +139,7 @@ const EventRenderedViewComponent = ({ ); }, - width: '120px', + width: '152px', }, { field: 'ecs.timestamp', diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index bef72a9defd409..cbbcd4599782a6 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -11384,7 +11384,6 @@ "xpack.fleet.upgradeAgents.upgradeMultipleDescription": "このアクションにより、複数のエージェントがバージョン{version}にアップグレードされます。このアクションは元に戻せません。続行していいですか?", "xpack.fleet.upgradeAgents.upgradeSingleDescription": "このアクションにより、「{hostName}」で実行中のエージェントがバージョン{version}にアップグレードされます。このアクションは元に戻せません。続行していいですか?", "xpack.fleet.upgradeAgents.upgradeSingleTitle": "エージェントを最新バージョンにアップグレード", - "xpack.fleet.upgradePackagePolicy.failedNotificationTitle": "{packagePolicyName}のアップグレードエラー", "xpack.fleet.upgradePackagePolicy.pageDescriptionFromUpgrade": "この統合をアップグレードし、選択したエージェントポリシーに変更をデプロイします", "xpack.fleet.upgradePackagePolicy.previousVersionFlyout.title": "'{name}'パッケージポリシー", "xpack.fleet.upgradePackagePolicy.statusCallout.errorContent": "この統合には、バージョン{currentVersion}から{upgradeVersion}で競合するフィールドがあります。構成を確認して保存し、アップグレードを実行してください。{previousConfigurationLink}を参照して比較できます。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index a92a956f0533c5..28acf3d603e578 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -11508,7 +11508,6 @@ "xpack.fleet.upgradeAgents.upgradeMultipleTitle": "将{count, plural, one {代理} other { {count} 个代理} =true {所有选定代理}}升级到最新版本", "xpack.fleet.upgradeAgents.upgradeSingleDescription": "此操作会将“{hostName}”上运行的代理升级到版本 {version}。此操作无法撤消。是否确定要继续?", "xpack.fleet.upgradeAgents.upgradeSingleTitle": "将代理升级到最新版本", - "xpack.fleet.upgradePackagePolicy.failedNotificationTitle": "升级 {packagePolicyName} 时出错", "xpack.fleet.upgradePackagePolicy.pageDescriptionFromUpgrade": "升级此集成并将更改部署到选定代理策略", "xpack.fleet.upgradePackagePolicy.previousVersionFlyout.title": "“{name}”软件包策略", "xpack.fleet.upgradePackagePolicy.statusCallout.errorContent": "此集成在版本 {currentVersion} 和 {upgradeVersion} 之间有冲突字段。请复查配置并保存,以执行升级。您可以参考您的 {previousConfigurationLink}以进行比较。", diff --git a/x-pack/plugins/uptime/e2e/config.ts b/x-pack/plugins/uptime/e2e/config.ts index c5d573afccd967..d2c7a691e0a49f 100644 --- a/x-pack/plugins/uptime/e2e/config.ts +++ b/x-pack/plugins/uptime/e2e/config.ts @@ -43,7 +43,6 @@ async function config({ readConfigFile }: FtrConfigProviderContext) { `--uiSettings.overrides.theme:darkMode=true`, `--elasticsearch.username=kibana_system`, `--elasticsearch.password=changeme`, - '--migrations.enableV2=false', '--xpack.reporting.enabled=false', ], }, diff --git a/x-pack/plugins/uptime/public/apps/plugin.ts b/x-pack/plugins/uptime/public/apps/plugin.ts index 124de9a60110cb..0cd0af6231c9c6 100644 --- a/x-pack/plugins/uptime/public/apps/plugin.ts +++ b/x-pack/plugins/uptime/public/apps/plugin.ts @@ -221,6 +221,7 @@ export class UptimePlugin registerExtension({ package: 'synthetics', view: 'package-policy-edit', + useLatestPackageVersion: true, Component: LazySyntheticsPolicyEditExtension, }); diff --git a/x-pack/test/accessibility/apps/upgrade_assistant.ts b/x-pack/test/accessibility/apps/upgrade_assistant.ts index 452f6051e0640b..e387eed65d3fdb 100644 --- a/x-pack/test/accessibility/apps/upgrade_assistant.ts +++ b/x-pack/test/accessibility/apps/upgrade_assistant.ts @@ -52,7 +52,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const es = getService('es'); const log = getService('log'); - describe('Upgrade Assistant', () => { + // Failing: See https://github.com/elastic/kibana/issues/115859 + describe.skip('Upgrade Assistant', () => { before(async () => { await PageObjects.upgradeAssistant.navigateToPage(); diff --git a/x-pack/test/apm_api_integration/configs/index.ts b/x-pack/test/apm_api_integration/configs/index.ts index ad1f897debe329..3bc03eb5b42597 100644 --- a/x-pack/test/apm_api_integration/configs/index.ts +++ b/x-pack/test/apm_api_integration/configs/index.ts @@ -11,22 +11,13 @@ import { createTestConfig, CreateTestConfig } from '../common/config'; const apmFtrConfigs = { basic: { license: 'basic' as const, - kibanaConfig: { - // disable v2 migrations to prevent issue where kibana index is deleted - // during a migration - 'migrations.enableV2': 'false', - }, }, trial: { license: 'trial' as const, - kibanaConfig: { - 'migrations.enableV2': 'false', - }, }, rules: { license: 'trial' as const, kibanaConfig: { - 'migrations.enableV2': 'false', 'xpack.ruleRegistry.write.enabled': 'true', }, }, diff --git a/x-pack/test/fleet_api_integration/apis/package_policy/upgrade.ts b/x-pack/test/fleet_api_integration/apis/package_policy/upgrade.ts index 0be2d7d0a74689..a61a77fd37f6b2 100644 --- a/x-pack/test/fleet_api_integration/apis/package_policy/upgrade.ts +++ b/x-pack/test/fleet_api_integration/apis/package_policy/upgrade.ts @@ -146,7 +146,7 @@ export default function (providerContext: FtrProviderContext) { describe('upgrade', function () { it('should respond with an error when "dryRun: false" is provided', async function () { - const { body }: { body: UpgradePackagePolicyResponse } = await supertest + await supertest .post(`/api/fleet/package_policies/upgrade`) .set('kbn-xsrf', 'xxxx') .send({ @@ -154,10 +154,7 @@ export default function (providerContext: FtrProviderContext) { dryRun: false, packageVersion: '0.2.0-add-non-required-test-var', }) - .expect(200); - - expect(body.length).to.be(1); - expect(body[0].success).to.be(false); + .expect(400); }); }); }); @@ -1041,31 +1038,121 @@ export default function (providerContext: FtrProviderContext) { describe('when package policy is not found', function () { it('should return an 200 with errors when "dryRun:true" is provided', async function () { - const { body }: { body: UpgradePackagePolicyDryRunResponse } = await supertest + await supertest .post(`/api/fleet/package_policies/upgrade`) .set('kbn-xsrf', 'xxxx') .send({ packagePolicyIds: ['xxxx', 'yyyy'], dryRun: true, }) - .expect(200); - - expect(body[0].hasErrors).to.be(true); - expect(body[1].hasErrors).to.be(true); + .expect(404); }); it('should return a 200 with errors and "success:false" when "dryRun:false" is provided', async function () { - const { body }: { body: UpgradePackagePolicyResponse } = await supertest + await supertest .post(`/api/fleet/package_policies/upgrade`) .set('kbn-xsrf', 'xxxx') .send({ packagePolicyIds: ['xxxx', 'yyyy'], dryRun: false, }) + .expect(404); + }); + }); + + describe("when policy's package version is up to date", function () { + withTestPackageVersion('0.1.0'); + + beforeEach(async function () { + const { body: agentPolicyResponse } = await supertest + .post(`/api/fleet/agent_policies`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: 'Test policy', + namespace: 'default', + }) .expect(200); - expect(body[0].success).to.be(false); - expect(body[1].success).to.be(false); + agentPolicyId = agentPolicyResponse.item.id; + + const { body: packagePolicyResponse } = await supertest + .post(`/api/fleet/package_policies`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: 'package_policy_upgrade_1', + description: '', + namespace: 'default', + policy_id: agentPolicyId, + enabled: true, + output_id: '', + inputs: [ + { + policy_template: 'package_policy_upgrade', + type: 'test_input', + enabled: true, + streams: [ + { + id: 'test-package_policy_upgrade-xxxx', + enabled: true, + data_stream: { + type: 'test_stream', + dataset: 'package_policy_upgrade.test_stream', + }, + }, + ], + }, + ], + package: { + name: 'package_policy_upgrade', + title: 'This is a test package for upgrading package policies', + version: '0.1.0', + }, + }) + .expect(200); + + packagePolicyId = packagePolicyResponse.item.id; + }); + + afterEach(async function () { + await supertest + .post(`/api/fleet/package_policies/delete`) + .set('kbn-xsrf', 'xxxx') + .send({ packagePolicyIds: [packagePolicyId] }) + .expect(200); + + await supertest + .post('/api/fleet/agent_policies/delete') + .set('kbn-xsrf', 'xxxx') + .send({ agentPolicyId }) + .expect(200); + }); + + describe('dry run', function () { + it('should respond with a bad request', async function () { + await supertest + .post(`/api/fleet/package_policies/upgrade`) + .set('kbn-xsrf', 'xxxx') + .send({ + packagePolicyIds: [packagePolicyId], + dryRun: true, + packageVersion: '0.1.0', + }) + .expect(400); + }); + }); + + describe('upgrade', function () { + it('should respond with a bad request', async function () { + await supertest + .post(`/api/fleet/package_policies/upgrade`) + .set('kbn-xsrf', 'xxxx') + .send({ + packagePolicyIds: [packagePolicyId], + dryRun: false, + packageVersion: '0.1.0', + }) + .expect(400); + }); }); }); });