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

[7.x] [Alerting] Allow rule types to extract/inject saved object references on rule CRU (#101896) #106333

Merged
merged 1 commit into from
Jul 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ function getTShirtSizeByIdAndThreshold(

export const alertType: AlertType<
AlwaysFiringParams,
never,
{ count?: number },
{ triggerdOnCycle: number },
never,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ function getCraftFilter(craft: string) {

export const alertType: AlertType<
{ outerSpaceCapacity: number; craft: string; op: string },
never,
{ peopleInSpace: number },
{ craft: string },
never,
Expand Down
47 changes: 47 additions & 0 deletions x-pack/plugins/alerting/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ The following table describes the properties of the `options` object.
|executor|This is where the code for the rule type lives. This is a function to be called when executing a rule on an interval basis. For full details, see the executor section below.|Function|
|producer|The id of the application producing this rule type.|string|
|minimumLicenseRequired|The value of a minimum license. Most of the rules are licensed as "basic".|string|
|useSavedObjectReferences.extractReferences|(Optional) When developing a rule type, you can choose to implement hooks for extracting saved object references from rule parameters. This hook will be invoked when a rule is created or updated. Implementing this hook is optional, but if an extract hook is implemented, an inject hook must also be implemented.|Function
|useSavedObjectReferences.injectReferences|(Optional) When developing a rule type, you can choose to implement hooks for injecting saved object references into rule parameters. This hook will be invoked when a rule is retrieved (get or find). Implementing this hook is optional, but if an inject hook is implemented, an extract hook must also be implemented.|Function
|isExportable|Whether the rule type is exportable from the Saved Objects Management UI.|boolean|

### Executor
Expand Down Expand Up @@ -173,6 +175,19 @@ For example, if the `context` has one variable `foo` which is an object that has
}
```

### useSavedObjectReferences Hooks

This is an optional pair of functions that can be implemented by a rule type. Both `extractReferences` and `injectReferences` functions must be implemented if either is impemented.

**useSavedObjectReferences.extractReferences**

This function should take the rule type params as input and extract out any saved object IDs stored within the params. For each saved object ID, a new saved object reference should be created and a saved object reference should replace the saved object ID in the rule params. This function should return the modified rule type params (with saved object reference name, not IDs) and an array of saved object references.


**useSavedObjectReferences.injectReferences**


This function should take the rule type params (with saved object references) and the saved object references array as input and inject the saved object ID in place of any saved object references in the rule type params. Note that any error thrown within this function will be propagated.
## Licensing

Currently most rule types are free features. But some rule types are subscription features, such as the tracking containment rule.
Expand Down Expand Up @@ -210,6 +225,13 @@ import {
interface MyRuleTypeParams extends AlertTypeParams {
server: string;
threshold: number;
testSavedObjectId: string;
}

interface MyRuleTypeExtractedParams extends AlertTypeParams {
server: string;
threshold: number;
testSavedObjectRef: string;
}

interface MyRuleTypeState extends AlertTypeState {
Expand All @@ -229,6 +251,7 @@ type MyRuleTypeActionGroups = 'default' | 'warning';

const myRuleType: AlertType<
MyRuleTypeParams,
MyRuleTypeExtractedParams,
MyRuleTypeState,
MyRuleTypeAlertState,
MyRuleTypeAlertContext,
Expand Down Expand Up @@ -274,6 +297,7 @@ const myRuleType: AlertType<
rule,
}: AlertExecutorOptions<
MyRuleTypeParams,
MyRuleTypeExtractedParams,
MyRuleTypeState,
MyRuleTypeAlertState,
MyRuleTypeAlertContext,
Expand Down Expand Up @@ -320,6 +344,29 @@ const myRuleType: AlertType<
};
},
producer: 'alerting',
useSavedObjectReferences: {
extractReferences: (params: Params): RuleParamsAndRefs<ExtractedParams> => {
const { testSavedObjectId, ...otherParams } = params;

const testSavedObjectRef = 'testRef_0';
const references = [
{
name: `testRef_0`,
id: testSavedObjectId,
type: 'index-pattern',
},
];
return { params: { ...otherParams, testSavedObjectRef }, references };
},
injectReferences: (params: SavedObjectAttributes, references: SavedObjectReference[]) => {
const { testSavedObjectRef, ...otherParams } = params;
const reference = references.find((ref) => ref.name === testSavedObjectRef);
if (!reference) {
throw new Error(`Test reference "${testSavedObjectRef}"`);
}
return { ...otherParams, testSavedObjectId: reference.id } as Params;
},
}
};

server.newPlatform.setup.plugins.alerting.registerType(myRuleType);
Expand Down
17 changes: 9 additions & 8 deletions x-pack/plugins/alerting/server/alert_type_registry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ describe('has()', () => {

describe('register()', () => {
test('throws if AlertType Id contains invalid characters', () => {
const alertType: AlertType<never, never, never, never, 'default'> = {
const alertType: AlertType<never, never, never, never, never, 'default'> = {
id: 'test',
name: 'Test',
actionGroups: [
Expand Down Expand Up @@ -90,7 +90,7 @@ describe('register()', () => {
});

test('throws if AlertType Id isnt a string', () => {
const alertType: AlertType<never, never, never, never, 'default'> = {
const alertType: AlertType<never, never, never, never, never, 'default'> = {
id: (123 as unknown) as string,
name: 'Test',
actionGroups: [
Expand All @@ -113,7 +113,7 @@ describe('register()', () => {
});

test('throws if AlertType action groups contains reserved group id', () => {
const alertType: AlertType<never, never, never, never, 'default' | 'NotReserved'> = {
const alertType: AlertType<never, never, never, never, never, 'default' | 'NotReserved'> = {
id: 'test',
name: 'Test',
actionGroups: [
Expand Down Expand Up @@ -146,7 +146,7 @@ describe('register()', () => {
});

test('allows an AlertType to specify a custom recovery group', () => {
const alertType: AlertType<never, never, never, never, 'default', 'backToAwesome'> = {
const alertType: AlertType<never, never, never, never, never, 'default', 'backToAwesome'> = {
id: 'test',
name: 'Test',
actionGroups: [
Expand Down Expand Up @@ -187,6 +187,7 @@ describe('register()', () => {
never,
never,
never,
never,
'default' | 'backToAwesome',
'backToAwesome'
> = {
Expand Down Expand Up @@ -222,7 +223,7 @@ describe('register()', () => {
});

test('registers the executor with the task manager', () => {
const alertType: AlertType<never, never, never, never, 'default'> = {
const alertType: AlertType<never, never, never, never, never, 'default'> = {
id: 'test',
name: 'Test',
actionGroups: [
Expand Down Expand Up @@ -253,7 +254,7 @@ describe('register()', () => {
});

test('shallow clones the given alert type', () => {
const alertType: AlertType<never, never, never, never, 'default'> = {
const alertType: AlertType<never, never, never, never, never, 'default'> = {
id: 'test',
name: 'Test',
actionGroups: [
Expand Down Expand Up @@ -506,8 +507,8 @@ function alertTypeWithVariables<ActionGroupIds extends string>(
id: ActionGroupIds,
context: string,
state: string
): AlertType<never, never, never, never, ActionGroupIds> {
const baseAlert: AlertType<never, never, never, never, ActionGroupIds> = {
): AlertType<never, never, never, never, never, ActionGroupIds> {
const baseAlert: AlertType<never, never, never, never, never, ActionGroupIds> = {
id,
name: `${id}-name`,
actionGroups: [],
Expand Down
23 changes: 22 additions & 1 deletion x-pack/plugins/alerting/server/alert_type_registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ const alertIdSchema = schema.string({

export type NormalizedAlertType<
Params extends AlertTypeParams,
ExtractedParams extends AlertTypeParams,
State extends AlertTypeState,
InstanceState extends AlertInstanceState,
InstanceContext extends AlertInstanceContext,
Expand All @@ -82,13 +83,22 @@ export type NormalizedAlertType<
> = {
actionGroups: Array<ActionGroup<ActionGroupIds | RecoveryActionGroupId>>;
} & Omit<
AlertType<Params, State, InstanceState, InstanceContext, ActionGroupIds, RecoveryActionGroupId>,
AlertType<
Params,
ExtractedParams,
State,
InstanceState,
InstanceContext,
ActionGroupIds,
RecoveryActionGroupId
>,
'recoveryActionGroup' | 'actionGroups'
> &
Pick<
Required<
AlertType<
Params,
ExtractedParams,
State,
InstanceState,
InstanceContext,
Expand All @@ -100,6 +110,7 @@ export type NormalizedAlertType<
>;

export type UntypedNormalizedAlertType = NormalizedAlertType<
AlertTypeParams,
AlertTypeParams,
AlertTypeState,
AlertInstanceState,
Expand Down Expand Up @@ -132,6 +143,7 @@ export class AlertTypeRegistry {

public register<
Params extends AlertTypeParams,
ExtractedParams extends AlertTypeParams,
State extends AlertTypeState,
InstanceState extends AlertInstanceState,
InstanceContext extends AlertInstanceContext,
Expand All @@ -140,6 +152,7 @@ export class AlertTypeRegistry {
>(
alertType: AlertType<
Params,
ExtractedParams,
State,
InstanceState,
InstanceContext,
Expand All @@ -161,6 +174,7 @@ export class AlertTypeRegistry {

const normalizedAlertType = augmentActionGroupsWithReserved<
Params,
ExtractedParams,
State,
InstanceState,
InstanceContext,
Expand All @@ -179,6 +193,7 @@ export class AlertTypeRegistry {
createTaskRunner: (context: RunContext) =>
this.taskRunnerFactory.create<
Params,
ExtractedParams,
State,
InstanceState,
InstanceContext,
Expand All @@ -198,6 +213,7 @@ export class AlertTypeRegistry {

public get<
Params extends AlertTypeParams = AlertTypeParams,
ExtractedParams extends AlertTypeParams = AlertTypeParams,
State extends AlertTypeState = AlertTypeState,
InstanceState extends AlertInstanceState = AlertInstanceState,
InstanceContext extends AlertInstanceContext = AlertInstanceContext,
Expand All @@ -207,6 +223,7 @@ export class AlertTypeRegistry {
id: string
): NormalizedAlertType<
Params,
ExtractedParams,
State,
InstanceState,
InstanceContext,
Expand All @@ -230,6 +247,7 @@ export class AlertTypeRegistry {
*/
return (this.alertTypes.get(id)! as unknown) as NormalizedAlertType<
Params,
ExtractedParams,
State,
InstanceState,
InstanceContext,
Expand Down Expand Up @@ -284,6 +302,7 @@ function normalizedActionVariables(actionVariables: AlertType['actionVariables']

function augmentActionGroupsWithReserved<
Params extends AlertTypeParams,
ExtractedParams extends AlertTypeParams,
State extends AlertTypeState,
InstanceState extends AlertInstanceState,
InstanceContext extends AlertInstanceContext,
Expand All @@ -292,6 +311,7 @@ function augmentActionGroupsWithReserved<
>(
alertType: AlertType<
Params,
ExtractedParams,
State,
InstanceState,
InstanceContext,
Expand All @@ -300,6 +320,7 @@ function augmentActionGroupsWithReserved<
>
): NormalizedAlertType<
Params,
ExtractedParams,
State,
InstanceState,
InstanceContext,
Expand Down
Loading