Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[EventLog] Added event log API to get events for multiple saved objects. #87596

Merged
merged 12 commits into from
Jan 13, 2021
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 }))
)
: new Promise(() => []);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
: new Promise(() => []);
: Promise.resolve([])

I don't think the new Promise(() => []) is doing what we want - it seems to return a promise that never resolves, but I think we want a promise that resolves to an empty array instead.

Same pattern is in the alerts plugin ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even better, current PR can close the opened issue #70856 and the alerting related work will be a separate PR

});

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

Expand All @@ -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 {
Expand All @@ -245,16 +245,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 +266,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 +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
);

Expand All @@ -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' });
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 })))
: new Promise(() => []);
});

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
20 changes: 10 additions & 10 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 @@ -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 @@ -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 @@ -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
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
26 changes: 13 additions & 13 deletions x-pack/plugins/event_log/server/event_log_client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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');
});
Expand All @@ -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]`);
});

Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -228,15 +228,15 @@ describe('EventLogStart', () => {
references: [],
});

esContext.esAdapter.queryEventsBySavedObject.mockResolvedValue({
esContext.esAdapter.queryEventsBySavedObjects.mockResolvedValue({
page: 0,
per_page: 0,
total: 0,
data: [],
});

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]`);
Expand All @@ -260,15 +260,15 @@ describe('EventLogStart', () => {
references: [],
});

esContext.esAdapter.queryEventsBySavedObject.mockResolvedValue({
esContext.esAdapter.queryEventsBySavedObjects.mockResolvedValue({
page: 0,
per_page: 0,
total: 0,
data: [],
});

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]`);
Expand Down
Loading