elastic / kibana

Your window into the Elastic Stack
https://www.elastic.co/products/kibana
Other
19.77k stars 8.18k forks source link

[Inventory] [POC] Explore variations of `internal/inventory/entities` API to support grouping entities #194859

Open Bluefinger opened 6 days ago

Bluefinger commented 6 days ago

With the need for grouping entities for Inventory, it became clear there's going to be a number of potential ways to approach this. For the sakes of making a good decision on the way forward on the API side, we should do a couple of POCs to explore the following:

The purpose of this is to discover the following:

We should not assume we'd only group by entity.type, but any relevant field could be selected for the first-level (and later, more than one field for grouping).

elasticmachine commented 6 days ago

Pinging @elastic/obs-ux-infra_services-team (Team:obs-ux-infra_services)

Bluefinger commented 2 days ago

Adding some of the ideas for this by @cauemarcondes here

GET /internal/inventory/entities/group_by/{field}

export const groupEntitiesRoute = createInventoryServerRoute({
  endpoint: 'GET /internal/inventory/entities/group_by/{field}',
  params: t.type({
    path: t.type({
      field: t.string,
    }),
    query: t.partial({
      where: jsonRt.pipe(t.array(t.string)),
    }),
  }),
  options: {
    tags: ['access:inventory'],
  },
  handler: async ({ params, context, logger }) => {
    const coreContext = await context.core;
    const inventoryEsClient = createObservabilityEsClient({
      client: coreContext.elasticsearch.client.asCurrentUser,
      logger,
      plugin: `@kbn/${INVENTORY_APP_ID}-plugin`,
    });

    const { field } = params.path;
    const { where } = params.query;
    const whereClauses = where?.map((filter) => `WHERE ${filter}`).join('\n |');

    const groups = await inventoryEsClient.esql('get_entities_groups', {
      query: `
        FROM entities*latest
        ${whereClauses ? `| ${whereClauses}` : ''}
        | STATS count = COUNT(*) by ${field}
      `,
    });

    return esqlResultToPlainObjects(groups);
  },
});

We'd call it like: groupBy = ['entity.type', 'agent.name']

  1. Initial request: Group by entity.type: http://localhost:5699/foo/internal/inventory/entities/group_by/entity.type?where=[]
  2. User opens entity type container accordion (Group by agent.name filtering by the selected entity.type): http://localhost:5699/foo/internal/inventory/entities/group_by/agent.name?where=["entity.type==\"container\""]