[telemetry] report config deprecations (#99887)
* return the list of changes config keys during deprecation * gather changed config keys in the core * adjust Security plugin deprecations tests * update docs * update interface * update telemetry schema * update spaces tests * update tests in other x-pack plugins * remove testing instruction * improve tests. get rid of snapshots
This commit is contained in:
parent
987c736957
commit
f915b6fe73
|
@ -26,11 +26,13 @@ const createConfigServiceMock = ({
|
|||
addDeprecationProvider: jest.fn(),
|
||||
validate: jest.fn(),
|
||||
getHandledDeprecatedConfigs: jest.fn(),
|
||||
getDeprecatedConfigPath$: jest.fn(),
|
||||
};
|
||||
|
||||
mocked.atPath.mockReturnValue(new BehaviorSubject(atPath));
|
||||
mocked.atPathSync.mockReturnValue(atPath);
|
||||
mocked.getConfig$.mockReturnValue(new BehaviorSubject(new ObjectToConfigAdapter(getConfig$)));
|
||||
mocked.getDeprecatedConfigPath$.mockReturnValue(new BehaviorSubject({ set: [], unset: [] }));
|
||||
mocked.getUsedPaths.mockResolvedValue([]);
|
||||
mocked.getUnusedPaths.mockResolvedValue([]);
|
||||
mocked.isEnabledAtPath.mockResolvedValue(true);
|
||||
|
|
|
@ -11,10 +11,17 @@ import type { applyDeprecations } from './deprecation/apply_deprecations';
|
|||
|
||||
jest.mock('../../../package.json', () => mockPackage);
|
||||
|
||||
const changedPaths = {
|
||||
set: ['foo'],
|
||||
unset: ['bar.baz'],
|
||||
};
|
||||
|
||||
export { changedPaths as mockedChangedPaths };
|
||||
|
||||
export const mockApplyDeprecations = jest.fn<
|
||||
Record<string, any>,
|
||||
ReturnType<typeof applyDeprecations>,
|
||||
Parameters<typeof applyDeprecations>
|
||||
>((config, deprecations, createAddDeprecation) => config);
|
||||
>((config, deprecations, createAddDeprecation) => ({ config, changedPaths }));
|
||||
|
||||
jest.mock('./deprecation/apply_deprecations', () => ({
|
||||
applyDeprecations: mockApplyDeprecations,
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { first, take } from 'rxjs/operators';
|
||||
|
||||
import { mockApplyDeprecations } from './config_service.test.mocks';
|
||||
import { mockApplyDeprecations, mockedChangedPaths } from './config_service.test.mocks';
|
||||
import { rawConfigServiceMock } from './raw/raw_config_service.mock';
|
||||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
|
@ -420,7 +420,7 @@ test('logs deprecation warning during validation', async () => {
|
|||
const addDeprecation = createAddDeprecation!('');
|
||||
addDeprecation({ message: 'some deprecation message' });
|
||||
addDeprecation({ message: 'another deprecation message' });
|
||||
return config;
|
||||
return { config, changedPaths: mockedChangedPaths };
|
||||
});
|
||||
|
||||
loggerMock.clear(logger);
|
||||
|
@ -446,12 +446,12 @@ test('does not log warnings for silent deprecations during validation', async ()
|
|||
const addDeprecation = createAddDeprecation!('');
|
||||
addDeprecation({ message: 'some deprecation message', silent: true });
|
||||
addDeprecation({ message: 'another deprecation message' });
|
||||
return config;
|
||||
return { config, changedPaths: mockedChangedPaths };
|
||||
})
|
||||
.mockImplementationOnce((config, deprecations, createAddDeprecation) => {
|
||||
const addDeprecation = createAddDeprecation!('');
|
||||
addDeprecation({ message: 'I am silent', silent: true });
|
||||
return config;
|
||||
return { config, changedPaths: mockedChangedPaths };
|
||||
});
|
||||
|
||||
loggerMock.clear(logger);
|
||||
|
@ -521,7 +521,7 @@ describe('getHandledDeprecatedConfigs', () => {
|
|||
const addDeprecation = createAddDeprecation!(deprecation.path);
|
||||
addDeprecation({ message: `some deprecation message`, documentationUrl: 'some-url' });
|
||||
});
|
||||
return config;
|
||||
return { config, changedPaths: mockedChangedPaths };
|
||||
});
|
||||
|
||||
await configService.validate();
|
||||
|
@ -541,3 +541,18 @@ describe('getHandledDeprecatedConfigs', () => {
|
|||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDeprecatedConfigPath$', () => {
|
||||
it('returns all config paths changes during deprecation', async () => {
|
||||
const rawConfig$ = new BehaviorSubject<Record<string, any>>({ key: 'value' });
|
||||
const rawConfigProvider = rawConfigServiceMock.create({ rawConfig$ });
|
||||
|
||||
const configService = new ConfigService(rawConfigProvider, defaultEnv, logger);
|
||||
await configService.setSchema('key', schema.string());
|
||||
await configService.validate();
|
||||
|
||||
const deprecatedConfigPath$ = configService.getDeprecatedConfigPath$();
|
||||
const deprecatedConfigPath = await deprecatedConfigPath$.pipe(first()).toPromise();
|
||||
expect(deprecatedConfigPath).toEqual(mockedChangedPaths);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -22,6 +22,7 @@ import {
|
|||
ConfigDeprecationProvider,
|
||||
configDeprecationFactory,
|
||||
DeprecatedConfigDetails,
|
||||
ChangedDeprecatedPaths,
|
||||
} from './deprecation';
|
||||
import { LegacyObjectToConfigAdapter } from './legacy';
|
||||
|
||||
|
@ -36,6 +37,10 @@ export class ConfigService {
|
|||
private validated = false;
|
||||
private readonly config$: Observable<Config>;
|
||||
private lastConfig?: Config;
|
||||
private readonly deprecatedConfigPaths = new BehaviorSubject<ChangedDeprecatedPaths>({
|
||||
set: [],
|
||||
unset: [],
|
||||
});
|
||||
|
||||
/**
|
||||
* Whenever a config if read at a path, we mark that path as 'handled'. We can
|
||||
|
@ -57,7 +62,8 @@ export class ConfigService {
|
|||
this.config$ = combineLatest([this.rawConfigProvider.getConfig$(), this.deprecations]).pipe(
|
||||
map(([rawConfig, deprecations]) => {
|
||||
const migrated = applyDeprecations(rawConfig, deprecations);
|
||||
return new LegacyObjectToConfigAdapter(migrated);
|
||||
this.deprecatedConfigPaths.next(migrated.changedPaths);
|
||||
return new LegacyObjectToConfigAdapter(migrated.config);
|
||||
}),
|
||||
tap((config) => {
|
||||
this.lastConfig = config;
|
||||
|
@ -191,6 +197,10 @@ export class ConfigService {
|
|||
return config.getFlattenedPaths().filter((path) => isPathHandled(path, handledPaths));
|
||||
}
|
||||
|
||||
public getDeprecatedConfigPath$() {
|
||||
return this.deprecatedConfigPaths.asObservable();
|
||||
}
|
||||
|
||||
private async logDeprecation() {
|
||||
const rawConfig = await this.rawConfigProvider.getConfig$().pipe(take(1)).toPromise();
|
||||
const deprecations = await this.deprecations.pipe(take(1)).toPromise();
|
||||
|
|
|
@ -82,7 +82,7 @@ describe('applyDeprecations', () => {
|
|||
it('returns the migrated config', () => {
|
||||
const initialConfig = { foo: 'bar', deprecated: 'deprecated', renamed: 'renamed' };
|
||||
|
||||
const migrated = applyDeprecations(initialConfig, [
|
||||
const { config: migrated } = applyDeprecations(initialConfig, [
|
||||
wrapHandler(deprecations.unused('deprecated')),
|
||||
wrapHandler(deprecations.rename('renamed', 'newname')),
|
||||
]);
|
||||
|
@ -93,7 +93,7 @@ describe('applyDeprecations', () => {
|
|||
it('does not alter the initial config', () => {
|
||||
const initialConfig = { foo: 'bar', deprecated: 'deprecated' };
|
||||
|
||||
const migrated = applyDeprecations(initialConfig, [
|
||||
const { config: migrated } = applyDeprecations(initialConfig, [
|
||||
wrapHandler(deprecations.unused('deprecated')),
|
||||
]);
|
||||
|
||||
|
@ -110,7 +110,7 @@ describe('applyDeprecations', () => {
|
|||
return { unset: [{ path: 'unknown' }] };
|
||||
});
|
||||
|
||||
const migrated = applyDeprecations(
|
||||
const { config: migrated } = applyDeprecations(
|
||||
initialConfig,
|
||||
[wrapHandler(handler, 'pathA')],
|
||||
createAddDeprecation
|
||||
|
@ -128,7 +128,7 @@ describe('applyDeprecations', () => {
|
|||
return { rewrite: [{ path: 'foo' }] };
|
||||
});
|
||||
|
||||
const migrated = applyDeprecations(
|
||||
const { config: migrated } = applyDeprecations(
|
||||
initialConfig,
|
||||
[wrapHandler(handler, 'pathA')],
|
||||
createAddDeprecation
|
||||
|
@ -136,4 +136,25 @@ describe('applyDeprecations', () => {
|
|||
|
||||
expect(migrated).toEqual(initialConfig);
|
||||
});
|
||||
|
||||
it('returns a list of changes config paths', () => {
|
||||
const addDeprecation = jest.fn();
|
||||
const createAddDeprecation = jest.fn().mockReturnValue(addDeprecation);
|
||||
const initialConfig = { foo: 'bar', deprecated: 'deprecated' };
|
||||
|
||||
const handler = jest.fn().mockImplementation((config) => {
|
||||
return { set: [{ path: 'foo', value: 'bar' }], unset: [{ path: 'baz' }] };
|
||||
});
|
||||
|
||||
const { changedPaths } = applyDeprecations(
|
||||
initialConfig,
|
||||
[wrapHandler(handler, 'pathA')],
|
||||
createAddDeprecation
|
||||
);
|
||||
|
||||
expect(changedPaths).toEqual({
|
||||
set: ['foo'],
|
||||
unset: ['baz'],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,7 +8,11 @@
|
|||
|
||||
import { cloneDeep, unset } from 'lodash';
|
||||
import { set } from '@elastic/safer-lodash-set';
|
||||
import { ConfigDeprecationWithContext, AddConfigDeprecation } from './types';
|
||||
import type {
|
||||
AddConfigDeprecation,
|
||||
ChangedDeprecatedPaths,
|
||||
ConfigDeprecationWithContext,
|
||||
} from './types';
|
||||
|
||||
const noopAddDeprecationFactory: () => AddConfigDeprecation = () => () => undefined;
|
||||
/**
|
||||
|
@ -22,22 +26,31 @@ export const applyDeprecations = (
|
|||
config: Record<string, any>,
|
||||
deprecations: ConfigDeprecationWithContext[],
|
||||
createAddDeprecation: (pluginId: string) => AddConfigDeprecation = noopAddDeprecationFactory
|
||||
) => {
|
||||
): { config: Record<string, any>; changedPaths: ChangedDeprecatedPaths } => {
|
||||
const result = cloneDeep(config);
|
||||
const changedPaths: ChangedDeprecatedPaths = {
|
||||
set: [],
|
||||
unset: [],
|
||||
};
|
||||
deprecations.forEach(({ deprecation, path }) => {
|
||||
const commands = deprecation(result, path, createAddDeprecation(path));
|
||||
if (commands) {
|
||||
if (commands.set) {
|
||||
changedPaths.set.push(...commands.set.map((c) => c.path));
|
||||
commands.set.forEach(function ({ path: commandPath, value }) {
|
||||
set(result, commandPath, value);
|
||||
});
|
||||
}
|
||||
if (commands.unset) {
|
||||
changedPaths.unset.push(...commands.unset.map((c) => c.path));
|
||||
commands.unset.forEach(function ({ path: commandPath }) {
|
||||
unset(result, commandPath);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
return result;
|
||||
return {
|
||||
config: result,
|
||||
changedPaths,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -14,6 +14,7 @@ export type {
|
|||
AddConfigDeprecation,
|
||||
ConfigDeprecationProvider,
|
||||
DeprecatedConfigDetails,
|
||||
ChangedDeprecatedPaths,
|
||||
} from './types';
|
||||
export { configDeprecationFactory } from './deprecation_factory';
|
||||
export { applyDeprecations } from './apply_deprecations';
|
||||
|
|
|
@ -55,6 +55,16 @@ export type ConfigDeprecation = (
|
|||
addDeprecation: AddConfigDeprecation
|
||||
) => void | ConfigDeprecationCommand;
|
||||
|
||||
/**
|
||||
* List of config paths changed during deprecation.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface ChangedDeprecatedPaths {
|
||||
set: string[];
|
||||
unset: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Outcome of deprecation operation. Allows mutating config values in a declarative way.
|
||||
*
|
||||
|
|
|
@ -13,6 +13,7 @@ export type {
|
|||
ConfigDeprecationWithContext,
|
||||
ConfigDeprecation,
|
||||
ConfigDeprecationCommand,
|
||||
ChangedDeprecatedPaths,
|
||||
} from './deprecation';
|
||||
|
||||
export { applyDeprecations, configDeprecationFactory } from './deprecation';
|
||||
|
|
|
@ -16,7 +16,7 @@ function collectDeprecations(
|
|||
) {
|
||||
const deprecations = provider(configDeprecationFactory);
|
||||
const deprecationMessages: string[] = [];
|
||||
const migrated = applyDeprecations(
|
||||
const { config: migrated } = applyDeprecations(
|
||||
settings,
|
||||
deprecations.map((deprecation) => ({
|
||||
deprecation,
|
||||
|
|
|
@ -116,6 +116,10 @@ const createStartContractMock = () => {
|
|||
maxImportExportSize: 10000,
|
||||
maxImportPayloadBytes: 26214400,
|
||||
},
|
||||
deprecatedKeys: {
|
||||
set: ['path.to.a.prop'],
|
||||
unset: [],
|
||||
},
|
||||
},
|
||||
environment: {
|
||||
memory: {
|
||||
|
|
|
@ -91,7 +91,8 @@ describe('CoreUsageDataService', () => {
|
|||
const savedObjectsStartPromise = Promise.resolve(
|
||||
savedObjectsServiceMock.createStartContract()
|
||||
);
|
||||
service.setup({ http, metrics, savedObjectsStartPromise });
|
||||
const changedDeprecatedConfigPath$ = configServiceMock.create().getDeprecatedConfigPath$();
|
||||
service.setup({ http, metrics, savedObjectsStartPromise, changedDeprecatedConfigPath$ });
|
||||
|
||||
const savedObjects = await savedObjectsStartPromise;
|
||||
expect(savedObjects.createInternalRepository).toHaveBeenCalledTimes(1);
|
||||
|
@ -105,7 +106,13 @@ describe('CoreUsageDataService', () => {
|
|||
const savedObjectsStartPromise = Promise.resolve(
|
||||
savedObjectsServiceMock.createStartContract()
|
||||
);
|
||||
const coreUsageData = service.setup({ http, metrics, savedObjectsStartPromise });
|
||||
const changedDeprecatedConfigPath$ = configServiceMock.create().getDeprecatedConfigPath$();
|
||||
const coreUsageData = service.setup({
|
||||
http,
|
||||
metrics,
|
||||
savedObjectsStartPromise,
|
||||
changedDeprecatedConfigPath$,
|
||||
});
|
||||
const typeRegistry = typeRegistryMock.create();
|
||||
|
||||
coreUsageData.registerType(typeRegistry);
|
||||
|
@ -126,7 +133,13 @@ describe('CoreUsageDataService', () => {
|
|||
const savedObjectsStartPromise = Promise.resolve(
|
||||
savedObjectsServiceMock.createStartContract()
|
||||
);
|
||||
const coreUsageData = service.setup({ http, metrics, savedObjectsStartPromise });
|
||||
const changedDeprecatedConfigPath$ = configServiceMock.create().getDeprecatedConfigPath$();
|
||||
const coreUsageData = service.setup({
|
||||
http,
|
||||
metrics,
|
||||
savedObjectsStartPromise,
|
||||
changedDeprecatedConfigPath$,
|
||||
});
|
||||
|
||||
const usageStatsClient = coreUsageData.getClient();
|
||||
expect(usageStatsClient).toBeInstanceOf(CoreUsageStatsClient);
|
||||
|
@ -142,7 +155,11 @@ describe('CoreUsageDataService', () => {
|
|||
const savedObjectsStartPromise = Promise.resolve(
|
||||
savedObjectsServiceMock.createStartContract()
|
||||
);
|
||||
service.setup({ http, metrics, savedObjectsStartPromise });
|
||||
const changedDeprecatedConfigPath$ = new BehaviorSubject({
|
||||
set: ['new.path'],
|
||||
unset: ['deprecated.path'],
|
||||
});
|
||||
service.setup({ http, metrics, savedObjectsStartPromise, changedDeprecatedConfigPath$ });
|
||||
const elasticsearch = elasticsearchServiceMock.createStart();
|
||||
elasticsearch.client.asInternalUser.cat.indices.mockResolvedValueOnce({
|
||||
body: [
|
||||
|
@ -180,6 +197,14 @@ describe('CoreUsageDataService', () => {
|
|||
expect(getCoreUsageData()).resolves.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"config": Object {
|
||||
"deprecatedKeys": Object {
|
||||
"set": Array [
|
||||
"new.path",
|
||||
],
|
||||
"unset": Array [
|
||||
"deprecated.path",
|
||||
],
|
||||
},
|
||||
"elasticsearch": Object {
|
||||
"apiVersion": "master",
|
||||
"customHeadersConfigured": false,
|
||||
|
@ -381,12 +406,10 @@ describe('CoreUsageDataService', () => {
|
|||
elasticsearch,
|
||||
});
|
||||
|
||||
await expect(getConfigsUsageData()).resolves.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"pluginA.enabled": "[redacted]",
|
||||
"pluginAB.enabled": "[redacted]",
|
||||
}
|
||||
`);
|
||||
await expect(getConfigsUsageData()).resolves.toEqual({
|
||||
'pluginA.enabled': '[redacted]',
|
||||
'pluginAB.enabled': '[redacted]',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an object of plugin config usage', async () => {
|
||||
|
@ -418,23 +441,21 @@ describe('CoreUsageDataService', () => {
|
|||
elasticsearch,
|
||||
});
|
||||
|
||||
await expect(getConfigsUsageData()).resolves.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"elasticsearch.password": "[redacted]",
|
||||
"elasticsearch.username": "[redacted]",
|
||||
"logging.json": false,
|
||||
"pluginA.arrayOfNumbers": "[redacted]",
|
||||
"pluginA.enabled": true,
|
||||
"pluginA.objectConfig.debug": true,
|
||||
"pluginA.objectConfig.username": "[redacted]",
|
||||
"pluginAB.enabled": false,
|
||||
"pluginB.arrayOfObjects": "[redacted]",
|
||||
"plugins.paths": "[redacted]",
|
||||
"server.basePath": "/zvt",
|
||||
"server.port": 5603,
|
||||
"server.rewriteBasePath": true,
|
||||
}
|
||||
`);
|
||||
await expect(getConfigsUsageData()).resolves.toEqual({
|
||||
'elasticsearch.password': '[redacted]',
|
||||
'elasticsearch.username': '[redacted]',
|
||||
'logging.json': false,
|
||||
'pluginA.arrayOfNumbers': '[redacted]',
|
||||
'pluginA.enabled': true,
|
||||
'pluginA.objectConfig.debug': true,
|
||||
'pluginA.objectConfig.username': '[redacted]',
|
||||
'pluginAB.enabled': false,
|
||||
'pluginB.arrayOfObjects': '[redacted]',
|
||||
'plugins.paths': '[redacted]',
|
||||
'server.basePath': '/zvt',
|
||||
'server.port': 5603,
|
||||
'server.rewriteBasePath': true,
|
||||
});
|
||||
});
|
||||
|
||||
describe('config explicitly exposed to usage', () => {
|
||||
|
@ -457,12 +478,10 @@ describe('CoreUsageDataService', () => {
|
|||
elasticsearch,
|
||||
});
|
||||
|
||||
await expect(getConfigsUsageData()).resolves.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"pluginA.objectConfig.debug": "[redacted]",
|
||||
"server.basePath": "[redacted]",
|
||||
}
|
||||
`);
|
||||
await expect(getConfigsUsageData()).resolves.toEqual({
|
||||
'pluginA.objectConfig.debug': '[redacted]',
|
||||
'server.basePath': '[redacted]',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns config value on safe complete match', async () => {
|
||||
|
@ -478,11 +497,9 @@ describe('CoreUsageDataService', () => {
|
|||
elasticsearch,
|
||||
});
|
||||
|
||||
await expect(getConfigsUsageData()).resolves.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"server.basePath": "/zvt",
|
||||
}
|
||||
`);
|
||||
await expect(getConfigsUsageData()).resolves.toEqual({
|
||||
'server.basePath': '/zvt',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns [redacted] on unsafe parent match', async () => {
|
||||
|
@ -501,12 +518,10 @@ describe('CoreUsageDataService', () => {
|
|||
elasticsearch,
|
||||
});
|
||||
|
||||
await expect(getConfigsUsageData()).resolves.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"pluginA.objectConfig.debug": "[redacted]",
|
||||
"pluginA.objectConfig.username": "[redacted]",
|
||||
}
|
||||
`);
|
||||
await expect(getConfigsUsageData()).resolves.toEqual({
|
||||
'pluginA.objectConfig.debug': '[redacted]',
|
||||
'pluginA.objectConfig.username': '[redacted]',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns config value on safe parent match', async () => {
|
||||
|
@ -525,12 +540,10 @@ describe('CoreUsageDataService', () => {
|
|||
elasticsearch,
|
||||
});
|
||||
|
||||
await expect(getConfigsUsageData()).resolves.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"pluginA.objectConfig.debug": true,
|
||||
"pluginA.objectConfig.username": "some_user",
|
||||
}
|
||||
`);
|
||||
await expect(getConfigsUsageData()).resolves.toEqual({
|
||||
'pluginA.objectConfig.debug': true,
|
||||
'pluginA.objectConfig.username': 'some_user',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns [redacted] on explicitly marked as safe array of objects', async () => {
|
||||
|
@ -546,11 +559,9 @@ describe('CoreUsageDataService', () => {
|
|||
elasticsearch,
|
||||
});
|
||||
|
||||
await expect(getConfigsUsageData()).resolves.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"pluginB.arrayOfObjects": "[redacted]",
|
||||
}
|
||||
`);
|
||||
await expect(getConfigsUsageData()).resolves.toEqual({
|
||||
'pluginB.arrayOfObjects': '[redacted]',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns values on explicitly marked as safe array of numbers', async () => {
|
||||
|
@ -566,15 +577,9 @@ describe('CoreUsageDataService', () => {
|
|||
elasticsearch,
|
||||
});
|
||||
|
||||
await expect(getConfigsUsageData()).resolves.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"pluginA.arrayOfNumbers": Array [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
],
|
||||
}
|
||||
`);
|
||||
await expect(getConfigsUsageData()).resolves.toEqual({
|
||||
'pluginA.arrayOfNumbers': [1, 2, 3],
|
||||
});
|
||||
});
|
||||
|
||||
it('returns values on explicitly marked as safe array of strings', async () => {
|
||||
|
@ -590,15 +595,9 @@ describe('CoreUsageDataService', () => {
|
|||
elasticsearch,
|
||||
});
|
||||
|
||||
await expect(getConfigsUsageData()).resolves.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"plugins.paths": Array [
|
||||
"pluginA",
|
||||
"pluginAB",
|
||||
"pluginB",
|
||||
],
|
||||
}
|
||||
`);
|
||||
await expect(getConfigsUsageData()).resolves.toEqual({
|
||||
'plugins.paths': ['pluginA', 'pluginAB', 'pluginB'],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -619,12 +618,10 @@ describe('CoreUsageDataService', () => {
|
|||
elasticsearch,
|
||||
});
|
||||
|
||||
await expect(getConfigsUsageData()).resolves.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"pluginA.objectConfig.debug": "[redacted]",
|
||||
"pluginA.objectConfig.username": "[redacted]",
|
||||
}
|
||||
`);
|
||||
await expect(getConfigsUsageData()).resolves.toEqual({
|
||||
'pluginA.objectConfig.debug': '[redacted]',
|
||||
'pluginA.objectConfig.username': '[redacted]',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns config value on safe parent match', async () => {
|
||||
|
@ -640,13 +637,11 @@ describe('CoreUsageDataService', () => {
|
|||
elasticsearch,
|
||||
});
|
||||
|
||||
await expect(getConfigsUsageData()).resolves.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"elasticsearch.password": "[redacted]",
|
||||
"elasticsearch.username": "[redacted]",
|
||||
"pluginA.objectConfig.username": "[redacted]",
|
||||
}
|
||||
`);
|
||||
await expect(getConfigsUsageData()).resolves.toEqual({
|
||||
'elasticsearch.password': '[redacted]',
|
||||
'elasticsearch.username': '[redacted]',
|
||||
'pluginA.objectConfig.username': '[redacted]',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns [redacted] on implicit array of objects', async () => {
|
||||
|
@ -658,11 +653,9 @@ describe('CoreUsageDataService', () => {
|
|||
elasticsearch,
|
||||
});
|
||||
|
||||
await expect(getConfigsUsageData()).resolves.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"pluginB.arrayOfObjects": "[redacted]",
|
||||
}
|
||||
`);
|
||||
await expect(getConfigsUsageData()).resolves.toEqual({
|
||||
'pluginB.arrayOfObjects': '[redacted]',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns values on implicit array of numbers', async () => {
|
||||
|
@ -674,16 +667,11 @@ describe('CoreUsageDataService', () => {
|
|||
elasticsearch,
|
||||
});
|
||||
|
||||
await expect(getConfigsUsageData()).resolves.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"pluginA.arrayOfNumbers": Array [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
],
|
||||
}
|
||||
`);
|
||||
await expect(getConfigsUsageData()).resolves.toEqual({
|
||||
'pluginA.arrayOfNumbers': [1, 2, 3],
|
||||
});
|
||||
});
|
||||
|
||||
it('returns [redacted] on implicit array of strings', async () => {
|
||||
configService.getUsedPaths.mockResolvedValue(['plugins.paths']);
|
||||
|
||||
|
@ -693,11 +681,9 @@ describe('CoreUsageDataService', () => {
|
|||
elasticsearch,
|
||||
});
|
||||
|
||||
await expect(getConfigsUsageData()).resolves.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"plugins.paths": "[redacted]",
|
||||
}
|
||||
`);
|
||||
await expect(getConfigsUsageData()).resolves.toEqual({
|
||||
'plugins.paths': '[redacted]',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns config value for numbers', async () => {
|
||||
|
@ -709,11 +695,9 @@ describe('CoreUsageDataService', () => {
|
|||
elasticsearch,
|
||||
});
|
||||
|
||||
await expect(getConfigsUsageData()).resolves.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"server.port": 5603,
|
||||
}
|
||||
`);
|
||||
await expect(getConfigsUsageData()).resolves.toEqual({
|
||||
'server.port': 5603,
|
||||
});
|
||||
});
|
||||
|
||||
it('returns config value for booleans', async () => {
|
||||
|
@ -728,12 +712,10 @@ describe('CoreUsageDataService', () => {
|
|||
elasticsearch,
|
||||
});
|
||||
|
||||
await expect(getConfigsUsageData()).resolves.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"logging.json": false,
|
||||
"pluginA.objectConfig.debug": true,
|
||||
}
|
||||
`);
|
||||
await expect(getConfigsUsageData()).resolves.toEqual({
|
||||
'logging.json': false,
|
||||
'pluginA.objectConfig.debug': true,
|
||||
});
|
||||
});
|
||||
|
||||
it('ignores exposed to usage configs but not used', async () => {
|
||||
|
@ -749,11 +731,9 @@ describe('CoreUsageDataService', () => {
|
|||
elasticsearch,
|
||||
});
|
||||
|
||||
await expect(getConfigsUsageData()).resolves.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"logging.json": false,
|
||||
}
|
||||
`);
|
||||
await expect(getConfigsUsageData()).resolves.toEqual({
|
||||
'logging.json': false,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -779,7 +759,8 @@ describe('CoreUsageDataService', () => {
|
|||
savedObjectsServiceMock.createStartContract()
|
||||
);
|
||||
|
||||
service.setup({ http, metrics, savedObjectsStartPromise });
|
||||
const changedDeprecatedConfigPath$ = configServiceMock.create().getDeprecatedConfigPath$();
|
||||
service.setup({ http, metrics, savedObjectsStartPromise, changedDeprecatedConfigPath$ });
|
||||
|
||||
// Use the stopTimer$ to delay calling stop() until the third frame
|
||||
const stopTimer$ = cold('---a|');
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { Subject } from 'rxjs';
|
||||
import { Subject, Observable } from 'rxjs';
|
||||
import { takeUntil, first } from 'rxjs/operators';
|
||||
import { get } from 'lodash';
|
||||
import { hasConfigPathIntersection } from '@kbn/config';
|
||||
import { hasConfigPathIntersection, ChangedDeprecatedPaths } from '@kbn/config';
|
||||
|
||||
import { CoreService } from 'src/core/types';
|
||||
import { Logger, SavedObjectsServiceStart, SavedObjectTypeRegistry } from 'src/core/server';
|
||||
|
@ -39,6 +39,7 @@ export interface SetupDeps {
|
|||
http: InternalHttpServiceSetup;
|
||||
metrics: MetricsServiceSetup;
|
||||
savedObjectsStartPromise: Promise<SavedObjectsServiceStart>;
|
||||
changedDeprecatedConfigPath$: Observable<ChangedDeprecatedPaths>;
|
||||
}
|
||||
|
||||
export interface StartDeps {
|
||||
|
@ -89,6 +90,7 @@ export class CoreUsageDataService implements CoreService<CoreUsageDataSetup, Cor
|
|||
private opsMetrics?: OpsMetrics;
|
||||
private kibanaConfig?: KibanaConfigType;
|
||||
private coreUsageStatsClient?: CoreUsageStatsClient;
|
||||
private deprecatedConfigPaths: ChangedDeprecatedPaths = { set: [], unset: [] };
|
||||
|
||||
constructor(core: CoreContext) {
|
||||
this.logger = core.logger.get('core-usage-stats-service');
|
||||
|
@ -257,6 +259,8 @@ export class CoreUsageDataService implements CoreService<CoreUsageDataSetup, Cor
|
|||
maxImportPayloadBytes: this.soConfig.maxImportPayloadBytes.getValueInBytes(),
|
||||
maxImportExportSize: this.soConfig.maxImportExportSize,
|
||||
},
|
||||
|
||||
deprecatedKeys: this.deprecatedConfigPaths,
|
||||
},
|
||||
environment: {
|
||||
memory: {
|
||||
|
@ -376,7 +380,7 @@ export class CoreUsageDataService implements CoreService<CoreUsageDataSetup, Cor
|
|||
}, {} as Record<string, any | any[]>);
|
||||
}
|
||||
|
||||
setup({ http, metrics, savedObjectsStartPromise }: SetupDeps) {
|
||||
setup({ http, metrics, savedObjectsStartPromise, changedDeprecatedConfigPath$ }: SetupDeps) {
|
||||
metrics
|
||||
.getOpsMetrics$()
|
||||
.pipe(takeUntil(this.stop$))
|
||||
|
@ -417,6 +421,10 @@ export class CoreUsageDataService implements CoreService<CoreUsageDataSetup, Cor
|
|||
this.kibanaConfig = config;
|
||||
});
|
||||
|
||||
changedDeprecatedConfigPath$
|
||||
.pipe(takeUntil(this.stop$))
|
||||
.subscribe((deprecatedConfigPaths) => (this.deprecatedConfigPaths = deprecatedConfigPaths));
|
||||
|
||||
const internalRepositoryPromise = savedObjectsStartPromise.then((savedObjects) =>
|
||||
savedObjects.createInternalRepository([CORE_USAGE_STATS_TYPE])
|
||||
);
|
||||
|
|
|
@ -254,6 +254,11 @@ export interface CoreConfigUsageData {
|
|||
// uiSettings: {
|
||||
// overridesCount: number;
|
||||
// };
|
||||
|
||||
deprecatedKeys: {
|
||||
set: string[];
|
||||
unset: string[];
|
||||
};
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
|
|
@ -399,6 +399,11 @@ export interface ContextSetup {
|
|||
|
||||
// @internal
|
||||
export interface CoreConfigUsageData {
|
||||
// (undocumented)
|
||||
deprecatedKeys: {
|
||||
set: string[];
|
||||
unset: string[];
|
||||
};
|
||||
// (undocumented)
|
||||
elasticsearch: {
|
||||
sniffOnStart: boolean;
|
||||
|
|
|
@ -153,6 +153,7 @@ export class Server {
|
|||
http: httpSetup,
|
||||
metrics: metricsSetup,
|
||||
savedObjectsStartPromise: this.savedObjectsStartPromise,
|
||||
changedDeprecatedConfigPath$: this.configService.getDeprecatedConfigPath$(),
|
||||
});
|
||||
|
||||
const savedObjectsSetup = await this.savedObjects.setup({
|
||||
|
@ -265,6 +266,7 @@ export class Server {
|
|||
await this.http.start();
|
||||
|
||||
startTransaction?.end();
|
||||
|
||||
return this.coreStart;
|
||||
}
|
||||
|
||||
|
|
|
@ -308,6 +308,23 @@ export function getCoreUsageCollector(
|
|||
},
|
||||
},
|
||||
},
|
||||
|
||||
deprecatedKeys: {
|
||||
set: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'keyword',
|
||||
_meta: { description: 'Config path added during config deprecation.' },
|
||||
},
|
||||
},
|
||||
unset: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'keyword',
|
||||
_meta: { description: 'Config path removed during config deprecation.' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
environment: {
|
||||
memory: {
|
||||
|
|
|
@ -6950,6 +6950,28 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"deprecatedKeys": {
|
||||
"properties": {
|
||||
"set": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "keyword",
|
||||
"_meta": {
|
||||
"description": "Config path added during config deprecation."
|
||||
}
|
||||
}
|
||||
},
|
||||
"unset": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "keyword",
|
||||
"_meta": {
|
||||
"description": "Config path removed during config deprecation."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -15,7 +15,7 @@ const applyReportingDeprecations = (settings: Record<string, any> = {}) => {
|
|||
const deprecationMessages: string[] = [];
|
||||
const _config: any = {};
|
||||
_config[CONFIG_PATH] = settings;
|
||||
const migrated = applyDeprecations(
|
||||
const { config: migrated } = applyDeprecations(
|
||||
_config,
|
||||
deprecations.map((deprecation) => ({
|
||||
deprecation,
|
||||
|
|
|
@ -14,7 +14,7 @@ import { securityConfigDeprecationProvider } from './config_deprecations';
|
|||
const applyConfigDeprecations = (settings: Record<string, any> = {}) => {
|
||||
const deprecations = securityConfigDeprecationProvider(configDeprecationFactory);
|
||||
const deprecationMessages: string[] = [];
|
||||
const migrated = applyDeprecations(
|
||||
const { config: migrated } = applyDeprecations(
|
||||
settings,
|
||||
deprecations.map((deprecation) => ({
|
||||
deprecation,
|
||||
|
|
|
@ -13,7 +13,7 @@ import { spacesConfigDeprecationProvider } from './config';
|
|||
const applyConfigDeprecations = (settings: Record<string, any> = {}) => {
|
||||
const deprecations = spacesConfigDeprecationProvider(configDeprecationFactory);
|
||||
const deprecationMessages: string[] = [];
|
||||
const migrated = applyDeprecations(
|
||||
const { config: migrated } = applyDeprecations(
|
||||
settings,
|
||||
deprecations.map((deprecation) => ({
|
||||
deprecation,
|
||||
|
|
|
@ -16,7 +16,7 @@ const applyTaskManagerDeprecations = (settings: Record<string, unknown> = {}) =>
|
|||
const _config = {
|
||||
[CONFIG_PATH]: settings,
|
||||
};
|
||||
const migrated = applyDeprecations(
|
||||
const { config: migrated } = applyDeprecations(
|
||||
_config,
|
||||
deprecations.map((deprecation) => ({
|
||||
deprecation,
|
||||
|
|
Loading…
Reference in a new issue