Skip to content

Commit

Permalink
TEMP COMMIT. REBASE ME
Browse files Browse the repository at this point in the history
  • Loading branch information
banderror committed May 3, 2021
1 parent 3d78a23 commit 7e4efc3
Show file tree
Hide file tree
Showing 7 changed files with 913 additions and 0 deletions.
84 changes: 84 additions & 0 deletions x-pack/plugins/rule_registry/server/plugin_v2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// /*
// * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// * or more contributor license agreements. Licensed under the Elastic License
// * 2.0; you may not use this file except in compliance with the Elastic License
// * 2.0.
// */

// import { PluginInitializerContext, Plugin, CoreSetup } from 'src/core/server';
// import { PluginSetupContract as AlertingPluginSetupContract } from '../../alerting/server';
// import { BaseRuleFieldMap, baseRuleFieldMap } from '../common';
// import { EventLogService, Schema, defaultIlmPolicy } from './event_log';
// import { RuleRegistry } from './rule_registry_v2';
// import { RuleRegistryConfig } from '.';

// export type RuleRegistryPluginSetupContract = RuleRegistry<BaseRuleFieldMap>;

// export class RuleRegistryPlugin implements Plugin<RuleRegistryPluginSetupContract> {
// private readonly initContext: PluginInitializerContext;
// private eventLogService: EventLogService | null;

// constructor(initContext: PluginInitializerContext) {
// this.initContext = initContext;
// this.eventLogService = null;
// }

// public setup(
// core: CoreSetup,
// plugins: { alerting: AlertingPluginSetupContract }
// ): RuleRegistryPluginSetupContract {
// const globalConfig = this.initContext.config.legacy.get();
// const config = this.initContext.config.get<RuleRegistryConfig>();
// const logger = this.initContext.logger.get();

// this.eventLogService = new EventLogService({
// config: {
// kibanaIndexName: globalConfig.kibana.index,
// kibanaVersion: this.initContext.env.packageInfo.version,
// isWriteEnabled: config.unsafe.write.enabled,
// },
// dependencies: {
// clusterClient: core.getStartServices().then(([{ elasticsearch }]) => elasticsearch.client),
// logger: logger.get('event-log'),
// },
// });

// const rootLogProvider = this.eventLogService.registerLog({
// name: 'alerting',
// schema: Schema.create(baseRuleFieldMap),
// ilmPolicy: defaultIlmPolicy,
// });

// const alertsLogProvider = rootLogProvider.registerLog({
// name: 'alerts',
// schema: Schema.create(baseRuleFieldMap),
// });

// const executionLogProvider = rootLogProvider.registerLog({
// name: 'execlog',
// schema: Schema.create(baseRuleFieldMap),
// });

// const rootRegistry = new RuleRegistry({
// alertingPlugin: plugins.alerting,
// alertsLogProvider,
// executionLogProvider,
// logger: logger.get('root'),
// writeEnabled: config.unsafe.write.enabled,
// });

// return rootRegistry;
// }

// public start() {
// if (this.eventLogService) {
// this.eventLogService.start();
// }
// }

// public stop() {
// if (this.eventLogService) {
// this.eventLogService.stop();
// }
// }
// }
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { Either, isLeft, isRight } from 'fp-ts/lib/Either';
import { Errors } from 'io-ts';
import { PathReporter } from 'io-ts/lib/PathReporter';
import { Logger } from 'kibana/server';
import { IScopedClusterClient as ScopedClusterClient } from 'src/core/server';
import { castArray, compact } from 'lodash';
import { ESSearchRequest } from 'typings/elasticsearch';
import { IndexPatternsFetcher } from '../../../../../../src/plugins/data/server';
import { TypeOfFieldMap } from '../../../common';
import { ScopedRuleRegistryClient, EventsOf } from './types';
import { BaseRuleFieldMap } from '../../../common';
import { RuleRegistry } from '..';
import { IEventLogProvider } from '../../event_log';

const createPathReporterError = (either: Either<Errors, unknown>) => {
const error = new Error(`Failed to validate alert event`);
error.stack += '\n' + PathReporter.report(either).join('\n');
return error;
};

