Skip to content

Commit

Permalink
[EventLog] Added event log API to get events for multiple saved objec…
Browse files Browse the repository at this point in the history
…ts. (#87596)

* Added alerting API to get all active instances

* modofied event log findEventsBySavedObject to support bulk ids, renamed to findEventsBySavedObjectIds

* fixed faling typechecks

* fixed crash on zpd/api/event_log/alert/84c00970-5130-11eb-9fa7/_find for non existing id

* fixed faling typechecks

* fixed faling typechecks

* fixed due to comments

* fixed due to comments

* fixed failing test

* fixed due to comments
  • Loading branch information
YulNaumenko committed Jan 13, 2021
1 parent 5e4402c commit fb67443
Show file tree
Hide file tree
Showing 18 changed files with 320 additions and 102 deletions.
8 changes: 7 additions & 1 deletion x-pack/plugins/actions/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
ElasticsearchServiceStart,
ILegacyClusterClient,
SavedObjectsClientContract,
SavedObjectsBulkGetObject,
} from '../../../../src/core/server';

import {
Expand Down Expand Up @@ -333,7 +334,12 @@ export class ActionsPlugin implements Plugin<Promise<PluginSetupContract>, Plugi

this.eventLogService!.registerSavedObjectProvider('action', (request) => {
const client = secureGetActionsClientWithRequest(request);
return async (type: string, id: string) => (await client).get({ id });
return (objects?: SavedObjectsBulkGetObject[]) =>
objects
? Promise.all(
objects.map(async (objectItem) => await (await client).get({ id: objectItem.id }))
)
: Promise.resolve([]);
});

const getScopedSavedObjectsClientWithoutAccessToActions = (request: KibanaRequest) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,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(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -188,18 +188,20 @@ 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,
Expand All @@ -210,7 +212,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!);
Expand All @@ -222,7 +224,7 @@ describe('getAlertInstanceSummary()', () => {

test('calls event log client with start date', async () => {
unsecuredSavedObjectsClient.get.mockResolvedValueOnce(getAlertInstanceSummarySavedObject());
eventLogClient.findEventsBySavedObject.mockResolvedValueOnce(
eventLogClient.findEventsBySavedObjectIds.mockResolvedValueOnce(
AlertInstanceSummaryFindEventsResult
);

Expand All @@ -232,8 +234,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 {
Expand All @@ -245,16 +247,16 @@ describe('getAlertInstanceSummary()', () => {

test('calls event log client with relative start date', async () => {
unsecuredSavedObjectsClient.get.mockResolvedValueOnce(getAlertInstanceSummarySavedObject());
eventLogClient.findEventsBySavedObject.mockResolvedValueOnce(
eventLogClient.findEventsBySavedObjectIds.mockResolvedValueOnce(
AlertInstanceSummaryFindEventsResult
);

const dateStart = '2m';
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 {
Expand All @@ -266,7 +268,7 @@ describe('getAlertInstanceSummary()', () => {

test('invalid start date throws an error', async () => {
unsecuredSavedObjectsClient.get.mockResolvedValueOnce(getAlertInstanceSummarySavedObject());
eventLogClient.findEventsBySavedObject.mockResolvedValueOnce(
eventLogClient.findEventsBySavedObjectIds.mockResolvedValueOnce(
AlertInstanceSummaryFindEventsResult
);

Expand All @@ -280,7 +282,7 @@ describe('getAlertInstanceSummary()', () => {

test('saved object get throws an error', async () => {
unsecuredSavedObjectsClient.get.mockRejectedValueOnce(new Error('OMG!'));
eventLogClient.findEventsBySavedObject.mockResolvedValueOnce(
eventLogClient.findEventsBySavedObjectIds.mockResolvedValueOnce(
AlertInstanceSummaryFindEventsResult
);

Expand All @@ -291,7 +293,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' });
Expand Down
6 changes: 5 additions & 1 deletion x-pack/plugins/alerts/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
ILegacyClusterClient,
StatusServiceSetup,
ServiceStatus,
SavedObjectsBulkGetObject,
} from '../../../../src/core/server';

import {
Expand Down Expand Up @@ -370,7 +371,10 @@ export class AlertingPlugin {

this.eventLogService!.registerSavedObjectProvider('alert', (request) => {
const client = getAlertsClientWithRequest(request);
return (type: string, id: string) => client.get({ id });
return (objects?: SavedObjectsBulkGetObject[]) =>
objects
? Promise.all(objects.map(async (objectItem) => await client.get({ id: objectItem.id })))
: Promise.resolve([]);
});

scheduleAlertingTelemetry(this.telemetryLogger, plugins.taskManager);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
52 changes: 26 additions & 26 deletions x-pack/plugins/event_log/server/es/cluster_client_adapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
);

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
);

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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' }
);

Expand All @@ -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 }
);

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 }
);

Expand Down Expand Up @@ -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 {
Expand Down
13 changes: 6 additions & 7 deletions x-pack/plugins/event_log/server/es/cluster_client_adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,11 +194,11 @@ export class ClusterClientAdapter {
}
}

public async queryEventsBySavedObject(
public async queryEventsBySavedObjects(
index: string,
namespace: string | undefined,
type: string,
id: string,
ids: string[],
// eslint-disable-next-line @typescript-eslint/naming-convention
{ page, per_page: perPage, start, end, sort_field, sort_order }: FindOptionsType
): Promise<QueryEventsBySavedObjectResult> {
Expand Down Expand Up @@ -249,10 +249,9 @@ export class ClusterClientAdapter {
},
},
{
term: {
'kibana.saved_objects.id': {
value: id,
},
terms: {
// default maximum of 65,536 terms, configurable by index.max_terms_count
'kibana.saved_objects.id': ids,
},
},
namespaceQuery,
Expand Down Expand Up @@ -298,7 +297,7 @@ export class ClusterClientAdapter {
};
} catch (err) {
throw new Error(
`querying for Event Log by for type "${type}" and id "${id}" failed with: ${err.message}`
`querying for Event Log by for type "${type}" and ids "${ids}" failed with: ${err.message}`
);
}
}
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/event_log/server/event_log_client.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { IEventLogClient } from './types';

const createEventLogClientMock = () => {
const mock: jest.Mocked<IEventLogClient> = {
findEventsBySavedObject: jest.fn(),
findEventsBySavedObjectIds: jest.fn(),
};
return mock;
};
Expand Down
Loading

0 comments on commit fb67443

Please sign in to comment.