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

[Event log] Use Alerts client & Actions client when fetching these types of SOs #73257

Merged
merged 11 commits into from
Aug 11, 2020
Merged
1 change: 1 addition & 0 deletions x-pack/.i18nrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"xpack.actions": "plugins/actions",
"xpack.uiActionsEnhanced": ["plugins/ui_actions_enhanced", "examples/ui_actions_enhanced_examples"],
"xpack.alerts": "plugins/alerts",
"xpack.eventLog": "plugins/event_log",
"xpack.alertingBuiltins": "plugins/alerting_builtins",
"xpack.apm": ["legacy/plugins/apm", "plugins/apm"],
"xpack.beatsManagement": ["legacy/plugins/beats_management", "plugins/beats_management"],
Expand Down
7 changes: 7 additions & 0 deletions x-pack/plugins/actions/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ export class ActionsPlugin implements Plugin<Promise<PluginSetupContract>, Plugi
private licenseState: ILicenseState | null = null;
private spaces?: SpacesServiceSetup;
private security?: SecurityPluginSetup;
private eventLogService?: IEventLogService;
private eventLogger?: IEventLogger;
private isESOUsingEphemeralEncryptionKey?: boolean;
private readonly telemetryLogger: Logger;
Expand Down Expand Up @@ -160,6 +161,7 @@ export class ActionsPlugin implements Plugin<Promise<PluginSetupContract>, Plugi
plugins.features.registerFeature(ACTIONS_FEATURE);
setupSavedObjects(core.savedObjects, plugins.encryptedSavedObjects);

this.eventLogService = plugins.eventLog;
plugins.eventLog.registerProviderActions(EVENT_LOG_PROVIDER, Object.values(EVENT_LOG_ACTIONS));
this.eventLogger = plugins.eventLog.getLogger({
event: { provider: EVENT_LOG_PROVIDER },
Expand Down Expand Up @@ -295,6 +297,11 @@ export class ActionsPlugin implements Plugin<Promise<PluginSetupContract>, Plugi
});
};

this.eventLogService!.registerSavedObjectProvider('action', (request) => {
const client = getActionsClientWithRequest(request);
return async (type: string, id: string) => (await client).get({ id });
});

const getScopedSavedObjectsClientWithoutAccessToActions = (request: KibanaRequest) =>
core.savedObjects.getScopedClient(request);