export function createScopedRuleRegistryClient<TFieldMap extends BaseRuleFieldMap>({
ruleUuids,
scopedClusterClient,
eventLogProvider,
logger,
registry,
ruleData,
}: {
ruleUuids: string[];
scopedClusterClient: ScopedClusterClient;
eventLogProvider: IEventLogProvider<TFieldMap>;
logger: Logger;
registry: RuleRegistry<TFieldMap>;
ruleData?: {
rule: {
id: string;
uuid: string;
category: string;
name: string;
};
producer: string;
tags: string[];
};
}): ScopedRuleRegistryClient<TFieldMap> {
const fieldmapType = registry.getFieldMapType();

const defaults = ruleData
? {
'rule.uuid': ruleData.rule.uuid,
'rule.id': ruleData.rule.id,
'rule.name': ruleData.rule.name,
'rule.category': ruleData.rule.category,
'kibana.rac.producer': ruleData.producer,
tags: ruleData.tags,
}
: {};

const client: ScopedRuleRegistryClient<BaseRuleFieldMap> = {
search: async (searchRequest) => {
const fields = [
'rule.id',
...(searchRequest.body?.fields ? castArray(searchRequest.body.fields) : []),
];

const eventLog = await eventLogProvider.getLog();
const query = eventLog.getEvents().buildQuery();

const response = await query.search({
...searchRequest,
body: {
...searchRequest.body,
query: {
bool: {
filter: [
{ terms: { 'rule.uuid': ruleUuids } },
...compact([searchRequest.body?.query]),
],
},
},
fields,
},
});

return {
body: response.body as any,
events: compact(
response.body.hits.hits.map((hit) => {
const ruleTypeId: string = hit.fields!['rule.id'][0];

const registryOfType = registry.getRegistryByRuleTypeId(ruleTypeId);

if (ruleTypeId && !registryOfType) {
logger.warn(
`Could not find type ${ruleTypeId} in registry, decoding with default type`
);
}

const type = registryOfType?.getFieldMapType() ?? fieldmapType;

const validation = type.decode(hit.fields);
if (isLeft(validation)) {
const error = createPathReporterError(validation);
logger.error(error);
return undefined;
}
return type.encode(validation.right);
})
) as EventsOf<ESSearchRequest, TFieldMap>,
};
},
getDynamicIndexPattern: async () => {
const { logIndexBasePattern } = eventLogProvider.getIndexSpec().indexNames;

const indexPatternsFetcher = new IndexPatternsFetcher(scopedClusterClient.asInternalUser);
const fields = await indexPatternsFetcher.getFieldsForWildcard({
pattern: logIndexBasePattern,
});

return {
fields,
timeFieldName: '@timestamp',
title: logIndexBasePattern,
};
},
index: async (doc) => {
const validation = fieldmapType.decode({
...doc,
...defaults,
});

if (isLeft(validation)) {
throw createPathReporterError(validation);
}

const x = validation.right;

const eventLog = await eventLogProvider.getLog();
const eventLogger = eventLog.getLogger('alerts');
eventLogger.logEvent(validation.right);
},
bulkIndex: async (docs) => {
const validations = docs.map((doc) => {
return fieldmapType.decode({
...doc,
...defaults,
});
});

const validationErrors = compact(
validations.map((validation) =>
isLeft(validation) ? createPathReporterError(validation) : null
)
);

const validDocuments = compact(
validations.map((validation) => (isRight(validation) ? validation.right : null))
);

validationErrors.forEach((error) => {
logger.error(error);
});

const eventLog = await eventLogProvider.getLog();
const eventLogger = eventLog.getLogger('alerts');

validDocuments.forEach((doc) => {
eventLogger.logEvent(doc);
});
},
};

// @ts-expect-error: We can't use ScopedRuleRegistryClient<BaseRuleFieldMap>
// when creating the client, due to #41693 which will be fixed in 4.2
return client;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { FieldDescriptor } from 'src/plugins/data/server';
import { ESSearchRequest, ESSearchResponse } from 'typings/elasticsearch';
import {
PatternsUnionOf,
PickWithPatterns,
OutputOfFieldMap,
BaseRuleFieldMap,
} from '../../../common';
import { Event } from '../../event_log';

export type PrepopulatedRuleEventFields = keyof Pick<
BaseRuleFieldMap,
'rule.uuid' | 'rule.id' | 'rule.name' | 'rule.category' | 'kibana.rac.producer'
>;

type FieldsOf<TFieldMap extends BaseRuleFieldMap> =
| Array<{ field: PatternsUnionOf<TFieldMap> } | PatternsUnionOf<TFieldMap>>
| PatternsUnionOf<TFieldMap>;

type Fields<TPattern extends string> = Array<{ field: TPattern } | TPattern> | TPattern;

type FieldsESSearchRequest<TFieldMap extends BaseRuleFieldMap> = ESSearchRequest & {
body?: { fields: FieldsOf<TFieldMap> };
};

export type EventsOf<
TFieldsESSearchRequest extends ESSearchRequest,
TFieldMap extends BaseRuleFieldMap
> = TFieldsESSearchRequest extends { body: { fields: infer TFields } }
? TFields extends Fields<infer TPattern>
? Array<OutputOfFieldMap<PickWithPatterns<TFieldMap, TPattern[]>>>
: never
: never;

export interface ScopedRuleRegistryClient<TFieldMap extends BaseRuleFieldMap> {
search<TSearchRequest extends FieldsESSearchRequest<TFieldMap>>(
request: TSearchRequest
): Promise<{
body: ESSearchResponse<unknown, TSearchRequest>;
events: EventsOf<TSearchRequest, TFieldMap>;
}>;
getDynamicIndexPattern(): Promise<{
title: string;
timeFieldName: string;
fields: FieldDescriptor[];
}>;

index(event: Event<TFieldMap>): Promise<void>;
bulkIndex(events: Array<Event<TFieldMap>>): Promise<void>;
}
9 changes: 9 additions & 0 deletions x-pack/plugins/rule_registry/server/rule_registry_v2/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

export * from './public_api';
export * from './rule_registry';
Loading

0 comments on commit 7e4efc3

Please sign in to comment.