Skip to content

Commit

Permalink
[RAM] System actions update rule api (#171099)
Browse files Browse the repository at this point in the history
## Summary

Summarize your PR. If it involves visual changes include a screenshot or
gif.


- [ ] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
guskovaue and kibanamachine committed Nov 28, 2023
1 parent d8a7569 commit f2f6f7d
Show file tree
Hide file tree
Showing 11 changed files with 209 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@
export { transformRuleAttributesToRuleDomain } from './transform_rule_attributes_to_rule_domain';
export { transformRuleDomainToRuleAttributes } from './transform_rule_domain_to_rule_attributes';
export { transformRuleDomainToRule } from './transform_rule_domain_to_rule';
export { transformDomainActionsToRawActions } from './transform_domain_actions_to_raw_actions';
export { transformRawActionsToDomainActions } from './transform_raw_actions_to_domain_actions';
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,6 @@ describe('bulkEnableRulesRoute', () => {
bulkEnableRulesRoute({ router, licenseState });
const [_, handler] = router.patch.mock.calls[0];

// rulesClient.bulkDisableRules.mockResolvedValueOnce(bulkDisableActionsResult);
rulesClient.bulkEnableRules.mockResolvedValueOnce(bulkEnableActionsResult);

const [context, req, res] = mockHandlerArguments(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { validateHours } from './validate_hours';

export const actionsSchema = schema.arrayOf(
schema.object({
group: schema.string(),
group: schema.maybe(schema.string()),
id: schema.string(),
params: schema.recordOf(schema.string(), schema.any(), { defaultValue: {} }),
frequency: schema.maybe(
Expand Down
6 changes: 5 additions & 1 deletion x-pack/plugins/alerting/server/routes/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ export type {
} from './rewrite_request_case';
export { verifyAccessAndContext } from './verify_access_and_context';
export { countUsageOfPredefinedIds } from './count_usage_of_predefined_ids';
export { rewriteActionsReq, rewriteActionsRes } from './rewrite_actions';
export {
rewriteActionsReq,
rewriteActionsRes,
rewriteActionsReqWithSystemActions,
} from './rewrite_actions';
export { actionsSchema } from './actions_schema';
export { rewriteRule, rewriteRuleLastRun } from './rewrite_rule';
export { rewriteNamespaces } from './rewrite_namespaces';
Expand Down
37 changes: 37 additions & 0 deletions x-pack/plugins/alerting/server/routes/lib/rewrite_actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { omit } from 'lodash';
import { NormalizedAlertAction } from '../../rules_client';
import { RuleAction } from '../../types';
import { actionsSchema } from './actions_schema';
import { RuleActionTypes } from '../../../common';

export const rewriteActionsReq = (
actions?: TypeOf<typeof actionsSchema>
Expand All @@ -31,6 +32,42 @@ export const rewriteActionsReq = (
});
};

export const rewriteActionsReqWithSystemActions = (
actions: TypeOf<typeof actionsSchema>,
isSystemAction: (connectorId: string) => boolean
): NormalizedAlertAction[] => {
if (!actions) return [];

return actions.map(({ frequency, alerts_filter: alertsFilter, ...action }) => {
if (isSystemAction(action.id)) {
return {
id: action.id,
params: action.params,
...(action.uuid ? { uuid: action.uuid } : {}),
type: RuleActionTypes.SYSTEM,
};
}

return {
group: action.group ?? 'default',
id: action.id,
params: action.params,
...(action.uuid ? { uuid: action.uuid } : {}),
...(frequency
? {
frequency: {
summary: frequency.summary,
throttle: frequency.throttle,
notifyWhen: frequency.notify_when,
},
}
: {}),
...(alertsFilter ? { alertsFilter } : {}),
type: RuleActionTypes.DEFAULT,
};
});
};

export const rewriteActionsRes = (actions?: RuleAction[]) => {
const rewriteFrequency = ({ notifyWhen, ...rest }: NonNullable<RuleAction['frequency']>) => ({
...rest,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@

export { transformRuleToRuleResponse } from './transform_rule_to_rule_response/latest';
export { transformRuleToRuleResponse as transformRuleToRuleResponseV1 } from './transform_rule_to_rule_response/v1';
export { transformRuleActions } from './transform_rule_to_rule_response/latest';
export { transformRuleActions as transformRuleActionsV1 } from './transform_rule_to_rule_response/v1';
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
* 2.0.
*/

export { transformRuleToRuleResponse } from './v1';
export { transformRuleToRuleResponse, transformRuleActions } from './v1';
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const transformMonitoring = (monitoring: Monitoring): MonitoringV1 => {
};
};

const transformRuleActions = (actions: Rule['actions']): RuleResponseV1['actions'] => {
export const transformRuleActions = (actions: Rule['actions']): RuleResponseV1['actions'] => {
return actions.map((action) => {
if (action.type === RuleActionTypes.SYSTEM) {
const { id, actionTypeId, params, uuid } = action;
Expand Down
39 changes: 29 additions & 10 deletions x-pack/plugins/alerting/server/routes/update_rule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,17 @@
*/

import { schema } from '@kbn/config-schema';
import { TypeOf } from '@kbn/config-schema/src/types/object_type';
import { IRouter } from '@kbn/core/server';
import { ILicenseState, RuleTypeDisabledError, validateDurationSchema } from '../lib';
import { UpdateOptions } from '../rules_client';
import {
verifyAccessAndContext,
RewriteResponseCase,
RewriteRequestCase,
AsApiContract,
handleDisabledApiKeysError,
rewriteActionsReq,
rewriteActionsRes,
actionsSchema,
rewriteRuleLastRun,
rewriteActionsReqWithSystemActions,
} from './lib';
import {
RuleTypeParams,
Expand All @@ -26,6 +25,13 @@ import {
validateNotifyWhenType,
PartialRule,
} from '../types';
import { transformRuleActions } from './rule/transforms';
import { RuleResponse } from '../../common/routes/rule/response';

type RuleBody = TypeOf<typeof bodySchema>;
interface RuleUpdateOptionsResult extends Omit<UpdateOptions<RuleTypeParams>, 'data'> {
data: RuleBody;
}

const paramSchema = schema.object({
id: schema.string(),
Expand Down Expand Up @@ -54,18 +60,22 @@ const bodySchema = schema.object({
),
});

const rewriteBodyReq: RewriteRequestCase<UpdateOptions<RuleTypeParams>> = (result) => {
const rewriteBodyReq = (
result: RuleUpdateOptionsResult,
isSystemAction: (connectorId: string) => boolean
): UpdateOptions<RuleTypeParams> => {
const { notify_when: notifyWhen, actions, ...rest } = result.data;
return {
...result,
data: {
...rest,
notifyWhen,
actions: rewriteActionsReq(actions),
actions: rewriteActionsReqWithSystemActions(actions, isSystemAction),
},
};
};
const rewriteBodyRes: RewriteResponseCase<PartialRule<RuleTypeParams>> = ({

const rewriteBodyRes = ({
actions,
alertTypeId,
scheduledTaskId,
Expand All @@ -84,7 +94,10 @@ const rewriteBodyRes: RewriteResponseCase<PartialRule<RuleTypeParams>> = ({
lastRun,
nextRun,
...rest
}) => ({
}: PartialRule<RuleTypeParams>): Omit<
AsApiContract<PartialRule<RuleTypeParams> & { actions?: RuleResponse['actions'] }>,
'actions'
> => ({
...rest,
api_key_owner: apiKeyOwner,
created_by: createdBy,
Expand All @@ -109,7 +122,7 @@ const rewriteBodyRes: RewriteResponseCase<PartialRule<RuleTypeParams>> = ({
: {}),
...(actions
? {
actions: rewriteActionsRes(actions),
actions: transformRuleActions(actions),
}
: {}),
...(lastRun ? { last_run: rewriteRuleLastRun(lastRun) } : {}),
Expand All @@ -133,10 +146,16 @@ export const updateRuleRoute = (
router.handleLegacyErrors(
verifyAccessAndContext(licenseState, async function (context, req, res) {
const rulesClient = (await context.alerting).getRulesClient();
const actionsClient = (await context.actions).getActionsClient();

const { id } = req.params;
const rule = req.body;
try {
const alertRes = await rulesClient.update(rewriteBodyReq({ id, data: rule }));
const alertRes = await rulesClient.update(
rewriteBodyReq({ id, data: rule }, (connectorId: string) =>
actionsClient.isSystemAction(connectorId)
)
);
return res.ok({
body: rewriteBodyRes(alertRes),
});
Expand Down
49 changes: 40 additions & 9 deletions x-pack/plugins/alerting/server/rules_client/methods/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
RuleTypeParams,
RuleNotifyWhenType,
IntervalSchedule,
RuleSystemAction,
RuleActionTypes,
} from '../../types';
import { validateRuleTypeParams, getRuleNotifyWhenType } from '../../lib';
import { WriteOperations, AlertingAuthorizationEntity } from '../../authorization';
Expand All @@ -37,6 +39,12 @@ import {
validateScheduleLimit,
ValidateScheduleLimitResult,
} from '../../application/rule/methods/get_schedule_frequency';
import { validateSystemActions } from '../../lib/validate_system_actions';
import { denormalizeActions } from '../lib/denormalize_actions';
import {
transformDomainActionsToRawActions,
transformRawActionsToDomainActions,
} from '../../application/rule/transforms';

type ShouldIncrementRevision = (params?: RuleTypeParams) => boolean;

Expand Down Expand Up @@ -211,12 +219,22 @@ async function updateAlert<Params extends RuleTypeParams>(
): Promise<PartialRule<Params>> {
const { attributes, version } = currentRule;
const data = { ...initialData, actions: addGeneratedActionValues(initialData.actions) };
const actionsClient = await context.getActionsClient();

const systemActions = initialData.actions.filter(
(action): action is RuleSystemAction => action.type === RuleActionTypes.SYSTEM
);

const ruleType = context.ruleTypeRegistry.get(attributes.alertTypeId);

// Validate
const validatedAlertTypeParams = validateRuleTypeParams(data.params, ruleType.validate.params);
await validateActions(context, ruleType, data, allowMissingConnectorSecrets);
await validateSystemActions({
actionsClient,
connectorAdapterRegistry: context.connectorAdapterRegistry,
systemActions,
});

// Throw error if schedule interval is less than the minimum and we are enforcing it
const intervalInMs = parseDuration(data.schedule.interval);
Expand All @@ -230,11 +248,14 @@ async function updateAlert<Params extends RuleTypeParams>(
}

// Extract saved object references for this rule
const {
references,
params: updatedParams,
actions,
} = await extractReferences(context, ruleType, data.actions, validatedAlertTypeParams);
const { references, params: updatedParams } = await extractReferences(
context,
ruleType,
data.actions,
validatedAlertTypeParams
);

const { actions: actionsWithRefs } = await denormalizeActions(context, data.actions);

const username = await context.getUserName();

Expand Down Expand Up @@ -262,7 +283,7 @@ async function updateAlert<Params extends RuleTypeParams>(
...data,
...apiKeyAttributes,
params: updatedParams as RawRule['params'],
actions,
actions: actionsWithRefs,
notifyWhen,
revision,
updatedBy: username,
Expand All @@ -278,7 +299,7 @@ async function updateAlert<Params extends RuleTypeParams>(
try {
updatedObject = await context.unsecuredSavedObjectsClient.create<RawRule>(
'alert',
createAttributes,
{ ...createAttributes, actions: transformDomainActionsToRawActions(createAttributes) },
{
id,
overwrite: true,
Expand Down Expand Up @@ -311,8 +332,7 @@ async function updateAlert<Params extends RuleTypeParams>(
`Rule schedule interval (${data.schedule.interval}) for "${ruleType.id}" rule type with ID "${id}" is less than the minimum value (${context.minimumScheduleInterval.value}). Running rules at this interval may impact alerting performance. Set "xpack.alerting.rules.minimumScheduleInterval.enforce" to true to prevent such changes.`
);
}

return getPartialRuleFromRaw(
const rules = getPartialRuleFromRaw<Params>(
context,
id,
ruleType,
Expand All @@ -321,4 +341,15 @@ async function updateAlert<Params extends RuleTypeParams>(
false,
true
);

return {
...rules,
actions: transformRawActionsToDomainActions({
ruleId: id,
references: updatedObject.references,
actions: updatedObject.attributes.actions,
omitGeneratedValues: false,
isSystemAction: (connectorId: string) => actionsClient.isSystemAction(connectorId),
}),
};
}
Loading

0 comments on commit f2f6f7d

Please sign in to comment.