[Entities] Add spaceId to entities (#183943)

## Summary

This PR closes https://github.com/elastic/observed-asset-model/issues/67
by capturing the `spaceId` from the API request and storing the
`entity.spaceId` via the ingest pipeline.

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Chris Cowan 2024-05-31 10:00:38 -06:00 committed by GitHub
parent d9aa9893c6
commit cc317a0813
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 53 additions and 25 deletions

View file

@ -15,6 +15,7 @@ export const entitySchema = z.intersection(
indexPatterns: arrayOfStringsSchema,
identityFields: arrayOfStringsSchema,
metric: z.record(z.string(), z.number()),
spaceId: z.string(),
}),
}),
z.record(z.string(), z.string().or(z.number()))

View file

@ -10,6 +10,7 @@
"assetManager"
],
"optionalPlugins": [
"spaces"
],
"requiredPlugins": [
"apmDataAccess",

View file

@ -15,9 +15,10 @@ import { generateIngestPipelineId } from './ingest_pipeline/generate_ingest_pipe
export async function createAndInstallIngestPipeline(
esClient: ElasticsearchClient,
definition: EntityDefinition,
logger: Logger
logger: Logger,
spaceId: string
) {
const processors = generateProcessors(definition);
const processors = generateProcessors(definition, spaceId);
const id = generateIngestPipelineId(definition);
try {
await retryTransientEsErrors(

View file

@ -8,6 +8,12 @@ Array [
"value": "{{{_ingest.timestamp}}}",
},
},
Object {
"set": Object {
"field": "entity.spaceId",
"value": "test",
},
},
Object {
"set": Object {
"field": "entity.definitionId",

View file

@ -10,7 +10,8 @@ import { entityDefinition } from '../helpers/fixtures/entity_definition';
describe('generateProcessors(definition)', () => {
it('should genearte a valid pipeline', () => {
const processors = generateProcessors(entityDefinition);
const spaceId = 'test';
const processors = generateProcessors(entityDefinition, spaceId);
expect(processors).toMatchSnapshot();
});
});

View file

@ -43,7 +43,7 @@ function createMetadataPainlessScript(definition: EntityDefinition) {
}, '');
}
export function generateProcessors(definition: EntityDefinition) {
export function generateProcessors(definition: EntityDefinition, spaceId: string) {
return [
{
set: {
@ -51,6 +51,12 @@ export function generateProcessors(definition: EntityDefinition) {
value: '{{{_ingest.timestamp}}}',
},
},
{
set: {
field: 'entity.spaceId',
value: spaceId,
},
},
{
set: {
field: 'entity.definitionId',

View file

@ -70,7 +70,12 @@ export class AssetManagerServerPlugin
});
const router = core.http.createRouter();
setupRoutes<RequestHandlerContext>({ router, assetClient, logger: this.logger });
setupRoutes<RequestHandlerContext>({
router,
assetClient,
logger: this.logger,
spaces: plugins.spaces,
});
return {
assetClient,

View file

@ -24,6 +24,7 @@ import { ENTITY_API_PREFIX } from '../../../common/constants_entities';
export function createEntityDefinitionRoute<T extends RequestHandlerContext>({
router,
logger,
spaces,
}: SetupRouteOptions<T>) {
router.post<unknown, unknown, EntityDefinition>(
{
@ -42,12 +43,15 @@ export function createEntityDefinitionRoute<T extends RequestHandlerContext>({
let definitionCreated = false;
let ingestPipelineCreated = false;
let transformCreated = false;
const soClient = (await context.core).savedObjects.client;
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const core = await context.core;
const soClient = core.savedObjects.client;
const esClient = core.elasticsearch.client.asCurrentUser;
const spaceId = spaces?.spacesService.getSpaceId(req) ?? 'default';
try {
const definition = await saveEntityDefinition(soClient, req.body);
definitionCreated = true;
await createAndInstallIngestPipeline(esClient, definition, logger);
await createAndInstallIngestPipeline(esClient, definition, logger, spaceId);
ingestPipelineCreated = true;
await createAndInstallTransform(esClient, definition, logger);
transformCreated = true;

View file

@ -23,6 +23,7 @@ import { ENTITY_API_PREFIX } from '../../../common/constants_entities';
export function resetEntityDefinitionRoute<T extends RequestHandlerContext>({
router,
logger,
spaces,
}: SetupRouteOptions<T>) {
router.post<{ id: string }, unknown, unknown>(
{
@ -37,6 +38,7 @@ export function resetEntityDefinitionRoute<T extends RequestHandlerContext>({
try {
const soClient = (await context.core).savedObjects.client;
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const spaceId = spaces?.spacesService.getSpaceId(req) ?? 'default';
const definition = await readEntityDefinition(soClient, req.params.id, logger);
@ -46,7 +48,7 @@ export function resetEntityDefinitionRoute<T extends RequestHandlerContext>({
await deleteIndex(esClient, definition, logger);
// Recreate everything
await createAndInstallIngestPipeline(esClient, definition, logger);
await createAndInstallIngestPipeline(esClient, definition, logger, spaceId);
await createAndInstallTransform(esClient, definition, logger);
await startTransform(esClient, definition, logger);

View file

@ -18,19 +18,15 @@ import { createEntityDefinitionRoute } from './entities/create';
import { deleteEntityDefinitionRoute } from './entities/delete';
import { resetEntityDefinitionRoute } from './entities/reset';
export function setupRoutes<T extends RequestHandlerContext>({
router,
assetClient,
logger,
}: SetupRouteOptions<T>) {
pingRoute<T>({ router, assetClient, logger });
sampleAssetsRoutes<T>({ router, assetClient, logger });
assetsRoutes<T>({ router, assetClient, logger });
hostsRoutes<T>({ router, assetClient, logger });
servicesRoutes<T>({ router, assetClient, logger });
containersRoutes<T>({ router, assetClient, logger });
podsRoutes<T>({ router, assetClient, logger });
createEntityDefinitionRoute<T>({ router, assetClient, logger });
deleteEntityDefinitionRoute<T>({ router, assetClient, logger });
resetEntityDefinitionRoute<T>({ router, assetClient, logger });
export function setupRoutes<T extends RequestHandlerContext>(dependencies: SetupRouteOptions<T>) {
pingRoute<T>(dependencies);
sampleAssetsRoutes<T>(dependencies);
assetsRoutes<T>(dependencies);
hostsRoutes<T>(dependencies);
servicesRoutes<T>(dependencies);
containersRoutes<T>(dependencies);
podsRoutes<T>(dependencies);
createEntityDefinitionRoute<T>(dependencies);
deleteEntityDefinitionRoute<T>(dependencies);
resetEntityDefinitionRoute<T>(dependencies);
}

View file

@ -7,10 +7,12 @@
import { IRouter, RequestHandlerContextBase } from '@kbn/core-http-server';
import { Logger } from '@kbn/core/server';
import { SpacesPluginSetup } from '@kbn/spaces-plugin/server';
import { AssetClient } from '../lib/asset_client';
export interface SetupRouteOptions<T extends RequestHandlerContextBase> {
router: IRouter<T>;
assetClient: AssetClient;
logger: Logger;
spaces?: SpacesPluginSetup;
}

View file

@ -11,6 +11,7 @@ import {
ApmDataAccessPluginStart,
} from '@kbn/apm-data-access-plugin/server';
import { MetricsDataPluginSetup } from '@kbn/metrics-data-access-plugin/server';
import { SpacesPluginSetup } from '@kbn/spaces-plugin/server';
export interface ElasticsearchAccessorOptions {
elasticsearchClient: ElasticsearchClient;
@ -19,6 +20,7 @@ export interface ElasticsearchAccessorOptions {
export interface AssetManagerPluginSetupDependencies {
apmDataAccess: ApmDataAccessPluginSetup;
metricsDataAccess: MetricsDataPluginSetup;
spaces?: SpacesPluginSetup;
}
export interface AssetManagerPluginStartDependencies {
apmDataAccess: ApmDataAccessPluginStart;

View file

@ -29,6 +29,7 @@
"@kbn/core-saved-objects-api-server-mocks",
"@kbn/entities-schema",
"@kbn/es-query",
"@kbn/zod-helpers"
"@kbn/zod-helpers",
"@kbn/spaces-plugin"
]
}