From c737c393cf55518cc1bdda31b7a7da7e51403f36 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 13 Oct 2021 14:22:40 -0700 Subject: [PATCH] [Actions] Fixed actions telemetry for multiple namespaces usage (#114748) * [Actions] Fixed actions telemetry for multiple namespaces usage * fixed tests --- .../server/usage/actions_telemetry.test.ts | 159 ++++++++++-------- .../actions/server/usage/actions_telemetry.ts | 46 +++-- x-pack/plugins/actions/server/usage/task.ts | 21 +-- 3 files changed, 121 insertions(+), 105 deletions(-) diff --git a/x-pack/plugins/actions/server/usage/actions_telemetry.test.ts b/x-pack/plugins/actions/server/usage/actions_telemetry.test.ts index 4049d8fc3b59..0e6b7fff0445 100644 --- a/x-pack/plugins/actions/server/usage/actions_telemetry.test.ts +++ b/x-pack/plugins/actions/server/usage/actions_telemetry.test.ts @@ -116,7 +116,7 @@ Object { test('getInUseTotalCount', async () => { const mockEsClient = elasticsearchClientMock.createClusterClient().asScoped().asInternalUser; - mockEsClient.search.mockReturnValue( + mockEsClient.search.mockReturnValueOnce( // @ts-expect-error not full search response elasticsearchClientMock.createSuccessTransportRequestPromise({ aggregations: { @@ -134,28 +134,35 @@ Object { }, }) ); - const actionsBulkGet = jest.fn(); - actionsBulkGet.mockReturnValue({ - saved_objects: [ - { - id: '1', - attributes: { - actionTypeId: '.server-log', - }, - }, - { - id: '123', - attributes: { - actionTypeId: '.slack', - }, - }, - ], - }); - const telemetry = await getInUseTotalCount(mockEsClient, actionsBulkGet, 'test'); - expect(mockEsClient.search).toHaveBeenCalledTimes(1); - expect(actionsBulkGet).toHaveBeenCalledTimes(1); + mockEsClient.search.mockReturnValueOnce( + // @ts-expect-error not full search response + elasticsearchClientMock.createSuccessTransportRequestPromise({ + hits: { + hits: [ + { + _source: { + action: { + id: '1', + actionTypeId: '.server-log', + }, + }, + }, + { + _source: { + action: { + id: '2', + actionTypeId: '.slack', + }, + }, + }, + ], + }, + }) + ); + const telemetry = await getInUseTotalCount(mockEsClient, 'test'); + expect(mockEsClient.search).toHaveBeenCalledTimes(2); expect(telemetry).toMatchInlineSnapshot(` Object { "countByAlertHistoryConnectorType": 0, @@ -170,7 +177,7 @@ Object { test('getInUseTotalCount should count preconfigured alert history connector usage', async () => { const mockEsClient = elasticsearchClientMock.createClusterClient().asScoped().asInternalUser; - mockEsClient.search.mockReturnValue( + mockEsClient.search.mockReturnValueOnce( // @ts-expect-error not full search response elasticsearchClientMock.createSuccessTransportRequestPromise({ aggregations: { @@ -202,28 +209,34 @@ Object { }, }) ); - const actionsBulkGet = jest.fn(); - actionsBulkGet.mockReturnValue({ - saved_objects: [ - { - id: '1', - attributes: { - actionTypeId: '.server-log', - }, + mockEsClient.search.mockReturnValueOnce( + // @ts-expect-error not full search response + elasticsearchClientMock.createSuccessTransportRequestPromise({ + hits: { + hits: [ + { + _source: { + action: { + id: '1', + actionTypeId: '.server-log', + }, + }, + }, + { + _source: { + action: { + id: '2', + actionTypeId: '.slack', + }, + }, + }, + ], }, - { - id: '123', - attributes: { - actionTypeId: '.slack', - }, - }, - ], - }); - const telemetry = await getInUseTotalCount(mockEsClient, actionsBulkGet, 'test'); - - expect(mockEsClient.search).toHaveBeenCalledTimes(1); - expect(actionsBulkGet).toHaveBeenCalledTimes(1); + }) + ); + const telemetry = await getInUseTotalCount(mockEsClient, 'test'); + expect(mockEsClient.search).toHaveBeenCalledTimes(2); expect(telemetry).toMatchInlineSnapshot(` Object { "countByAlertHistoryConnectorType": 1, @@ -359,7 +372,7 @@ Object { test('getInUseTotalCount() accounts for preconfigured connectors', async () => { const mockEsClient = elasticsearchClientMock.createClusterClient().asScoped().asInternalUser; - mockEsClient.search.mockReturnValue( + mockEsClient.search.mockReturnValueOnce( // @ts-expect-error not full search response elasticsearchClientMock.createSuccessTransportRequestPromise({ aggregations: { @@ -399,34 +412,42 @@ Object { }, }) ); - const actionsBulkGet = jest.fn(); - actionsBulkGet.mockReturnValue({ - saved_objects: [ - { - id: '1', - attributes: { - actionTypeId: '.server-log', - }, + mockEsClient.search.mockReturnValueOnce( + // @ts-expect-error not full search response + elasticsearchClientMock.createSuccessTransportRequestPromise({ + hits: { + hits: [ + { + _source: { + action: { + id: '1', + actionTypeId: '.server-log', + }, + }, + }, + { + _source: { + action: { + id: '2', + actionTypeId: '.slack', + }, + }, + }, + { + _source: { + action: { + id: '3', + actionTypeId: '.email', + }, + }, + }, + ], }, - { - id: '123', - attributes: { - actionTypeId: '.slack', - }, - }, - { - id: '456', - attributes: { - actionTypeId: '.email', - }, - }, - ], - }); - const telemetry = await getInUseTotalCount(mockEsClient, actionsBulkGet, 'test'); - - expect(mockEsClient.search).toHaveBeenCalledTimes(1); - expect(actionsBulkGet).toHaveBeenCalledTimes(1); + }) + ); + const telemetry = await getInUseTotalCount(mockEsClient, 'test'); + expect(mockEsClient.search).toHaveBeenCalledTimes(2); expect(telemetry).toMatchInlineSnapshot(` Object { "countByAlertHistoryConnectorType": 1, diff --git a/x-pack/plugins/actions/server/usage/actions_telemetry.ts b/x-pack/plugins/actions/server/usage/actions_telemetry.ts index 544d6a411ccd..4a3d0c70e535 100644 --- a/x-pack/plugins/actions/server/usage/actions_telemetry.ts +++ b/x-pack/plugins/actions/server/usage/actions_telemetry.ts @@ -5,12 +5,7 @@ * 2.0. */ -import { - ElasticsearchClient, - SavedObjectsBaseOptions, - SavedObjectsBulkGetObject, - SavedObjectsBulkResponse, -} from 'kibana/server'; +import { ElasticsearchClient } from 'kibana/server'; import { AlertHistoryEsIndexConnectorId } from '../../common'; import { ActionResult, PreConfiguredAction } from '../types'; @@ -86,10 +81,6 @@ export async function getTotalCount( export async function getInUseTotalCount( esClient: ElasticsearchClient, - actionsBulkGet: ( - objects?: SavedObjectsBulkGetObject[] | undefined, - options?: SavedObjectsBaseOptions | undefined - ) => Promise>>>, kibanaIndex: string ): Promise<{ countTotal: number; @@ -259,15 +250,34 @@ export async function getInUseTotalCount( const preconfiguredActionsAggs = // @ts-expect-error aggegation type is not specified actionResults.aggregations.preconfigured_actions?.preconfiguredActionRefIds.value; - const bulkFilter = Object.entries(aggs.connectorIds).map(([key]) => ({ - id: key, - type: 'action', - fields: ['id', 'actionTypeId'], - })); - const actions = await actionsBulkGet(bulkFilter); - const countByActionTypeId = actions.saved_objects.reduce( + const { + body: { hits: actions }, + } = await esClient.search<{ + action: ActionResult; + }>({ + index: kibanaIndex, + _source_includes: ['action'], + body: { + query: { + bool: { + must: [ + { + term: { type: 'action' }, + }, + { + terms: { + _id: Object.entries(aggs.connectorIds).map(([key]) => `action:${key}`), + }, + }, + ], + }, + }, + }, + }); + const countByActionTypeId = actions.hits.reduce( (actionTypeCount: Record, action) => { - const alertTypeId = replaceFirstAndLastDotSymbols(action.attributes.actionTypeId); + const actionSource = action._source!; + const alertTypeId = replaceFirstAndLastDotSymbols(actionSource.action.actionTypeId); const currentCount = actionTypeCount[alertTypeId] !== undefined ? actionTypeCount[alertTypeId] : 0; actionTypeCount[alertTypeId] = currentCount + 1; diff --git a/x-pack/plugins/actions/server/usage/task.ts b/x-pack/plugins/actions/server/usage/task.ts index f37f830697eb..7cbfb87dedda 100644 --- a/x-pack/plugins/actions/server/usage/task.ts +++ b/x-pack/plugins/actions/server/usage/task.ts @@ -5,19 +5,14 @@ * 2.0. */ -import { - Logger, - CoreSetup, - SavedObjectsBulkGetObject, - SavedObjectsBaseOptions, -} from 'kibana/server'; +import { Logger, CoreSetup } from 'kibana/server'; import moment from 'moment'; import { RunContext, TaskManagerSetupContract, TaskManagerStartContract, } from '../../../task_manager/server'; -import { ActionResult, PreConfiguredAction } from '../types'; +import { PreConfiguredAction } from '../types'; import { getTotalCount, getInUseTotalCount } from './actions_telemetry'; export const TELEMETRY_TASK_TYPE = 'actions_telemetry'; @@ -83,22 +78,12 @@ export function telemetryTaskRunner( }, ]) => client.asInternalUser ); - const actionsBulkGet = ( - objects?: SavedObjectsBulkGetObject[], - options?: SavedObjectsBaseOptions - ) => { - return core - .getStartServices() - .then(([{ savedObjects }]) => - savedObjects.createInternalRepository(['action']).bulkGet(objects, options) - ); - }; return { async run() { const esClient = await getEsClient(); return Promise.all([ getTotalCount(esClient, kibanaIndex, preconfiguredActions), - getInUseTotalCount(esClient, actionsBulkGet, kibanaIndex), + getInUseTotalCount(esClient, kibanaIndex), ]) .then(([totalAggegations, totalInUse]) => { return {