Expand Down
7 changes: 7 additions & 0 deletions x-pack/plugins/alerts/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ export class AlertingPlugin {
private readonly alertsClientFactory: AlertsClientFactory;
private readonly telemetryLogger: Logger;
private readonly kibanaIndex: Promise<string>;
private eventLogService?: IEventLogService;
private eventLogger?: IEventLogger;

constructor(initializerContext: PluginInitializerContext) {
Expand Down Expand Up @@ -150,6 +151,7 @@ export class AlertingPlugin {

setupSavedObjects(core.savedObjects, plugins.encryptedSavedObjects);

this.eventLogService = plugins.eventLog;
plugins.eventLog.registerProviderActions(EVENT_LOG_PROVIDER, Object.values(EVENT_LOG_ACTIONS));
this.eventLogger = plugins.eventLog.getLogger({
event: { provider: EVENT_LOG_PROVIDER },
Expand Down Expand Up @@ -255,6 +257,11 @@ export class AlertingPlugin {
eventLogger: this.eventLogger!,
});

this.eventLogService!.registerSavedObjectProvider('alert', (request) => {
const client = getAlertsClientWithRequest(request);
return (type: string, id: string) => client.get({ id });
});

scheduleAlertingTelemetry(this.telemetryLogger, plugins.taskManager);

return {
Expand Down
55 changes: 33 additions & 22 deletions x-pack/plugins/event_log/server/event_log_client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,22 @@
import { KibanaRequest } from 'src/core/server';
import { EventLogClient } from './event_log_client';
import { contextMock } from './es/context.mock';
import { savedObjectsClientMock } from 'src/core/server/mocks';
import { merge } from 'lodash';
import moment from 'moment';

describe('EventLogStart', () => {
describe('findEventsBySavedObject', () => {
test('verifies that the user can access the specified saved object', async () => {
const esContext = contextMock.create();
const savedObjectsClient = savedObjectsClientMock.create();
const savedObjectGetter = jest.fn();

const eventLogClient = new EventLogClient({
esContext,
savedObjectsClient,
savedObjectGetter,
request: FakeRequest(),
});

savedObjectsClient.get.mockResolvedValueOnce({
savedObjectGetter.mockResolvedValueOnce({
id: 'saved-object-id',
type: 'saved-object-type',
attributes: {},
Expand All @@ -31,19 +31,21 @@ describe('EventLogStart', () => {

await eventLogClient.findEventsBySavedObject('saved-object-type', 'saved-object-id');

expect(savedObjectsClient.get).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 () => {
const esContext = contextMock.create();
const savedObjectsClient = savedObjectsClientMock.create();

const savedObjectGetter = jest.fn();

const eventLogClient = new EventLogClient({
esContext,
savedObjectsClient,
savedObjectGetter,
request: FakeRequest(),
});

savedObjectsClient.get.mockRejectedValue(new Error('Fail'));
savedObjectGetter.mockRejectedValue(new Error('Fail'));

expect(
eventLogClient.findEventsBySavedObject('saved-object-type', 'saved-object-id')
Expand All @@ -52,14 +54,16 @@ describe('EventLogStart', () => {

test('fetches all event that reference the saved object', async () => {
const esContext = contextMock.create();
const savedObjectsClient = savedObjectsClientMock.create();

const savedObjectGetter = jest.fn();

const eventLogClient = new EventLogClient({
esContext,
savedObjectsClient,
savedObjectGetter,
request: FakeRequest(),
});

savedObjectsClient.get.mockResolvedValueOnce({
savedObjectGetter.mockResolvedValueOnce({
id: 'saved-object-id',
type: 'saved-object-type',
attributes: {},
Expand Down Expand Up @@ -125,14 +129,16 @@ describe('EventLogStart', () => {

test('fetches all events in time frame that reference the saved object', async () => {
const esContext = contextMock.create();
const savedObjectsClient = savedObjectsClientMock.create();

const savedObjectGetter = jest.fn();

const eventLogClient = new EventLogClient({
esContext,
savedObjectsClient,
savedObjectGetter,
request: FakeRequest(),
});

savedObjectsClient.get.mockResolvedValueOnce({
savedObjectGetter.mockResolvedValueOnce({
id: 'saved-object-id',
type: 'saved-object-type',
attributes: {},
Expand Down Expand Up @@ -206,14 +212,16 @@ describe('EventLogStart', () => {

test('validates that the start date is valid', async () => {
const esContext = contextMock.create();
const savedObjectsClient = savedObjectsClientMock.create();

const savedObjectGetter = jest.fn();

const eventLogClient = new EventLogClient({
esContext,
savedObjectsClient,
savedObjectGetter,
request: FakeRequest(),
});

savedObjectsClient.get.mockResolvedValueOnce({
savedObjectGetter.mockResolvedValueOnce({
id: 'saved-object-id',
type: 'saved-object-type',
attributes: {},
Expand All @@ -236,14 +244,16 @@ describe('EventLogStart', () => {

test('validates that the end date is valid', async () => {
const esContext = contextMock.create();
const savedObjectsClient = savedObjectsClientMock.create();

const savedObjectGetter = jest.fn();

const eventLogClient = new EventLogClient({
esContext,
savedObjectsClient,
savedObjectGetter,
request: FakeRequest(),
});

savedObjectsClient.get.mockResolvedValueOnce({
savedObjectGetter.mockResolvedValueOnce({
id: 'saved-object-id',
type: 'saved-object-type',
attributes: {},
Expand Down Expand Up @@ -297,7 +307,8 @@ function fakeEvent(overrides = {}) {
}

function FakeRequest(): KibanaRequest {
const savedObjectsClient = savedObjectsClientMock.create();
const savedObjectGetter = jest.fn();

return ({
headers: {},
getBasePath: () => '',
Expand All @@ -311,6 +322,6 @@ function FakeRequest(): KibanaRequest {
url: '/',
},
},
getSavedObjectsClient: () => savedObjectsClient,
getSavedObjectsClient: () => savedObjectGetter,
} as unknown) as KibanaRequest;
}
18 changes: 7 additions & 11 deletions x-pack/plugins/event_log/server/event_log_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@

import { Observable } from 'rxjs';
import { schema, TypeOf } from '@kbn/config-schema';
import { LegacyClusterClient, SavedObjectsClientContract, KibanaRequest } from 'src/core/server';
import { LegacyClusterClient, KibanaRequest } from 'src/core/server';
import { SpacesServiceSetup } 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';
export type PluginClusterClient = Pick<LegacyClusterClient, 'callAsInternalUser' | 'asScoped'>;
export type AdminClusterClient$ = Observable<PluginClusterClient>;

Expand Down Expand Up @@ -58,26 +59,21 @@ export type FindOptionsType = Pick<

interface EventLogServiceCtorParams {
esContext: EsContext;
savedObjectsClient: SavedObjectsClientContract;
savedObjectGetter: SavedObjectGetter;
spacesService?: SpacesServiceSetup;
request: KibanaRequest;
}

// note that clusterClient may be null, indicating we can't write to ES
export class EventLogClient implements IEventLogClient {
private esContext: EsContext;
private savedObjectsClient: SavedObjectsClientContract;
private savedObjectGetter: SavedObjectGetter;
private spacesService?: SpacesServiceSetup;
private request: KibanaRequest;

constructor({
esContext,
savedObjectsClient,
spacesService,
request,
}: EventLogServiceCtorParams) {
constructor({ esContext, savedObjectGetter, spacesService, request }: EventLogServiceCtorParams) {
this.esContext = esContext;
this.savedObjectsClient = savedObjectsClient;
this.savedObjectGetter = savedObjectGetter;
this.spacesService = spacesService;
this.request = request;
}
Expand All @@ -93,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.savedObjectsClient.get(type, id);
await this.savedObjectGetter(type, id);

return await this.esContext.esAdapter.queryEventsBySavedObject(
this.esContext.esNames.alias,
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/event_log/server/event_log_service.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const createEventLogServiceMock = () => {
registerProviderActions: jest.fn(),
isProviderActionRegistered: jest.fn(),
getProviderActions: jest.fn(),
registerSavedObjectProvider: jest.fn(),
getLogger: jest.fn().mockReturnValue(eventLoggerMock.create()),
};
return mock;
Expand Down
25 changes: 25 additions & 0 deletions x-pack/plugins/event_log/server/event_log_service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ import { IEventLogConfig } from './types';
import { EventLogService } from './event_log_service';
import { contextMock } from './es/context.mock';
import { loggingSystemMock } from 'src/core/server/mocks';
import { savedObjectProviderRegistryMock } from './saved_object_provider_registry.mock';

const loggingService = loggingSystemMock.create();
const systemLogger = loggingService.get();
const savedObjectProviderRegistry = savedObjectProviderRegistryMock.create();

describe('EventLogService', () => {
gmmorris marked this conversation as resolved.
Show resolved Hide resolved
const esContext = contextMock.create();
Expand All @@ -21,6 +23,7 @@ describe('EventLogService', () => {
esContext,
systemLogger,
kibanaUUID: '42',
savedObjectProviderRegistry,
config: {
enabled,
logEntries,
Expand Down Expand Up @@ -65,6 +68,7 @@ describe('EventLogService', () => {
esContext,
systemLogger,
kibanaUUID: '42',
savedObjectProviderRegistry,
config: {
enabled: true,
logEntries: true,
Expand Down Expand Up @@ -102,6 +106,7 @@ describe('EventLogService', () => {
esContext,
systemLogger,
kibanaUUID: '42',
savedObjectProviderRegistry,
config: {
enabled: true,
logEntries: true,
Expand All @@ -112,4 +117,24 @@ describe('EventLogService', () => {
const eventLogger = service.getLogger({});
expect(eventLogger).toBeTruthy();
});

describe('registerSavedObjectProvider', () => {
test('register SavedObject Providers in the registry', () => {
const params = {
esContext,
systemLogger,
kibanaUUID: '42',
savedObjectProviderRegistry,
config: {
enabled: true,
logEntries: true,
indexEntries: true,
},
};
const service = new EventLogService(params);
const provider = jest.fn();
service.registerSavedObjectProvider('myType', provider);
expect(savedObjectProviderRegistry.registerProvider).toHaveBeenCalledWith('myType', provider);
});
});
});
16 changes: 15 additions & 1 deletion x-pack/plugins/event_log/server/event_log_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Plugin } from './plugin';
import { EsContext } from './es';
import { IEvent, IEventLogger, IEventLogService, IEventLogConfig } from './types';
import { EventLogger } from './event_logger';
import { SavedObjectProvider, SavedObjectProviderRegistry } from './saved_object_provider_registry';
export type PluginClusterClient = Pick<LegacyClusterClient, 'callAsInternalUser' | 'asScoped'>;
export type AdminClusterClient$ = Observable<PluginClusterClient>;

Expand All @@ -21,6 +22,7 @@ interface EventLogServiceCtorParams {
esContext: EsContext;
kibanaUUID: string;
systemLogger: SystemLogger;
savedObjectProviderRegistry: SavedObjectProviderRegistry;
}

// note that clusterClient may be null, indicating we can't write to ES
Expand All @@ -29,15 +31,23 @@ export class EventLogService implements IEventLogService {
private esContext: EsContext;
private systemLogger: SystemLogger;
private registeredProviderActions: Map<string, Set<string>>;
private savedObjectProviderRegistry: SavedObjectProviderRegistry;

public readonly kibanaUUID: string;

constructor({ config, esContext, kibanaUUID, systemLogger }: EventLogServiceCtorParams) {
constructor({
config,
esContext,
kibanaUUID,
systemLogger,
savedObjectProviderRegistry,
}: EventLogServiceCtorParams) {
this.config = config;
this.esContext = esContext;
this.kibanaUUID = kibanaUUID;
this.systemLogger = systemLogger;
this.registeredProviderActions = new Map<string, Set<string>>();
this.savedObjectProviderRegistry = savedObjectProviderRegistry;
}

public isEnabled(): boolean {
Expand Down Expand Up @@ -77,6 +87,10 @@ export class EventLogService implements IEventLogService {
return new Map(this.registeredProviderActions.entries());
}

registerSavedObjectProvider(type: string, provider: SavedObjectProvider) {
return this.savedObjectProviderRegistry.registerProvider(type, provider);
}

getLogger(initialProperties: IEvent): IEventLogger {
return new EventLogger({
esContext: this.esContext,
Expand Down
Loading