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

Add triggered actions list in task state #146183

Merged
merged 49 commits into from Dec 12, 2022

Conversation

ersin-erdal
Copy link
Contributor

@ersin-erdal ersin-erdal commented Nov 23, 2022

Fixes: #146049

This PR adds actions.date field to the alertInstances in the Task context, and TaskRunner uses it (and the new notifyWhen and throttle fields in the actions too) to decide if an action is throttled or not.

To verify:
Create a rule with an action and expect it to run as usual,
Then modify the action data in backend to mimic an action that has the new notifyWhen and throttle fields and expect it to run as expected as well.

I usually replace the following code with the below code snippet to mimic an action with the new fields:

data: rewriteBodyReq({
   ...rule,
   actions: [
            {
                   group: rule.actions[0].group,
                   id: rule.actions[0].id,
                   params: rule.actions[0].params,
                   frequency: {
                         summary: false,
                          notifyWhen: 'onThrottleInterval',
                          throttle: '5m',
                   },
              },
   ],
   notify_when: undefined,
   throttle: undefined,
}),

… 143376-alerts-summary-exec

# Conflicts:
#	x-pack/plugins/alerting/server/task_runner/execution_handler.test.ts
#	x-pack/plugins/alerting/server/task_runner/execution_handler.ts
#	x-pack/plugins/alerting/server/task_runner/task_runner.ts
@ersin-erdal ersin-erdal added Team:ResponseOps Label for the ResponseOps team (formerly the Cases and Alerting teams) release_note:feature Makes this part of the condensed release notes v8.7.0 labels Nov 23, 2022
@ersin-erdal ersin-erdal changed the title 143376 alerts summary exec Add lastTriggerDate field to the rule actions Nov 23, 2022
@ersin-erdal ersin-erdal changed the title Add lastTriggerDate field to the rule actions Add triggered actions list in task state Nov 26, 2022
@@ -470,8 +470,7 @@ export class TaskRunner<
);
this.countUsageOfActionExecutionAfterRuleCancellation();
} else {
await executionHandler.run(activeAlerts);
await executionHandler.run(currentRecoveredAlerts, true);
await executionHandler.run({ ...activeAlerts, ...currentRecoveredAlerts });
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I merged these to avoid triggering a summary action twice

@pmuellr
Copy link
Member

pmuellr commented Dec 5, 2022

I'm curious about this:

export const actionsSchema = t.record(t.string, actionSchema);
export type AlertActions = t.TypeOf<typeof actionsSchema>;
const lastScheduledActionsSchema = t.intersection([
t.partial({
subgroup: t.string,
}),
t.type({
group: t.string,
date: DateFromString,
}),
t.partial({ actions: actionsSchema }),
]);

It looks to me like actions is an object of where the keys are actionId (connector id), and the value is {date: ...}. But it's possible to use the same connector more than once within an action group. Two server log actions, for example. So it doesn't actually look like this is specific enough - it really needs to identify a SPECIFIC action, not any action that uses that connector id.

@ersin-erdal
Copy link
Contributor Author

ersin-erdal commented Dec 5, 2022

I'm curious about this:

export const actionsSchema = t.record(t.string, actionSchema);
export type AlertActions = t.TypeOf<typeof actionsSchema>;
const lastScheduledActionsSchema = t.intersection([
t.partial({
subgroup: t.string,
}),
t.type({
group: t.string,
date: DateFromString,
}),
t.partial({ actions: actionsSchema }),
]);

It looks to me like actions is an object of where the keys are actionId (connector id), and the value is {date: ...}. But it's possible to use the same connector more than once within an action group. Two server log actions, for example. So it doesn't actually look like this is specific enough - it really needs to identify a SPECIFIC action, not any action that uses that connector id.

Ok i thought actionId is not connectorId, it's a uuid that we generate and it sticks with the action. If it's not, i should replace it with the actionREf.

@ersin-erdal ersin-erdal closed this Dec 5, 2022
@ersin-erdal ersin-erdal reopened this Dec 5, 2022
@@ -33,13 +33,13 @@ export const bodySchema = schema.object({
enabled: schema.boolean({ defaultValue: true }),
consumer: schema.string(),
tags: schema.arrayOf(schema.string(), { defaultValue: [] }),
throttle: schema.nullable(schema.maybe(schema.string({ validate: validateDurationSchema }))),
throttle: schema.maybe(schema.nullable(schema.string({ validate: validateDurationSchema }))),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This order matters. schema.nullable() converts undefined to null

@mikecote mikecote self-requested a review December 7, 2022 14:06
Copy link
Contributor

@mikecote mikecote left a comment

Choose a reason for hiding this comment

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

Finished reviewing the code, will do some testing tomorrow 👍

Comment on lines -25 to +29
if (hasNotifyWhen && hasThrottle) usesRuleLevelFreqParams = true;
// I removed the below ` && hasThrottle` check temporarily.
// Currently the UI sends "throttle" as undefined but schema converts it to null, so they never become both undefined
// I changed the schema too, but as the UI (and tests) sends "notifyWhen" as string and "throttle" as undefined, they never become both defined.
// We should add it back when the UI is changed (https://github.com/elastic/kibana/issues/143369)
if (hasNotifyWhen) usesRuleLevelFreqParams = true;
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure I follow why this needs to be done temporarily until the UI changes. Is there an API breaking change introduced in the summarization process?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No there isn't any breaking change. But it's a bit confusing, took me some time to figure out as well...

I want to test the new frequency fields by creating a new rule with notifyWhen and throttle in action level.
But as per the above code, both rule level notifyWhen and throttle should be undefined.
As the current schema converts undefined throttle field value to null (schema.nullable -> schema.maybe order) it was impossible, so i changed it.
Then functional tests started to fail because the current UI sends notifyWhen as string and throttle as undefined! So the following if case never returns true if (hasNotifyWhen && hasThrottle) usesRuleLevelFreqParams = true;

Therefore i removed the hasThrottle part...

Actually, as per our design, when there are notifyWhen and throttle on action level, rule level ones should be null, not undefined... but we can tackle that when we implement the UI part of the meta...

Copy link
Contributor

@mikecote mikecote left a comment

Choose a reason for hiding this comment

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

Tested locally and LGTM!

Copy link
Member

@afharo afharo left a comment

Choose a reason for hiding this comment

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

Core changes LGTM

@kibana-ci
Copy link
Collaborator

💚 Build Succeeded

Metrics [docs]

Public APIs missing comments

Total count of every public API that lacks a comment. Target amount is 0. Run node scripts/build_api_docs --plugin [yourplugin] --stats comments for more detailed information.

id before after diff
alerting 408 411 +3

Page load bundle

Size of the bundles that are downloaded on every page load. Target size is below 100kb

id before after diff
alerting 39.3KB 39.4KB +118.0B

Saved Objects .kibana field count

Every field in each saved object type adds overhead to Elasticsearch. Kibana needs to keep the total field count below Elasticsearch's default limit of 1000 fields. Only specify field mappings for the fields you wish to search on or query. See https://www.elastic.co/guide/en/kibana/master/saved-objects-service.html#_mappings

id before after diff
alert 95 99 +4
Unknown metric groups

API count

id before after diff
alerting 417 420 +3

ESLint disabled in files

id before after diff
osquery 1 2 +1

ESLint disabled line counts

id before after diff
enterpriseSearch 19 21 +2
fleet 60 66 +6
osquery 109 115 +6
securitySolution 445 451 +6
total +20

Total ESLint disabled count

id before after diff
enterpriseSearch 20 22 +2
fleet 69 75 +6
osquery 110 117 +7
securitySolution 521 527 +6
total +21

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

@ersin-erdal ersin-erdal merged commit d152e0a into elastic:main Dec 12, 2022
@kibanamachine kibanamachine added the backport:skip This commit does not require backporting label Dec 12, 2022
@ersin-erdal ersin-erdal deleted the 143376-alerts-summary-exec branch December 12, 2022 14:42
@@ -56,6 +56,22 @@ export const alertMappings: SavedObjectsTypeMappingDefinition = {
enabled: false,
type: 'object',
},
frequency: {
Copy link
Contributor

Choose a reason for hiding this comment

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

If we're not querying these fields (index: false) why are we specifying these fields in the mappings?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We use those fields but not query by them.
I can't create a rule that has those fields without adding them in the mapping, or am i wrong?

i get:
mapping set to strict, dynamic introduction of [frequency] within [alert.actions] is not allowed: strict_dynamic_mapping_exception: [strict_dynamic_mapping_exception] Reason: mapping set to strict, dynamic introduction of [frequency] within [alert.actions] is not allowed

if they are not in the mapping.

saarikabhasi pushed a commit to saarikabhasi/kibana that referenced this pull request Dec 14, 2022
Fixes: elastic#146049 

This PR adds `actions.date` field to the alertInstances in the Task
context, and TaskRunner uses it (and the new `notifyWhen` and `throttle`
fields in the actions too) to decide if an action is throttled or not.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport:skip This commit does not require backporting release_note:feature Makes this part of the condensed release notes Team:ResponseOps Label for the ResponseOps team (formerly the Cases and Alerting teams) v8.7.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Alert Summaries] Add lastTriggerDate field to rule action
8 participants