mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Profling] reading kibana yml values (#159015)
kibana.yml config definition example ```yaml xpack.profiling.collector.host: 'foo' xpack.profiling.collector.secret_token: 'bar' xpack.profiling.collector.tls_enabled: true xpack.profiling.collector.tls_supported_protocols: ['baz', 'qux'] xpack.profiling.collector.tls_certificate_path: 'path' xpack.profiling.collector.tls_key_path: 'key' xpack.profiling.symbolizer.host: 'foo' xpack.profiling.symbolizer.secret_token: 'bar' xpack.profiling.symbolizer.tls_enabled: true xpack.profiling.symbolizer.tls_supported_protocols: ['baz', 'qux'] xpack.profiling.symbolizer.tls_certificate_path: 'path' xpack.profiling.symbolizer.tls_key_path: 'key' ``` This PR reads the config defined in the kibana.yml (example above) and generates the vars object that will be used to create both `profiling collector` and `profiling symbolizer`. It also generates the `secret_token` which is a 16-long string [a-zA-Z0-9].
This commit is contained in:
parent
9f5ecaa913
commit
b8b4f75145
7 changed files with 167 additions and 0 deletions
|
@ -9,8 +9,19 @@ import { schema, TypeOf } from '@kbn/config-schema';
|
|||
import type { PluginConfigDescriptor, PluginInitializerContext } from '@kbn/core/server';
|
||||
import { ProfilingPlugin } from './plugin';
|
||||
|
||||
const packageInputSchema = schema.object({
|
||||
host: schema.maybe(schema.string()),
|
||||
secret_token: schema.maybe(schema.string()),
|
||||
tls_enabled: schema.maybe(schema.boolean()),
|
||||
tls_supported_protocols: schema.maybe(schema.arrayOf(schema.string())),
|
||||
tls_certificate_path: schema.maybe(schema.string()),
|
||||
tls_key_path: schema.maybe(schema.string()),
|
||||
});
|
||||
|
||||
const configSchema = schema.object({
|
||||
enabled: schema.boolean({ defaultValue: false }),
|
||||
symbolizer: schema.maybe(packageInputSchema),
|
||||
collector: schema.maybe(packageInputSchema),
|
||||
elasticsearch: schema.maybe(
|
||||
schema.object({
|
||||
hosts: schema.string(),
|
||||
|
@ -21,6 +32,7 @@ const configSchema = schema.object({
|
|||
});
|
||||
|
||||
export type ProfilingConfig = TypeOf<typeof configSchema>;
|
||||
export type PackageInputType = TypeOf<typeof packageInputSchema>;
|
||||
|
||||
// plugin config
|
||||
export const config: PluginConfigDescriptor<ProfilingConfig> = {
|
||||
|
|
102
x-pack/plugins/profiling/server/lib/setup/fleet_policies.test.ts
Normal file
102
x-pack/plugins/profiling/server/lib/setup/fleet_policies.test.ts
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* 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 { PackageInputType } from '../..';
|
||||
import { getVarsFor } from './fleet_policies';
|
||||
|
||||
const secretTokenRegex = /^[a-zA-Z0-9]+$/;
|
||||
|
||||
describe('getVarsFor', () => {
|
||||
it('returns secret_token when package input is not provided', () => {
|
||||
const config: PackageInputType = {};
|
||||
|
||||
const { secret_token: secretToken, ...result } = getVarsFor({
|
||||
config,
|
||||
includeSecretToken: true,
|
||||
});
|
||||
expect(secretToken?.type).toBe('text');
|
||||
expect(secretToken?.value).toBeDefined();
|
||||
expect(secretToken?.value).toBeDefined();
|
||||
expect(secretTokenRegex.test(secretToken?.value)).toBeTruthy();
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
|
||||
it('returns the vars object for the keys defined plus secret token', () => {
|
||||
const config: PackageInputType = {
|
||||
host: 'example.com',
|
||||
tls_enabled: true,
|
||||
tls_supported_protocols: ['foo', 'bar'],
|
||||
tls_certificate_path: '123',
|
||||
tls_key_path: '456',
|
||||
};
|
||||
|
||||
const { secret_token: secretToken, ...result } = getVarsFor({
|
||||
config,
|
||||
includeSecretToken: true,
|
||||
});
|
||||
expect(secretToken?.type).toBe('text');
|
||||
expect(secretToken?.value.length).toBe(16);
|
||||
expect(secretTokenRegex.test(secretToken?.value)).toBeTruthy();
|
||||
expect(result).toEqual({
|
||||
host: { type: 'text', value: 'example.com' },
|
||||
tls_enabled: { type: 'bool', value: true },
|
||||
tls_supported_protocols: { type: 'text', value: ['foo', 'bar'] },
|
||||
tls_certificate_path: { type: 'text', value: '123' },
|
||||
tls_key_path: { type: 'text', value: '456' },
|
||||
});
|
||||
});
|
||||
|
||||
it('discards secret_token defined and generate a new one', () => {
|
||||
const config: PackageInputType = {
|
||||
host: 'example.com',
|
||||
tls_enabled: true,
|
||||
tls_supported_protocols: ['foo', 'bar'],
|
||||
tls_certificate_path: '123',
|
||||
tls_key_path: '456',
|
||||
secret_token: 'bar!',
|
||||
};
|
||||
|
||||
const { secret_token: secretToken, ...result } = getVarsFor({
|
||||
config,
|
||||
includeSecretToken: true,
|
||||
});
|
||||
expect(secretToken?.type).toBe('text');
|
||||
expect(secretToken?.value).not.toBe('bar!');
|
||||
expect(secretToken?.value.length).toBe(16);
|
||||
expect(secretTokenRegex.test(secretToken?.value)).toBeTruthy();
|
||||
expect(result).toEqual({
|
||||
host: { type: 'text', value: 'example.com' },
|
||||
tls_enabled: { type: 'bool', value: true },
|
||||
tls_supported_protocols: { type: 'text', value: ['foo', 'bar'] },
|
||||
tls_certificate_path: { type: 'text', value: '123' },
|
||||
tls_key_path: { type: 'text', value: '456' },
|
||||
});
|
||||
});
|
||||
|
||||
it('returns vars without secret_token', () => {
|
||||
const config: PackageInputType = {
|
||||
host: 'example.com',
|
||||
tls_enabled: true,
|
||||
tls_supported_protocols: ['foo', 'bar'],
|
||||
tls_certificate_path: '123',
|
||||
tls_key_path: '456',
|
||||
};
|
||||
|
||||
const { secret_token: secretToken, ...result } = getVarsFor({
|
||||
config,
|
||||
includeSecretToken: false,
|
||||
});
|
||||
expect(secretToken).toBeUndefined();
|
||||
expect(result).toEqual({
|
||||
host: { type: 'text', value: 'example.com' },
|
||||
tls_enabled: { type: 'bool', value: true },
|
||||
tls_supported_protocols: { type: 'text', value: ['foo', 'bar'] },
|
||||
tls_certificate_path: { type: 'text', value: '123' },
|
||||
tls_key_path: { type: 'text', value: '456' },
|
||||
});
|
||||
});
|
||||
});
|
|
@ -11,6 +11,7 @@ import { fetchFindLatestPackageOrThrow } from '@kbn/fleet-plugin/server/services
|
|||
import { getApmPolicy } from './get_apm_policy';
|
||||
import { ProfilingSetupOptions } from './types';
|
||||
import { PartialSetupState } from '../../../common/setup';
|
||||
import { PackageInputType } from '../..';
|
||||
|
||||
async function createIngestAPIKey(esClient: ElasticsearchClient) {
|
||||
const apiKeyResponse = await esClient.security.createApiKey({
|
||||
|
@ -125,10 +126,47 @@ export async function validateCollectorPackagePolicy({
|
|||
};
|
||||
}
|
||||
|
||||
export function generateSecretToken() {
|
||||
let result = '';
|
||||
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
|
||||
for (let i = 0; i < 16; i++) {
|
||||
const randomIndex = Math.floor(Math.random() * characters.length);
|
||||
result += characters.charAt(randomIndex);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function getVarsFor({
|
||||
config,
|
||||
includeSecretToken,
|
||||
}: {
|
||||
config: PackageInputType;
|
||||
includeSecretToken: boolean;
|
||||
}) {
|
||||
const configKeys = Object.keys(config) as Array<keyof PackageInputType>;
|
||||
if (includeSecretToken) {
|
||||
configKeys.push('secret_token');
|
||||
}
|
||||
|
||||
return configKeys.reduce<
|
||||
Partial<Record<keyof PackageInputType, { type: 'text' | 'bool'; value: any }>>
|
||||
>((acc, currKey) => {
|
||||
const value = currKey === 'secret_token' ? generateSecretToken() : config[currKey];
|
||||
const type = typeof value === 'boolean' ? 'bool' : 'text';
|
||||
return {
|
||||
...acc,
|
||||
[currKey]: { type, value },
|
||||
};
|
||||
}, {});
|
||||
}
|
||||
|
||||
export async function createCollectorPackagePolicy({
|
||||
client,
|
||||
soClient,
|
||||
packagePolicyClient,
|
||||
config,
|
||||
}: ProfilingSetupOptions) {
|
||||
const packageName = 'profiler_collector';
|
||||
const { version } = await fetchFindLatestPackageOrThrow(packageName, { prerelease: true });
|
||||
|
@ -148,6 +186,9 @@ export async function createCollectorPackagePolicy({
|
|||
enabled: true,
|
||||
streams: [],
|
||||
type: 'pf-elastic-collector',
|
||||
vars: config?.collector
|
||||
? getVarsFor({ config: config.collector, includeSecretToken: true })
|
||||
: {},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
@ -175,6 +216,7 @@ export async function createSymbolizerPackagePolicy({
|
|||
client,
|
||||
soClient,
|
||||
packagePolicyClient,
|
||||
config,
|
||||
}: ProfilingSetupOptions) {
|
||||
const packageName = 'profiler_symbolizer';
|
||||
const { version } = await fetchFindLatestPackageOrThrow(packageName, { prerelease: true });
|
||||
|
@ -194,6 +236,10 @@ export async function createSymbolizerPackagePolicy({
|
|||
enabled: true,
|
||||
streams: [],
|
||||
type: 'pf-elastic-symbolizer',
|
||||
// doesnt have secret token
|
||||
vars: config?.symbolizer
|
||||
? getVarsFor({ config: config.symbolizer, includeSecretToken: false })
|
||||
: {},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
import { SavedObjectsClientContract } from '@kbn/core/server';
|
||||
import { PackagePolicyClient } from '@kbn/fleet-plugin/server';
|
||||
import { Logger } from '@kbn/logging';
|
||||
import { ProfilingConfig } from '../..';
|
||||
import { ProfilingESClient } from '../../utils/create_profiling_es_client';
|
||||
|
||||
export interface ProfilingSetupOptions {
|
||||
|
@ -17,4 +18,5 @@ export interface ProfilingSetupOptions {
|
|||
logger: Logger;
|
||||
spaceId: string;
|
||||
isCloudEnabled: boolean;
|
||||
config: ProfilingConfig;
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ export class ProfilingPlugin
|
|||
dependencies: {
|
||||
start: depsStart,
|
||||
setup: deps,
|
||||
config,
|
||||
},
|
||||
services: {
|
||||
createProfilingEsClient: ({
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server';
|
||||
import type { KibanaRequest } from '@kbn/core-http-server';
|
||||
import type { IRouter, Logger } from '@kbn/core/server';
|
||||
import { ProfilingConfig } from '..';
|
||||
import {
|
||||
ProfilingPluginSetupDeps,
|
||||
ProfilingPluginStartDeps,
|
||||
|
@ -31,6 +32,7 @@ export interface RouteRegisterParameters {
|
|||
dependencies: {
|
||||
start: ProfilingPluginStartDeps;
|
||||
setup: ProfilingPluginSetupDeps;
|
||||
config: ProfilingConfig;
|
||||
};
|
||||
services: {
|
||||
createProfilingEsClient: (params: {
|
||||
|
|
|
@ -63,6 +63,7 @@ export function registerSetupRoute({
|
|||
soClient: core.savedObjects.client,
|
||||
spaceId: dependencies.setup.spaces.spacesService.getSpaceId(request),
|
||||
isCloudEnabled: dependencies.setup.cloud.isCloudEnabled,
|
||||
config: dependencies.config,
|
||||
};
|
||||
|
||||
logger.info('Checking if Elasticsearch and Fleet are setup for Universal Profiling');
|
||||
|
@ -127,6 +128,7 @@ export function registerSetupRoute({
|
|||
soClient: core.savedObjects.client,
|
||||
spaceId: dependencies.setup.spaces.spacesService.getSpaceId(request),
|
||||
isCloudEnabled: dependencies.setup.cloud.isCloudEnabled,
|
||||
config: dependencies.config,
|
||||
};
|
||||
|
||||
logger.info('Setting up Elasticsearch and Fleet for Universal Profiling');
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue