Skip to content

Commit

Permalink
[Logs/Metrics UI] Add deprecated field configuration to Deprecations …
Browse files Browse the repository at this point in the history
…API (#115103)

* [Logs/Metrics UI] Add deprecated field configuration to Deprecations API

* Add correction steps

* Add unit test for source config deprecations

* Apply suggestions from code review

Co-authored-by: Chris Cowan <[email protected]>

* Lint fix

Co-authored-by: Chris Cowan <[email protected]>
  • Loading branch information
Zacqary and simianhacker authored Oct 19, 2021
1 parent 2aaa515 commit adbb808
Show file tree
Hide file tree
Showing 3 changed files with 304 additions and 0 deletions.
86 changes: 86 additions & 0 deletions x-pack/plugins/infra/server/deprecations.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* 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 { getInfraDeprecationsFactory } from './deprecations';

describe('Infra plugin deprecations', () => {
describe('Source configuration deprecations', () => {
test('returns no deprecations when all fields are set to the default values', async () => {
const sources = {
getAllSourceConfigurations: () => [
{
configuration: {
name: 'Default',
fields: {
timestamp: '@timestamp',
tiebreaker: '_doc',
container: 'container.id',
host: 'host.name',
pod: 'kubernetes.pod.uid',
},
},
},
{
configuration: {
name: 'Alternate',
fields: {
timestamp: '@timestamp',
tiebreaker: '_doc',
container: 'container.id',
host: 'host.name',
pod: 'kubernetes.pod.uid',
},
},
},
],
};
const getDeprecations = getInfraDeprecationsFactory(sources as any);
const deprecations = await getDeprecations({} as any);
expect(deprecations.length).toBe(0);
});
});
test('returns expected deprecations when some fields are not set to default values in one or more source configurations', async () => {
const sources = {
getAllSourceConfigurations: () => [
{
configuration: {
name: 'Default',
fields: {
timestamp: 'not-@timestamp',
tiebreaker: '_doc',
container: 'not-container.id',
host: 'host.name',
pod: 'not-kubernetes.pod.uid',
},
},
},
{
configuration: {
name: 'Alternate',
fields: {
timestamp: 'not-@timestamp',
tiebreaker: 'not-_doc',
container: 'container.id',
host: 'not-host.name',
pod: 'kubernetes.pod.uid',
},
},
},
],
};
const getDeprecations = getInfraDeprecationsFactory(sources as any);
const deprecations = await getDeprecations({} as any);
expect(deprecations.length).toBe(5);
expect(
deprecations.map((d) =>
d.title.replace(/Source configuration field "(.*)" is deprecated./, '$1')
)
).toEqual(
expect.arrayContaining(['timestamp', 'tiebreaker', 'container ID', 'host name', 'pod ID'])
);
});
});
211 changes: 211 additions & 0 deletions x-pack/plugins/infra/server/deprecations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
/*
* 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 { get } from 'lodash';
import {
ConfigDeprecationProvider,
ConfigDeprecation,
DeprecationsDetails,
GetDeprecationsContext,
} from 'src/core/server';
import { InfraSources } from './lib/sources';

const deprecatedFieldMessage = (fieldName: string, defaultValue: string, configNames: string[]) =>
i18n.translate('xpack.infra.deprecations.deprecatedFieldDescription', {
defaultMessage:
'Configuring the "{fieldName}" field has been deprecated and will be removed in 8.0.0. This plugin is designed to work with ECS, and expects this field to have a value of `{defaultValue}`. It has a different value configured in Source {configCount, plural, one {Configuration} other {Configurations}}: {configNames}',
values: {
fieldName,
defaultValue,
configNames: configNames.join(', '),
configCount: configNames.length,
},
});

const DEFAULT_VALUES = {
timestamp: '@timestamp',
tiebreaker: '_doc',
container: 'container.id',
host: 'host.name',
pod: 'kubernetes.pod.uid',
};

const FIELD_DEPRECATION_FACTORIES: Record<string, (configNames: string[]) => DeprecationsDetails> =
{
timestamp: (configNames) => ({
level: 'critical',
title: i18n.translate('xpack.infra.deprecations.timestampFieldTitle', {
defaultMessage: 'Source configuration field "timestamp" is deprecated.',
}),
message: deprecatedFieldMessage(
i18n.translate('xpack.infra.deprecations.timestampFieldName', {
defaultMessage: 'timestamp',
}),
DEFAULT_VALUES.timestamp,
configNames
),
correctiveActions: {
manualSteps: [
i18n.translate('xpack.infra.deprecations.timestampAdjustIndexing', {
defaultMessage: 'Adjust your indexing to use "{field}" as a timestamp.',
values: { field: '@timestamp' },
}),
],
},
}),
tiebreaker: (configNames) => ({
level: 'critical',
title: i18n.translate('xpack.infra.deprecations.tiebreakerFieldTitle', {
defaultMessage: 'Source configuration field "tiebreaker" is deprecated.',
}),
message: deprecatedFieldMessage(
i18n.translate('xpack.infra.deprecations.tiebreakerFieldName', {
defaultMessage: 'tiebreaker',
}),
DEFAULT_VALUES.tiebreaker,
configNames
),
correctiveActions: {
manualSteps: [
i18n.translate('xpack.infra.deprecations.tiebreakerAdjustIndexing', {
defaultMessage: 'Adjust your indexing to use "{field}" as a tiebreaker.',
values: { field: '_doc' },
}),
],
},
}),
host: (configNames) => ({
level: 'critical',
title: i18n.translate('xpack.infra.deprecations.hostnameFieldTitle', {
defaultMessage: 'Source configuration field "host name" is deprecated.',
}),
message: deprecatedFieldMessage(
i18n.translate('xpack.infra.deprecations.hostnameFieldName', {
defaultMessage: 'host name',
}),
DEFAULT_VALUES.host,
configNames
),
correctiveActions: {
manualSteps: [
i18n.translate('xpack.infra.deprecations.hostAdjustIndexing', {
defaultMessage: 'Adjust your indexing to identify hosts using "{field}"',
values: { field: 'host.name' },
}),
],
},
}),
pod: (configNames) => ({
level: 'critical',
title: i18n.translate('xpack.infra.deprecations.podIdFieldTitle', {
defaultMessage: 'Source configuration field "pod ID" is deprecated.',
}),
message: deprecatedFieldMessage(
i18n.translate('xpack.infra.deprecations.podIdFieldName', { defaultMessage: 'pod ID' }),
DEFAULT_VALUES.pod,
configNames
),
correctiveActions: {
manualSteps: [
i18n.translate('xpack.infra.deprecations.podAdjustIndexing', {
defaultMessage: 'Adjust your indexing to identify Kubernetes pods using "{field}"',
values: { field: 'kubernetes.pod.uid' },
}),
],
},
}),
container: (configNames) => ({
level: 'critical',
title: i18n.translate('xpack.infra.deprecations.containerIdFieldTitle', {
defaultMessage: 'Source configuration field "container ID" is deprecated.',
}),
message: deprecatedFieldMessage(
i18n.translate('xpack.infra.deprecations.containerIdFieldName', {
defaultMessage: 'container ID',
}),
DEFAULT_VALUES.container,
configNames
),
correctiveActions: {
manualSteps: [
i18n.translate('xpack.infra.deprecations.containerAdjustIndexing', {
defaultMessage: 'Adjust your indexing to identify Docker containers using "{field}"',
values: { field: 'container.id' },
}),
],
},
}),
};

export const configDeprecations: ConfigDeprecationProvider = () => [
...Object.keys(FIELD_DEPRECATION_FACTORIES).map(
(key): ConfigDeprecation =>
(completeConfig, rootPath, addDeprecation) => {
const configuredValue = get(completeConfig, `xpack.infra.sources.default.fields.${key}`);
if (typeof configuredValue === 'undefined') {
return completeConfig;
}
addDeprecation({
title: i18n.translate('xpack.infra.deprecations.deprecatedFieldConfigTitle', {
defaultMessage: '"{fieldKey}" is deprecated.',
values: {
fieldKey: key,
},
}),
message: i18n.translate('xpack.infra.deprecations.deprecatedFieldConfigDescription', {
defaultMessage:
'Configuring "xpack.infra.sources.default.fields.{fieldKey}" has been deprecated and will be removed in 8.0.0.',
values: {
fieldKey: key,
},
}),
level: 'warning',
correctiveActions: {
manualSteps: [
i18n.translate('xpack.infra.deprecations.removeConfigField', {
defaultMessage:
'Remove "xpack.infra.sources.default.fields.{fieldKey}" from your Kibana configuration.',
values: { fieldKey: key },
}),
],
},
} as Parameters<typeof addDeprecation>[0]);

return completeConfig;
}
),
];

export const getInfraDeprecationsFactory =
(sources: InfraSources) =>
async ({ savedObjectsClient }: GetDeprecationsContext) => {
const deprecatedFieldsToSourceConfigMap: Map<string, string[]> = new Map();
const sourceConfigurations = await sources.getAllSourceConfigurations(savedObjectsClient);

for (const { configuration } of sourceConfigurations) {
const { name, fields } = configuration;
for (const [key, defaultValue] of Object.entries(DEFAULT_VALUES)) {
const configuredValue = Reflect.get(fields, key);
if (configuredValue !== defaultValue) {
const affectedConfigNames = deprecatedFieldsToSourceConfigMap.get(key) ?? [];
affectedConfigNames.push(name);
deprecatedFieldsToSourceConfigMap.set(key, affectedConfigNames);
}
}
}

const deprecations: DeprecationsDetails[] = [];
if (deprecatedFieldsToSourceConfigMap.size > 0) {
for (const [fieldName, affectedConfigNames] of deprecatedFieldsToSourceConfigMap.entries()) {
const deprecationFactory = Reflect.get(FIELD_DEPRECATION_FACTORIES, fieldName);
deprecations.push(deprecationFactory(affectedConfigNames));
}
}

return deprecations;
};
7 changes: 7 additions & 0 deletions x-pack/plugins/infra/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import { UsageCollector } from './usage/usage_collector';
import { createGetLogQueryFields } from './services/log_queries/get_log_query_fields';
import { handleEsError } from '../../../../src/plugins/es_ui_shared/server';
import { RulesService } from './services/rules';
import { configDeprecations, getInfraDeprecationsFactory } from './deprecations';

export const config: PluginConfigDescriptor = {
schema: schema.object({
Expand Down Expand Up @@ -67,6 +68,7 @@ export const config: PluginConfigDescriptor = {
})
),
}),
deprecations: configDeprecations,
};

export type InfraConfig = TypeOf<typeof config.schema>;
Expand Down Expand Up @@ -191,6 +193,11 @@ export class InfraServerPlugin implements Plugin<InfraPluginSetup> {
const logEntriesService = new LogEntriesService();
logEntriesService.setup(core, { ...plugins, sources });

// register deprecated source configuration fields
core.deprecations.registerDeprecations({
getDeprecations: getInfraDeprecationsFactory(sources),
});

return {
defineInternalSourceConfiguration(sourceId, sourceProperties) {
sources.defineInternalSourceConfiguration(sourceId, sourceProperties);
Expand Down

0 comments on commit adbb808

Please sign in to comment.