diff --git a/x-pack/plugins/reporting/server/deprecations.ts b/x-pack/plugins/reporting/server/deprecations.ts deleted file mode 100644 index 61074fff012a24..00000000000000 --- a/x-pack/plugins/reporting/server/deprecations.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { CoreSetup, DeprecationsDetails, RegisterDeprecationsConfig } from 'src/core/server'; -import { ReportingCore } from '.'; - -const deprecatedRole = 'reporting_user'; -const upgradableConfig = 'xpack.reporting.roles.enabled: false'; - -export async function registerDeprecations( - reporting: ReportingCore, - { deprecations: deprecationsService }: CoreSetup -) { - const deprecationsConfig: RegisterDeprecationsConfig = { - getDeprecations: async ({ esClient }) => { - const usingDeprecatedConfig = !reporting.getContract().usesUiCapabilities(); - const deprecations: DeprecationsDetails[] = []; - const { body: users } = await esClient.asCurrentUser.security.getUser(); - - const reportingUsers = Object.entries(users) - .filter(([username, user]) => user.roles.includes(deprecatedRole)) - .map(([, user]) => user.username); - const numReportingUsers = reportingUsers.length; - - if (numReportingUsers > 0) { - const usernames = reportingUsers.join('", "'); - deprecations.push({ - message: `The deprecated "${deprecatedRole}" role has been found for ${numReportingUsers} user(s): "${usernames}"`, - documentationUrl: 'https://www.elastic.co/guide/en/kibana/current/secure-reporting.html', - level: 'critical', - correctiveActions: { - manualSteps: [ - ...(usingDeprecatedConfig ? [`Set "${upgradableConfig}" 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 "${deprecatedRole}" role from the user(s).`, - ], - }, - }); - } - - return deprecations; - }, - }; - - deprecationsService.registerDeprecations(deprecationsConfig); - - return deprecationsConfig; -} diff --git a/x-pack/plugins/reporting/server/deprecations/index.ts b/x-pack/plugins/reporting/server/deprecations/index.ts new file mode 100644 index 00000000000000..9ecb3b7ab88ad6 --- /dev/null +++ b/x-pack/plugins/reporting/server/deprecations/index.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { CoreSetup } from 'src/core/server'; +import { ReportingCore } from '../core'; + +import { getDeprecationsInfo as getIlmPolicyDeprecationsInfo } from './migrate_existing_indices_ilm_policy'; +import { getDeprecationsInfo as getReportingRoleDeprecationsInfo } from './reporting_role'; + +export const registerDeprecations = ({ + core, + reportingCore, +}: { + core: CoreSetup; + reportingCore: ReportingCore; +}) => { + core.deprecations.registerDeprecations({ + getDeprecations: async (ctx) => { + return [ + ...(await getIlmPolicyDeprecationsInfo(ctx, { reportingCore })), + ...(await getReportingRoleDeprecationsInfo(ctx, { reportingCore })), + ]; + }, + }); +}; diff --git a/x-pack/plugins/reporting/server/deprecations/migrage_existing_indices_ilm_policy.test.ts b/x-pack/plugins/reporting/server/deprecations/migrage_existing_indices_ilm_policy.test.ts new file mode 100644 index 00000000000000..485c4e62a208fa --- /dev/null +++ b/x-pack/plugins/reporting/server/deprecations/migrage_existing_indices_ilm_policy.test.ts @@ -0,0 +1,98 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { GetDeprecationsContext } from 'src/core/server'; +import { elasticsearchServiceMock, savedObjectsClientMock } from 'src/core/server/mocks'; + +import { ReportingCore } from '../core'; +import { createMockConfigSchema, createMockReportingCore } from '../test_helpers'; + +import { getDeprecationsInfo } from './migrate_existing_indices_ilm_policy'; + +type ScopedClusterClientMock = ReturnType< + typeof elasticsearchServiceMock.createScopedClusterClient +>; + +const { createApiResponse } = elasticsearchServiceMock; + +describe("Migrate existing indices' ILM policy deprecations", () => { + let esClient: ScopedClusterClientMock; + let deprecationsCtx: GetDeprecationsContext; + let reportingCore: ReportingCore; + + beforeEach(async () => { + esClient = elasticsearchServiceMock.createScopedClusterClient(); + deprecationsCtx = { esClient, savedObjectsClient: savedObjectsClientMock.create() }; + reportingCore = await createMockReportingCore(createMockConfigSchema()); + }); + + const createIndexSettings = (lifecycleName: string) => ({ + aliases: {}, + mappings: {}, + settings: { + index: { + lifecycle: { + name: lifecycleName, + }, + }, + }, + }); + + it('returns deprecation information when reporting indices are not using the reporting ILM policy', async () => { + esClient.asInternalUser.indices.getSettings.mockResolvedValueOnce( + createApiResponse({ + body: { + indexA: createIndexSettings('not-reporting-lifecycle'), + indexB: createIndexSettings('kibana-reporting'), + }, + }) + ); + + expect(await getDeprecationsInfo(deprecationsCtx, { reportingCore })).toMatchInlineSnapshot(` + Array [ + Object { + "correctiveActions": Object { + "api": Object { + "method": "PUT", + "path": "/api/reporting/deprecations/migrate_ilm_policy", + }, + "manualSteps": Array [ + "Update all reporting indices to use the \\"kibana-reporting\\" policy using the index settings API.", + ], + }, + "level": "warning", + "message": "New reporting indices will be managed by the \\"kibana-reporting\\" provisioned ILM policy. You must edit this policy to manage the report lifecycle. This change targets all indices prefixed with \\".reporting-*\\".", + }, + ] + `); + }); + + it('does not return deprecations when all reporting indices are managed by the provisioned ILM policy', async () => { + esClient.asInternalUser.indices.getSettings.mockResolvedValueOnce( + createApiResponse({ + body: { + indexA: createIndexSettings('kibana-reporting'), + indexB: createIndexSettings('kibana-reporting'), + }, + }) + ); + + expect(await getDeprecationsInfo(deprecationsCtx, { reportingCore })).toMatchInlineSnapshot( + `Array []` + ); + + esClient.asInternalUser.indices.getSettings.mockResolvedValueOnce( + createApiResponse({ + body: {}, + }) + ); + + expect(await getDeprecationsInfo(deprecationsCtx, { reportingCore })).toMatchInlineSnapshot( + `Array []` + ); + }); +}); diff --git a/x-pack/plugins/reporting/server/deprecations/migrate_existing_indices_ilm_policy.ts b/x-pack/plugins/reporting/server/deprecations/migrate_existing_indices_ilm_policy.ts new file mode 100644 index 00000000000000..a3dd4205b9e65a --- /dev/null +++ b/x-pack/plugins/reporting/server/deprecations/migrate_existing_indices_ilm_policy.ts @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import { DeprecationsDetails, GetDeprecationsContext } from 'src/core/server'; +import { API_MIGRATE_ILM_POLICY_URL, ILM_POLICY_NAME } from '../../common/constants'; +import { ReportingCore } from '../core'; +import { deprecations } from '../lib/deprecations'; + +interface ExtraDependencies { + reportingCore: ReportingCore; +} + +export const getDeprecationsInfo = async ( + { esClient }: GetDeprecationsContext, + { reportingCore }: ExtraDependencies +): Promise => { + const store = await reportingCore.getStore(); + const indexPattern = store.getReportingIndexPattern(); + + const migrationStatus = await deprecations.checkIlmMigrationStatus({ + reportingCore, + elasticsearchClient: esClient.asInternalUser, + }); + + if (migrationStatus !== 'ok') { + return [ + { + level: 'warning', + message: i18n.translate('xpack.reporting.deprecations.migrateIndexIlmPolicyActionMessage', { + defaultMessage: `New reporting indices will be managed by the "{reportingIlmPolicy}" provisioned ILM policy. You must edit this policy to manage the report lifecycle. This change targets all indices prefixed with "{indexPattern}".`, + values: { + reportingIlmPolicy: ILM_POLICY_NAME, + indexPattern, + }, + }), + correctiveActions: { + manualSteps: [ + i18n.translate( + 'xpack.reporting.deprecations.migrateIndexIlmPolicy.manualStepOneMessage', + { + defaultMessage: + 'Update all reporting indices to use the "{reportingIlmPolicy}" policy using the index settings API.', + values: { reportingIlmPolicy: ILM_POLICY_NAME }, + } + ), + ], + api: { + method: 'PUT', + path: API_MIGRATE_ILM_POLICY_URL, + }, + }, + }, + ]; + } + + return []; +}; diff --git a/x-pack/plugins/reporting/server/deprecations.test.ts b/x-pack/plugins/reporting/server/deprecations/reporting_role.test.ts similarity index 83% rename from x-pack/plugins/reporting/server/deprecations.test.ts rename to x-pack/plugins/reporting/server/deprecations/reporting_role.test.ts index cce4721b941a0a..b52d51d3e93111 100644 --- a/x-pack/plugins/reporting/server/deprecations.test.ts +++ b/x-pack/plugins/reporting/server/deprecations/reporting_role.test.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { ReportingCore } from '.'; -import { registerDeprecations } from './deprecations'; -import { createMockConfigSchema, createMockReportingCore } from './test_helpers'; -import { coreMock, elasticsearchServiceMock } from 'src/core/server/mocks'; +import { ReportingCore } from '..'; +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; @@ -26,17 +26,22 @@ beforeEach(async () => { }); test('logs no deprecations when setup has no issues', async () => { - const { getDeprecations } = await registerDeprecations(reportingCore, coreMock.createSetup()); - expect(await getDeprecations(context)).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'] } }, }); - - const { getDeprecations } = await registerDeprecations(reportingCore, coreMock.createSetup()); - expect(await getDeprecations(context)).toMatchInlineSnapshot(` + expect( + await getDeprecationsInfo(context, { + reportingCore, + }) + ).toMatchInlineSnapshot(` Array [ Object { "correctiveActions": Object { @@ -61,8 +66,11 @@ test('logs multiple entries when multiple reporting_user role issues are found', }, }); - const { getDeprecations } = await registerDeprecations(reportingCore, coreMock.createSetup()); - expect(await getDeprecations(context)).toMatchInlineSnapshot(` + expect( + await getDeprecationsInfo(context, { + reportingCore, + }) + ).toMatchInlineSnapshot(` Array [ Object { "correctiveActions": Object { @@ -87,8 +95,11 @@ test('logs an expanded message when a config issue and a reporting_user role iss const mockReportingConfig = createMockConfigSchema({ roles: { enabled: true } }); reportingCore = await createMockReportingCore(mockReportingConfig); - const { getDeprecations } = await registerDeprecations(reportingCore, coreMock.createSetup()); - expect(await getDeprecations(context)).toMatchInlineSnapshot(` + expect( + await getDeprecationsInfo(context, { + reportingCore, + }) + ).toMatchInlineSnapshot(` Array [ Object { "correctiveActions": Object { diff --git a/x-pack/plugins/reporting/server/deprecations/reporting_role.ts b/x-pack/plugins/reporting/server/deprecations/reporting_role.ts new file mode 100644 index 00000000000000..d5138043060a62 --- /dev/null +++ b/x-pack/plugins/reporting/server/deprecations/reporting_role.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { GetDeprecationsContext, DeprecationsDetails } from 'src/core/server'; +import { ReportingCore } from '..'; + +const deprecatedRole = 'reporting_user'; +const upgradableConfig = 'xpack.reporting.roles.enabled: false'; + +interface ExtraDependencies { + reportingCore: ReportingCore; +} + +export const getDeprecationsInfo = async ( + { esClient }: GetDeprecationsContext, + { reportingCore }: ExtraDependencies +): Promise => { + const usingDeprecatedConfig = !reportingCore.getContract().usesUiCapabilities(); + const deprecations: DeprecationsDetails[] = []; + const { body: users } = await esClient.asCurrentUser.security.getUser(); + + const reportingUsers = Object.entries(users) + .filter(([username, user]) => user.roles.includes(deprecatedRole)) + .map(([, user]) => user.username); + const numReportingUsers = reportingUsers.length; + + if (numReportingUsers > 0) { + const usernames = reportingUsers.join('", "'); + deprecations.push({ + message: `The deprecated "${deprecatedRole}" role has been found for ${numReportingUsers} user(s): "${usernames}"`, + documentationUrl: 'https://www.elastic.co/guide/en/kibana/current/secure-reporting.html', + level: 'critical', + correctiveActions: { + manualSteps: [ + ...(usingDeprecatedConfig ? [`Set "${upgradableConfig}" 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 "${deprecatedRole}" role from the user(s).`, + ], + }, + }); + } + + return deprecations; +}; diff --git a/x-pack/plugins/reporting/server/plugin.ts b/x-pack/plugins/reporting/server/plugin.ts index dc0ddf27a53b36..185b47a980bfe1 100644 --- a/x-pack/plugins/reporting/server/plugin.ts +++ b/x-pack/plugins/reporting/server/plugin.ts @@ -65,7 +65,10 @@ export class ReportingPlugin }); registerUiSettings(core); - registerDeprecations(reportingCore, core); + registerDeprecations({ + core, + reportingCore, + }); registerReportingUsageCollector(reportingCore, plugins); registerRoutes(reportingCore, this.logger);