From 79d58bb925c9baf2bdcbe7e091688f395c69b34a Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 6 Jan 2021 15:43:01 -0800 Subject: [PATCH 01/10] Added alerting API to get all active instances --- .../server/es/cluster_client_adapter.ts | 108 ++++++++++++++++++ .../event_log/server/event_log_client.ts | 31 ++++- x-pack/plugins/event_log/server/plugin.ts | 2 +- .../server/saved_object_provider_registry.ts | 32 ++++-- x-pack/plugins/event_log/server/types.ts | 6 + 5 files changed, 164 insertions(+), 15 deletions(-) diff --git a/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts b/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts index 0ac1193998cef..3e8ed5cf0353c 100644 --- a/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts +++ b/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts @@ -303,6 +303,114 @@ export class ClusterClientAdapter { } } + public async queryEventsBySavedObjects( + index: string, + namespace: string | undefined, + type: string, + ids: string[], + // eslint-disable-next-line @typescript-eslint/naming-convention + { page, per_page: perPage, start, end, sort_field, sort_order }: FindOptionsType + ): Promise { + const defaultNamespaceQuery = { + bool: { + must_not: { + exists: { + field: 'kibana.saved_objects.namespace', + }, + }, + }, + }; + const namedNamespaceQuery = { + term: { + 'kibana.saved_objects.namespace': { + value: namespace, + }, + }, + }; + const namespaceQuery = namespace === undefined ? defaultNamespaceQuery : namedNamespaceQuery; + + const body = { + size: perPage, + from: (page - 1) * perPage, + sort: { [sort_field]: { order: sort_order } }, + query: { + bool: { + must: reject( + [ + { + nested: { + path: 'kibana.saved_objects', + query: { + bool: { + must: [ + { + term: { + 'kibana.saved_objects.rel': { + value: SAVED_OBJECT_REL_PRIMARY, + }, + }, + }, + { + term: { + 'kibana.saved_objects.type': { + value: type, + }, + }, + }, + { + terms: { + // default maximum of 65,536 terms, configurable by index.max_terms_count + 'kibana.saved_objects.id': ids, + }, + }, + namespaceQuery, + ], + }, + }, + }, + }, + start && { + range: { + '@timestamp': { + gte: start, + }, + }, + }, + end && { + range: { + '@timestamp': { + lte: end, + }, + }, + }, + ], + isUndefined + ), + }, + }, + }; + + try { + const { + hits: { hits, total }, + }: ESSearchResponse = await this.callEs('search', { + index, + track_total_hits: true, + body, + }); + return { + page, + per_page: perPage, + total: total.value, + data: hits.map((hit) => hit._source) as IValidatedEvent[], + }; + } catch (err) { + throw new Error( + `querying for Event Log by for type "${type}" and ids "${ids}" failed with: ${err.message}` + ); + } + } + // We have a common problem typing ES-DSL Queries // eslint-disable-next-line @typescript-eslint/no-explicit-any private async callEs(operation: string, body?: any) { diff --git a/x-pack/plugins/event_log/server/event_log_client.ts b/x-pack/plugins/event_log/server/event_log_client.ts index 9b7d4e00b2761..2c5c7dc84b844 100644 --- a/x-pack/plugins/event_log/server/event_log_client.ts +++ b/x-pack/plugins/event_log/server/event_log_client.ts @@ -12,7 +12,7 @@ import { SpacesServiceStart } from '../../spaces/server'; import { EsContext } from './es'; import { IEventLogClient } from './types'; import { QueryEventsBySavedObjectResult } from './es/cluster_client_adapter'; -import { SavedObjectGetter } from './saved_object_provider_registry'; +import { SavedObjectBulkGetter, SavedObjectGetter } from './saved_object_provider_registry'; export type PluginClusterClient = Pick; export type AdminClusterClient$ = Observable; @@ -59,7 +59,7 @@ export type FindOptionsType = Pick< interface EventLogServiceCtorParams { esContext: EsContext; - savedObjectGetter: SavedObjectGetter; + savedObjectGetter: SavedObjectBulkGetter; spacesService?: SpacesServiceStart; request: KibanaRequest; } @@ -67,7 +67,7 @@ interface EventLogServiceCtorParams { // note that clusterClient may be null, indicating we can't write to ES export class EventLogClient implements IEventLogClient { private esContext: EsContext; - private savedObjectGetter: SavedObjectGetter; + private savedObjectGetter: SavedObjectBulkGetter; private spacesService?: SpacesServiceStart; private request: KibanaRequest; @@ -89,7 +89,7 @@ export class EventLogClient implements IEventLogClient { const namespace = space && this.spacesService?.spaceIdToNamespace(space.id); // verify the user has the required permissions to view this saved object - await this.savedObjectGetter(type, id); + await this.savedObjectGetter([{ type, id }]); return await this.esContext.esAdapter.queryEventsBySavedObject( this.esContext.esNames.indexPattern, @@ -99,4 +99,27 @@ export class EventLogClient implements IEventLogClient { findOptions ); } + + async findEventsBySavedObjects( + type: string, + ids: string[], + options?: Partial + ): Promise { + const findOptions = findOptionsSchema.validate(options ?? {}); + + const space = await this.spacesService?.getActiveSpace(this.request); + const namespace = space && this.spacesService?.spaceIdToNamespace(space.id); + + // verify the user has the required permissions to view this saved object + // await this.savedObjectGetter(type, id); + // TODO: + + return await this.esContext.esAdapter.queryEventsBySavedObjects( + this.esContext.esNames.indexPattern, + namespace, + type, + ids, + findOptions + ); + } } diff --git a/x-pack/plugins/event_log/server/plugin.ts b/x-pack/plugins/event_log/server/plugin.ts index d85de565b4d8e..194dcfc8aa621 100644 --- a/x-pack/plugins/event_log/server/plugin.ts +++ b/x-pack/plugins/event_log/server/plugin.ts @@ -135,7 +135,7 @@ export class Plugin implements CorePlugin { const client = core.savedObjects.getScopedClient(request); - return client.get.bind(client); + return client.bulkGet.bind(client); }); this.eventLogClientService = new EventLogClientService({ diff --git a/x-pack/plugins/event_log/server/saved_object_provider_registry.ts b/x-pack/plugins/event_log/server/saved_object_provider_registry.ts index 87a1da5dd6f4a..f263e1c84a029 100644 --- a/x-pack/plugins/event_log/server/saved_object_provider_registry.ts +++ b/x-pack/plugins/event_log/server/saved_object_provider_registry.ts @@ -5,7 +5,11 @@ */ import { i18n } from '@kbn/i18n'; -import { KibanaRequest, SavedObjectsClientContract } from 'src/core/server'; +import { + KibanaRequest, + SavedObjectsBulkGetObject, + SavedObjectsClientContract, +} from 'src/core/server'; import { fromNullable, getOrElse } from 'fp-ts/lib/Option'; import { pipe } from 'fp-ts/lib/pipeable'; @@ -13,7 +17,12 @@ import { pipe } from 'fp-ts/lib/pipeable'; export type SavedObjectGetter = ( ...params: Parameters ) => Promise; -export type SavedObjectProvider = (request: KibanaRequest) => SavedObjectGetter; + +export type SavedObjectBulkGetter = ( + ...params: Parameters +) => Promise; + +export type SavedObjectProvider = (request: KibanaRequest) => SavedObjectBulkGetter; export class SavedObjectProviderRegistry { private providers = new Map(); @@ -34,7 +43,7 @@ export class SavedObjectProviderRegistry { this.providers.set(type, provider); } - public getProvidersClient(request: KibanaRequest): SavedObjectGetter { + public getProvidersClient(request: KibanaRequest): SavedObjectBulkGetter { if (!this.defaultProvider) { throw new Error( i18n.translate( @@ -49,20 +58,23 @@ export class SavedObjectProviderRegistry { // `scopedProviders` is a cache of providers which are scoped t othe current request. // The client will only instantiate a provider on-demand and it will cache each // one to enable the request to reuse each provider. - const scopedProviders = new Map(); + + // would be nice to have a simple version support in API: + // curl -X GET "localhost:9200/my-index-000001/_mget?pretty" -H 'Content-Type: application/json' -d' { "ids" : ["1", "2"] } ' + const scopedProviders = new Map(); const defaultGetter = this.defaultProvider(request); - return (type: string, id: string) => { + return (objects: SavedObjectsBulkGetObject[] | undefined) => { const getter = pipe( - fromNullable(scopedProviders.get(type)), + fromNullable(scopedProviders.get('objects')), getOrElse(() => { - const client = this.providers.has(type) - ? this.providers.get(type)!(request) + const client = this.providers.has(objects![0].type) + ? this.providers.get(objects![0].type)!(request) : defaultGetter; - scopedProviders.set(type, client); + scopedProviders.set(objects![0].type, client); return client; }) ); - return getter(type, id); + return getter(objects); }; } } diff --git a/x-pack/plugins/event_log/server/types.ts b/x-pack/plugins/event_log/server/types.ts index 66030ee3910dc..03e9ce6338edf 100644 --- a/x-pack/plugins/event_log/server/types.ts +++ b/x-pack/plugins/event_log/server/types.ts @@ -56,6 +56,12 @@ export interface IEventLogClient { id: string, options?: Partial ): Promise; + + findEventsBySavedObjects( + type: string, + ids: string[], + options?: Partial + ): Promise; } export interface IEventLogger { From b36f0dbbd3d02cf23c5e2caeab3fcd368979f68c Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 6 Jan 2021 21:58:58 -0800 Subject: [PATCH 02/10] modofied event log findEventsBySavedObject to support bulk ids, renamed to findEventsBySavedObjectIds --- .../server/alerts_client/alerts_client.ts | 2 +- .../tests/get_alert_instance_summary.test.ts | 30 ++-- .../server/es/cluster_client_adapter.ts | 109 --------------- .../event_log/server/event_log_client.test.ts | 26 ++-- .../event_log/server/event_log_client.ts | 35 +---- x-pack/plugins/event_log/server/plugin.ts | 2 + .../event_log/server/routes/find.test.ts | 24 ++-- .../plugins/event_log/server/routes/find.ts | 4 +- .../server/routes/find_by_ids.test.ts | 128 ++++++++++++++++++ .../event_log/server/routes/find_by_ids.ts | 64 +++++++++ .../saved_object_provider_registry.test.ts | 6 +- .../server/saved_object_provider_registry.ts | 25 ++-- x-pack/plugins/event_log/server/types.ts | 8 +- 13 files changed, 258 insertions(+), 205 deletions(-) create mode 100644 x-pack/plugins/event_log/server/routes/find_by_ids.test.ts create mode 100644 x-pack/plugins/event_log/server/routes/find_by_ids.ts diff --git a/x-pack/plugins/alerts/server/alerts_client/alerts_client.ts b/x-pack/plugins/alerts/server/alerts_client/alerts_client.ts index e21fee4ce3d61..55cd335b0bee3 100644 --- a/x-pack/plugins/alerts/server/alerts_client/alerts_client.ts +++ b/x-pack/plugins/alerts/server/alerts_client/alerts_client.ts @@ -413,7 +413,7 @@ export class AlertsClient { this.logger.debug(`getAlertInstanceSummary(): search the event log for alert ${id}`); let events: IEvent[]; try { - const queryResults = await eventLogClient.findEventsBySavedObject('alert', id, { + const queryResults = await eventLogClient.findEventsBySavedObjectIds('alert', [id], { page: 1, per_page: 10000, start: parsedDateStart.toISOString(), diff --git a/x-pack/plugins/alerts/server/alerts_client/tests/get_alert_instance_summary.test.ts b/x-pack/plugins/alerts/server/alerts_client/tests/get_alert_instance_summary.test.ts index 555c316038daa..b7c00c1eff828 100644 --- a/x-pack/plugins/alerts/server/alerts_client/tests/get_alert_instance_summary.test.ts +++ b/x-pack/plugins/alerts/server/alerts_client/tests/get_alert_instance_summary.test.ts @@ -131,7 +131,7 @@ describe('getAlertInstanceSummary()', () => { total: events.length, data: events, }; - eventLogClient.findEventsBySavedObject.mockResolvedValueOnce(eventsResult); + eventLogClient.findEventsBySavedObjectIds.mockResolvedValueOnce(eventsResult); const dateStart = new Date(Date.now() - 60 * 1000).toISOString(); @@ -188,18 +188,18 @@ describe('getAlertInstanceSummary()', () => { test('calls saved objects and event log client with default params', async () => { unsecuredSavedObjectsClient.get.mockResolvedValueOnce(getAlertInstanceSummarySavedObject()); - eventLogClient.findEventsBySavedObject.mockResolvedValueOnce( + eventLogClient.findEventsBySavedObjectIds.mockResolvedValueOnce( AlertInstanceSummaryFindEventsResult ); await alertsClient.getAlertInstanceSummary({ id: '1' }); expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledTimes(1); - expect(eventLogClient.findEventsBySavedObject).toHaveBeenCalledTimes(1); - expect(eventLogClient.findEventsBySavedObject.mock.calls[0]).toMatchInlineSnapshot(` + expect(eventLogClient.findEventsBySavedObjectIds).toHaveBeenCalledTimes(1); + expect(eventLogClient.findEventsBySavedObjectIds.mock.calls[0]).toMatchInlineSnapshot(` Array [ "alert", - "1", + Array ["1"], Object { "end": "2019-02-12T21:01:22.479Z", "page": 1, @@ -210,7 +210,7 @@ describe('getAlertInstanceSummary()', () => { ] `); // calculate the expected start/end date for one test - const { start, end } = eventLogClient.findEventsBySavedObject.mock.calls[0][2]!; + const { start, end } = eventLogClient.findEventsBySavedObjectIds.mock.calls[0][2]!; expect(end).toBe(mockedDateString); const startMillis = Date.parse(start!); @@ -222,7 +222,7 @@ describe('getAlertInstanceSummary()', () => { test('calls event log client with start date', async () => { unsecuredSavedObjectsClient.get.mockResolvedValueOnce(getAlertInstanceSummarySavedObject()); - eventLogClient.findEventsBySavedObject.mockResolvedValueOnce( + eventLogClient.findEventsBySavedObjectIds.mockResolvedValueOnce( AlertInstanceSummaryFindEventsResult ); @@ -232,8 +232,8 @@ describe('getAlertInstanceSummary()', () => { await alertsClient.getAlertInstanceSummary({ id: '1', dateStart }); expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledTimes(1); - expect(eventLogClient.findEventsBySavedObject).toHaveBeenCalledTimes(1); - const { start, end } = eventLogClient.findEventsBySavedObject.mock.calls[0][2]!; + expect(eventLogClient.findEventsBySavedObjectIds).toHaveBeenCalledTimes(1); + const { start, end } = eventLogClient.findEventsBySavedObjectIds.mock.calls[0][2]!; expect({ start, end }).toMatchInlineSnapshot(` Object { @@ -245,7 +245,7 @@ describe('getAlertInstanceSummary()', () => { test('calls event log client with relative start date', async () => { unsecuredSavedObjectsClient.get.mockResolvedValueOnce(getAlertInstanceSummarySavedObject()); - eventLogClient.findEventsBySavedObject.mockResolvedValueOnce( + eventLogClient.findEventsBySavedObjectIds.mockResolvedValueOnce( AlertInstanceSummaryFindEventsResult ); @@ -253,8 +253,8 @@ describe('getAlertInstanceSummary()', () => { await alertsClient.getAlertInstanceSummary({ id: '1', dateStart }); expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledTimes(1); - expect(eventLogClient.findEventsBySavedObject).toHaveBeenCalledTimes(1); - const { start, end } = eventLogClient.findEventsBySavedObject.mock.calls[0][2]!; + expect(eventLogClient.findEventsBySavedObjectIds).toHaveBeenCalledTimes(1); + const { start, end } = eventLogClient.findEventsBySavedObjectIds.mock.calls[0][2]!; expect({ start, end }).toMatchInlineSnapshot(` Object { @@ -266,7 +266,7 @@ describe('getAlertInstanceSummary()', () => { test('invalid start date throws an error', async () => { unsecuredSavedObjectsClient.get.mockResolvedValueOnce(getAlertInstanceSummarySavedObject()); - eventLogClient.findEventsBySavedObject.mockResolvedValueOnce( + eventLogClient.findEventsBySavedObjectIds.mockResolvedValueOnce( AlertInstanceSummaryFindEventsResult ); @@ -280,7 +280,7 @@ describe('getAlertInstanceSummary()', () => { test('saved object get throws an error', async () => { unsecuredSavedObjectsClient.get.mockRejectedValueOnce(new Error('OMG!')); - eventLogClient.findEventsBySavedObject.mockResolvedValueOnce( + eventLogClient.findEventsBySavedObjectIds.mockResolvedValueOnce( AlertInstanceSummaryFindEventsResult ); @@ -291,7 +291,7 @@ describe('getAlertInstanceSummary()', () => { test('findEvents throws an error', async () => { unsecuredSavedObjectsClient.get.mockResolvedValueOnce(getAlertInstanceSummarySavedObject()); - eventLogClient.findEventsBySavedObject.mockRejectedValueOnce(new Error('OMG 2!')); + eventLogClient.findEventsBySavedObjectIds.mockRejectedValueOnce(new Error('OMG 2!')); // error eaten but logged await alertsClient.getAlertInstanceSummary({ id: '1' }); diff --git a/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts b/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts index 3e8ed5cf0353c..5d4c33f319fcc 100644 --- a/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts +++ b/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts @@ -194,115 +194,6 @@ export class ClusterClientAdapter { } } - public async queryEventsBySavedObject( - index: string, - namespace: string | undefined, - type: string, - id: string, - // eslint-disable-next-line @typescript-eslint/naming-convention - { page, per_page: perPage, start, end, sort_field, sort_order }: FindOptionsType - ): Promise { - const defaultNamespaceQuery = { - bool: { - must_not: { - exists: { - field: 'kibana.saved_objects.namespace', - }, - }, - }, - }; - const namedNamespaceQuery = { - term: { - 'kibana.saved_objects.namespace': { - value: namespace, - }, - }, - }; - const namespaceQuery = namespace === undefined ? defaultNamespaceQuery : namedNamespaceQuery; - - const body = { - size: perPage, - from: (page - 1) * perPage, - sort: { [sort_field]: { order: sort_order } }, - query: { - bool: { - must: reject( - [ - { - nested: { - path: 'kibana.saved_objects', - query: { - bool: { - must: [ - { - term: { - 'kibana.saved_objects.rel': { - value: SAVED_OBJECT_REL_PRIMARY, - }, - }, - }, - { - term: { - 'kibana.saved_objects.type': { - value: type, - }, - }, - }, - { - term: { - 'kibana.saved_objects.id': { - value: id, - }, - }, - }, - namespaceQuery, - ], - }, - }, - }, - }, - start && { - range: { - '@timestamp': { - gte: start, - }, - }, - }, - end && { - range: { - '@timestamp': { - lte: end, - }, - }, - }, - ], - isUndefined - ), - }, - }, - }; - - try { - const { - hits: { hits, total }, - }: ESSearchResponse = await this.callEs('search', { - index, - track_total_hits: true, - body, - }); - return { - page, - per_page: perPage, - total: total.value, - data: hits.map((hit) => hit._source) as IValidatedEvent[], - }; - } catch (err) { - throw new Error( - `querying for Event Log by for type "${type}" and id "${id}" failed with: ${err.message}` - ); - } - } - public async queryEventsBySavedObjects( index: string, namespace: string | undefined, diff --git a/x-pack/plugins/event_log/server/event_log_client.test.ts b/x-pack/plugins/event_log/server/event_log_client.test.ts index d6793be425585..68d5d07e07b35 100644 --- a/x-pack/plugins/event_log/server/event_log_client.test.ts +++ b/x-pack/plugins/event_log/server/event_log_client.test.ts @@ -11,7 +11,7 @@ import { merge } from 'lodash'; import moment from 'moment'; describe('EventLogStart', () => { - describe('findEventsBySavedObject', () => { + describe('findEventsBySavedObjectIds', () => { test('verifies that the user can access the specified saved object', async () => { const esContext = contextMock.create(); const savedObjectGetter = jest.fn(); @@ -29,7 +29,7 @@ describe('EventLogStart', () => { references: [], }); - await eventLogClient.findEventsBySavedObject('saved-object-type', 'saved-object-id'); + await eventLogClient.findEventsBySavedObjectIds('saved-object-type', ['saved-object-id']); expect(savedObjectGetter).toHaveBeenCalledWith('saved-object-type', 'saved-object-id'); }); @@ -48,7 +48,7 @@ describe('EventLogStart', () => { savedObjectGetter.mockRejectedValue(new Error('Fail')); expect( - eventLogClient.findEventsBySavedObject('saved-object-type', 'saved-object-id') + eventLogClient.findEventsBySavedObjectIds('saved-object-type', ['saved-object-id']) ).rejects.toMatchInlineSnapshot(`[Error: Fail]`); }); @@ -107,13 +107,13 @@ describe('EventLogStart', () => { total: expectedEvents.length, data: expectedEvents, }; - esContext.esAdapter.queryEventsBySavedObject.mockResolvedValue(result); + esContext.esAdapter.queryEventsBySavedObjects.mockResolvedValue(result); expect( - await eventLogClient.findEventsBySavedObject('saved-object-type', 'saved-object-id') + await eventLogClient.findEventsBySavedObjectIds('saved-object-type', ['saved-object-id']) ).toEqual(result); - expect(esContext.esAdapter.queryEventsBySavedObject).toHaveBeenCalledWith( + expect(esContext.esAdapter.queryEventsBySavedObjects).toHaveBeenCalledWith( esContext.esNames.indexPattern, undefined, 'saved-object-type', @@ -182,19 +182,19 @@ describe('EventLogStart', () => { total: expectedEvents.length, data: expectedEvents, }; - esContext.esAdapter.queryEventsBySavedObject.mockResolvedValue(result); + esContext.esAdapter.queryEventsBySavedObjects.mockResolvedValue(result); const start = moment().subtract(1, 'days').toISOString(); const end = moment().add(1, 'days').toISOString(); expect( - await eventLogClient.findEventsBySavedObject('saved-object-type', 'saved-object-id', { + await eventLogClient.findEventsBySavedObjectIds('saved-object-type', ['saved-object-id'], { start, end, }) ).toEqual(result); - expect(esContext.esAdapter.queryEventsBySavedObject).toHaveBeenCalledWith( + expect(esContext.esAdapter.queryEventsBySavedObjects).toHaveBeenCalledWith( esContext.esNames.indexPattern, undefined, 'saved-object-type', @@ -228,7 +228,7 @@ describe('EventLogStart', () => { references: [], }); - esContext.esAdapter.queryEventsBySavedObject.mockResolvedValue({ + esContext.esAdapter.queryEventsBySavedObjects.mockResolvedValue({ page: 0, per_page: 0, total: 0, @@ -236,7 +236,7 @@ describe('EventLogStart', () => { }); expect( - eventLogClient.findEventsBySavedObject('saved-object-type', 'saved-object-id', { + eventLogClient.findEventsBySavedObjectIds('saved-object-type', ['saved-object-id'], { start: 'not a date string', }) ).rejects.toMatchInlineSnapshot(`[Error: [start]: Invalid Date]`); @@ -260,7 +260,7 @@ describe('EventLogStart', () => { references: [], }); - esContext.esAdapter.queryEventsBySavedObject.mockResolvedValue({ + esContext.esAdapter.queryEventsBySavedObjects.mockResolvedValue({ page: 0, per_page: 0, total: 0, @@ -268,7 +268,7 @@ describe('EventLogStart', () => { }); expect( - eventLogClient.findEventsBySavedObject('saved-object-type', 'saved-object-id', { + eventLogClient.findEventsBySavedObjectIds('saved-object-type', ['saved-object-id'], { end: 'not a date string', }) ).rejects.toMatchInlineSnapshot(`[Error: [end]: Invalid Date]`); diff --git a/x-pack/plugins/event_log/server/event_log_client.ts b/x-pack/plugins/event_log/server/event_log_client.ts index 2c5c7dc84b844..63453c6327da2 100644 --- a/x-pack/plugins/event_log/server/event_log_client.ts +++ b/x-pack/plugins/event_log/server/event_log_client.ts @@ -12,7 +12,7 @@ import { SpacesServiceStart } from '../../spaces/server'; import { EsContext } from './es'; import { IEventLogClient } from './types'; import { QueryEventsBySavedObjectResult } from './es/cluster_client_adapter'; -import { SavedObjectBulkGetter, SavedObjectGetter } from './saved_object_provider_registry'; +import { SavedObjectBulkGetterResult } from './saved_object_provider_registry'; export type PluginClusterClient = Pick; export type AdminClusterClient$ = Observable; @@ -59,7 +59,7 @@ export type FindOptionsType = Pick< interface EventLogServiceCtorParams { esContext: EsContext; - savedObjectGetter: SavedObjectBulkGetter; + savedObjectGetter: SavedObjectBulkGetterResult; spacesService?: SpacesServiceStart; request: KibanaRequest; } @@ -67,7 +67,7 @@ interface EventLogServiceCtorParams { // note that clusterClient may be null, indicating we can't write to ES export class EventLogClient implements IEventLogClient { private esContext: EsContext; - private savedObjectGetter: SavedObjectBulkGetter; + private savedObjectGetter: SavedObjectBulkGetterResult; private spacesService?: SpacesServiceStart; private request: KibanaRequest; @@ -78,29 +78,7 @@ export class EventLogClient implements IEventLogClient { this.request = request; } - async findEventsBySavedObject( - type: string, - id: string, - options?: Partial - ): Promise { - const findOptions = findOptionsSchema.validate(options ?? {}); - - const space = await this.spacesService?.getActiveSpace(this.request); - const namespace = space && this.spacesService?.spaceIdToNamespace(space.id); - - // verify the user has the required permissions to view this saved object - await this.savedObjectGetter([{ type, id }]); - - return await this.esContext.esAdapter.queryEventsBySavedObject( - this.esContext.esNames.indexPattern, - namespace, - type, - id, - findOptions - ); - } - - async findEventsBySavedObjects( + async findEventsBySavedObjectIds( type: string, ids: string[], options?: Partial @@ -110,9 +88,8 @@ export class EventLogClient implements IEventLogClient { const space = await this.spacesService?.getActiveSpace(this.request); const namespace = space && this.spacesService?.spaceIdToNamespace(space.id); - // verify the user has the required permissions to view this saved object - // await this.savedObjectGetter(type, id); - // TODO: + // verify the user has the required permissions to view this saved objects + await this.savedObjectGetter(type, ids); return await this.esContext.esAdapter.queryEventsBySavedObjects( this.esContext.esNames.indexPattern, diff --git a/x-pack/plugins/event_log/server/plugin.ts b/x-pack/plugins/event_log/server/plugin.ts index 194dcfc8aa621..6471db7d5dd69 100644 --- a/x-pack/plugins/event_log/server/plugin.ts +++ b/x-pack/plugins/event_log/server/plugin.ts @@ -31,6 +31,7 @@ import { EventLogService } from './event_log_service'; import { createEsContext, EsContext } from './es'; import { EventLogClientService } from './event_log_start_service'; import { SavedObjectProviderRegistry } from './saved_object_provider_registry'; +import { findByIdsRoute } from './routes/find_by_ids'; export type PluginClusterClient = Pick; @@ -99,6 +100,7 @@ export class Plugin implements CorePlugin { total: events.length, data: events, }; - eventLogClient.findEventsBySavedObject.mockResolvedValueOnce(result); + eventLogClient.findEventsBySavedObjectIds.mockResolvedValueOnce(result); const [context, req, res] = mockHandlerArguments( eventLogClient, { - params: { id: '1', type: 'action' }, + params: { ids: ['1'], type: 'action' }, }, ['ok'] ); await handler(context, req, res); - expect(eventLogClient.findEventsBySavedObject).toHaveBeenCalledTimes(1); + expect(eventLogClient.findEventsBySavedObjectIds).toHaveBeenCalledTimes(1); - const [type, id] = eventLogClient.findEventsBySavedObject.mock.calls[0]; + const [type, ids] = eventLogClient.findEventsBySavedObjectIds.mock.calls[0]; expect(type).toEqual(`action`); - expect(id).toEqual(`1`); + expect(ids).toEqual(`[1]`); expect(res.ok).toHaveBeenCalledWith({ body: result, @@ -63,7 +63,7 @@ describe('find', () => { findRoute(router, systemLogger); const [, handler] = router.get.mock.calls[0]; - eventLogClient.findEventsBySavedObject.mockResolvedValueOnce({ + eventLogClient.findEventsBySavedObjectIds.mockResolvedValueOnce({ page: 0, per_page: 10, total: 0, @@ -73,7 +73,7 @@ describe('find', () => { const [context, req, res] = mockHandlerArguments( eventLogClient, { - params: { id: '1', type: 'action' }, + params: { ids: ['1'], type: 'action' }, query: { page: 3, per_page: 10 }, }, ['ok'] @@ -81,9 +81,9 @@ describe('find', () => { await handler(context, req, res); - expect(eventLogClient.findEventsBySavedObject).toHaveBeenCalledTimes(1); + expect(eventLogClient.findEventsBySavedObjectIds).toHaveBeenCalledTimes(1); - const [type, id, options] = eventLogClient.findEventsBySavedObject.mock.calls[0]; + const [type, id, options] = eventLogClient.findEventsBySavedObjectIds.mock.calls[0]; expect(type).toEqual(`action`); expect(id).toEqual(`1`); expect(options).toMatchObject({}); @@ -104,12 +104,12 @@ describe('find', () => { findRoute(router, systemLogger); const [, handler] = router.get.mock.calls[0]; - eventLogClient.findEventsBySavedObject.mockRejectedValueOnce(new Error('oof!')); + eventLogClient.findEventsBySavedObjectIds.mockRejectedValueOnce(new Error('oof!')); const [context, req, res] = mockHandlerArguments( eventLogClient, { - params: { id: '1', type: 'action' }, + params: { ids: ['1'], type: 'action' }, query: { page: 3, per_page: 10 }, }, ['ok'] @@ -119,7 +119,7 @@ describe('find', () => { expect(systemLogger.debug).toHaveBeenCalledTimes(1); expect(systemLogger.debug).toHaveBeenCalledWith( - 'error calling eventLog findEventsBySavedObject(action, 1, {"page":3,"per_page":10}): oof!' + 'error calling eventLog findEventsBySavedObjectIds(action, [1], {"page":3,"per_page":10}): oof!' ); }); }); diff --git a/x-pack/plugins/event_log/server/routes/find.ts b/x-pack/plugins/event_log/server/routes/find.ts index 3880ac2c10129..50785de72cfc5 100644 --- a/x-pack/plugins/event_log/server/routes/find.ts +++ b/x-pack/plugins/event_log/server/routes/find.ts @@ -47,10 +47,10 @@ export const findRoute = (router: IRouter, systemLogger: Logger) => { try { return res.ok({ - body: await eventLogClient.findEventsBySavedObject(type, id, query), + body: await eventLogClient.findEventsBySavedObjectIds(type, [id], query), }); } catch (err) { - const call = `findEventsBySavedObject(${type}, ${id}, ${JSON.stringify(query)})`; + const call = `findEventsBySavedObjectIds(${type}, [${id}], ${JSON.stringify(query)})`; systemLogger.debug(`error calling eventLog ${call}: ${err.message}`); return res.notFound(); } diff --git a/x-pack/plugins/event_log/server/routes/find_by_ids.test.ts b/x-pack/plugins/event_log/server/routes/find_by_ids.test.ts new file mode 100644 index 0000000000000..9704cbaafed11 --- /dev/null +++ b/x-pack/plugins/event_log/server/routes/find_by_ids.test.ts @@ -0,0 +1,128 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { httpServiceMock } from 'src/core/server/mocks'; +import { mockHandlerArguments, fakeEvent } from './_mock_handler_arguments'; +import { eventLogClientMock } from '../event_log_client.mock'; +import { loggingSystemMock } from 'src/core/server/mocks'; +import { findByIdsRoute } from './find_by_ids'; + +const eventLogClient = eventLogClientMock.create(); +const systemLogger = loggingSystemMock.createLogger(); + +beforeEach(() => { + jest.resetAllMocks(); +}); + +describe('find_by_ids', () => { + it('finds events with proper parameters', async () => { + const router = httpServiceMock.createRouter(); + + findByIdsRoute(router, systemLogger); + + const [config, handler] = router.post.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot(`"/api/event_log/{type}/_find"`); + + const events = [fakeEvent(), fakeEvent()]; + const result = { + page: 0, + per_page: 10, + total: events.length, + data: events, + }; + eventLogClient.findEventsBySavedObjectIds.mockResolvedValueOnce(result); + + const [context, req, res] = mockHandlerArguments( + eventLogClient, + { + params: { type: 'action' }, + body: { ids: ['1'] }, + }, + ['ok'] + ); + + await handler(context, req, res); + + expect(eventLogClient.findEventsBySavedObjectIds).toHaveBeenCalledTimes(1); + + const [type, ids] = eventLogClient.findEventsBySavedObjectIds.mock.calls[0]; + expect(type).toEqual(`action`); + expect(ids).toEqual(`1`); + + expect(res.ok).toHaveBeenCalledWith({ + body: result, + }); + }); + + it('supports optional pagination parameters', async () => { + const router = httpServiceMock.createRouter(); + + findByIdsRoute(router, systemLogger); + + const [, handler] = router.post.mock.calls[0]; + eventLogClient.findEventsBySavedObjectIds.mockResolvedValueOnce({ + page: 0, + per_page: 10, + total: 0, + data: [], + }); + + const [context, req, res] = mockHandlerArguments( + eventLogClient, + { + params: { type: 'action' }, + body: { ids: ['1'] }, + query: { page: 3, per_page: 10 }, + }, + ['ok'] + ); + + await handler(context, req, res); + + expect(eventLogClient.findEventsBySavedObjectIds).toHaveBeenCalledTimes(1); + + const [type, id, options] = eventLogClient.findEventsBySavedObjectIds.mock.calls[0]; + expect(type).toEqual(`action`); + expect(id).toEqual(`1`); + expect(options).toMatchObject({}); + + expect(res.ok).toHaveBeenCalledWith({ + body: { + page: 0, + per_page: 10, + total: 0, + data: [], + }, + }); + }); + + it('logs a warning when the query throws an error', async () => { + const router = httpServiceMock.createRouter(); + + findByIdsRoute(router, systemLogger); + + const [, handler] = router.get.mock.calls[0]; + eventLogClient.findEventsBySavedObjectIds.mockRejectedValueOnce(new Error('oof!')); + + const [context, req, res] = mockHandlerArguments( + eventLogClient, + { + params: { type: 'action' }, + body: { ids: ['1'] }, + query: { page: 3, per_page: 10 }, + }, + ['ok'] + ); + + await handler(context, req, res); + + expect(systemLogger.debug).toHaveBeenCalledTimes(1); + expect(systemLogger.debug).toHaveBeenCalledWith( + 'error calling eventLog findEventsBySavedObjectIds(action, [1], {"page":3,"per_page":10}): oof!' + ); + }); +}); diff --git a/x-pack/plugins/event_log/server/routes/find_by_ids.ts b/x-pack/plugins/event_log/server/routes/find_by_ids.ts new file mode 100644 index 0000000000000..83acc957d1e3a --- /dev/null +++ b/x-pack/plugins/event_log/server/routes/find_by_ids.ts @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { schema, TypeOf } from '@kbn/config-schema'; +import { + IRouter, + RequestHandlerContext, + KibanaRequest, + IKibanaResponse, + KibanaResponseFactory, + Logger, +} from 'src/core/server'; + +import { BASE_EVENT_LOG_API_PATH } from '../../common'; +import { findOptionsSchema, FindOptionsType } from '../event_log_client'; + +const paramSchema = schema.object({ + type: schema.string(), +}); + +const bodySchema = schema.object({ + ids: schema.arrayOf(schema.string(), { defaultValue: [] }), +}); + +export const findByIdsRoute = (router: IRouter, systemLogger: Logger) => { + router.post( + { + path: `${BASE_EVENT_LOG_API_PATH}/{type}/_find`, + validate: { + params: paramSchema, + query: findOptionsSchema, + body: bodySchema, + }, + }, + router.handleLegacyErrors(async function ( + context: RequestHandlerContext, + req: KibanaRequest, FindOptionsType, TypeOf>, + res: KibanaResponseFactory + ): Promise { + if (!context.eventLog) { + return res.badRequest({ body: 'RouteHandlerContext is not registered for eventLog' }); + } + const eventLogClient = context.eventLog.getEventLogClient(); + const { + params: { type }, + body: { ids }, + query, + } = req; + + try { + return res.ok({ + body: await eventLogClient.findEventsBySavedObjectIds(type, ids, query), + }); + } catch (err) { + const call = `findEventsBySavedObject(${type}, [${ids}], ${JSON.stringify(query)})`; + systemLogger.debug(`error calling eventLog ${call}: ${err.message}`); + return res.notFound(); + } + }) + ); +}; diff --git a/x-pack/plugins/event_log/server/saved_object_provider_registry.test.ts b/x-pack/plugins/event_log/server/saved_object_provider_registry.test.ts index 6a02d54c87514..7954edc3e9ab2 100644 --- a/x-pack/plugins/event_log/server/saved_object_provider_registry.test.ts +++ b/x-pack/plugins/event_log/server/saved_object_provider_registry.test.ts @@ -45,7 +45,7 @@ describe('SavedObjectProviderRegistry', () => { getter.mockResolvedValue(alert); - expect(await registry.getProvidersClient(request)('alert', alert.id)).toMatchObject(alert); + expect(await registry.getProvidersClient(request)('alert', [alert.id])).toMatchObject(alert); expect(provider).toHaveBeenCalledWith(request); expect(getter).toHaveBeenCalledWith('alert', alert.id); @@ -70,7 +70,9 @@ describe('SavedObjectProviderRegistry', () => { defaultProvider.mockReturnValue(getter); getter.mockResolvedValue(action); - expect(await registry.getProvidersClient(request)('action', action.id)).toMatchObject(action); + expect(await registry.getProvidersClient(request)('action', [action.id])).toMatchObject( + action + ); expect(getter).toHaveBeenCalledWith('action', action.id); expect(defaultProvider).toHaveBeenCalledWith(request); diff --git a/x-pack/plugins/event_log/server/saved_object_provider_registry.ts b/x-pack/plugins/event_log/server/saved_object_provider_registry.ts index f263e1c84a029..7496a6a2b2b56 100644 --- a/x-pack/plugins/event_log/server/saved_object_provider_registry.ts +++ b/x-pack/plugins/event_log/server/saved_object_provider_registry.ts @@ -5,23 +5,17 @@ */ import { i18n } from '@kbn/i18n'; -import { - KibanaRequest, - SavedObjectsBulkGetObject, - SavedObjectsClientContract, -} from 'src/core/server'; +import { KibanaRequest, SavedObjectsClientContract } from 'src/core/server'; import { fromNullable, getOrElse } from 'fp-ts/lib/Option'; import { pipe } from 'fp-ts/lib/pipeable'; -export type SavedObjectGetter = ( - ...params: Parameters -) => Promise; - export type SavedObjectBulkGetter = ( ...params: Parameters ) => Promise; +export type SavedObjectBulkGetterResult = (type: string, ids: string[]) => Promise; + export type SavedObjectProvider = (request: KibanaRequest) => SavedObjectBulkGetter; export class SavedObjectProviderRegistry { @@ -43,7 +37,7 @@ export class SavedObjectProviderRegistry { this.providers.set(type, provider); } - public getProvidersClient(request: KibanaRequest): SavedObjectBulkGetter { + public getProvidersClient(request: KibanaRequest): SavedObjectBulkGetterResult { if (!this.defaultProvider) { throw new Error( i18n.translate( @@ -63,14 +57,15 @@ export class SavedObjectProviderRegistry { // curl -X GET "localhost:9200/my-index-000001/_mget?pretty" -H 'Content-Type: application/json' -d' { "ids" : ["1", "2"] } ' const scopedProviders = new Map(); const defaultGetter = this.defaultProvider(request); - return (objects: SavedObjectsBulkGetObject[] | undefined) => { + return (type: string, ids: string[]) => { + const objects = [{ type, id: ids[0] }]; const getter = pipe( - fromNullable(scopedProviders.get('objects')), + fromNullable(scopedProviders.get(type)), getOrElse(() => { - const client = this.providers.has(objects![0].type) - ? this.providers.get(objects![0].type)!(request) + const client = this.providers.has(type) + ? this.providers.get(type)!(request) : defaultGetter; - scopedProviders.set(objects![0].type, client); + scopedProviders.set(type, client); return client; }) ); diff --git a/x-pack/plugins/event_log/server/types.ts b/x-pack/plugins/event_log/server/types.ts index 03e9ce6338edf..ff2ae81632923 100644 --- a/x-pack/plugins/event_log/server/types.ts +++ b/x-pack/plugins/event_log/server/types.ts @@ -51,13 +51,7 @@ export interface IEventLogClientService { } export interface IEventLogClient { - findEventsBySavedObject( - type: string, - id: string, - options?: Partial - ): Promise; - - findEventsBySavedObjects( + findEventsBySavedObjectIds( type: string, ids: string[], options?: Partial From c1d7a143055c2951de46d8aac93c4b0f5049f04f Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 7 Jan 2021 12:27:15 -0800 Subject: [PATCH 03/10] fixed faling typechecks --- x-pack/plugins/actions/server/plugin.ts | 7 ++++++- x-pack/plugins/alerts/server/plugin.ts | 7 ++++++- .../event_log/server/saved_object_provider_registry.ts | 9 ++++++++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/actions/server/plugin.ts b/x-pack/plugins/actions/server/plugin.ts index 7c41bf99af472..9b2109b3ef4fa 100644 --- a/x-pack/plugins/actions/server/plugin.ts +++ b/x-pack/plugins/actions/server/plugin.ts @@ -19,6 +19,7 @@ import { ElasticsearchServiceStart, ILegacyClusterClient, SavedObjectsClientContract, + SavedObjectsBulkGetObject, } from '../../../../src/core/server'; import { @@ -333,7 +334,11 @@ export class ActionsPlugin implements Plugin, Plugi this.eventLogService!.registerSavedObjectProvider('action', (request) => { const client = secureGetActionsClientWithRequest(request); - return async (type: string, id: string) => (await client).get({ id }); + return async (objects?: SavedObjectsBulkGetObject[]) => { + if (objects) { + Promise.all(objects.map(async (objectItem) => (await client).get({ id: objectItem.id }))); + } + }; }); const getScopedSavedObjectsClientWithoutAccessToActions = (request: KibanaRequest) => diff --git a/x-pack/plugins/alerts/server/plugin.ts b/x-pack/plugins/alerts/server/plugin.ts index d15ae0ca55ef9..5ba953c8d5260 100644 --- a/x-pack/plugins/alerts/server/plugin.ts +++ b/x-pack/plugins/alerts/server/plugin.ts @@ -33,6 +33,7 @@ import { ILegacyClusterClient, StatusServiceSetup, ServiceStatus, + SavedObjectsBulkGetObject, } from '../../../../src/core/server'; import { @@ -370,7 +371,11 @@ export class AlertingPlugin { this.eventLogService!.registerSavedObjectProvider('alert', (request) => { const client = getAlertsClientWithRequest(request); - return (type: string, id: string) => client.get({ id }); + return async (objects?: SavedObjectsBulkGetObject[]) => { + if (objects) { + Promise.all(objects.map(async (objectItem) => (await client).get({ id: objectItem.id }))); + } + }; }); scheduleAlertingTelemetry(this.telemetryLogger, plugins.taskManager); diff --git a/x-pack/plugins/event_log/server/saved_object_provider_registry.ts b/x-pack/plugins/event_log/server/saved_object_provider_registry.ts index 7496a6a2b2b56..ff9f1500b692d 100644 --- a/x-pack/plugins/event_log/server/saved_object_provider_registry.ts +++ b/x-pack/plugins/event_log/server/saved_object_provider_registry.ts @@ -10,6 +10,10 @@ import { KibanaRequest, SavedObjectsClientContract } from 'src/core/server'; import { fromNullable, getOrElse } from 'fp-ts/lib/Option'; import { pipe } from 'fp-ts/lib/pipeable'; +export type SavedObjectGetter = ( + ...params: Parameters +) => Promise; + export type SavedObjectBulkGetter = ( ...params: Parameters ) => Promise; @@ -58,7 +62,10 @@ export class SavedObjectProviderRegistry { const scopedProviders = new Map(); const defaultGetter = this.defaultProvider(request); return (type: string, ids: string[]) => { - const objects = [{ type, id: ids[0] }]; + const objects = ids.reduce( + (prev: Array<{ type: string; id: string }>, id) => [...prev, { type, id }], + [] + ); const getter = pipe( fromNullable(scopedProviders.get(type)), getOrElse(() => { From 9c1cbd6deab6bba38c71e4e5452f156fc9e63bae Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 7 Jan 2021 14:38:20 -0800 Subject: [PATCH 04/10] fixed crash on zpd/api/event_log/alert/84c00970-5130-11eb-9fa7/_find for non existing id --- x-pack/plugins/actions/server/plugin.ts | 11 ++++++----- x-pack/plugins/alerts/server/plugin.ts | 9 ++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/actions/server/plugin.ts b/x-pack/plugins/actions/server/plugin.ts index 9b2109b3ef4fa..83c2628f9a225 100644 --- a/x-pack/plugins/actions/server/plugin.ts +++ b/x-pack/plugins/actions/server/plugin.ts @@ -334,11 +334,12 @@ export class ActionsPlugin implements Plugin, Plugi this.eventLogService!.registerSavedObjectProvider('action', (request) => { const client = secureGetActionsClientWithRequest(request); - return async (objects?: SavedObjectsBulkGetObject[]) => { - if (objects) { - Promise.all(objects.map(async (objectItem) => (await client).get({ id: objectItem.id }))); - } - }; + return (objects?: SavedObjectsBulkGetObject[]) => + objects + ? Promise.all( + objects.map(async (objectItem) => await (await client).get({ id: objectItem.id })) + ) + : new Promise(() => []); }); const getScopedSavedObjectsClientWithoutAccessToActions = (request: KibanaRequest) => diff --git a/x-pack/plugins/alerts/server/plugin.ts b/x-pack/plugins/alerts/server/plugin.ts index 5ba953c8d5260..ddb8eb58a8430 100644 --- a/x-pack/plugins/alerts/server/plugin.ts +++ b/x-pack/plugins/alerts/server/plugin.ts @@ -371,11 +371,10 @@ export class AlertingPlugin { this.eventLogService!.registerSavedObjectProvider('alert', (request) => { const client = getAlertsClientWithRequest(request); - return async (objects?: SavedObjectsBulkGetObject[]) => { - if (objects) { - Promise.all(objects.map(async (objectItem) => (await client).get({ id: objectItem.id }))); - } - }; + return (objects?: SavedObjectsBulkGetObject[]) => + objects + ? Promise.all(objects.map(async (objectItem) => await client.get({ id: objectItem.id }))) + : new Promise(() => []); }); scheduleAlertingTelemetry(this.telemetryLogger, plugins.taskManager); From 410a1d304b8e4dfed6e739d02a5867985d2e3b7d Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 7 Jan 2021 15:02:04 -0800 Subject: [PATCH 05/10] fixed faling typechecks --- .../server/es/cluster_client_adapter.mock.ts | 2 +- .../server/es/cluster_client_adapter.test.ts | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/event_log/server/es/cluster_client_adapter.mock.ts b/x-pack/plugins/event_log/server/es/cluster_client_adapter.mock.ts index c1f60f2d63049..55871c975d353 100644 --- a/x-pack/plugins/event_log/server/es/cluster_client_adapter.mock.ts +++ b/x-pack/plugins/event_log/server/es/cluster_client_adapter.mock.ts @@ -16,7 +16,7 @@ const createClusterClientMock = () => { createIndexTemplate: jest.fn(), doesAliasExist: jest.fn(), createIndex: jest.fn(), - queryEventsBySavedObject: jest.fn(), + queryEventsBySavedObjects: jest.fn(), shutdown: jest.fn(), }; return mock; diff --git a/x-pack/plugins/event_log/server/es/cluster_client_adapter.test.ts b/x-pack/plugins/event_log/server/es/cluster_client_adapter.test.ts index 2b1d89f12be56..677b55a95d153 100644 --- a/x-pack/plugins/event_log/server/es/cluster_client_adapter.test.ts +++ b/x-pack/plugins/event_log/server/es/cluster_client_adapter.test.ts @@ -327,11 +327,11 @@ describe('queryEventsBySavedObject', () => { total: { value: 0 }, }, }); - await clusterClientAdapter.queryEventsBySavedObject( + await clusterClientAdapter.queryEventsBySavedObjects( 'index-name', 'namespace', 'saved-object-type', - 'saved-object-id', + ['saved-object-id'], DEFAULT_OPTIONS ); @@ -406,11 +406,11 @@ describe('queryEventsBySavedObject', () => { total: { value: 0 }, }, }); - await clusterClientAdapter.queryEventsBySavedObject( + await clusterClientAdapter.queryEventsBySavedObjects( 'index-name', undefined, 'saved-object-type', - 'saved-object-id', + ['saved-object-id'], DEFAULT_OPTIONS ); @@ -487,11 +487,11 @@ describe('queryEventsBySavedObject', () => { total: { value: 0 }, }, }); - await clusterClientAdapter.queryEventsBySavedObject( + await clusterClientAdapter.queryEventsBySavedObjects( 'index-name', 'namespace', 'saved-object-type', - 'saved-object-id', + ['saved-object-id'], { ...DEFAULT_OPTIONS, sort_field: 'event.end', sort_order: 'desc' } ); @@ -515,11 +515,11 @@ describe('queryEventsBySavedObject', () => { const start = '2020-07-08T00:52:28.350Z'; - await clusterClientAdapter.queryEventsBySavedObject( + await clusterClientAdapter.queryEventsBySavedObjects( 'index-name', 'namespace', 'saved-object-type', - 'saved-object-id', + ['saved-object-id'], { ...DEFAULT_OPTIONS, start } ); @@ -605,11 +605,11 @@ describe('queryEventsBySavedObject', () => { const start = '2020-07-08T00:52:28.350Z'; const end = '2020-07-08T00:00:00.000Z'; - await clusterClientAdapter.queryEventsBySavedObject( + await clusterClientAdapter.queryEventsBySavedObjects( 'index-name', 'namespace', 'saved-object-type', - 'saved-object-id', + ['saved-object-id'], { ...DEFAULT_OPTIONS, start, end } ); From bcae93ca77f05d0c16490db95fa23e5a0d1d9dbd Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 11 Jan 2021 09:14:16 -0800 Subject: [PATCH 06/10] fixed faling typechecks --- .../server/es/cluster_client_adapter.test.ts | 32 +++++++++---------- .../event_log/server/event_log_client.mock.ts | 2 +- .../event_log/server/event_log_client.test.ts | 6 ++-- .../event_log/server/routes/find.test.ts | 12 +++---- .../server/routes/find_by_ids.test.ts | 6 ++-- .../event_log/server/routes/find_by_ids.ts | 2 +- .../saved_object_provider_registry.test.ts | 4 +-- 7 files changed, 32 insertions(+), 32 deletions(-) diff --git a/x-pack/plugins/event_log/server/es/cluster_client_adapter.test.ts b/x-pack/plugins/event_log/server/es/cluster_client_adapter.test.ts index 677b55a95d153..545b3b1517145 100644 --- a/x-pack/plugins/event_log/server/es/cluster_client_adapter.test.ts +++ b/x-pack/plugins/event_log/server/es/cluster_client_adapter.test.ts @@ -365,10 +365,10 @@ describe('queryEventsBySavedObject', () => { }, }, Object { - "term": Object { - "kibana.saved_objects.id": Object { - "value": "saved-object-id", - }, + "terms": Object { + "kibana.saved_objects.id": Array [ + "saved-object-id", + ], }, }, Object { @@ -444,10 +444,10 @@ describe('queryEventsBySavedObject', () => { }, }, Object { - "term": Object { - "kibana.saved_objects.id": Object { - "value": "saved-object-id", - }, + "terms": Object { + "kibana.saved_objects.id": Array [ + "saved-object-id", + ], }, }, Object { @@ -553,10 +553,10 @@ describe('queryEventsBySavedObject', () => { }, }, Object { - "term": Object { - "kibana.saved_objects.id": Object { - "value": "saved-object-id", - }, + "terms": Object { + "kibana.saved_objects.id": Array [ + "saved-object-id", + ], }, }, Object { @@ -643,10 +643,10 @@ describe('queryEventsBySavedObject', () => { }, }, Object { - "term": Object { - "kibana.saved_objects.id": Object { - "value": "saved-object-id", - }, + "terms": Object { + "kibana.saved_objects.id": Array [ + "saved-object-id", + ], }, }, Object { diff --git a/x-pack/plugins/event_log/server/event_log_client.mock.ts b/x-pack/plugins/event_log/server/event_log_client.mock.ts index 31cab802555d0..65934d62a5a9a 100644 --- a/x-pack/plugins/event_log/server/event_log_client.mock.ts +++ b/x-pack/plugins/event_log/server/event_log_client.mock.ts @@ -8,7 +8,7 @@ import { IEventLogClient } from './types'; const createEventLogClientMock = () => { const mock: jest.Mocked = { - findEventsBySavedObject: jest.fn(), + findEventsBySavedObjectIds: jest.fn(), }; return mock; }; diff --git a/x-pack/plugins/event_log/server/event_log_client.test.ts b/x-pack/plugins/event_log/server/event_log_client.test.ts index 68d5d07e07b35..b9beebdc76db4 100644 --- a/x-pack/plugins/event_log/server/event_log_client.test.ts +++ b/x-pack/plugins/event_log/server/event_log_client.test.ts @@ -31,7 +31,7 @@ describe('EventLogStart', () => { await eventLogClient.findEventsBySavedObjectIds('saved-object-type', ['saved-object-id']); - expect(savedObjectGetter).toHaveBeenCalledWith('saved-object-type', 'saved-object-id'); + expect(savedObjectGetter).toHaveBeenCalledWith('saved-object-type', ['saved-object-id']); }); test('throws when the user doesnt have permission to access the specified saved object', async () => { @@ -117,7 +117,7 @@ describe('EventLogStart', () => { esContext.esNames.indexPattern, undefined, 'saved-object-type', - 'saved-object-id', + ['saved-object-id'], { page: 1, per_page: 10, @@ -198,7 +198,7 @@ describe('EventLogStart', () => { esContext.esNames.indexPattern, undefined, 'saved-object-type', - 'saved-object-id', + ['saved-object-id'], { page: 1, per_page: 10, diff --git a/x-pack/plugins/event_log/server/routes/find.test.ts b/x-pack/plugins/event_log/server/routes/find.test.ts index 391daddb72ab2..639995a7c3793 100644 --- a/x-pack/plugins/event_log/server/routes/find.test.ts +++ b/x-pack/plugins/event_log/server/routes/find.test.ts @@ -39,7 +39,7 @@ describe('find', () => { const [context, req, res] = mockHandlerArguments( eventLogClient, { - params: { ids: ['1'], type: 'action' }, + params: { id: '1', type: 'action' }, }, ['ok'] ); @@ -50,7 +50,7 @@ describe('find', () => { const [type, ids] = eventLogClient.findEventsBySavedObjectIds.mock.calls[0]; expect(type).toEqual(`action`); - expect(ids).toEqual(`[1]`); + expect(ids).toEqual(['1']); expect(res.ok).toHaveBeenCalledWith({ body: result, @@ -73,7 +73,7 @@ describe('find', () => { const [context, req, res] = mockHandlerArguments( eventLogClient, { - params: { ids: ['1'], type: 'action' }, + params: { id: '1', type: 'action' }, query: { page: 3, per_page: 10 }, }, ['ok'] @@ -83,9 +83,9 @@ describe('find', () => { expect(eventLogClient.findEventsBySavedObjectIds).toHaveBeenCalledTimes(1); - const [type, id, options] = eventLogClient.findEventsBySavedObjectIds.mock.calls[0]; + const [type, ids, options] = eventLogClient.findEventsBySavedObjectIds.mock.calls[0]; expect(type).toEqual(`action`); - expect(id).toEqual(`1`); + expect(ids).toEqual(['1']); expect(options).toMatchObject({}); expect(res.ok).toHaveBeenCalledWith({ @@ -109,7 +109,7 @@ describe('find', () => { const [context, req, res] = mockHandlerArguments( eventLogClient, { - params: { ids: ['1'], type: 'action' }, + params: { id: '1', type: 'action' }, query: { page: 3, per_page: 10 }, }, ['ok'] diff --git a/x-pack/plugins/event_log/server/routes/find_by_ids.test.ts b/x-pack/plugins/event_log/server/routes/find_by_ids.test.ts index 9704cbaafed11..f28c36164e95e 100644 --- a/x-pack/plugins/event_log/server/routes/find_by_ids.test.ts +++ b/x-pack/plugins/event_log/server/routes/find_by_ids.test.ts @@ -51,7 +51,7 @@ describe('find_by_ids', () => { const [type, ids] = eventLogClient.findEventsBySavedObjectIds.mock.calls[0]; expect(type).toEqual(`action`); - expect(ids).toEqual(`1`); + expect(ids).toEqual(['1']); expect(res.ok).toHaveBeenCalledWith({ body: result, @@ -87,7 +87,7 @@ describe('find_by_ids', () => { const [type, id, options] = eventLogClient.findEventsBySavedObjectIds.mock.calls[0]; expect(type).toEqual(`action`); - expect(id).toEqual(`1`); + expect(id).toEqual(['1']); expect(options).toMatchObject({}); expect(res.ok).toHaveBeenCalledWith({ @@ -105,7 +105,7 @@ describe('find_by_ids', () => { findByIdsRoute(router, systemLogger); - const [, handler] = router.get.mock.calls[0]; + const [, handler] = router.post.mock.calls[0]; eventLogClient.findEventsBySavedObjectIds.mockRejectedValueOnce(new Error('oof!')); const [context, req, res] = mockHandlerArguments( diff --git a/x-pack/plugins/event_log/server/routes/find_by_ids.ts b/x-pack/plugins/event_log/server/routes/find_by_ids.ts index 83acc957d1e3a..a7ee0f35ac59e 100644 --- a/x-pack/plugins/event_log/server/routes/find_by_ids.ts +++ b/x-pack/plugins/event_log/server/routes/find_by_ids.ts @@ -55,7 +55,7 @@ export const findByIdsRoute = (router: IRouter, systemLogger: Logger) => { body: await eventLogClient.findEventsBySavedObjectIds(type, ids, query), }); } catch (err) { - const call = `findEventsBySavedObject(${type}, [${ids}], ${JSON.stringify(query)})`; + const call = `findEventsBySavedObjectIds(${type}, [${ids}], ${JSON.stringify(query)})`; systemLogger.debug(`error calling eventLog ${call}: ${err.message}`); return res.notFound(); } diff --git a/x-pack/plugins/event_log/server/saved_object_provider_registry.test.ts b/x-pack/plugins/event_log/server/saved_object_provider_registry.test.ts index 7954edc3e9ab2..f6d42a6113518 100644 --- a/x-pack/plugins/event_log/server/saved_object_provider_registry.test.ts +++ b/x-pack/plugins/event_log/server/saved_object_provider_registry.test.ts @@ -48,7 +48,7 @@ describe('SavedObjectProviderRegistry', () => { expect(await registry.getProvidersClient(request)('alert', [alert.id])).toMatchObject(alert); expect(provider).toHaveBeenCalledWith(request); - expect(getter).toHaveBeenCalledWith('alert', alert.id); + expect(getter).toHaveBeenCalledWith([{ id: alert.id, type: 'alert' }]); }); test('should get SavedObject using the default provider for unregistered types', async () => { @@ -74,7 +74,7 @@ describe('SavedObjectProviderRegistry', () => { action ); - expect(getter).toHaveBeenCalledWith('action', action.id); + expect(getter).toHaveBeenCalledWith([{ id: action.id, type: 'action' }]); expect(defaultProvider).toHaveBeenCalledWith(request); }); }); From efa68c2bfa42fd822d34eccdb011e48b5e9cedcf Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 11 Jan 2021 09:21:48 -0800 Subject: [PATCH 07/10] fixed due to comments --- x-pack/plugins/alerts/server/plugin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/alerts/server/plugin.ts b/x-pack/plugins/alerts/server/plugin.ts index ddb8eb58a8430..cb165fa56d046 100644 --- a/x-pack/plugins/alerts/server/plugin.ts +++ b/x-pack/plugins/alerts/server/plugin.ts @@ -374,7 +374,7 @@ export class AlertingPlugin { return (objects?: SavedObjectsBulkGetObject[]) => objects ? Promise.all(objects.map(async (objectItem) => await client.get({ id: objectItem.id }))) - : new Promise(() => []); + : Promise.resolve([]); }); scheduleAlertingTelemetry(this.telemetryLogger, plugins.taskManager); From 04586c89528f8325f4887d3efd79f378353a5768 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 11 Jan 2021 09:23:54 -0800 Subject: [PATCH 08/10] fixed due to comments --- x-pack/plugins/actions/server/plugin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/actions/server/plugin.ts b/x-pack/plugins/actions/server/plugin.ts index 83c2628f9a225..133e5f9c6aa2c 100644 --- a/x-pack/plugins/actions/server/plugin.ts +++ b/x-pack/plugins/actions/server/plugin.ts @@ -339,7 +339,7 @@ export class ActionsPlugin implements Plugin, Plugi ? Promise.all( objects.map(async (objectItem) => await (await client).get({ id: objectItem.id })) ) - : new Promise(() => []); + : Promise.resolve([]); }); const getScopedSavedObjectsClientWithoutAccessToActions = (request: KibanaRequest) => From a4769331057be247b127224cd74741daa124a42e Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 11 Jan 2021 11:01:55 -0800 Subject: [PATCH 09/10] fixed failing test --- .../alerts_client/tests/get_alert_instance_summary.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/alerts/server/alerts_client/tests/get_alert_instance_summary.test.ts b/x-pack/plugins/alerts/server/alerts_client/tests/get_alert_instance_summary.test.ts index b7c00c1eff828..6c0612df030dd 100644 --- a/x-pack/plugins/alerts/server/alerts_client/tests/get_alert_instance_summary.test.ts +++ b/x-pack/plugins/alerts/server/alerts_client/tests/get_alert_instance_summary.test.ts @@ -199,7 +199,9 @@ describe('getAlertInstanceSummary()', () => { expect(eventLogClient.findEventsBySavedObjectIds.mock.calls[0]).toMatchInlineSnapshot(` Array [ "alert", - Array ["1"], + Array [ + "1", + ], Object { "end": "2019-02-12T21:01:22.479Z", "page": 1, From eae966412d72b602d546d5f75b5782c453f6d583 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Tue, 12 Jan 2021 13:31:21 -0800 Subject: [PATCH 10/10] fixed due to comments --- .../event_log/server/saved_object_provider_registry.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/x-pack/plugins/event_log/server/saved_object_provider_registry.ts b/x-pack/plugins/event_log/server/saved_object_provider_registry.ts index ff9f1500b692d..3c3e93afec394 100644 --- a/x-pack/plugins/event_log/server/saved_object_provider_registry.ts +++ b/x-pack/plugins/event_log/server/saved_object_provider_registry.ts @@ -62,10 +62,7 @@ export class SavedObjectProviderRegistry { const scopedProviders = new Map(); const defaultGetter = this.defaultProvider(request); return (type: string, ids: string[]) => { - const objects = ids.reduce( - (prev: Array<{ type: string; id: string }>, id) => [...prev, { type, id }], - [] - ); + const objects = ids.map((id: string) => ({ type, id })); const getter = pipe( fromNullable(scopedProviders.get(type)), getOrElse(() => {