[EEM] Migrate to using @kbn/server-route-repository (#191102)

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Milton Hultgren 2024-09-06 11:11:28 +02:00 committed by GitHub
parent 8a429b5953
commit b9319a6ad4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 612 additions and 571 deletions

View file

@ -6,7 +6,7 @@
* Side Public License, v 1.
*/
type Method = 'get' | 'post' | 'put' | 'delete';
type Method = 'get' | 'post' | 'put' | 'patch' | 'delete';
export function parseEndpoint(endpoint: string) {
const parts = endpoint.split(' ');
@ -15,7 +15,7 @@ export function parseEndpoint(endpoint: string) {
const pathname = parts[1].trim();
const version = parts[2]?.trim();
if (!['get', 'post', 'put', 'delete'].includes(method)) {
if (!['get', 'post', 'put', 'patch', 'delete'].includes(method)) {
throw new Error(`Endpoint ${endpoint} was not prefixed with a valid HTTP method`);
}

View file

@ -8,7 +8,12 @@ components:
type: object
properties:
installOnly:
type: boolean
anyOf:
- type: string
enum:
- "true"
- "false"
- type: boolean
default: false
additionalProperties: false
getEntityDefinitionQuerySchema:
@ -39,7 +44,12 @@ components:
type: object
properties:
deleteData:
type: boolean
anyOf:
- type: string
enum:
- "true"
- "false"
- type: boolean
default: false
additionalProperties: false
entityDefinitionSchema:
@ -393,6 +403,7 @@ paths:
application/json:
schema:
type: object
required: enabled
properties:
enabled:
type: boolean
@ -422,6 +433,7 @@ paths:
application/json:
schema:
type: object
required: success
properties:
success:
type: boolean
@ -447,6 +459,7 @@ paths:
application/json:
schema:
type: object
required: success
properties:
success:
type: boolean
@ -491,7 +504,8 @@ paths:
$ref: "#/components/schemas/entityDefinitionSchema"
"400":
description: The entity definition cannot be installed; see the error for more
details
details but commonly due to validation failures of the definition ID
or metrics format
"409":
description: An entity definition with this ID already exists
delete:
@ -564,4 +578,39 @@ paths:
type: boolean
running:
type: boolean
patch:
description: Update an entity definition.
tags:
- definitions
parameters:
- in: query
name: installOnly
description: If true, the definition transforms will not be started
required: false
schema:
type: boolean
default: false
requestBody:
description: The definition properties to update
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/entityDefinitionUpdateSchema"
responses:
"200":
description: Success
content:
application/json:
schema:
$ref: "#/components/schemas/entityDefinitionSchema"
"400":
description: The entity definition cannot be installed; see the error for more
details
"403":
description: User is not allowed to update the entity definition
"404":
description: The entity definition does not exist
"409":
description: The entity definition is being updated by another request
tags: []

View file

@ -11,5 +11,3 @@ import { BooleanFromString } from '@kbn/zod-helpers';
export const createEntityDefinitionQuerySchema = z.object({
installOnly: z.optional(BooleanFromString).default(false),
});
export type CreateEntityDefinitionQuery = z.infer<typeof createEntityDefinitionQuerySchema>;

View file

@ -15,5 +15,3 @@ export const deleteEntityDefinitionParamsSchema = z.object({
export const deleteEntityDefinitionQuerySchema = z.object({
deleteData: z.optional(BooleanFromString).default(false),
});
export type DeleteEntityDefinitionQuery = z.infer<typeof deleteEntityDefinitionQuerySchema>;

View file

@ -5,32 +5,60 @@
* 2.0.
*/
import { HttpStart } from '@kbn/core/public';
import { CreateEntityDefinitionQuery, DeleteEntityDefinitionQuery } from '@kbn/entities-schema';
import { EntityManagerUnauthorizedError } from './errors';
import { IEntityClient } from '../types';
import { CoreSetup, CoreStart } from '@kbn/core/public';
import {
ClientRequestParamsOf,
RouteRepositoryClient,
createRepositoryClient,
isHttpFetchError,
} from '@kbn/server-route-repository-client';
import {
ManagedEntityEnabledResponse,
EnableManagedEntityResponse,
DisableManagedEntityResponse,
EnableManagedEntityResponse,
ManagedEntityEnabledResponse,
} from '../../common/types_api';
import type { EntityManagerRouteRepository } from '../../server';
import { EntityManagerUnauthorizedError } from './errors';
export class EntityClient implements IEntityClient {
constructor(private readonly http: HttpStart) {}
type EntityManagerRepositoryClient = RouteRepositoryClient<EntityManagerRouteRepository>;
type QueryParamOf<T extends { params?: any }> = Exclude<T['params'], undefined>['query'];
type DeleteEntityDefinitionQuery = QueryParamOf<
ClientRequestParamsOf<
EntityManagerRouteRepository,
'DELETE /internal/entities/managed/enablement'
>
>;
type CreateEntityDefinitionQuery = QueryParamOf<
ClientRequestParamsOf<EntityManagerRouteRepository, 'PUT /internal/entities/managed/enablement'>
>;
export class EntityClient {
public readonly repositoryClient: EntityManagerRepositoryClient;
constructor(core: CoreStart | CoreSetup) {
this.repositoryClient = createRepositoryClient<EntityManagerRouteRepository>(core).fetch;
}
async isManagedEntityDiscoveryEnabled(): Promise<ManagedEntityEnabledResponse> {
return await this.http.get('/internal/entities/managed/enablement');
return await this.repositoryClient('GET /internal/entities/managed/enablement');
}
async enableManagedEntityDiscovery(
query?: CreateEntityDefinitionQuery
): Promise<EnableManagedEntityResponse> {
try {
return await this.http.put('/internal/entities/managed/enablement', {
query,
return await this.repositoryClient('PUT /internal/entities/managed/enablement', {
params: {
query: {
installOnly: query?.installOnly,
},
},
});
} catch (err) {
if (err.body?.statusCode === 403) {
if (isHttpFetchError(err) && err.body?.statusCode === 403) {
throw new EntityManagerUnauthorizedError(err.body.message);
}
throw err;
@ -41,9 +69,15 @@ export class EntityClient implements IEntityClient {
query?: DeleteEntityDefinitionQuery
): Promise<DisableManagedEntityResponse> {
try {
return await this.http.delete('/internal/entities/managed/enablement', { query });
return await this.repositoryClient('DELETE /internal/entities/managed/enablement', {
params: {
query: {
deleteData: query?.deleteData,
},
},
});
} catch (err) {
if (err.body?.statusCode === 403) {
if (isHttpFetchError(err) && err.body?.statusCode === 403) {
throw new EntityManagerUnauthorizedError(err.body.message);
}
throw err;

View file

@ -22,14 +22,14 @@ export class Plugin implements EntityManagerPluginClass {
}
setup(core: CoreSetup) {
const entityClient = new EntityClient(core.http);
const entityClient = new EntityClient(core);
return {
entityClient,
};
}
start(core: CoreStart) {
const entityClient = new EntityClient(core.http);
const entityClient = new EntityClient(core);
return {
entityClient,
};

View file

@ -5,30 +5,17 @@
* 2.0.
*/
import type { Plugin as PluginClass } from '@kbn/core/public';
import { CreateEntityDefinitionQuery } from '@kbn/entities-schema';
import {
DisableManagedEntityResponse,
EnableManagedEntityResponse,
ManagedEntityEnabledResponse,
} from '../common/types_api';
import type { EntityClient } from './lib/entity_client';
export interface EntityManagerPublicPluginSetup {
entityClient: IEntityClient;
entityClient: EntityClient;
}
export interface EntityManagerPublicPluginStart {
entityClient: IEntityClient;
entityClient: EntityClient;
}
export type EntityManagerPluginClass = PluginClass<
EntityManagerPublicPluginSetup | undefined,
EntityManagerPublicPluginStart | undefined
EntityManagerPublicPluginSetup,
EntityManagerPublicPluginStart
>;
export interface IEntityClient {
isManagedEntityDiscoveryEnabled: () => Promise<ManagedEntityEnabledResponse>;
enableManagedEntityDiscovery: (
query?: CreateEntityDefinitionQuery
) => Promise<EnableManagedEntityResponse>;
disableManagedEntityDiscovery: () => Promise<DisableManagedEntityResponse>;
}

View file

@ -8,8 +8,14 @@
import { PluginInitializerContext } from '@kbn/core-plugins-server';
import { EntityManagerConfig } from '../common/config';
import { EntityManagerServerPluginSetup, EntityManagerServerPluginStart, config } from './plugin';
import { EntityManagerRouteRepository } from './routes';
export type { EntityManagerConfig, EntityManagerServerPluginSetup, EntityManagerServerPluginStart };
export type {
EntityManagerConfig,
EntityManagerServerPluginSetup,
EntityManagerServerPluginStart,
EntityManagerRouteRepository,
};
export { config };
export const plugin = async (context: PluginInitializerContext<EntityManagerConfig>) => {

View file

@ -5,29 +5,30 @@
* 2.0.
*/
import { firstValueFrom } from 'rxjs';
import {
Plugin,
CoreSetup,
RequestHandlerContext,
CoreStart,
PluginInitializerContext,
PluginConfigDescriptor,
Logger,
KibanaRequest,
Logger,
Plugin,
PluginConfigDescriptor,
PluginInitializerContext,
} from '@kbn/core/server';
import { registerRoutes } from '@kbn/server-route-repository';
import { firstValueFrom } from 'rxjs';
import { EntityManagerConfig, configSchema, exposeToBrowserConfig } from '../common/config';
import { builtInDefinitions } from './lib/entities/built_in';
import { upgradeBuiltInEntityDefinitions } from './lib/entities/upgrade_entity_definition';
import { EntityClient } from './lib/entity_client';
import { installEntityManagerTemplates } from './lib/manage_index_templates';
import { setupRoutes } from './routes';
import { entityManagerRouteRepository } from './routes';
import { EntityManagerRouteDependencies } from './routes/types';
import { EntityDiscoveryApiKeyType, entityDefinition } from './saved_objects';
import {
EntityManagerPluginSetupDependencies,
EntityManagerPluginStartDependencies,
EntityManagerServerSetup,
} from './types';
import { EntityManagerConfig, configSchema, exposeToBrowserConfig } from '../common/config';
import { entityDefinition, EntityDiscoveryApiKeyType } from './saved_objects';
import { upgradeBuiltInEntityDefinitions } from './lib/entities/upgrade_entity_definition';
import { builtInDefinitions } from './lib/entities/built_in';
import { EntityClient } from './lib/entity_client';
export type EntityManagerServerPluginSetup = ReturnType<EntityManagerServerPlugin['setup']>;
export type EntityManagerServerPluginStart = ReturnType<EntityManagerServerPlugin['start']>;
@ -64,23 +65,24 @@ export class EntityManagerServerPlugin
attributesToIncludeInAAD: new Set(['id', 'name']),
});
const router = core.http.createRouter();
this.server = {
config: this.config,
logger: this.logger,
} as EntityManagerServerSetup;
setupRoutes<RequestHandlerContext>({
router,
logger: this.logger,
server: this.server,
getScopedClient: async ({ request }: { request: KibanaRequest }) => {
const [coreStart] = await core.getStartServices();
const esClient = coreStart.elasticsearch.client.asScoped(request).asCurrentUser;
const soClient = coreStart.savedObjects.getScopedClient(request);
return new EntityClient({ esClient, soClient, logger: this.logger });
registerRoutes<EntityManagerRouteDependencies>({
repository: entityManagerRouteRepository,
dependencies: {
server: this.server,
getScopedClient: async ({ request }: { request: KibanaRequest }) => {
const [coreStart] = await core.getStartServices();
const esClient = coreStart.elasticsearch.client.asScoped(request).asCurrentUser;
const soClient = coreStart.savedObjects.getScopedClient(request);
return new EntityClient({ esClient, soClient, logger: this.logger });
},
},
core,
logger: this.logger,
});
return {};

View file

@ -0,0 +1,12 @@
/*
* 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 { createServerRouteFactory } from '@kbn/server-route-repository';
import { EntityManagerRouteHandlerResources } from './types';
export const createEntityManagerServerRoute =
createServerRouteFactory<EntityManagerRouteHandlerResources>();

View file

@ -6,9 +6,6 @@
*/
import semver from 'semver';
import { RequestHandlerContext } from '@kbn/core/server';
import { SetupRouteOptions } from '../types';
import { checkIfEntityDiscoveryAPIKeyIsValid, readEntityDiscoveryAPIKey } from '../../lib/auth';
import {
ERROR_API_KEY_NOT_FOUND,
ERROR_API_KEY_NOT_VALID,
@ -16,9 +13,11 @@ import {
ERROR_DEFINITION_STOPPED,
ERROR_PARTIAL_BUILTIN_INSTALLATION,
} from '../../../common/errors';
import { findEntityDefinitions } from '../../lib/entities/find_entity_definition';
import { checkIfEntityDiscoveryAPIKeyIsValid, readEntityDiscoveryAPIKey } from '../../lib/auth';
import { builtInDefinitions } from '../../lib/entities/built_in';
import { findEntityDefinitions } from '../../lib/entities/find_entity_definition';
import { getClientsFromAPIKey } from '../../lib/utils';
import { createEntityManagerServerRoute } from '../create_entity_manager_server_route';
/**
* @openapi
@ -34,6 +33,7 @@ import { getClientsFromAPIKey } from '../../lib/utils';
* application/json:
* schema:
* type: object
* required: enabled
* properties:
* enabled:
* type: boolean
@ -42,77 +42,70 @@ import { getClientsFromAPIKey } from '../../lib/utils';
* type: string
* example: api_key_not_found
*/
export function checkEntityDiscoveryEnabledRoute<T extends RequestHandlerContext>({
router,
server,
logger,
}: SetupRouteOptions<T>) {
router.get<unknown, unknown, unknown>(
{
path: '/internal/entities/managed/enablement',
validate: false,
},
async (context, req, res) => {
try {
logger.debug('reading entity discovery API key from saved object');
const apiKey = await readEntityDiscoveryAPIKey(server);
export const checkEntityDiscoveryEnabledRoute = createEntityManagerServerRoute({
endpoint: 'GET /internal/entities/managed/enablement',
handler: async ({ response, logger, server }) => {
try {
logger.debug('reading entity discovery API key from saved object');
const apiKey = await readEntityDiscoveryAPIKey(server);
if (apiKey === undefined) {
return res.ok({ body: { enabled: false, reason: ERROR_API_KEY_NOT_FOUND } });
}
logger.debug('validating existing entity discovery API key');
const isValid = await checkIfEntityDiscoveryAPIKeyIsValid(server, apiKey);
if (!isValid) {
return res.ok({ body: { enabled: false, reason: ERROR_API_KEY_NOT_VALID } });
}
const { esClient, soClient } = getClientsFromAPIKey({ apiKey, server });
const entityDiscoveryState = await Promise.all(
builtInDefinitions.map(async (builtInDefinition) => {
const definitions = await findEntityDefinitions({
esClient,
soClient,
id: builtInDefinition.id,
});
return { installedDefinition: definitions[0], builtInDefinition };
})
).then((results) =>
results.reduce(
(state, { installedDefinition, builtInDefinition }) => {
return {
installed: Boolean(state.installed && installedDefinition?.state.installed),
running: Boolean(state.running && installedDefinition?.state.running),
outdated:
state.outdated ||
(installedDefinition &&
semver.neq(installedDefinition.version, builtInDefinition.version)),
};
},
{ installed: true, running: true, outdated: false }
)
);
if (!entityDiscoveryState.installed) {
return res.ok({ body: { enabled: false, reason: ERROR_PARTIAL_BUILTIN_INSTALLATION } });
}
if (!entityDiscoveryState.running) {
return res.ok({ body: { enabled: false, reason: ERROR_DEFINITION_STOPPED } });
}
if (entityDiscoveryState.outdated) {
return res.ok({ body: { enabled: false, reason: ERROR_BUILTIN_UPGRADE_REQUIRED } });
}
return res.ok({ body: { enabled: true } });
} catch (err) {
logger.error(err);
return res.customError({ statusCode: 500, body: err });
if (apiKey === undefined) {
return response.ok({ body: { enabled: false, reason: ERROR_API_KEY_NOT_FOUND } });
}
logger.debug('validating existing entity discovery API key');
const isValid = await checkIfEntityDiscoveryAPIKeyIsValid(server, apiKey);
if (!isValid) {
return response.ok({ body: { enabled: false, reason: ERROR_API_KEY_NOT_VALID } });
}
const { esClient, soClient } = getClientsFromAPIKey({ apiKey, server });
const entityDiscoveryState = await Promise.all(
builtInDefinitions.map(async (builtInDefinition) => {
const definitions = await findEntityDefinitions({
esClient,
soClient,
id: builtInDefinition.id,
});
return { installedDefinition: definitions[0], builtInDefinition };
})
).then((results) =>
results.reduce(
(state, { installedDefinition, builtInDefinition }) => {
return {
installed: Boolean(state.installed && installedDefinition?.state.installed),
running: Boolean(state.running && installedDefinition?.state.running),
outdated:
state.outdated ||
(installedDefinition &&
semver.neq(installedDefinition.version, builtInDefinition.version)),
};
},
{ installed: true, running: true, outdated: false }
)
);
if (!entityDiscoveryState.installed) {
return response.ok({
body: { enabled: false, reason: ERROR_PARTIAL_BUILTIN_INSTALLATION },
});
}
if (!entityDiscoveryState.running) {
return response.ok({ body: { enabled: false, reason: ERROR_DEFINITION_STOPPED } });
}
if (entityDiscoveryState.outdated) {
return response.ok({ body: { enabled: false, reason: ERROR_BUILTIN_UPGRADE_REQUIRED } });
}
return response.ok({ body: { enabled: true } });
} catch (err) {
logger.error(err);
return response.customError({ statusCode: 500, body: err });
}
);
}
},
});

View file

@ -5,13 +5,13 @@
* 2.0.
*/
import { RequestHandlerContext } from '@kbn/core/server';
import { schema } from '@kbn/config-schema';
import { SetupRouteOptions } from '../types';
import { z } from '@kbn/zod';
import { BooleanFromString } from '@kbn/zod-helpers';
import { deleteEntityDiscoveryAPIKey, readEntityDiscoveryAPIKey } from '../../lib/auth';
import { uninstallBuiltInEntityDefinitions } from '../../lib/entities/uninstall_entity_definition';
import { canDisableEntityDiscovery } from '../../lib/auth/privileges';
import { uninstallBuiltInEntityDefinitions } from '../../lib/entities/uninstall_entity_definition';
import { EntityDiscoveryApiKeyType } from '../../saved_objects';
import { createEntityManagerServerRoute } from '../create_entity_manager_server_route';
/**
* @openapi
@ -29,72 +29,65 @@ import { EntityDiscoveryApiKeyType } from '../../saved_objects';
* type: boolean
* default: false
* responses:
* 403:
* description: The current user does not have the required permissions to disable entity discovery
* 200:
* description: Built-in entity discovery successfully disabled
* content:
* application/json:
* schema:
* type: object
* required: success
* properties:
* success:
* type: boolean
* 403:
* description: The current user does not have the required permissions to disable entity discovery
*/
export function disableEntityDiscoveryRoute<T extends RequestHandlerContext>({
router,
server,
logger,
}: SetupRouteOptions<T>) {
router.delete<unknown, { deleteData?: boolean }, unknown>(
{
path: '/internal/entities/managed/enablement',
validate: {
query: schema.object({
deleteData: schema.maybe(schema.boolean({ defaultValue: false })),
}),
},
},
async (context, req, res) => {
try {
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const canDisable = await canDisableEntityDiscovery(esClient);
if (!canDisable) {
return res.forbidden({
body: {
message:
'Current Kibana user does not have the required permissions to disable entity discovery',
},
});
}
const soClient = (await context.core).savedObjects.getClient({
includedHiddenTypes: [EntityDiscoveryApiKeyType.name],
export const disableEntityDiscoveryRoute = createEntityManagerServerRoute({
endpoint: 'DELETE /internal/entities/managed/enablement',
params: z.object({
query: z.object({
deleteData: z.optional(BooleanFromString).default(false),
}),
}),
handler: async ({ context, response, params, logger, server }) => {
try {
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const canDisable = await canDisableEntityDiscovery(esClient);
if (!canDisable) {
return response.forbidden({
body: {
message:
'Current Kibana user does not have the required permissions to disable entity discovery',
},
});
await uninstallBuiltInEntityDefinitions({
soClient,
esClient,
logger,
deleteData: req.query.deleteData,
});
server.logger.debug('reading entity discovery API key from saved object');
const apiKey = await readEntityDiscoveryAPIKey(server);
// api key could be deleted outside of the apis, it does not affect the
// disablement flow
if (apiKey) {
await deleteEntityDiscoveryAPIKey(soClient);
await server.security.authc.apiKeys.invalidateAsInternalUser({
ids: [apiKey.id],
});
}
return res.ok({ body: { success: true } });
} catch (err) {
logger.error(err);
return res.customError({ statusCode: 500, body: err });
}
const soClient = (await context.core).savedObjects.getClient({
includedHiddenTypes: [EntityDiscoveryApiKeyType.name],
});
await uninstallBuiltInEntityDefinitions({
soClient,
esClient,
logger,
deleteData: params.query.deleteData,
});
server.logger.debug('reading entity discovery API key from saved object');
const apiKey = await readEntityDiscoveryAPIKey(server);
// api key could be deleted outside of the apis, it does not affect the
// disablement flow
if (apiKey) {
await deleteEntityDiscoveryAPIKey(soClient);
await server.security.authc.apiKeys.invalidateAsInternalUser({
ids: [apiKey.id],
});
}
return response.ok({ body: { success: true } });
} catch (err) {
logger.error(err);
return response.customError({ statusCode: 500, body: err });
}
);
}
},
});

View file

@ -5,12 +5,9 @@
* 2.0.
*/
import { RequestHandlerContext } from '@kbn/core/server';
import {
CreateEntityDefinitionQuery,
createEntityDefinitionQuerySchema,
} from '@kbn/entities-schema';
import { SetupRouteOptions } from '../types';
import { createEntityDefinitionQuerySchema } from '@kbn/entities-schema';
import { z } from '@kbn/zod';
import { ERROR_API_KEY_SERVICE_DISABLED } from '../../../common/errors';
import {
canEnableEntityDiscovery,
checkIfAPIKeysAreEnabled,
@ -22,9 +19,9 @@ import {
} from '../../lib/auth';
import { builtInDefinitions } from '../../lib/entities/built_in';
import { installBuiltInEntityDefinitions } from '../../lib/entities/install_entity_definition';
import { ERROR_API_KEY_SERVICE_DISABLED } from '../../../common/errors';
import { EntityDiscoveryApiKeyType } from '../../saved_objects';
import { startTransform } from '../../lib/entities/start_transform';
import { EntityDiscoveryApiKeyType } from '../../saved_objects';
import { createEntityManagerServerRoute } from '../create_entity_manager_server_route';
/**
* @openapi
@ -42,14 +39,13 @@ import { startTransform } from '../../lib/entities/start_transform';
* type: boolean
* default: false
* responses:
* 403:
* description: The current user does not have the required permissions to enable entity discovery
* 200:
* description: OK - Verify result in response body
* content:
* application/json:
* schema:
* type: object
* required: success
* properties:
* success:
* type: boolean
@ -60,90 +56,84 @@ import { startTransform } from '../../lib/entities/start_transform';
* message:
* type: string
* example: API key service is not enabled; try configuring `xpack.security.authc.api_key.enabled` in your elasticsearch config
* 403:
* description: The current user does not have the required permissions to enable entity discovery
*/
export function enableEntityDiscoveryRoute<T extends RequestHandlerContext>({
router,
server,
logger,
}: SetupRouteOptions<T>) {
router.put<unknown, CreateEntityDefinitionQuery, unknown>(
{
path: '/internal/entities/managed/enablement',
validate: {
query: createEntityDefinitionQuerySchema,
},
},
async (context, req, res) => {
try {
const apiKeysEnabled = await checkIfAPIKeysAreEnabled(server);
if (!apiKeysEnabled) {
return res.ok({
body: {
success: false,
reason: ERROR_API_KEY_SERVICE_DISABLED,
message:
'API key service is not enabled; try configuring `xpack.security.authc.api_key.enabled` in your elasticsearch config',
},
});
}
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const canEnable = await canEnableEntityDiscovery(esClient);
if (!canEnable) {
return res.forbidden({
body: {
message:
'Current Kibana user does not have the required permissions to enable entity discovery',
},
});
}
const soClient = (await context.core).savedObjects.getClient({
includedHiddenTypes: [EntityDiscoveryApiKeyType.name],
export const enableEntityDiscoveryRoute = createEntityManagerServerRoute({
endpoint: 'PUT /internal/entities/managed/enablement',
params: z.object({
query: createEntityDefinitionQuerySchema,
}),
handler: async ({ context, request, response, params, server, logger }) => {
try {
const apiKeysEnabled = await checkIfAPIKeysAreEnabled(server);
if (!apiKeysEnabled) {
return response.ok({
body: {
success: false,
reason: ERROR_API_KEY_SERVICE_DISABLED,
message:
'API key service is not enabled; try configuring `xpack.security.authc.api_key.enabled` in your elasticsearch config',
},
});
const existingApiKey = await readEntityDiscoveryAPIKey(server);
if (existingApiKey !== undefined) {
const isValid = await checkIfEntityDiscoveryAPIKeyIsValid(server, existingApiKey);
if (!isValid) {
await deleteEntityDiscoveryAPIKey(soClient);
await server.security.authc.apiKeys.invalidateAsInternalUser({
ids: [existingApiKey.id],
});
}
}
const apiKey = await generateEntityDiscoveryAPIKey(server, req);
if (apiKey === undefined) {
return res.customError({
statusCode: 500,
body: new Error('could not generate entity discovery API key'),
});
}
await saveEntityDiscoveryAPIKey(soClient, apiKey);
const installedDefinitions = await installBuiltInEntityDefinitions({
esClient,
soClient,
logger,
definitions: builtInDefinitions,
});
if (!req.query.installOnly) {
await Promise.all(
installedDefinitions.map((installedDefinition) =>
startTransform(esClient, installedDefinition, logger)
)
);
}
return res.ok({ body: { success: true } });
} catch (err) {
logger.error(err);
return res.customError({ statusCode: 500, body: err });
}
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const canEnable = await canEnableEntityDiscovery(esClient);
if (!canEnable) {
return response.forbidden({
body: {
message:
'Current Kibana user does not have the required permissions to enable entity discovery',
},
});
}
const soClient = (await context.core).savedObjects.getClient({
includedHiddenTypes: [EntityDiscoveryApiKeyType.name],
});
const existingApiKey = await readEntityDiscoveryAPIKey(server);
if (existingApiKey !== undefined) {
const isValid = await checkIfEntityDiscoveryAPIKeyIsValid(server, existingApiKey);
if (!isValid) {
await deleteEntityDiscoveryAPIKey(soClient);
await server.security.authc.apiKeys.invalidateAsInternalUser({
ids: [existingApiKey.id],
});
}
}
const apiKey = await generateEntityDiscoveryAPIKey(server, request);
if (apiKey === undefined) {
return response.customError({
statusCode: 500,
body: new Error('could not generate entity discovery API key'),
});
}
await saveEntityDiscoveryAPIKey(soClient, apiKey);
const installedDefinitions = await installBuiltInEntityDefinitions({
esClient,
soClient,
logger,
definitions: builtInDefinitions,
});
if (!params.query.installOnly) {
await Promise.all(
installedDefinitions.map((installedDefinition) =>
startTransform(esClient, installedDefinition, logger)
)
);
}
return response.ok({ body: { success: true } });
} catch (err) {
logger.error(err);
return response.customError({ statusCode: 500, body: err });
}
);
}
},
});

View file

@ -0,0 +1,16 @@
/*
* 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 { checkEntityDiscoveryEnabledRoute } from './check';
import { enableEntityDiscoveryRoute } from './enable';
import { disableEntityDiscoveryRoute } from './disable';
export const enablementRoutes = {
...checkEntityDiscoveryEnabledRoute,
...enableEntityDiscoveryRoute,
...disableEntityDiscoveryRoute,
};

View file

@ -5,18 +5,13 @@
* 2.0.
*/
import { RequestHandlerContext } from '@kbn/core/server';
import {
EntityDefinition,
entityDefinitionSchema,
createEntityDefinitionQuerySchema,
CreateEntityDefinitionQuery,
} from '@kbn/entities-schema';
import { SetupRouteOptions } from '../types';
import { createEntityDefinitionQuerySchema, entityDefinitionSchema } from '@kbn/entities-schema';
import { z } from '@kbn/zod';
import { EntityDefinitionIdInvalid } from '../../lib/entities/errors/entity_definition_id_invalid';
import { EntityIdConflict } from '../../lib/entities/errors/entity_id_conflict_error';
import { EntitySecurityException } from '../../lib/entities/errors/entity_security_exception';
import { InvalidTransformError } from '../../lib/entities/errors/invalid_transform_error';
import { EntityDefinitionIdInvalid } from '../../lib/entities/errors/entity_definition_id_invalid';
import { createEntityManagerServerRoute } from '../create_entity_manager_server_route';
/**
* @openapi
@ -50,47 +45,39 @@ import { EntityDefinitionIdInvalid } from '../../lib/entities/errors/entity_defi
* 409:
* description: An entity definition with this ID already exists
* 400:
* description: The entity definition cannot be installed; see the error for more details
* description: The entity definition cannot be installed; see the error for more details but commonly due to validation failures of the definition ID or metrics format
*/
export function createEntityDefinitionRoute<T extends RequestHandlerContext>({
router,
getScopedClient,
logger,
}: SetupRouteOptions<T>) {
router.post<unknown, CreateEntityDefinitionQuery, EntityDefinition>(
{
path: '/internal/entities/definition',
validate: {
body: entityDefinitionSchema.strict(),
query: createEntityDefinitionQuerySchema,
},
},
async (context, request, res) => {
try {
const client = await getScopedClient({ request });
const definition = await client.createEntityDefinition({
definition: request.body,
installOnly: request.query.installOnly,
});
export const createEntityDefinitionRoute = createEntityManagerServerRoute({
endpoint: 'POST /internal/entities/definition',
params: z.object({
query: createEntityDefinitionQuerySchema,
body: entityDefinitionSchema,
}),
handler: async ({ request, response, params, logger, getScopedClient }) => {
try {
const client = await getScopedClient({ request });
const definition = await client.createEntityDefinition({
definition: params.body,
installOnly: params.query.installOnly,
});
return res.ok({ body: definition });
} catch (e) {
logger.error(e);
return response.ok({ body: definition });
} catch (e) {
logger.error(e);
if (e instanceof EntityDefinitionIdInvalid) {
return res.badRequest({ body: e });
}
if (e instanceof EntityIdConflict) {
return res.conflict({ body: e });
}
if (e instanceof EntitySecurityException || e instanceof InvalidTransformError) {
return res.customError({ body: e, statusCode: 400 });
}
return res.customError({ body: e, statusCode: 500 });
if (e instanceof EntityDefinitionIdInvalid) {
return response.badRequest({ body: e });
}
if (e instanceof EntityIdConflict) {
return response.conflict({ body: e });
}
if (e instanceof EntitySecurityException || e instanceof InvalidTransformError) {
return response.customError({ body: e, statusCode: 400 });
}
return response.customError({ body: e, statusCode: 500 });
}
);
}
},
});

View file

@ -5,15 +5,15 @@
* 2.0.
*/
import { RequestHandlerContext } from '@kbn/core/server';
import {
deleteEntityDefinitionParamsSchema,
deleteEntityDefinitionQuerySchema,
} from '@kbn/entities-schema';
import { SetupRouteOptions } from '../types';
import { z } from '@kbn/zod';
import { EntityDefinitionNotFound } from '../../lib/entities/errors/entity_not_found';
import { EntitySecurityException } from '../../lib/entities/errors/entity_security_exception';
import { InvalidTransformError } from '../../lib/entities/errors/invalid_transform_error';
import { EntityDefinitionNotFound } from '../../lib/entities/errors/entity_not_found';
import { createEntityManagerServerRoute } from '../create_entity_manager_server_route';
/**
* @openapi
@ -49,39 +49,31 @@ import { EntityDefinitionNotFound } from '../../lib/entities/errors/entity_not_f
* 404:
* description: Entity definition with given ID not found
*/
export function deleteEntityDefinitionRoute<T extends RequestHandlerContext>({
router,
getScopedClient,
logger,
}: SetupRouteOptions<T>) {
router.delete<{ id: string }, { deleteData?: boolean }, unknown>(
{
path: '/internal/entities/definition/{id}',
validate: {
params: deleteEntityDefinitionParamsSchema.strict(),
query: deleteEntityDefinitionQuerySchema.strict(),
},
},
async (context, request, res) => {
try {
const client = await getScopedClient({ request });
await client.deleteEntityDefinition({
id: request.params.id,
deleteData: request.query.deleteData,
});
export const deleteEntityDefinitionRoute = createEntityManagerServerRoute({
endpoint: 'DELETE /internal/entities/definition/{id}',
params: z.object({
path: deleteEntityDefinitionParamsSchema,
query: deleteEntityDefinitionQuerySchema,
}),
handler: async ({ request, response, params, logger, getScopedClient }) => {
try {
const client = await getScopedClient({ request });
await client.deleteEntityDefinition({
id: params.path.id,
deleteData: params.query.deleteData,
});
return res.ok({ body: { acknowledged: true } });
} catch (e) {
logger.error(e);
return response.ok({ body: { acknowledged: true } });
} catch (e) {
logger.error(e);
if (e instanceof EntityDefinitionNotFound) {
return res.notFound({ body: e });
}
if (e instanceof EntitySecurityException || e instanceof InvalidTransformError) {
return res.customError({ body: e, statusCode: 400 });
}
return res.customError({ body: e, statusCode: 500 });
if (e instanceof EntityDefinitionNotFound) {
return response.notFound({ body: e });
}
if (e instanceof EntitySecurityException || e instanceof InvalidTransformError) {
return response.customError({ body: e, statusCode: 400 });
}
return response.customError({ body: e, statusCode: 500 });
}
);
}
},
});

View file

@ -5,10 +5,9 @@
* 2.0.
*/
import { z } from '@kbn/zod';
import { RequestHandlerContext } from '@kbn/core/server';
import { getEntityDefinitionQuerySchema } from '@kbn/entities-schema';
import { SetupRouteOptions } from '../types';
import { z } from '@kbn/zod';
import { createEntityManagerServerRoute } from '../create_entity_manager_server_route';
/**
* @openapi
@ -49,32 +48,23 @@ import { SetupRouteOptions } from '../types';
* running:
* type: boolean
*/
export function getEntityDefinitionRoute<T extends RequestHandlerContext>({
router,
getScopedClient,
logger,
}: SetupRouteOptions<T>) {
router.get<{ id?: string }, { page?: number; perPage?: number }, unknown>(
{
path: '/internal/entities/definition/{id?}',
validate: {
query: getEntityDefinitionQuerySchema.strict(),
params: z.object({ id: z.optional(z.string()) }),
},
},
async (context, request, res) => {
try {
const client = await getScopedClient({ request });
const result = await client.getEntityDefinitions({
page: request.query.page,
perPage: request.query.perPage,
});
export const getEntityDefinitionRoute = createEntityManagerServerRoute({
endpoint: 'GET /internal/entities/definition',
params: z.object({
query: getEntityDefinitionQuerySchema,
}),
handler: async ({ request, response, params, logger, getScopedClient }) => {
try {
const client = await getScopedClient({ request });
const result = await client.getEntityDefinitions({
page: params?.query?.page,
perPage: params?.query?.perPage,
});
return res.ok({ body: result });
} catch (e) {
logger.error(e);
return res.customError({ body: e, statusCode: 500 });
}
return response.ok({ body: result });
} catch (e) {
logger.error(e);
return response.customError({ body: e, statusCode: 500 });
}
);
}
},
});

View file

@ -0,0 +1,20 @@
/*
* 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 { createEntityDefinitionRoute } from './create';
import { deleteEntityDefinitionRoute } from './delete';
import { getEntityDefinitionRoute } from './get';
import { resetEntityDefinitionRoute } from './reset';
import { updateEntityDefinitionRoute } from './update';
export const entitiesRoutes = {
...createEntityDefinitionRoute,
...deleteEntityDefinitionRoute,
...getEntityDefinitionRoute,
...resetEntityDefinitionRoute,
...updateEntityDefinitionRoute,
};

View file

@ -5,22 +5,8 @@
* 2.0.
*/
import { RequestHandlerContext } from '@kbn/core/server';
import { resetEntityDefinitionParamsSchema } from '@kbn/entities-schema';
import { SetupRouteOptions } from '../types';
import { EntitySecurityException } from '../../lib/entities/errors/entity_security_exception';
import { InvalidTransformError } from '../../lib/entities/errors/invalid_transform_error';
import { readEntityDefinition } from '../../lib/entities/read_entity_definition';
import {
stopAndDeleteHistoryBackfillTransform,
stopAndDeleteHistoryTransform,
stopAndDeleteLatestTransform,
} from '../../lib/entities/stop_and_delete_transform';
import {
deleteHistoryIngestPipeline,
deleteLatestIngestPipeline,
} from '../../lib/entities/delete_ingest_pipeline';
import { deleteIndices } from '../../lib/entities/delete_index';
import { z } from '@kbn/zod';
import {
createAndInstallHistoryIngestPipeline,
createAndInstallLatestIngestPipeline,
@ -30,60 +16,67 @@ import {
createAndInstallHistoryTransform,
createAndInstallLatestTransform,
} from '../../lib/entities/create_and_install_transform';
import { startTransform } from '../../lib/entities/start_transform';
import { deleteIndices } from '../../lib/entities/delete_index';
import {
deleteHistoryIngestPipeline,
deleteLatestIngestPipeline,
} from '../../lib/entities/delete_ingest_pipeline';
import { EntityDefinitionNotFound } from '../../lib/entities/errors/entity_not_found';
import { EntitySecurityException } from '../../lib/entities/errors/entity_security_exception';
import { InvalidTransformError } from '../../lib/entities/errors/invalid_transform_error';
import { isBackfillEnabled } from '../../lib/entities/helpers/is_backfill_enabled';
import { readEntityDefinition } from '../../lib/entities/read_entity_definition';
import { startTransform } from '../../lib/entities/start_transform';
import {
stopAndDeleteHistoryBackfillTransform,
stopAndDeleteHistoryTransform,
stopAndDeleteLatestTransform,
} from '../../lib/entities/stop_and_delete_transform';
import { createEntityManagerServerRoute } from '../create_entity_manager_server_route';
export function resetEntityDefinitionRoute<T extends RequestHandlerContext>({
router,
logger,
}: SetupRouteOptions<T>) {
router.post<{ id: string }, unknown, unknown>(
{
path: '/internal/entities/definition/{id}/_reset',
validate: {
params: resetEntityDefinitionParamsSchema.strict(),
},
},
async (context, req, res) => {
try {
const soClient = (await context.core).savedObjects.client;
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
export const resetEntityDefinitionRoute = createEntityManagerServerRoute({
endpoint: 'POST /internal/entities/definition/{id}/_reset',
params: z.object({
path: resetEntityDefinitionParamsSchema,
}),
handler: async ({ context, response, params, logger }) => {
try {
const soClient = (await context.core).savedObjects.client;
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const definition = await readEntityDefinition(soClient, req.params.id, logger);
const definition = await readEntityDefinition(soClient, params.path.id, logger);
// Delete the transform and ingest pipeline
await stopAndDeleteHistoryTransform(esClient, definition, logger);
if (isBackfillEnabled(definition)) {
await stopAndDeleteHistoryBackfillTransform(esClient, definition, logger);
}
await stopAndDeleteLatestTransform(esClient, definition, logger);
await deleteHistoryIngestPipeline(esClient, definition, logger);
await deleteLatestIngestPipeline(esClient, definition, logger);
await deleteIndices(esClient, definition, logger);
// Recreate everything
await createAndInstallHistoryIngestPipeline(esClient, definition, logger);
await createAndInstallLatestIngestPipeline(esClient, definition, logger);
await createAndInstallHistoryTransform(esClient, definition, logger);
if (isBackfillEnabled(definition)) {
await createAndInstallHistoryBackfillTransform(esClient, definition, logger);
}
await createAndInstallLatestTransform(esClient, definition, logger);
await startTransform(esClient, definition, logger);
return res.ok({ body: { acknowledged: true } });
} catch (e) {
logger.error(e);
if (e instanceof EntityDefinitionNotFound) {
return res.notFound({ body: e });
}
if (e instanceof EntitySecurityException || e instanceof InvalidTransformError) {
return res.customError({ body: e, statusCode: 400 });
}
return res.customError({ body: e, statusCode: 500 });
// Delete the transform and ingest pipeline
await stopAndDeleteHistoryTransform(esClient, definition, logger);
if (isBackfillEnabled(definition)) {
await stopAndDeleteHistoryBackfillTransform(esClient, definition, logger);
}
await stopAndDeleteLatestTransform(esClient, definition, logger);
await deleteHistoryIngestPipeline(esClient, definition, logger);
await deleteLatestIngestPipeline(esClient, definition, logger);
await deleteIndices(esClient, definition, logger);
// Recreate everything
await createAndInstallHistoryIngestPipeline(esClient, definition, logger);
await createAndInstallLatestIngestPipeline(esClient, definition, logger);
await createAndInstallHistoryTransform(esClient, definition, logger);
if (isBackfillEnabled(definition)) {
await createAndInstallHistoryBackfillTransform(esClient, definition, logger);
}
await createAndInstallLatestTransform(esClient, definition, logger);
await startTransform(esClient, definition, logger);
return response.ok({ body: { acknowledged: true } });
} catch (e) {
logger.error(e);
if (e instanceof EntityDefinitionNotFound) {
return response.notFound({ body: e });
}
if (e instanceof EntitySecurityException || e instanceof InvalidTransformError) {
return response.customError({ body: e, statusCode: 400 });
}
return response.customError({ body: e, statusCode: 500 });
}
);
}
},
});

View file

@ -5,28 +5,25 @@
* 2.0.
*/
import { z } from '@kbn/zod';
import { RequestHandlerContext } from '@kbn/core/server';
import {
createEntityDefinitionQuerySchema,
CreateEntityDefinitionQuery,
entityDefinitionUpdateSchema,
EntityDefinitionUpdate,
} from '@kbn/entities-schema';
import { SetupRouteOptions } from '../types';
import { z } from '@kbn/zod';
import { EntitySecurityException } from '../../lib/entities/errors/entity_security_exception';
import { InvalidTransformError } from '../../lib/entities/errors/invalid_transform_error';
import { startTransform } from '../../lib/entities/start_transform';
import { findEntityDefinitionById } from '../../lib/entities/find_entity_definition';
import {
installationInProgress,
reinstallEntityDefinition,
} from '../../lib/entities/install_entity_definition';
import { findEntityDefinitionById } from '../../lib/entities/find_entity_definition';
import { startTransform } from '../../lib/entities/start_transform';
import { createEntityManagerServerRoute } from '../create_entity_manager_server_route';
/**
* @openapi
* /internal/entities/definition:
* put:
* patch:
* description: Update an entity definition.
* tags:
* - definitions
@ -61,71 +58,63 @@ import { findEntityDefinitionById } from '../../lib/entities/find_entity_definit
* 409:
* description: The entity definition is being updated by another request
*/
export function updateEntityDefinitionRoute<T extends RequestHandlerContext>({
router,
server,
}: SetupRouteOptions<T>) {
router.patch<{ id: string }, CreateEntityDefinitionQuery, EntityDefinitionUpdate>(
{
path: '/internal/entities/definition/{id}',
validate: {
body: entityDefinitionUpdateSchema.strict(),
query: createEntityDefinitionQuerySchema,
params: z.object({ id: z.string() }),
},
},
async (context, req, res) => {
const { logger } = server;
const core = await context.core;
const soClient = core.savedObjects.client;
const esClient = core.elasticsearch.client.asCurrentUser;
export const updateEntityDefinitionRoute = createEntityManagerServerRoute({
endpoint: 'PATCH /internal/entities/definition/{id}',
params: z.object({
path: z.object({ id: z.string() }),
query: createEntityDefinitionQuerySchema,
body: entityDefinitionUpdateSchema,
}),
handler: async ({ context, response, params, logger }) => {
const core = await context.core;
const soClient = core.savedObjects.client;
const esClient = core.elasticsearch.client.asCurrentUser;
try {
const installedDefinition = await findEntityDefinitionById({
soClient,
esClient,
id: req.params.id,
try {
const installedDefinition = await findEntityDefinitionById({
soClient,
esClient,
id: params.path.id,
});
if (!installedDefinition) {
return response.notFound({
body: { message: `Entity definition [${params.path.id}] not found` },
});
if (!installedDefinition) {
return res.notFound({
body: { message: `Entity definition [${req.params.id}] not found` },
});
}
if (installedDefinition.managed) {
return res.forbidden({
body: { message: `Managed definition cannot be modified` },
});
}
if (installationInProgress(installedDefinition)) {
return res.conflict({
body: { message: `Entity definition [${req.params.id}] has changes in progress` },
});
}
const updatedDefinition = await reinstallEntityDefinition({
soClient,
esClient,
logger,
definition: installedDefinition,
definitionUpdate: req.body,
});
if (!req.query.installOnly) {
await startTransform(esClient, updatedDefinition, logger);
}
return res.ok({ body: updatedDefinition });
} catch (e) {
logger.error(e);
if (e instanceof EntitySecurityException || e instanceof InvalidTransformError) {
return res.customError({ body: e, statusCode: 400 });
}
return res.customError({ body: e, statusCode: 500 });
}
if (installedDefinition.managed) {
return response.forbidden({
body: { message: `Managed definition cannot be modified` },
});
}
if (installationInProgress(installedDefinition)) {
return response.conflict({
body: { message: `Entity definition [${params.path.id}] has changes in progress` },
});
}
const updatedDefinition = await reinstallEntityDefinition({
soClient,
esClient,
logger,
definition: installedDefinition,
definitionUpdate: params.body,
});
if (!params.query.installOnly) {
await startTransform(esClient, updatedDefinition, logger);
}
return response.ok({ body: updatedDefinition });
} catch (e) {
logger.error(e);
if (e instanceof EntitySecurityException || e instanceof InvalidTransformError) {
return response.customError({ body: e, statusCode: 400 });
}
return response.customError({ body: e, statusCode: 500 });
}
);
}
},
});

View file

@ -5,24 +5,12 @@
* 2.0.
*/
import { RequestHandlerContext } from '@kbn/core/server';
import { SetupRouteOptions } from './types';
import { createEntityDefinitionRoute } from './entities/create';
import { deleteEntityDefinitionRoute } from './entities/delete';
import { resetEntityDefinitionRoute } from './entities/reset';
import { getEntityDefinitionRoute } from './entities/get';
import { updateEntityDefinitionRoute } from './entities/update';
import { checkEntityDiscoveryEnabledRoute } from './enablement/check';
import { enableEntityDiscoveryRoute } from './enablement/enable';
import { disableEntityDiscoveryRoute } from './enablement/disable';
import { enablementRoutes } from './enablement';
import { entitiesRoutes } from './entities';
export function setupRoutes<T extends RequestHandlerContext>(dependencies: SetupRouteOptions<T>) {
createEntityDefinitionRoute<T>(dependencies);
deleteEntityDefinitionRoute<T>(dependencies);
resetEntityDefinitionRoute<T>(dependencies);
getEntityDefinitionRoute<T>(dependencies);
checkEntityDiscoveryEnabledRoute<T>(dependencies);
enableEntityDiscoveryRoute<T>(dependencies);
disableEntityDiscoveryRoute<T>(dependencies);
updateEntityDefinitionRoute<T>(dependencies);
}
export const entityManagerRouteRepository = {
...enablementRoutes,
...entitiesRoutes,
};
export type EntityManagerRouteRepository = typeof entityManagerRouteRepository;

View file

@ -5,14 +5,15 @@
* 2.0.
*/
import { IRouter, KibanaRequest, RequestHandlerContextBase } from '@kbn/core-http-server';
import { Logger } from '@kbn/core/server';
import { EntityManagerServerSetup } from '../types';
import { KibanaRequest } from '@kbn/core-http-server';
import { DefaultRouteHandlerResources } from '@kbn/server-route-repository';
import { EntityClient } from '../lib/entity_client';
import { EntityManagerServerSetup } from '../types';
export interface SetupRouteOptions<T extends RequestHandlerContextBase> {
router: IRouter<T>;
export interface EntityManagerRouteDependencies {
server: EntityManagerServerSetup;
logger: Logger;
getScopedClient: ({ request }: { request: KibanaRequest }) => Promise<EntityClient>;
}
export type EntityManagerRouteHandlerResources = EntityManagerRouteDependencies &
DefaultRouteHandlerResources;

View file

@ -28,6 +28,9 @@
"@kbn/encrypted-saved-objects-plugin",
"@kbn/logging-mocks",
"@kbn/licensing-plugin",
"@kbn/server-route-repository-client",
"@kbn/server-route-repository",
"@kbn/zod",
"@kbn/zod-helpers",
]
}