[8.16] Backport: [eem] rename fields to snake case #195895 (#198501)

Backporting https://github.com/elastic/kibana/pull/195895 into 8.16.

---------

Co-authored-by: Kevin Lacabane <kevin.lacabane@elastic.co>
This commit is contained in:
Tiago Vila Verde 2024-10-31 22:22:48 +01:00 committed by GitHub
parent 0e3ac4798e
commit 931579bab9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
44 changed files with 559 additions and 391 deletions

View file

@ -59,7 +59,7 @@ export const entityDefinitionRuntimePrivileges = {
index: [
{
names: [ENTITY_INTERNAL_INDICES_PATTERN],
privileges: ['create_index', 'index', 'create_doc', 'auto_configure', 'read'],
privileges: ['create_index', 'delete_index', 'index', 'create_doc', 'auto_configure', 'read'],
},
{
names: [...BUILT_IN_ALLOWED_INDICES, ENTITY_INTERNAL_INDICES_PATTERN],

View file

@ -29,7 +29,7 @@ export const builtInServicesFromEcsEntityDefinition: EntityDefinition =
identityFields: ['service.name'],
displayNameTemplate: '{{service.name}}',
metadata: [
{ source: '_index', destination: 'sourceIndex' },
{ source: '_index', destination: 'source_index' },
{
source: 'data_stream.type',
destination: 'source_data_stream.type',
@ -38,7 +38,7 @@ export const builtInServicesFromEcsEntityDefinition: EntityDefinition =
source: 'data_stream.dataset',
destination: 'source_data_stream.dataset',
},
{ source: 'agent.name', aggregation: { type: 'terms', limit: 100 } },
'agent.name',
'service.environment',
'service.name',
'service.namespace',

View file

@ -25,7 +25,7 @@ export async function createAndInstallIngestPipelines(
id: latestId,
processors: latestProcessors,
_meta: {
definitionVersion: definition.version,
definition_version: definition.version,
managed: definition.managed,
},
}),

View file

@ -14,11 +14,13 @@ export async function deleteIndices(
definition: EntityDefinition,
logger: Logger
) {
const index = generateLatestIndexName(definition);
try {
const index = generateLatestIndexName(definition);
await esClient.indices.delete({ index, ignore_unavailable: true });
} catch (e) {
logger.error(`Unable to remove entity definition index [${definition.id}}]`);
logger.error(
`Unable to remove entity definition index ${index} for definition [${definition.id}]`
);
throw e;
}
}

View file

@ -16,25 +16,25 @@ Array [
},
Object {
"set": Object {
"field": "entity.definitionId",
"field": "entity.definition_id",
"value": "builtin_mock_entity_definition",
},
},
Object {
"set": Object {
"field": "entity.definitionVersion",
"field": "entity.definition_version",
"value": "1.0.0",
},
},
Object {
"set": Object {
"field": "entity.schemaVersion",
"field": "entity.schema_version",
"value": "v1",
},
},
Object {
"set": Object {
"field": "entity.identityFields",
"field": "entity.identity_fields",
"value": Array [
"log.logger",
],
@ -92,7 +92,7 @@ if (ctx.entity?.metadata?.sourceIndex?.data != null) {
},
Object {
"set": Object {
"field": "entity.displayName",
"field": "entity.display_name",
"value": "{{log.logger}}",
},
},
@ -121,25 +121,25 @@ Array [
},
Object {
"set": Object {
"field": "entity.definitionId",
"field": "entity.definition_id",
"value": "admin-console-services",
},
},
Object {
"set": Object {
"field": "entity.definitionVersion",
"field": "entity.definition_version",
"value": "1.0.0",
},
},
Object {
"set": Object {
"field": "entity.schemaVersion",
"field": "entity.schema_version",
"value": "v1",
},
},
Object {
"set": Object {
"field": "entity.identityFields",
"field": "entity.identity_fields",
"value": Array [
"log.logger",
],
@ -197,7 +197,7 @@ if (ctx.entity?.metadata?.sourceIndex?.data != null) {
},
Object {
"set": Object {
"field": "entity.displayName",
"field": "entity.display_name",
"value": "{{log.logger}}",
},
},

View file

@ -117,25 +117,25 @@ export function generateLatestProcessors(definition: EntityDefinition) {
},
{
set: {
field: 'entity.definitionId',
field: 'entity.definition_id',
value: definition.id,
},
},
{
set: {
field: 'entity.definitionVersion',
field: 'entity.definition_version',
value: definition.version,
},
},
{
set: {
field: 'entity.schemaVersion',
field: 'entity.schema_version',
value: ENTITY_SCHEMA_VERSION_V1,
},
},
{
set: {
field: 'entity.identityFields',
field: 'entity.identity_fields',
value: definition.identityFields.map((identityField) => identityField.field),
},
},
@ -173,7 +173,7 @@ export function generateLatestProcessors(definition: EntityDefinition) {
// This must happen AFTER we lift the identity fields into the root of the document
{
set: {
field: 'entity.displayName',
field: 'entity.display_name',
value: definition.displayNameTemplate,
},
},

View file

@ -74,7 +74,7 @@ const assertHasCreatedDefinition = (
id: generateLatestIngestPipelineId(definition),
processors: expect.anything(),
_meta: {
definitionVersion: definition.version,
definition_version: definition.version,
managed: definition.managed,
},
});
@ -112,7 +112,7 @@ const assertHasUpgradedDefinition = (
id: generateLatestIngestPipelineId(definition),
processors: expect.anything(),
_meta: {
definitionVersion: definition.version,
definition_version: definition.version,
managed: definition.managed,
},
});
@ -260,7 +260,7 @@ describe('install_entity_definition', () => {
describe('installBuiltInEntityDefinitions', () => {
it('should install definition when not found', async () => {
const builtInDefinitions = [mockEntityDefinition];
const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser;
const clusterClient = elasticsearchClientMock.createScopedClusterClient();
const soClient = savedObjectsClientMock.create();
soClient.find.mockResolvedValue({ saved_objects: [], total: 0, page: 1, per_page: 10 });
soClient.update.mockResolvedValue({
@ -271,18 +271,19 @@ describe('install_entity_definition', () => {
});
await installBuiltInEntityDefinitions({
esClient,
clusterClient,
soClient,
definitions: builtInDefinitions,
logger: loggerMock.create(),
});
assertHasCreatedDefinition(mockEntityDefinition, soClient, esClient);
assertHasCreatedDefinition(mockEntityDefinition, soClient, clusterClient.asSecondaryAuthUser);
});
it('should reinstall when partial state found', async () => {
const builtInDefinitions = [mockEntityDefinition];
const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser;
const clusterClient = elasticsearchClientMock.createScopedClusterClient();
const esClient = clusterClient.asInternalUser;
// mock partially installed definition
esClient.ingest.getPipeline.mockResolvedValue({});
esClient.transform.getTransformStats.mockResolvedValue({ transforms: [], count: 0 });
@ -314,14 +315,18 @@ describe('install_entity_definition', () => {
});
await installBuiltInEntityDefinitions({
esClient,
clusterClient,
soClient,
definitions: builtInDefinitions,
logger: loggerMock.create(),
});
assertHasDeletedTransforms(mockEntityDefinition, esClient);
assertHasUpgradedDefinition(mockEntityDefinition, soClient, esClient);
assertHasDeletedTransforms(mockEntityDefinition, clusterClient.asSecondaryAuthUser);
assertHasUpgradedDefinition(
mockEntityDefinition,
soClient,
clusterClient.asSecondaryAuthUser
);
});
it('should reinstall when outdated version', async () => {
@ -329,7 +334,8 @@ describe('install_entity_definition', () => {
...mockEntityDefinition,
version: semver.inc(mockEntityDefinition.version, 'major') ?? '0.0.0',
};
const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser;
const clusterClient = elasticsearchClientMock.createScopedClusterClient();
const esClient = clusterClient.asInternalUser;
esClient.transform.getTransformStats.mockResolvedValue({ transforms: [], count: 0 });
const soClient = savedObjectsClientMock.create();
@ -359,14 +365,14 @@ describe('install_entity_definition', () => {
});
await installBuiltInEntityDefinitions({
esClient,
clusterClient,
soClient,
definitions: [updatedDefinition],
logger: loggerMock.create(),
});
assertHasDeletedTransforms(mockEntityDefinition, esClient);
assertHasUpgradedDefinition(updatedDefinition, soClient, esClient);
assertHasDeletedTransforms(mockEntityDefinition, clusterClient.asSecondaryAuthUser);
assertHasUpgradedDefinition(updatedDefinition, soClient, clusterClient.asSecondaryAuthUser);
});
it('should reinstall when stale upgrade', async () => {
@ -374,7 +380,8 @@ describe('install_entity_definition', () => {
...mockEntityDefinition,
version: semver.inc(mockEntityDefinition.version, 'major') ?? '0.0.0',
};
const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser;
const clusterClient = elasticsearchClientMock.createScopedClusterClient();
const esClient = clusterClient.asInternalUser;
esClient.transform.getTransformStats.mockResolvedValue({ transforms: [], count: 0 });
const soClient = savedObjectsClientMock.create();
@ -406,18 +413,19 @@ describe('install_entity_definition', () => {
});
await installBuiltInEntityDefinitions({
esClient,
clusterClient,
soClient,
definitions: [updatedDefinition],
logger: loggerMock.create(),
});
assertHasDeletedTransforms(mockEntityDefinition, esClient);
assertHasUpgradedDefinition(updatedDefinition, soClient, esClient);
assertHasDeletedTransforms(mockEntityDefinition, clusterClient.asSecondaryAuthUser);
assertHasUpgradedDefinition(updatedDefinition, soClient, clusterClient.asSecondaryAuthUser);
});
it('should reinstall when failed installation', async () => {
const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser;
const clusterClient = elasticsearchClientMock.createScopedClusterClient();
const esClient = clusterClient.asInternalUser;
esClient.transform.getTransformStats.mockResolvedValue({ transforms: [], count: 0 });
const soClient = savedObjectsClientMock.create();
@ -448,14 +456,18 @@ describe('install_entity_definition', () => {
});
await installBuiltInEntityDefinitions({
esClient,
clusterClient,
soClient,
definitions: [mockEntityDefinition],
logger: loggerMock.create(),
});
assertHasDeletedTransforms(mockEntityDefinition, esClient);
assertHasUpgradedDefinition(mockEntityDefinition, soClient, esClient);
assertHasDeletedTransforms(mockEntityDefinition, clusterClient.asSecondaryAuthUser);
assertHasUpgradedDefinition(
mockEntityDefinition,
soClient,
clusterClient.asSecondaryAuthUser
);
});
});
});

View file

@ -6,7 +6,7 @@
*/
import semver from 'semver';
import { ElasticsearchClient } from '@kbn/core-elasticsearch-server';
import { ElasticsearchClient, IScopedClusterClient } from '@kbn/core-elasticsearch-server';
import { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server';
import { EntityDefinition, EntityDefinitionUpdate } from '@kbn/entities-schema';
import { Logger } from '@kbn/logging';
@ -29,6 +29,7 @@ import { mergeEntityDefinitionUpdate } from './helpers/merge_definition_update';
import { EntityDefinitionWithState } from './types';
import { stopLatestTransform, stopTransforms } from './stop_transforms';
import { deleteLatestTransform, deleteTransforms } from './delete_transforms';
import { deleteIndices } from './delete_index';
export interface InstallDefinitionParams {
esClient: ElasticsearchClient;
@ -49,10 +50,7 @@ export async function installEntityDefinition({
validateDefinitionCanCreateValidTransformIds(definition);
if (await entityDefinitionExists(soClient, definition.id)) {
throw new EntityIdConflict(
`Entity definition with [${definition.id}] already exists.`,
definition
);
throw new EntityIdConflict(`Entity definition [${definition.id}] already exists.`, definition);
}
try {
@ -65,7 +63,7 @@ export async function installEntityDefinition({
return await install({ esClient, soClient, logger, definition: entityDefinition });
} catch (e) {
logger.error(`Failed to install entity definition ${definition.id}: ${e}`);
logger.error(`Failed to install entity definition [${definition.id}]: ${e}`);
await stopLatestTransform(esClient, definition, logger);
await deleteLatestTransform(esClient, definition, logger);
@ -90,28 +88,32 @@ export async function installEntityDefinition({
}
export async function installBuiltInEntityDefinitions({
esClient,
clusterClient,
soClient,
logger,
definitions,
}: Omit<InstallDefinitionParams, 'definition'> & {
}: Omit<InstallDefinitionParams, 'definition' | 'esClient'> & {
clusterClient: IScopedClusterClient;
definitions: EntityDefinition[];
}): Promise<EntityDefinition[]> {
if (definitions.length === 0) return [];
logger.debug(`Starting installation of ${definitions.length} built-in definitions`);
logger.info(`Checking installation of ${definitions.length} built-in definitions`);
const installPromises = definitions.map(async (builtInDefinition) => {
const installedDefinition = await findEntityDefinitionById({
esClient,
soClient,
esClient: clusterClient.asInternalUser,
id: builtInDefinition.id,
includeState: true,
});
if (!installedDefinition) {
// clean data from previous installation
await deleteIndices(clusterClient.asCurrentUser, builtInDefinition, logger);
return await installEntityDefinition({
definition: builtInDefinition,
esClient,
esClient: clusterClient.asSecondaryAuthUser,
soClient,
logger,
});
@ -127,15 +129,16 @@ export async function installBuiltInEntityDefinitions({
return installedDefinition;
}
logger.debug(
logger.info(
`Detected failed or outdated installation of definition [${installedDefinition.id}] v${installedDefinition.version}, installing v${builtInDefinition.version}`
);
return await reinstallEntityDefinition({
soClient,
esClient,
clusterClient,
logger,
definition: installedDefinition,
definitionUpdate: builtInDefinition,
deleteData: true,
});
});
@ -150,22 +153,16 @@ async function install({
definition,
logger,
}: InstallDefinitionParams): Promise<EntityDefinition> {
logger.debug(
() =>
`Installing definition ${definition.id} v${definition.version}\n${JSON.stringify(
definition,
null,
2
)}`
);
logger.info(`Installing definition [${definition.id}] v${definition.version}`);
logger.debug(() => JSON.stringify(definition, null, 2));
logger.debug(`Installing index templates for definition ${definition.id}`);
logger.debug(`Installing index templates for definition [${definition.id}]`);
const templates = await createAndInstallTemplates(esClient, definition, logger);
logger.debug(`Installing ingest pipelines for definition ${definition.id}`);
logger.debug(`Installing ingest pipelines for definition [${definition.id}]`);
const pipelines = await createAndInstallIngestPipelines(esClient, definition, logger);
logger.debug(`Installing transforms for definition ${definition.id}`);
logger.debug(`Installing transforms for definition [${definition.id}]`);
const transforms = await createAndInstallTransforms(esClient, definition, logger);
const updatedProps = await updateEntityDefinition(soClient, definition.id, {
@ -177,20 +174,23 @@ async function install({
// stop and delete the current transforms and reinstall all the components
export async function reinstallEntityDefinition({
esClient,
clusterClient,
soClient,
definition,
definitionUpdate,
logger,
}: InstallDefinitionParams & {
deleteData = false,
}: Omit<InstallDefinitionParams, 'esClient'> & {
clusterClient: IScopedClusterClient;
definitionUpdate: EntityDefinitionUpdate;
deleteData?: boolean;
}): Promise<EntityDefinition> {
try {
const updatedDefinition = mergeEntityDefinitionUpdate(definition, definitionUpdate);
logger.debug(
() =>
`Reinstalling definition ${definition.id} from v${definition.version} to v${
`Reinstalling definition [${definition.id}] from v${definition.version} to v${
definitionUpdate.version
}\n${JSON.stringify(updatedDefinition, null, 2)}`
);
@ -201,13 +201,17 @@ export async function reinstallEntityDefinition({
installStartedAt: new Date().toISOString(),
});
logger.debug(`Deleting transforms for definition ${definition.id} v${definition.version}`);
await stopAndDeleteTransforms(esClient, definition, logger);
logger.debug(`Deleting transforms for definition [${definition.id}] v${definition.version}`);
await stopAndDeleteTransforms(clusterClient.asSecondaryAuthUser, definition, logger);
if (deleteData) {
await deleteIndices(clusterClient.asCurrentUser, definition, logger);
}
return await install({
esClient,
soClient,
logger,
esClient: clusterClient.asSecondaryAuthUser,
definition: updatedDefinition,
});
} catch (err) {

View file

@ -3,7 +3,7 @@
exports[`generateLatestTransform(definition) should generate a valid latest transform 1`] = `
Object {
"_meta": Object {
"definitionVersion": "1.0.0",
"definition_version": "1.0.0",
"managed": false,
},
"defer_validation": true,
@ -42,7 +42,7 @@ Object {
},
},
},
"entity.lastSeenTimestamp": Object {
"entity.last_seen_timestamp": Object {
"max": Object {
"field": "@timestamp",
},

View file

@ -69,7 +69,7 @@ const generateTransformPutRequest = ({
return {
transform_id: transformId,
_meta: {
definitionVersion: definition.version,
definition_version: definition.version,
managed: definition.managed,
},
defer_validation: true,
@ -113,7 +113,7 @@ const generateTransformPutRequest = ({
aggs: {
...generateLatestMetricAggregations(definition),
...generateLatestMetadataAggregations(definition),
'entity.lastSeenTimestamp': {
'entity.last_seen_timestamp': {
max: {
field: definition.latest.timestampField,
},

View file

@ -35,18 +35,20 @@ export async function upgradeBuiltInEntityDefinitions({
);
}
const { esClient, soClient } = getClientsFromAPIKey({ apiKey, server });
const { clusterClient, soClient } = getClientsFromAPIKey({ apiKey, server });
logger.debug(`Starting built-in definitions upgrade`);
const upgradedDefinitions = await installBuiltInEntityDefinitions({
esClient,
clusterClient,
soClient,
definitions,
logger,
});
await Promise.all(
upgradedDefinitions.map((definition) => startTransforms(esClient, definition, logger))
upgradedDefinitions.map((definition) =>
startTransforms(clusterClient.asSecondaryAuthUser, definition, logger)
)
);
return { success: true, definitions: upgradedDefinitions };

View file

@ -40,7 +40,11 @@ export class EntityClient {
definition: EntityDefinition;
installOnly?: boolean;
}) {
this.options.logger.info(
`Creating definition [${definition.id}] v${definition.version} (installOnly=${installOnly})`
);
const secondaryAuthClient = this.options.clusterClient.asSecondaryAuthUser;
const installedDefinition = await installEntityDefinition({
definition,
esClient: secondaryAuthClient,
@ -62,16 +66,15 @@ export class EntityClient {
id: string;
definitionUpdate: EntityDefinitionUpdate;
}) {
const secondaryAuthClient = this.options.clusterClient.asSecondaryAuthUser;
const definition = await findEntityDefinitionById({
id,
soClient: this.options.soClient,
esClient: secondaryAuthClient,
esClient: this.options.clusterClient.asInternalUser,
includeState: true,
});
if (!definition) {
const message = `Unable to find entity definition with [${id}]`;
const message = `Unable to find entity definition [${id}]`;
this.options.logger.error(message);
throw new EntityDefinitionNotFound(message);
}
@ -86,25 +89,31 @@ export class EntityClient {
definition as EntityDefinitionWithState
).state.components.transforms.some((transform) => transform.running);
this.options.logger.info(
`Updating definition [${definition.id}] from v${definition.version} to v${definitionUpdate.version}`
);
const updatedDefinition = await reinstallEntityDefinition({
definition,
definitionUpdate,
soClient: this.options.soClient,
esClient: secondaryAuthClient,
clusterClient: this.options.clusterClient,
logger: this.options.logger,
});
if (shouldRestartTransforms) {
await startTransforms(secondaryAuthClient, updatedDefinition, this.options.logger);
await startTransforms(
this.options.clusterClient.asSecondaryAuthUser,
updatedDefinition,
this.options.logger
);
}
return updatedDefinition;
}
async deleteEntityDefinition({ id, deleteData = false }: { id: string; deleteData?: boolean }) {
const secondaryAuthClient = this.options.clusterClient.asSecondaryAuthUser;
const definition = await findEntityDefinitionById({
id,
esClient: secondaryAuthClient,
esClient: this.options.clusterClient.asInternalUser,
soClient: this.options.soClient,
});
@ -112,9 +121,12 @@ export class EntityClient {
throw new EntityDefinitionNotFound(`Unable to find entity definition with [${id}]`);
}
this.options.logger.info(
`Uninstalling definition [${definition.id}] v${definition.version} (deleteData=${deleteData})`
);
await uninstallEntityDefinition({
definition,
esClient: secondaryAuthClient,
esClient: this.options.clusterClient.asSecondaryAuthUser,
soClient: this.options.soClient,
logger: this.options.logger,
});
@ -146,7 +158,7 @@ export class EntityClient {
builtIn?: boolean;
}) {
const definitions = await findEntityDefinitions({
esClient: this.options.clusterClient.asSecondaryAuthUser,
esClient: this.options.clusterClient.asInternalUser,
soClient: this.options.soClient,
page,
perPage,
@ -160,6 +172,7 @@ export class EntityClient {
}
async startEntityDefinition(definition: EntityDefinition) {
this.options.logger.info(`Starting transforms for definition [${definition.id}]`);
return startTransforms(
this.options.clusterClient.asSecondaryAuthUser,
definition,
@ -168,6 +181,7 @@ export class EntityClient {
}
async stopEntityDefinition(definition: EntityDefinition) {
this.options.logger.info(`Stopping transforms for definition [${definition.id}]`);
return stopTransforms(
this.options.clusterClient.asSecondaryAuthUser,
definition,

View file

@ -11,7 +11,6 @@ import {
IndicesPutIndexTemplateRequest,
} from '@elastic/elasticsearch/lib/api/types';
import { ElasticsearchClient, Logger } from '@kbn/core/server';
import { entitiesHistoryBaseComponentTemplateConfig } from '../templates/components/base_history';
import { entitiesLatestBaseComponentTemplateConfig } from '../templates/components/base_latest';
import { entitiesEntityComponentTemplateConfig } from '../templates/components/entity';
import { entitiesEventComponentTemplateConfig } from '../templates/components/event';
@ -38,11 +37,6 @@ export const installEntityManagerTemplates = async ({
logger: Logger;
}) => {
await Promise.all([
upsertComponent({
esClient,
logger,
component: entitiesHistoryBaseComponentTemplateConfig,
}),
upsertComponent({
esClient,
logger,

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { ElasticsearchClient } from '@kbn/core-elasticsearch-server';
import { IScopedClusterClient } from '@kbn/core-elasticsearch-server';
import { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server';
import { getFakeKibanaRequest } from '@kbn/security-plugin/server/authentication/api_keys/fake_kibana_request';
import { EntityManagerServerSetup } from '../types';
@ -17,9 +17,9 @@ export const getClientsFromAPIKey = ({
}: {
apiKey: EntityDiscoveryAPIKey;
server: EntityManagerServerSetup;
}): { esClient: ElasticsearchClient; soClient: SavedObjectsClientContract } => {
}): { clusterClient: IScopedClusterClient; soClient: SavedObjectsClientContract } => {
const fakeRequest = getFakeKibanaRequest({ id: apiKey.id, api_key: apiKey.apiKey });
const esClient = server.core.elasticsearch.client.asScoped(fakeRequest).asSecondaryAuthUser;
const clusterClient = server.core.elasticsearch.client.asScoped(fakeRequest);
const soClient = server.core.savedObjects.getScopedClient(fakeRequest);
return { esClient, soClient };
return { clusterClient, soClient };
};

View file

@ -61,13 +61,13 @@ export const checkEntityDiscoveryEnabledRoute = createEntityManagerServerRoute({
return response.ok({ body: { enabled: false, reason: ERROR_API_KEY_NOT_VALID } });
}
const { esClient, soClient } = getClientsFromAPIKey({ apiKey, server });
const { clusterClient, soClient } = getClientsFromAPIKey({ apiKey, server });
const entityDiscoveryState = await Promise.all(
builtInDefinitions.map(async (builtInDefinition) => {
const definitions = await findEntityDefinitions({
esClient,
soClient,
esClient: clusterClient.asSecondaryAuthUser,
id: builtInDefinition.id,
includeState: true,
});

View file

@ -67,12 +67,13 @@ export const disableEntityDiscoveryRoute = createEntityManagerServerRoute({
includedHiddenTypes: [EntityDiscoveryApiKeyType.name],
});
logger.info('Disabling managed entity discovery');
await uninstallBuiltInEntityDefinitions({
entityClient,
deleteData: params.query.deleteData,
});
server.logger.debug('reading entity discovery API key from saved object');
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
@ -82,6 +83,7 @@ export const disableEntityDiscoveryRoute = createEntityManagerServerRoute({
ids: [apiKey.id],
});
}
logger.info('Managed entity discovery is disabled');
return response.ok({ body: { success: true } });
} catch (err) {

View file

@ -93,6 +93,7 @@ export const enableEntityDiscoveryRoute = createEntityManagerServerRoute({
});
}
logger.info(`Enabling managed entity discovery (installOnly=${params.query.installOnly})`);
const soClient = core.savedObjects.getClient({
includedHiddenTypes: [EntityDiscoveryApiKeyType.name],
});
@ -119,9 +120,9 @@ export const enableEntityDiscoveryRoute = createEntityManagerServerRoute({
await saveEntityDiscoveryAPIKey(soClient, apiKey);
const esClient = core.elasticsearch.client.asSecondaryAuthUser;
const clusterClient = core.elasticsearch.client;
const installedDefinitions = await installBuiltInEntityDefinitions({
esClient,
clusterClient,
soClient,
logger,
definitions: builtInDefinitions,
@ -130,10 +131,11 @@ export const enableEntityDiscoveryRoute = createEntityManagerServerRoute({
if (!params.query.installOnly) {
await Promise.all(
installedDefinitions.map((installedDefinition) =>
startTransforms(esClient, installedDefinition, logger)
startTransforms(clusterClient.asSecondaryAuthUser, installedDefinition, logger)
)
);
}
logger.info('Managed entity discovery is enabled');
return response.ok({ body: { success: true } });
} catch (err) {

View file

@ -5,21 +5,13 @@
* 2.0.
*/
import {
createEntityDefinitionQuerySchema,
entityDefinitionUpdateSchema,
} from '@kbn/entities-schema';
import { entityDefinitionUpdateSchema } from '@kbn/entities-schema';
import { z } from '@kbn/zod';
import { EntitySecurityException } from '../../lib/entities/errors/entity_security_exception';
import { InvalidTransformError } from '../../lib/entities/errors/invalid_transform_error';
import { findEntityDefinitionById } from '../../lib/entities/find_entity_definition';
import { startTransforms } from '../../lib/entities/start_transforms';
import {
installationInProgress,
reinstallEntityDefinition,
} from '../../lib/entities/install_entity_definition';
import { createEntityManagerServerRoute } from '../create_entity_manager_server_route';
import { EntityDefinitionNotFound } from '../../lib/entities/errors/entity_not_found';
import { EntityDefinitionUpdateConflict } from '../../lib/entities/errors/entity_definition_update_conflict';
/**
* @openapi
@ -29,13 +21,12 @@ import { createEntityManagerServerRoute } from '../create_entity_manager_server_
* tags:
* - definitions
* parameters:
* - in: query
* name: installOnly
* description: If true, the definition transforms will not be started
* required: false
* - in: path
* name: id
* description: The entity definition ID
* schema:
* type: boolean
* default: false
* type: string
* required: true
* requestBody:
* description: The definition properties to update
* required: true
@ -63,58 +54,37 @@ 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;
handler: async ({ request, response, params, logger, getScopedClient }) => {
const entityClient = await getScopedClient({ request });
try {
const installedDefinition = await findEntityDefinitionById({
soClient,
esClient,
const updatedDefinition = await entityClient.updateEntityDefinition({
id: params.path.id,
});
if (!installedDefinition) {
return response.notFound({
body: { message: `Entity definition [${params.path.id}] not found` },
});
}
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 startTransforms(esClient, updatedDefinition, logger);
}
return response.ok({ body: updatedDefinition });
} catch (e) {
logger.error(e);
if (e instanceof EntityDefinitionNotFound) {
return response.notFound({
body: { message: `Entity definition [${params.path.id}] not found` },
});
}
if (e instanceof EntityDefinitionUpdateConflict) {
return response.conflict({
body: { message: `Entity definition [${params.path.id}] has changes in progress` },
});
}
if (e instanceof EntitySecurityException || e instanceof InvalidTransformError) {
return response.customError({ body: e, statusCode: 400 });
}
return response.customError({ body: e, statusCode: 500 });
}
},

View file

@ -1,36 +0,0 @@
/*
* 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 { ClusterPutComponentTemplateRequest } from '@elastic/elasticsearch/lib/api/types';
import { ENTITY_HISTORY_BASE_COMPONENT_TEMPLATE_V1 } from '../../../common/constants_entities';
export const entitiesHistoryBaseComponentTemplateConfig: ClusterPutComponentTemplateRequest = {
name: ENTITY_HISTORY_BASE_COMPONENT_TEMPLATE_V1,
_meta: {
description:
"Component template for the ECS fields used in the Elastic Entity Model's entity discovery framework's history data set",
documentation: 'https://www.elastic.co/guide/en/ecs/current/ecs-base.html',
ecs_version: '8.0.0',
managed: true,
},
template: {
mappings: {
properties: {
'@timestamp': {
type: 'date',
},
labels: {
type: 'object',
},
tags: {
ignore_above: 1024,
type: 'keyword',
},
},
},
},
};

View file

@ -22,7 +22,7 @@ export const entitiesLatestBaseComponentTemplateConfig: ClusterPutComponentTempl
properties: {
entity: {
properties: {
displayName: {
display_name: {
type: 'text',
fields: {
keyword: {
@ -31,9 +31,6 @@ export const entitiesLatestBaseComponentTemplateConfig: ClusterPutComponentTempl
},
},
},
firstSeenTimestamp: {
type: 'date',
},
},
},
labels: {

View file

@ -29,22 +29,22 @@ export const entitiesEntityComponentTemplateConfig: ClusterPutComponentTemplateR
ignore_above: 1024,
type: 'keyword',
},
definitionId: {
definition_id: {
ignore_above: 1024,
type: 'keyword',
},
definitionVersion: {
definition_version: {
ignore_above: 1024,
type: 'keyword',
},
schemaVersion: {
schema_version: {
ignore_above: 1024,
type: 'keyword',
},
lastSeenTimestamp: {
last_seen_timestamp: {
type: 'date',
},
identityFields: {
identity_fields: {
type: 'keyword',
},
},