Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Reporting] Add deprecation notice to the upgrade assistant #104303

Merged
52 changes: 0 additions & 52 deletions x-pack/plugins/reporting/server/deprecations.ts

This file was deleted.

28 changes: 28 additions & 0 deletions x-pack/plugins/reporting/server/deprecations/index.ts
Original file line number Diff line number Diff line change
@@ -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 })),
];
},
});
};
Original file line number Diff line number Diff line change
@@ -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 []`
);
});
});
Original file line number Diff line number Diff line change
@@ -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<DeprecationsDetails[]> => {
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 [];
};
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand All @@ -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 {
Expand All @@ -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 {
Expand Down
48 changes: 48 additions & 0 deletions x-pack/plugins/reporting/server/deprecations/reporting_role.ts
Original file line number Diff line number Diff line change
@@ -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<DeprecationsDetails[]> => {
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;
};
5 changes: 4 additions & 1 deletion x-pack/plugins/reporting/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,10 @@ export class ReportingPlugin
});

registerUiSettings(core);
registerDeprecations(reportingCore, core);
registerDeprecations({
core,
reportingCore,
});
registerReportingUsageCollector(reportingCore, plugins);
registerRoutes(reportingCore, this.logger);

Expand Down