Do not mutate config in place during deprecations (#99629)

* refactor config deprecations to avoid config mutations

* remove dynamic access keys in core deprecations.

* refactor custom config deprecations to match the new signature

* improve config deprecations fixtures for nested keys

* add a test for xpack.banner config deprecations

* key --> path, add a test for invalid command
This commit is contained in:
Mikhail Shustov 2021-05-11 11:41:48 +02:00 committed by GitHub
parent df752023a0
commit 5fde16c2b3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 264 additions and 233 deletions

View file

@ -36,10 +36,9 @@ describe('applyDeprecations', () => {
const addDeprecation = jest.fn();
const createAddDeprecation = jest.fn().mockReturnValue(addDeprecation);
const initialConfig = { foo: 'bar', deprecated: 'deprecated' };
const alteredConfig = { foo: 'bar' };
const handlerA = jest.fn().mockReturnValue(alteredConfig);
const handlerB = jest.fn().mockImplementation((conf) => conf);
const handlerA = jest.fn().mockReturnValue({ unset: [{ path: 'deprecated' }] });
const handlerB = jest.fn().mockReturnValue(undefined);
applyDeprecations(
initialConfig,
@ -47,8 +46,6 @@ describe('applyDeprecations', () => {
createAddDeprecation
);
expect(handlerA).toHaveBeenCalledWith(initialConfig, 'pathA', addDeprecation);
expect(handlerB).toHaveBeenCalledWith(alteredConfig, 'pathB', addDeprecation);
expect(createAddDeprecation).toBeCalledTimes(2);
expect(createAddDeprecation).toHaveBeenNthCalledWith(1, 'pathA');
expect(createAddDeprecation).toHaveBeenNthCalledWith(2, 'pathB');
@ -60,8 +57,15 @@ describe('applyDeprecations', () => {
const initialConfig = { foo: 'bar', deprecated: 'deprecated' };
const alteredConfig = { foo: 'bar' };
const handlerA = jest.fn().mockReturnValue(alteredConfig);
const handlerB = jest.fn().mockImplementation((conf) => conf);
const configs: Array<{ fn: string; config: Record<string, any> }> = [];
const handlerA = jest.fn().mockImplementation((config) => {
// the first argument is mutated between calls, we store a copy of it
configs.push({ fn: 'handlerA', config: { ...config } });
return { unset: [{ path: 'deprecated' }] };
});
const handlerB = jest.fn().mockImplementation((config) => {
configs.push({ fn: 'handlerB', config: { ...config } });
});
applyDeprecations(
initialConfig,
@ -69,8 +73,10 @@ describe('applyDeprecations', () => {
createAddDeprecation
);
expect(handlerA).toHaveBeenCalledWith(initialConfig, 'pathA', addDeprecation);
expect(handlerB).toHaveBeenCalledWith(alteredConfig, 'pathB', addDeprecation);
expect(configs).toEqual([
{ fn: 'handlerA', config: initialConfig },
{ fn: 'handlerB', config: alteredConfig },
]);
});
it('returns the migrated config', () => {
@ -94,4 +100,40 @@ describe('applyDeprecations', () => {
expect(initialConfig).toEqual({ foo: 'bar', deprecated: 'deprecated' });
expect(migrated).toEqual({ foo: 'bar' });
});
it('ignores a command for unknown path', () => {
const addDeprecation = jest.fn();
const createAddDeprecation = jest.fn().mockReturnValue(addDeprecation);
const initialConfig = { foo: 'bar', deprecated: 'deprecated' };
const handler = jest.fn().mockImplementation((config) => {
return { unset: [{ path: 'unknown' }] };
});
const migrated = applyDeprecations(
initialConfig,
[wrapHandler(handler, 'pathA')],
createAddDeprecation
);
expect(migrated).toEqual(initialConfig);
});
it('ignores an unknown command', () => {
const addDeprecation = jest.fn();
const createAddDeprecation = jest.fn().mockReturnValue(addDeprecation);
const initialConfig = { foo: 'bar', deprecated: 'deprecated' };
const handler = jest.fn().mockImplementation((config) => {
return { rewrite: [{ path: 'foo' }] };
});
const migrated = applyDeprecations(
initialConfig,
[wrapHandler(handler, 'pathA')],
createAddDeprecation
);
expect(migrated).toEqual(initialConfig);
});
});

View file

@ -6,7 +6,8 @@
* Side Public License, v 1.
*/
import { cloneDeep } from 'lodash';
import { cloneDeep, unset } from 'lodash';
import { set } from '@elastic/safer-lodash-set';
import { ConfigDeprecationWithContext, AddConfigDeprecation } from './types';
const noopAddDeprecationFactory: () => AddConfigDeprecation = () => () => undefined;
@ -22,9 +23,21 @@ export const applyDeprecations = (
deprecations: ConfigDeprecationWithContext[],
createAddDeprecation: (pluginId: string) => AddConfigDeprecation = noopAddDeprecationFactory
) => {
let processed = cloneDeep(config);
const result = cloneDeep(config);
deprecations.forEach(({ deprecation, path }) => {
processed = deprecation(processed, path, createAddDeprecation(path));
const commands = deprecation(result, path, createAddDeprecation(path));
if (commands) {
if (commands.set) {
commands.set.forEach(function ({ path: commandPath, value }) {
set(result, commandPath, value);
});
}
if (commands.unset) {
commands.unset.forEach(function ({ path: commandPath }) {
unset(result, commandPath);
});
}
}
});
return processed;
return result;
};

View file

@ -29,15 +29,15 @@ describe('DeprecationFactory', () => {
property: 'value',
},
};
const processed = rename('deprecated', 'renamed')(rawConfig, 'myplugin', addDeprecation);
expect(processed).toEqual({
myplugin: {
renamed: 'toberenamed',
valid: 'valid',
},
someOtherPlugin: {
property: 'value',
},
const commands = rename('deprecated', 'renamed')(rawConfig, 'myplugin', addDeprecation);
expect(commands).toEqual({
set: [
{
path: 'myplugin.renamed',
value: 'toberenamed',
},
],
unset: [{ path: 'myplugin.deprecated' }],
});
expect(addDeprecation.mock.calls).toMatchInlineSnapshot(`
Array [
@ -64,16 +64,8 @@ describe('DeprecationFactory', () => {
property: 'value',
},
};
const processed = rename('deprecated', 'new')(rawConfig, 'myplugin', addDeprecation);
expect(processed).toEqual({
myplugin: {
new: 'new',
valid: 'valid',
},
someOtherPlugin: {
property: 'value',
},
});
const commands = rename('deprecated', 'new')(rawConfig, 'myplugin', addDeprecation);
expect(commands).toBeUndefined();
expect(addDeprecation).toHaveBeenCalledTimes(0);
});
it('handles nested keys', () => {
@ -88,22 +80,19 @@ describe('DeprecationFactory', () => {
property: 'value',
},
};
const processed = rename('oldsection.deprecated', 'newsection.renamed')(
const commands = rename('oldsection.deprecated', 'newsection.renamed')(
rawConfig,
'myplugin',
addDeprecation
);
expect(processed).toEqual({
myplugin: {
oldsection: {},
newsection: {
renamed: 'toberenamed',
expect(commands).toEqual({
set: [
{
path: 'myplugin.newsection.renamed',
value: 'toberenamed',
},
valid: 'valid',
},
someOtherPlugin: {
property: 'value',
},
],
unset: [{ path: 'myplugin.oldsection.deprecated' }],
});
expect(addDeprecation.mock.calls).toMatchInlineSnapshot(`
Array [
@ -127,11 +116,9 @@ describe('DeprecationFactory', () => {
renamed: 'renamed',
},
};
const processed = rename('deprecated', 'renamed')(rawConfig, 'myplugin', addDeprecation);
expect(processed).toEqual({
myplugin: {
renamed: 'renamed',
},
const commands = rename('deprecated', 'renamed')(rawConfig, 'myplugin', addDeprecation);
expect(commands).toEqual({
unset: [{ path: 'myplugin.deprecated' }],
});
expect(addDeprecation.mock.calls).toMatchInlineSnapshot(`
Array [
@ -162,19 +149,19 @@ describe('DeprecationFactory', () => {
property: 'value',
},
};
const processed = renameFromRoot('myplugin.deprecated', 'myplugin.renamed')(
const commands = renameFromRoot('myplugin.deprecated', 'myplugin.renamed')(
rawConfig,
'does-not-matter',
addDeprecation
);
expect(processed).toEqual({
myplugin: {
renamed: 'toberenamed',
valid: 'valid',
},
someOtherPlugin: {
property: 'value',
},
expect(commands).toEqual({
set: [
{
path: 'myplugin.renamed',
value: 'toberenamed',
},
],
unset: [{ path: 'myplugin.deprecated' }],
});
expect(addDeprecation.mock.calls).toMatchInlineSnapshot(`
Array [
@ -202,19 +189,19 @@ describe('DeprecationFactory', () => {
property: 'value',
},
};
const processed = renameFromRoot('oldplugin.deprecated', 'newplugin.renamed')(
const commands = renameFromRoot('oldplugin.deprecated', 'newplugin.renamed')(
rawConfig,
'does-not-matter',
addDeprecation
);
expect(processed).toEqual({
oldplugin: {
valid: 'valid',
},
newplugin: {
renamed: 'toberenamed',
property: 'value',
},
expect(commands).toEqual({
set: [
{
path: 'newplugin.renamed',
value: 'toberenamed',
},
],
unset: [{ path: 'oldplugin.deprecated' }],
});
expect(addDeprecation.mock.calls).toMatchInlineSnapshot(`
Array [
@ -242,20 +229,12 @@ describe('DeprecationFactory', () => {
property: 'value',
},
};
const processed = renameFromRoot('myplugin.deprecated', 'myplugin.new')(
const commands = renameFromRoot('myplugin.deprecated', 'myplugin.new')(
rawConfig,
'does-not-matter',
addDeprecation
);
expect(processed).toEqual({
myplugin: {
new: 'new',
valid: 'valid',
},
someOtherPlugin: {
property: 'value',
},
});
expect(commands).toBeUndefined();
expect(addDeprecation).toBeCalledTimes(0);
});
@ -266,15 +245,13 @@ describe('DeprecationFactory', () => {
renamed: 'renamed',
},
};
const processed = renameFromRoot('myplugin.deprecated', 'myplugin.renamed')(
const commands = renameFromRoot('myplugin.deprecated', 'myplugin.renamed')(
rawConfig,
'does-not-matter',
addDeprecation
);
expect(processed).toEqual({
myplugin: {
renamed: 'renamed',
},
expect(commands).toEqual({
unset: [{ path: 'myplugin.deprecated' }],
});
expect(addDeprecation.mock.calls).toMatchInlineSnapshot(`
@ -306,14 +283,9 @@ describe('DeprecationFactory', () => {
property: 'value',
},
};
const processed = unused('deprecated')(rawConfig, 'myplugin', addDeprecation);
expect(processed).toEqual({
myplugin: {
valid: 'valid',
},
someOtherPlugin: {
property: 'value',
},
const commands = unused('deprecated')(rawConfig, 'myplugin', addDeprecation);
expect(commands).toEqual({
unset: [{ path: 'myplugin.deprecated' }],
});
expect(addDeprecation.mock.calls).toMatchInlineSnapshot(`
Array [
@ -343,17 +315,10 @@ describe('DeprecationFactory', () => {
property: 'value',
},
};
const processed = unused('section.deprecated')(rawConfig, 'myplugin', addDeprecation);
expect(processed).toEqual({
myplugin: {
valid: 'valid',
section: {},
},
someOtherPlugin: {
property: 'value',
},
const commands = unused('section.deprecated')(rawConfig, 'myplugin', addDeprecation);
expect(commands).toEqual({
unset: [{ path: 'myplugin.section.deprecated' }],
});
expect(addDeprecation.mock.calls).toMatchInlineSnapshot(`
Array [
Array [
@ -379,15 +344,8 @@ describe('DeprecationFactory', () => {
property: 'value',
},
};
const processed = unused('deprecated')(rawConfig, 'myplugin', addDeprecation);
expect(processed).toEqual({
myplugin: {
valid: 'valid',
},
someOtherPlugin: {
property: 'value',
},
});
const commands = unused('deprecated')(rawConfig, 'myplugin', addDeprecation);
expect(commands).toBeUndefined();
expect(addDeprecation).toBeCalledTimes(0);
});
});
@ -403,20 +361,14 @@ describe('DeprecationFactory', () => {
property: 'value',
},
};
const processed = unusedFromRoot('myplugin.deprecated')(
const commands = unusedFromRoot('myplugin.deprecated')(
rawConfig,
'does-not-matter',
addDeprecation
);
expect(processed).toEqual({
myplugin: {
valid: 'valid',
},
someOtherPlugin: {
property: 'value',
},
expect(commands).toEqual({
unset: [{ path: 'myplugin.deprecated' }],
});
expect(addDeprecation.mock.calls).toMatchInlineSnapshot(`
Array [
Array [
@ -442,19 +394,12 @@ describe('DeprecationFactory', () => {
property: 'value',
},
};
const processed = unusedFromRoot('myplugin.deprecated')(
const commands = unusedFromRoot('myplugin.deprecated')(
rawConfig,
'does-not-matter',
addDeprecation
);
expect(processed).toEqual({
myplugin: {
valid: 'valid',
},
someOtherPlugin: {
property: 'value',
},
});
expect(commands).toBeUndefined();
expect(addDeprecation).toBeCalledTimes(0);
});
});

View file

@ -7,13 +7,12 @@
*/
import { get } from 'lodash';
import { set } from '@elastic/safer-lodash-set';
import { unset } from '@kbn/std';
import {
ConfigDeprecation,
AddConfigDeprecation,
ConfigDeprecationFactory,
DeprecatedConfigDetails,
ConfigDeprecationCommand,
} from './types';
const _rename = (
@ -23,20 +22,16 @@ const _rename = (
oldKey: string,
newKey: string,
details?: Partial<DeprecatedConfigDetails>
) => {
): void | ConfigDeprecationCommand => {
const fullOldPath = getPath(rootPath, oldKey);
const oldValue = get(config, fullOldPath);
if (oldValue === undefined) {
return config;
return;
}
unset(config, fullOldPath);
const fullNewPath = getPath(rootPath, newKey);
const newValue = get(config, fullNewPath);
if (newValue === undefined) {
set(config, fullNewPath, oldValue);
addDeprecation({
message: `"${fullOldPath}" is deprecated and has been replaced by "${fullNewPath}"`,
correctiveActions: {
@ -46,6 +41,10 @@ const _rename = (
},
...details,
});
return {
set: [{ path: fullNewPath, value: oldValue }],
unset: [{ path: fullOldPath }],
};
} else {
addDeprecation({
message: `"${fullOldPath}" is deprecated and has been replaced by "${fullNewPath}". However both key are present, ignoring "${fullOldPath}"`,
@ -59,7 +58,9 @@ const _rename = (
});
}
return config;
return {
unset: [{ path: fullOldPath }],
};
};
const _unused = (
@ -68,12 +69,11 @@ const _unused = (
addDeprecation: AddConfigDeprecation,
unusedKey: string,
details?: Partial<DeprecatedConfigDetails>
) => {
): void | ConfigDeprecationCommand => {
const fullPath = getPath(rootPath, unusedKey);
if (get(config, fullPath) === undefined) {
return config;
return;
}
unset(config, fullPath);
addDeprecation({
message: `${fullPath} is deprecated and is no longer used`,
correctiveActions: {
@ -83,7 +83,9 @@ const _unused = (
},
...details,
});
return config;
return {
unset: [{ path: fullPath }],
};
};
const rename = (

View file

@ -8,6 +8,7 @@
export type {
ConfigDeprecation,
ConfigDeprecationCommand,
ConfigDeprecationWithContext,
ConfigDeprecationFactory,
AddConfigDeprecation,

View file

@ -5,7 +5,7 @@
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { RecursiveReadonly } from '@kbn/utility-types';
/**
* Config deprecation hook used when invoking a {@link ConfigDeprecation}
*
@ -41,14 +41,29 @@ export interface DeprecatedConfigDetails {
* @remarks
* This should only be manually implemented if {@link ConfigDeprecationFactory} does not provide the proper helpers for a specific
* deprecation need.
* @param config must not be mutated, return {@link ConfigDeprecationCommand} to change config shape.
*
* @example
* ```typescript
* const provider: ConfigDeprecation = (config, path) => ({ unset: [{ key: 'path.to.key' }] })
* ```
* @internal
*/
export type ConfigDeprecation = (
config: RecursiveReadonly<Record<string, any>>,
fromPath: string,
addDeprecation: AddConfigDeprecation
) => void | ConfigDeprecationCommand;
/**
* Outcome of deprecation operation. Allows mutating config values in a declarative way.
*
* @public
*/
export type ConfigDeprecation = (
config: Record<string, any>,
fromPath: string,
addDeprecation: AddConfigDeprecation
) => Record<string, any>;
export interface ConfigDeprecationCommand {
set?: Array<{ path: string; value: any }>;
unset?: Array<{ path: string }>;
}
/**
* A provider that should returns a list of {@link ConfigDeprecation}.
@ -60,7 +75,7 @@ export type ConfigDeprecation = (
* const provider: ConfigDeprecationProvider = ({ rename, unused }) => [
* rename('oldKey', 'newKey'),
* unused('deprecatedKey'),
* myCustomDeprecation,
* (config, path) => ({ unset: [{ key: 'path.to.key' }] })
* ]
* ```
*

View file

@ -12,6 +12,7 @@ export type {
ConfigDeprecationProvider,
ConfigDeprecationWithContext,
ConfigDeprecation,
ConfigDeprecationCommand,
} from './deprecation';
export { applyDeprecations, configDeprecationFactory } from './deprecation';

View file

@ -6,29 +6,26 @@
* Side Public License, v 1.
*/
import { has, get } from 'lodash';
import { ConfigDeprecationProvider, ConfigDeprecation } from '@kbn/config';
const configPathDeprecation: ConfigDeprecation = (settings, fromPath, addDeprecation) => {
if (has(process.env, 'CONFIG_PATH')) {
if (process.env?.CONFIG_PATH) {
addDeprecation({
message: `Environment variable CONFIG_PATH is deprecated. It has been replaced with KBN_PATH_CONF pointing to a config folder`,
});
}
return settings;
};
const dataPathDeprecation: ConfigDeprecation = (settings, fromPath, addDeprecation) => {
if (has(process.env, 'DATA_PATH')) {
if (process.env?.DATA_PATH) {
addDeprecation({
message: `Environment variable "DATA_PATH" will be removed. It has been replaced with kibana.yml setting "path.data"`,
});
}
return settings;
};
const rewriteBasePathDeprecation: ConfigDeprecation = (settings, fromPath, addDeprecation) => {
if (has(settings, 'server.basePath') && !has(settings, 'server.rewriteBasePath')) {
if (settings.server?.basePath && !settings.server?.rewriteBasePath) {
addDeprecation({
message:
'You should set server.basePath along with server.rewriteBasePath. Starting in 7.0, Kibana ' +
@ -37,20 +34,19 @@ const rewriteBasePathDeprecation: ConfigDeprecation = (settings, fromPath, addDe
'current behavior and silence this warning.',
});
}
return settings;
};
const rewriteCorsSettings: ConfigDeprecation = (settings, fromPath, addDeprecation) => {
const corsSettings = get(settings, 'server.cors');
if (typeof get(settings, 'server.cors') === 'boolean') {
const corsSettings = settings.server?.cors;
if (typeof corsSettings === 'boolean') {
addDeprecation({
message: '"server.cors" is deprecated and has been replaced by "server.cors.enabled"',
});
settings.server.cors = {
enabled: corsSettings,
return {
set: [{ path: 'server.cors', value: { enabled: corsSettings } }],
};
}
return settings;
};
const cspRulesDeprecation: ConfigDeprecation = (settings, fromPath, addDeprecation) => {
@ -59,7 +55,7 @@ const cspRulesDeprecation: ConfigDeprecation = (settings, fromPath, addDeprecati
const SELF_POLICIES = Object.freeze(['script-src', 'style-src']);
const SELF_STRING = `'self'`;
const rules: string[] = get(settings, 'csp.rules');
const rules: string[] = settings.csp?.rules;
if (rules) {
const parsed = new Map(
rules.map((ruleStr) => {
@ -68,34 +64,39 @@ const cspRulesDeprecation: ConfigDeprecation = (settings, fromPath, addDeprecati
})
);
settings.csp.rules = [...parsed].map(([policy, sourceList]) => {
if (sourceList.find((source) => source.includes(NONCE_STRING))) {
addDeprecation({
message: `csp.rules no longer supports the {nonce} syntax. Replacing with 'self' in ${policy}`,
});
sourceList = sourceList.filter((source) => !source.includes(NONCE_STRING));
return {
set: [
{
path: 'csp.rules',
value: [...parsed].map(([policy, sourceList]) => {
if (sourceList.find((source) => source.includes(NONCE_STRING))) {
addDeprecation({
message: `csp.rules no longer supports the {nonce} syntax. Replacing with 'self' in ${policy}`,
});
sourceList = sourceList.filter((source) => !source.includes(NONCE_STRING));
// Add 'self' if not present
if (!sourceList.find((source) => source.includes(SELF_STRING))) {
sourceList.push(SELF_STRING);
}
}
// Add 'self' if not present
if (!sourceList.find((source) => source.includes(SELF_STRING))) {
sourceList.push(SELF_STRING);
}
}
if (
SELF_POLICIES.includes(policy) &&
!sourceList.find((source) => source.includes(SELF_STRING))
) {
addDeprecation({
message: `csp.rules must contain the 'self' source. Automatically adding to ${policy}.`,
});
sourceList.push(SELF_STRING);
}
if (
SELF_POLICIES.includes(policy) &&
!sourceList.find((source) => source.includes(SELF_STRING))
) {
addDeprecation({
message: `csp.rules must contain the 'self' source. Automatically adding to ${policy}.`,
});
sourceList.push(SELF_STRING);
}
return `${policy} ${sourceList.join(' ')}`.trim();
});
return `${policy} ${sourceList.join(' ')}`.trim();
}),
},
],
};
}
return settings;
};
const mapManifestServiceUrlDeprecation: ConfigDeprecation = (
@ -103,7 +104,7 @@ const mapManifestServiceUrlDeprecation: ConfigDeprecation = (
fromPath,
addDeprecation
) => {
if (has(settings, 'map.manifestServiceUrl')) {
if (settings.map?.manifestServiceUrl) {
addDeprecation({
message:
'You should no longer use the map.manifestServiceUrl setting in kibana.yml to configure the location ' +
@ -112,11 +113,10 @@ const mapManifestServiceUrlDeprecation: ConfigDeprecation = (
'modified for use in production environments.',
});
}
return settings;
};
const opsLoggingEventDeprecation: ConfigDeprecation = (settings, fromPath, addDeprecation) => {
if (has(settings, 'logging.events.ops')) {
if (settings.logging?.events?.ops) {
addDeprecation({
documentationUrl:
'https://github.com/elastic/kibana/blob/master/src/core/server/logging/README.mdx#loggingevents',
@ -127,11 +127,10 @@ const opsLoggingEventDeprecation: ConfigDeprecation = (settings, fromPath, addDe
'https://github.com/elastic/kibana/blob/master/src/core/server/logging/README.mdx',
});
}
return settings;
};
const requestLoggingEventDeprecation: ConfigDeprecation = (settings, fromPath, addDeprecation) => {
if (has(settings, 'logging.events.request') || has(settings, 'logging.events.response')) {
if (settings.logging?.events?.request || settings.logging?.events?.response) {
addDeprecation({
documentationUrl:
'https://github.com/elastic/kibana/blob/master/src/core/server/logging/README.mdx#loggingevents',
@ -142,11 +141,10 @@ const requestLoggingEventDeprecation: ConfigDeprecation = (settings, fromPath, a
'https://github.com/elastic/kibana/blob/master/src/core/server/logging/README.mdx',
});
}
return settings;
};
const timezoneLoggingDeprecation: ConfigDeprecation = (settings, fromPath, addDeprecation) => {
if (has(settings, 'logging.timezone')) {
if (settings.logging?.timezone) {
addDeprecation({
documentationUrl:
'https://github.com/elastic/kibana/blob/master/src/core/server/logging/README.mdx#loggingtimezone',
@ -157,11 +155,10 @@ const timezoneLoggingDeprecation: ConfigDeprecation = (settings, fromPath, addDe
'https://github.com/elastic/kibana/blob/master/src/core/server/logging/README.mdx',
});
}
return settings;
};
const destLoggingDeprecation: ConfigDeprecation = (settings, fromPath, addDeprecation) => {
if (has(settings, 'logging.dest')) {
if (settings.logging?.dest) {
addDeprecation({
documentationUrl:
'https://github.com/elastic/kibana/blob/master/src/core/server/logging/README.mdx#loggingdest',
@ -172,11 +169,10 @@ const destLoggingDeprecation: ConfigDeprecation = (settings, fromPath, addDeprec
'https://github.com/elastic/kibana/blob/master/src/core/server/logging/README.mdx',
});
}
return settings;
};
const quietLoggingDeprecation: ConfigDeprecation = (settings, fromPath, addDeprecation) => {
if (has(settings, 'logging.quiet')) {
if (settings.logging?.quiet) {
addDeprecation({
documentationUrl:
'https://github.com/elastic/kibana/blob/master/src/core/server/logging/README.mdx#loggingquiet',
@ -185,11 +181,10 @@ const quietLoggingDeprecation: ConfigDeprecation = (settings, fromPath, addDepre
'in 8.0. Moving forward, you can use "logging.root.level:error" in your logging configuration. ',
});
}
return settings;
};
const silentLoggingDeprecation: ConfigDeprecation = (settings, fromPath, addDeprecation) => {
if (has(settings, 'logging.silent')) {
if (settings.logging?.silent) {
addDeprecation({
documentationUrl:
'https://github.com/elastic/kibana/blob/master/src/core/server/logging/README.mdx#loggingsilent',
@ -198,11 +193,10 @@ const silentLoggingDeprecation: ConfigDeprecation = (settings, fromPath, addDepr
'in 8.0. Moving forward, you can use "logging.root.level:off" in your logging configuration. ',
});
}
return settings;
};
const verboseLoggingDeprecation: ConfigDeprecation = (settings, fromPath, addDeprecation) => {
if (has(settings, 'logging.verbose')) {
if (settings.logging?.verbose) {
addDeprecation({
documentationUrl:
'https://github.com/elastic/kibana/blob/master/src/core/server/logging/README.mdx#loggingverbose',
@ -211,7 +205,6 @@ const verboseLoggingDeprecation: ConfigDeprecation = (settings, fromPath, addDep
'in 8.0. Moving forward, you can use "logging.root.level:all" in your logging configuration. ',
});
}
return settings;
};
const jsonLoggingDeprecation: ConfigDeprecation = (settings, fromPath, addDeprecation) => {
@ -219,7 +212,7 @@ const jsonLoggingDeprecation: ConfigDeprecation = (settings, fromPath, addDeprec
// the dev CLI code in src/dev/cli_dev_mode/using_server_process.ts manually
// specifies `--logging.json=false`. Since it's executed in a child process, the
// ` legacyLoggingConfigSchema` returns `true` for the TTY check on `process.stdout.isTTY`
if (has(settings, 'logging.json') && settings.env !== 'development') {
if (settings.logging?.json && settings.env !== 'development') {
addDeprecation({
documentationUrl:
'https://github.com/elastic/kibana/blob/master/src/core/server/logging/README.mdx',
@ -232,11 +225,10 @@ const jsonLoggingDeprecation: ConfigDeprecation = (settings, fromPath, addDeprec
'https://github.com/elastic/kibana/blob/master/src/core/server/logging/README.mdx',
});
}
return settings;
};
const logRotateDeprecation: ConfigDeprecation = (settings, fromPath, addDeprecation) => {
if (has(settings, 'logging.rotate')) {
if (settings.logging?.rotate) {
addDeprecation({
documentationUrl:
'https://github.com/elastic/kibana/blob/master/src/core/server/logging/README.mdx#rolling-file-appender',
@ -247,11 +239,10 @@ const logRotateDeprecation: ConfigDeprecation = (settings, fromPath, addDeprecat
'https://github.com/elastic/kibana/blob/master/src/core/server/logging/README.mdx#rolling-file-appender',
});
}
return settings;
};
const logEventsLogDeprecation: ConfigDeprecation = (settings, fromPath, addDeprecation) => {
if (has(settings, 'logging.events.log')) {
if (settings.logging?.events?.log) {
addDeprecation({
documentationUrl:
'https://github.com/elastic/kibana/blob/master/src/core/server/logging/README.mdx#loggingevents',
@ -260,11 +251,10 @@ const logEventsLogDeprecation: ConfigDeprecation = (settings, fromPath, addDepre
'in 8.0. Moving forward, log levels can be customized on a per-logger basis using the new logging configuration. ',
});
}
return settings;
};
const logEventsErrorDeprecation: ConfigDeprecation = (settings, fromPath, addDeprecation) => {
if (has(settings, 'logging.events.error')) {
if (settings.logging?.events?.error) {
addDeprecation({
documentationUrl:
'https://github.com/elastic/kibana/blob/master/src/core/server/logging/README.mdx#loggingevents',
@ -273,18 +263,16 @@ const logEventsErrorDeprecation: ConfigDeprecation = (settings, fromPath, addDep
'in 8.0. Moving forward, you can use "logging.root.level: error" in your logging configuration. ',
});
}
return settings;
};
const logFilterDeprecation: ConfigDeprecation = (settings, fromPath, addDeprecation) => {
if (has(settings, 'logging.filter')) {
if (settings.logging?.filter) {
addDeprecation({
documentationUrl:
'https://github.com/elastic/kibana/blob/master/src/core/server/logging/README.mdx#loggingfilter',
message: '"logging.filter" has been deprecated and will be removed in 8.0.',
});
}
return settings;
};
export const coreDeprecationProvider: ConfigDeprecationProvider = ({ rename, unusedFromRoot }) => [

View file

@ -5,6 +5,7 @@
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { set } from '@elastic/safer-lodash-set';
import type { ConfigDeprecationProvider } from '@kbn/config';
import { configDeprecationFactory, applyDeprecations } from '@kbn/config';
@ -38,7 +39,7 @@ export const getDeprecationsFor = ({
settings?: Record<string, any>;
path: string;
}) => {
return collectDeprecations(provider, { [path]: settings }, path);
return collectDeprecations(provider, set({}, path, settings), path);
};
export const getDeprecationsForGlobalSettings = ({

View file

@ -147,7 +147,7 @@ const deprecations: ConfigDeprecationProvider = () => [
(settings, fromPath, addDeprecation) => {
const es = settings[fromPath];
if (!es) {
return settings;
return;
}
if (es.username === 'elastic') {
addDeprecation({
@ -171,7 +171,7 @@ const deprecations: ConfigDeprecationProvider = () => [
message: `Setting [${fromPath}.logQueries] is deprecated and no longer used. You should set the log level to "debug" for the "elasticsearch.queries" context in "logging.loggers" or use "logging.verbose: true".`,
});
}
return settings;
return;
},
];

View file

@ -6,7 +6,7 @@
* Side Public License, v 1.
*/
import { AddConfigDeprecation, CoreSetup, CoreStart, PluginConfigDescriptor } from 'kibana/server';
import type { CoreSetup, CoreStart, PluginConfigDescriptor } from 'kibana/server';
import { get } from 'lodash';
import { configSchema, ConfigSchema } from '../config';
@ -19,16 +19,12 @@ export const config: PluginConfigDescriptor<ConfigSchema> = {
deprecations: ({ renameFromRoot }) => [
// TODO: Remove deprecation once defaultAppId is deleted
renameFromRoot('kibana.defaultAppId', 'kibana_legacy.defaultAppId', { silent: true }),
(
completeConfig: Record<string, any>,
rootPath: string,
addDeprecation: AddConfigDeprecation
) => {
(completeConfig, rootPath, addDeprecation) => {
if (
get(completeConfig, 'kibana.defaultAppId') === undefined &&
get(completeConfig, 'kibana_legacy.defaultAppId') === undefined
) {
return completeConfig;
return;
}
addDeprecation({
message: `kibana.defaultAppId is deprecated and will be removed in 8.0. Please use the \`defaultRoute\` advanced setting instead`,
@ -40,7 +36,6 @@ export const config: PluginConfigDescriptor<ConfigSchema> = {
],
},
});
return completeConfig;
},
],
};

View file

@ -0,0 +1,38 @@
/*
* 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 { config } from './config';
import { getDeprecationsFor } from '../../../../src/core/server/test_utils';
function applyDeprecations(settings?: Record<string, any>) {
return getDeprecationsFor({ provider: config.deprecations!, settings, path: 'xpack.banners' });
}
describe('deprecations', () => {
it('replaces xpack.banners.placement from "header" to "top"', () => {
const { migrated } = applyDeprecations({
placement: 'header',
});
expect(migrated.xpack.banners.placement).toBe('top');
});
it('logs a warning message about xpack.banners.placement renaming', () => {
const { messages } = applyDeprecations({
placement: 'header',
});
expect(messages).toMatchInlineSnapshot(`
Array [
"The \`header\` value for xpack.banners.placement has been replaced by \`top\`",
]
`);
});
it('do not rename other placement values', () => {
const { migrated, messages } = applyDeprecations({
placement: 'disabled',
});
expect(migrated.xpack.banners.placement).toBe('disabled');
expect(messages.length).toBe(0);
});
});

View file

@ -46,10 +46,10 @@ export const config: PluginConfigDescriptor<BannersConfigType> = {
addDeprecation({
message: 'The `header` value for xpack.banners.placement has been replaced by `top`',
});
pluginConfig.placement = 'top';
return {
set: [{ path: `${fromPath}.placement`, value: 'top' }],
};
}
return rootConfig;
},
],
};

View file

@ -39,8 +39,6 @@ export const config: PluginConfigDescriptor<ReportingConfigType> = {
`through feature controls in Management > Security > Roles`,
});
}
return settings;
},
],
};

View file

@ -29,8 +29,6 @@ export const securityConfigDeprecationProvider: ConfigDeprecationProvider = ({
'Defining `xpack.security.authc.providers` as an array of provider types is deprecated. Use extended `object` format instead.',
});
}
return settings;
},
(settings, fromPath, addDeprecation) => {
const hasProviderType = (providerType: string) => {
@ -50,7 +48,6 @@ export const securityConfigDeprecationProvider: ConfigDeprecationProvider = ({
'Enabling both `basic` and `token` authentication providers in `xpack.security.authc.providers` is deprecated. Login page will only use `token` provider.',
});
}
return settings;
},
(settings, fromPath, addDeprecation) => {
const samlProviders = (settings?.xpack?.security?.authc?.providers?.saml ?? {}) as Record<
@ -63,8 +60,6 @@ export const securityConfigDeprecationProvider: ConfigDeprecationProvider = ({
'`xpack.security.authc.providers.saml.<provider-name>.maxRedirectURLSize` is deprecated and is no longer used',
});
}
return settings;
},
(settings, fromPath, addDeprecation) => {
if (settings?.xpack?.security?.enabled === false) {
@ -74,6 +69,5 @@ export const securityConfigDeprecationProvider: ConfigDeprecationProvider = ({
'To turn off security features, disable them in Elasticsearch instead.',
});
}
return settings;
},
];

View file

@ -30,7 +30,6 @@ const disabledDeprecation: ConfigDeprecation = (config, fromPath, addDeprecation
message: `Disabling the Spaces plugin (xpack.spaces.enabled) will not be supported in the next major version (8.0)`,
});
}
return config;
};
export const spacesConfigDeprecationProvider: ConfigDeprecationProvider = () => {

View file

@ -45,7 +45,6 @@ export const config: PluginConfigDescriptor<TaskManagerConfig> = {
message: `setting "${fromPath}.max_workers" (${taskManager?.max_workers}) greater than ${MAX_WORKERS_LIMIT} is deprecated. Values greater than ${MAX_WORKERS_LIMIT} will not be supported starting in 8.0.`,
});
}
return settings;
},
],
};