diff --git a/x-pack/plugins/apm/server/deprecations/deprecations.test.ts b/x-pack/plugins/apm/server/deprecations/deprecations.test.ts new file mode 100644 index 0000000000000..d706146faf212 --- /dev/null +++ b/x-pack/plugins/apm/server/deprecations/deprecations.test.ts @@ -0,0 +1,70 @@ +/* + * 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 { GetDeprecationsContext } from '../../../../../src/core/server'; +import { CloudSetup } from '../../../cloud/server'; +import { getDeprecations } from './'; +import { APMRouteHandlerResources } from '../'; +import { AgentPolicy } from '../../../fleet/common'; + +const deprecationContext = { + esClient: {}, + savedObjectsClient: {}, +} as GetDeprecationsContext; + +describe('getDeprecations', () => { + describe('when fleet is disabled', () => { + it('returns no deprecations', async () => { + const deprecationsCallback = getDeprecations({}); + const deprecations = await deprecationsCallback(deprecationContext); + expect(deprecations).toEqual([]); + }); + }); + + describe('when running on cloud with legacy apm-server', () => { + it('returns deprecations', async () => { + const deprecationsCallback = getDeprecations({ + cloudSetup: { isCloudEnabled: true } as unknown as CloudSetup, + fleet: { + start: () => ({ + agentPolicyService: { get: () => undefined }, + }), + } as unknown as APMRouteHandlerResources['plugins']['fleet'], + }); + const deprecations = await deprecationsCallback(deprecationContext); + expect(deprecations).not.toEqual([]); + }); + }); + + describe('when running on cloud with fleet', () => { + it('returns no deprecations', async () => { + const deprecationsCallback = getDeprecations({ + cloudSetup: { isCloudEnabled: true } as unknown as CloudSetup, + fleet: { + start: () => ({ + agentPolicyService: { get: () => ({ id: 'foo' } as AgentPolicy) }, + }), + } as unknown as APMRouteHandlerResources['plugins']['fleet'], + }); + const deprecations = await deprecationsCallback(deprecationContext); + expect(deprecations).toEqual([]); + }); + }); + + describe('when running on prem', () => { + it('returns no deprecations', async () => { + const deprecationsCallback = getDeprecations({ + cloudSetup: { isCloudEnabled: false } as unknown as CloudSetup, + fleet: { + start: () => ({ agentPolicyService: { get: () => undefined } }), + } as unknown as APMRouteHandlerResources['plugins']['fleet'], + }); + const deprecations = await deprecationsCallback(deprecationContext); + expect(deprecations).toEqual([]); + }); + }); +}); diff --git a/x-pack/plugins/apm/server/deprecations/index.ts b/x-pack/plugins/apm/server/deprecations/index.ts new file mode 100644 index 0000000000000..b592a2bf13268 --- /dev/null +++ b/x-pack/plugins/apm/server/deprecations/index.ts @@ -0,0 +1,74 @@ +/* + * 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 { GetDeprecationsContext, DeprecationsDetails } from 'src/core/server'; +import { i18n } from '@kbn/i18n'; +import { isEmpty } from 'lodash'; +import { CloudSetup } from '../../../cloud/server'; +import { getCloudAgentPolicy } from '../lib/fleet/get_cloud_apm_package_policy'; +import { APMRouteHandlerResources } from '../'; + +export function getDeprecations({ + cloudSetup, + fleet, +}: { + cloudSetup?: CloudSetup; + fleet?: APMRouteHandlerResources['plugins']['fleet']; +}) { + return async ({ + savedObjectsClient, + }: GetDeprecationsContext): Promise => { + const deprecations: DeprecationsDetails[] = []; + if (!fleet) { + return deprecations; + } + + const fleetPluginStart = await fleet.start(); + const cloudAgentPolicy = await getCloudAgentPolicy({ + fleetPluginStart, + savedObjectsClient, + }); + + const isCloudEnabled = !!cloudSetup?.isCloudEnabled; + + const hasCloudAgentPolicy = !isEmpty(cloudAgentPolicy); + + if (isCloudEnabled && !hasCloudAgentPolicy) { + deprecations.push({ + title: i18n.translate('xpack.apm.deprecations.legacyModeTitle', { + defaultMessage: 'APM Server running in legacy mode', + }), + message: i18n.translate('xpack.apm.deprecations.message', { + defaultMessage: + 'Running the APM Server binary directly is considered a legacy option and is deprecated since 7.16. Switch to APM Server managed by an Elastic Agent instead. Read our documentation to learn more.', + }), + documentationUrl: + 'https://www.elastic.co/guide/en/apm/server/current/apm-integration.html', + level: 'warning', + correctiveActions: { + manualSteps: [ + i18n.translate('xpack.apm.deprecations.steps.apm', { + defaultMessage: 'Navigate to Observability/APM', + }), + i18n.translate('xpack.apm.deprecations.steps.settings', { + defaultMessage: 'Click on "Settings"', + }), + i18n.translate('xpack.apm.deprecations.steps.schema', { + defaultMessage: 'Select "Schema" tab', + }), + i18n.translate('xpack.apm.deprecations.steps.switch', { + defaultMessage: + 'Click "Switch to data streams". You will be guided through the process', + }), + ], + }, + }); + } + + return deprecations; + }; +} diff --git a/x-pack/plugins/apm/server/plugin.ts b/x-pack/plugins/apm/server/plugin.ts index 56185d846562f..2296227de2a33 100644 --- a/x-pack/plugins/apm/server/plugin.ts +++ b/x-pack/plugins/apm/server/plugin.ts @@ -51,6 +51,7 @@ import { TRANSACTION_TYPE, } from '../common/elasticsearch_fieldnames'; import { tutorialProvider } from './tutorial'; +import { getDeprecations } from './deprecations'; export class APMPlugin implements @@ -222,6 +223,12 @@ export class APMPlugin ); })(); }); + core.deprecations.registerDeprecations({ + getDeprecations: getDeprecations({ + cloudSetup: plugins.cloud, + fleet: resourcePlugins.fleet, + }), + }); return { config$: mergedConfig$,