[ResponseOps][Rules] OAS schema registration for Rule APIs (#188445)

## Summary

Issue:  https://github.com/elastic/kibana/issues/187574

This PR updates `request` and `response` schemas below for rule APIs to
generate OAS documentation:
- `POST /api/alerting/rule/{id?}`
- `GET /api/alerting/rule/{id}`
- `DELETE /api/alerting/rule/{id}`
- `PUT /api/alerting/rule/{id}`
- `GET /api/alerting/rules/_find`
- `POST /api/alerting/rule/{rule_id}/alert/{alert_id}/_mute`


### How to test

1. Start ES
2. Add `server.oas.enabled: true` to `kibana.dev.yml`
3. Start Kibana `yarn start --no-base-path`
4. `curl -s -uelastic:changeme
http://localhost:5601/api/oas\?pathStartsWith\=/api/alerting/rule/ | jq`
5. For find api run `curl -s -uelastic:changeme
http://localhost:5601/api/oas\?pathStartsWith\=/api/alerting/rules/ |
jq`
This commit is contained in:
Janki Salvi 2024-07-24 17:06:21 +01:00 committed by GitHub
parent c77cd80070
commit 9422ef9977
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 1043 additions and 251 deletions

View file

@ -9,20 +9,57 @@ import { schema } from '@kbn/config-schema';
import { FilterStateStore } from '@kbn/es-query';
export const alertsFilterQuerySchema = schema.object({
kql: schema.string(),
kql: schema.string({ meta: { description: 'A filter written in Kibana Query Language (KQL).' } }),
filters: schema.arrayOf(
schema.object({
query: schema.maybe(schema.recordOf(schema.string(), schema.any())),
meta: schema.recordOf(schema.string(), schema.any()),
$state: schema.maybe(
schema.object({
store: schema.oneOf([
schema.literal(FilterStateStore.APP_STATE),
schema.literal(FilterStateStore.GLOBAL_STATE),
]),
query: schema.maybe(
schema.recordOf(
schema.string(),
schema.any({
meta: {
description: 'A query for the filter.',
},
})
)
),
meta: schema.recordOf(
schema.string(),
schema.any({
meta: {
description:
'An object with fields such as "controlledBy", "disabled", "field", "group", "index", "isMultiIndex", "key", "negate", "params", "type", "value"',
},
})
),
$state: schema.maybe(
schema.object({
store: schema.oneOf(
[
schema.literal(FilterStateStore.APP_STATE),
schema.literal(FilterStateStore.GLOBAL_STATE),
],
{
meta: {
description:
'A filter can be either specific to an application context or applied globally.',
},
}
),
})
),
}),
{
meta: {
description:
'A filter written in Elasticsearch Query Domain Specific Language (DSL) as defined in the `kbn-es-query` package.',
},
}
),
dsl: schema.maybe(
schema.string({
meta: {
description: 'A filter written in Elasticsearch Query Domain Specific Language (DSL).',
},
})
),
dsl: schema.maybe(schema.string()),
});

View file

@ -8,40 +8,156 @@
import { schema } from '@kbn/config-schema';
export const rRuleResponseSchema = schema.object({
dtstart: schema.string(),
tzid: schema.string(),
dtstart: schema.string({
meta: {
description: 'Rule start date in Coordinated Universal Time (UTC).',
},
}),
tzid: schema.string({
meta: {
description: 'Indicates timezone abbreviation.',
},
}),
freq: schema.maybe(
schema.oneOf([
schema.literal(0),
schema.literal(1),
schema.literal(2),
schema.literal(3),
schema.literal(4),
schema.literal(5),
schema.literal(6),
])
schema.oneOf(
[
schema.literal(0),
schema.literal(1),
schema.literal(2),
schema.literal(3),
schema.literal(4),
schema.literal(5),
schema.literal(6),
],
{
meta: {
description:
'Indicates frequency of the rule. Options are YEARLY, MONTHLY, WEEKLY, DAILY.',
},
}
)
),
until: schema.maybe(
schema.string({
meta: {
description: 'Recur the rule until this date.',
},
})
),
count: schema.maybe(
schema.number({
meta: {
description: 'Number of times the rule should recur until it stops.',
},
})
),
interval: schema.maybe(
schema.number({
meta: {
description:
'Indicates the interval of frequency. For example, 1 and YEARLY is every 1 year, 2 and WEEKLY is every 2 weeks.',
},
})
),
until: schema.maybe(schema.string()),
count: schema.maybe(schema.number()),
interval: schema.maybe(schema.number()),
wkst: schema.maybe(
schema.oneOf([
schema.literal('MO'),
schema.literal('TU'),
schema.literal('WE'),
schema.literal('TH'),
schema.literal('FR'),
schema.literal('SA'),
schema.literal('SU'),
])
schema.oneOf(
[
schema.literal('MO'),
schema.literal('TU'),
schema.literal('WE'),
schema.literal('TH'),
schema.literal('FR'),
schema.literal('SA'),
schema.literal('SU'),
],
{
meta: {
description: 'Indicates the start of week, defaults to Monday.',
},
}
)
),
byweekday: schema.maybe(
schema.arrayOf(
schema.oneOf([schema.string(), schema.number()], {
meta: {
description:
'Indicates the days of the week to recur or else nth-day-of-month strings. For example, "+2TU" second Tuesday of month, "-1FR" last Friday of the month, which are internally converted to a `byweekday/bysetpos` combination.',
},
})
)
),
bymonth: schema.maybe(
schema.arrayOf(
schema.number({
meta: {
description: 'Indicates months of the year that this rule should recur.',
},
})
)
),
bysetpos: schema.maybe(
schema.arrayOf(
schema.number({
meta: {
description:
'A positive or negative integer affecting the nth day of the month. For example, -2 combined with `byweekday` of FR is 2nd to last Friday of the month. It is recommended to not set this manually and just use `byweekday`.',
},
})
)
),
bymonthday: schema.maybe(
schema.arrayOf(
schema.number({
meta: {
description: 'Indicates the days of the month to recur.',
},
})
)
),
byyearday: schema.maybe(
schema.arrayOf(
schema.number({
meta: {
description: 'Indicates the days of the year that this rule should recur.',
},
})
)
),
byweekno: schema.maybe(
schema.arrayOf(
schema.number({
meta: {
description: 'Indicates number of the week hours to recur.',
},
})
)
),
byhour: schema.maybe(
schema.arrayOf(
schema.number({
meta: {
description: 'Indicates hours of the day to recur.',
},
})
)
),
byminute: schema.maybe(
schema.arrayOf(
schema.number({
meta: {
description: 'Indicates minutes of the hour to recur.',
},
})
)
),
bysecond: schema.maybe(
schema.arrayOf(
schema.number({
meta: {
description: 'Indicates seconds of the day to recur.',
},
})
)
),
byweekday: schema.maybe(schema.arrayOf(schema.oneOf([schema.string(), schema.number()]))),
bymonth: schema.maybe(schema.arrayOf(schema.number())),
bysetpos: schema.maybe(schema.arrayOf(schema.number())),
bymonthday: schema.maybe(schema.arrayOf(schema.number())),
byyearday: schema.maybe(schema.arrayOf(schema.number())),
byweekno: schema.maybe(schema.arrayOf(schema.number())),
byhour: schema.maybe(schema.arrayOf(schema.number())),
byminute: schema.maybe(schema.arrayOf(schema.number())),
bysecond: schema.maybe(schema.arrayOf(schema.number())),
});

View file

@ -114,7 +114,13 @@ export const actionSchema = schema.object(
})
),
alerts_filter: schema.maybe(actionAlertsFilterSchema),
use_alert_data_for_template: schema.maybe(schema.boolean()),
use_alert_data_for_template: schema.maybe(
schema.boolean({
meta: {
description: 'Indicates whether to use alert data as a template.',
},
})
),
},
{
meta: { description: 'An action that runs under defined conditions.' },
@ -183,5 +189,11 @@ export const createBodySchema = schema.object({
});
export const createParamsSchema = schema.object({
id: schema.maybe(schema.string()),
id: schema.maybe(
schema.string({
meta: {
description: 'The identifier for the rule.',
},
})
),
});

View file

@ -8,5 +8,9 @@
import { schema } from '@kbn/config-schema';
export const deleteRuleRequestParamsSchema = schema.object({
id: schema.string(),
id: schema.string({
meta: {
description: 'The identifier for the rule.',
},
}),
});

View file

@ -8,26 +8,98 @@
import { schema } from '@kbn/config-schema';
export const findRulesRequestQuerySchema = schema.object({
per_page: schema.number({ defaultValue: 10, min: 0 }),
page: schema.number({ defaultValue: 1, min: 1 }),
search: schema.maybe(schema.string()),
per_page: schema.number({
defaultValue: 10,
min: 0,
meta: {
description: 'The number of rules to return per page.',
},
}),
page: schema.number({
defaultValue: 1,
min: 1,
meta: {
description: 'The page number to return.',
},
}),
search: schema.maybe(
schema.string({
meta: {
description:
'An Elasticsearch simple_query_string query that filters the objects in the response.',
},
})
),
default_search_operator: schema.oneOf([schema.literal('OR'), schema.literal('AND')], {
defaultValue: 'OR',
meta: {
description: 'The default operator to use for the simple_query_string.',
},
}),
search_fields: schema.maybe(schema.oneOf([schema.arrayOf(schema.string()), schema.string()])),
sort_field: schema.maybe(schema.string()),
sort_order: schema.maybe(schema.oneOf([schema.literal('asc'), schema.literal('desc')])),
search_fields: schema.maybe(
schema.oneOf([schema.arrayOf(schema.string()), schema.string()], {
meta: {
description: 'The fields to perform the simple_query_string parsed query against.',
},
})
),
sort_field: schema.maybe(
schema.string({
meta: {
description:
'Determines which field is used to sort the results. The field must exist in the `attributes` key of the response.',
},
})
),
sort_order: schema.maybe(
schema.oneOf([schema.literal('asc'), schema.literal('desc')], {
meta: {
description: 'Determines the sort order.',
},
})
),
has_reference: schema.maybe(
// use nullable as maybe is currently broken
// in config-schema
schema.nullable(
schema.object({
type: schema.string(),
id: schema.string(),
schema.object(
{
type: schema.string(),
id: schema.string(),
},
{
meta: {
description:
'Filters the rules that have a relation with the reference objects with a specific type and identifier.',
},
}
)
)
),
fields: schema.maybe(
schema.arrayOf(
schema.string({
meta: {
description: 'The fields to return in the `attributes` key of the response.',
},
})
)
),
filter: schema.maybe(
schema.string({
meta: {
description:
'A KQL string that you filter with an attribute from your saved object. It should look like `savedObjectType.attributes.title: "myTitle"`. However, if you used a direct attribute of a saved object, such as `updatedAt`, you must define your filter, for example, `savedObjectType.updatedAt > 2018-12-22`.',
},
})
),
filter_consumers: schema.maybe(
schema.arrayOf(
schema.string({
meta: {
description: 'List of consumers to filter.',
},
})
)
),
fields: schema.maybe(schema.arrayOf(schema.string())),
filter: schema.maybe(schema.string()),
filter_consumers: schema.maybe(schema.arrayOf(schema.string())),
});

View file

@ -8,5 +8,9 @@
import { schema } from '@kbn/config-schema';
export const getRuleRequestParamsSchema = schema.object({
id: schema.string(),
id: schema.string({
meta: {
description: 'The identifier for the rule.',
},
}),
});

View file

@ -8,6 +8,14 @@
import { schema } from '@kbn/config-schema';
export const muteAlertParamsSchema = schema.object({
rule_id: schema.string(),
alert_id: schema.string(),
rule_id: schema.string({
meta: {
description: 'The identifier for the rule.',
},
}),
alert_id: schema.string({
meta: {
description: 'The identifier for the alert.',
},
}),
});

View file

@ -11,62 +11,159 @@ import { notifyWhenSchemaV1, alertDelaySchemaV1 } from '../../../response';
import { alertsFilterQuerySchemaV1 } from '../../../../alerts_filter_query';
export const actionFrequencySchema = schema.object({
summary: schema.boolean(),
summary: schema.boolean({
meta: { description: 'Indicates whether the action is a summary.' },
}),
notify_when: notifyWhenSchemaV1,
throttle: schema.nullable(schema.string({ validate: validateDurationV1 })),
throttle: schema.nullable(
schema.string({
validate: validateDurationV1,
meta: {
description:
'The throttle interval, which defines how often an alert generates repeated actions. It is specified in seconds, minutes, hours, or days and is applicable only if `notify_when` is set to `onThrottleInterval`. NOTE: You cannot specify the throttle interval at both the rule and action level. The recommended method is to set it for each action. If you set it at the rule level then update the rule in Kibana, it is automatically changed to use action-specific values.',
},
})
),
});
export const actionAlertsFilterSchema = schema.object({
query: schema.maybe(alertsFilterQuerySchemaV1),
timeframe: schema.maybe(
schema.object({
days: schema.arrayOf(
schema.oneOf([
schema.literal(1),
schema.literal(2),
schema.literal(3),
schema.literal(4),
schema.literal(5),
schema.literal(6),
schema.literal(7),
])
),
hours: schema.object({
start: schema.string({
validate: validateHoursV1,
schema.object(
{
days: schema.arrayOf(
schema.oneOf([
schema.literal(1),
schema.literal(2),
schema.literal(3),
schema.literal(4),
schema.literal(5),
schema.literal(6),
schema.literal(7),
]),
{
meta: {
description:
'Defines the days of the week that the action can run, represented as an array of numbers. For example, `1` represents Monday. An empty array is equivalent to specifying all the days of the week.',
},
}
),
hours: schema.object(
{
start: schema.string({
validate: validateHoursV1,
meta: { description: 'The start of the time frame in 24-hour notation (`hh:mm`).' },
}),
end: schema.string({
validate: validateHoursV1,
meta: { description: 'The end of the time frame in 24-hour notation (`hh:mm`).' },
}),
},
{
meta: {
description:
'Defines the range of time in a day that the action can run. If the `start` value is `00:00` and the `end` value is `24:00`, actions be generated all day.',
},
}
),
timezone: schema.string({
validate: validateTimezoneV1,
meta: {
description:
'The ISO time zone for the `hours` values. Values such as `UTC` and `UTC+1` also work but lack built-in daylight savings time support and are not recommended.',
},
}),
end: schema.string({
validate: validateHoursV1,
}),
}),
timezone: schema.string({ validate: validateTimezoneV1 }),
})
},
{ meta: { description: 'Defines a period that limits whether the action runs.' } }
)
),
});
export const actionSchema = schema.object({
group: schema.maybe(schema.string()),
id: schema.string(),
params: schema.recordOf(schema.string(), schema.any(), { defaultValue: {} }),
frequency: schema.maybe(actionFrequencySchema),
uuid: schema.maybe(schema.string()),
alerts_filter: schema.maybe(actionAlertsFilterSchema),
use_alert_data_for_template: schema.maybe(schema.boolean()),
});
export const actionSchema = schema.object(
{
group: schema.maybe(
schema.string({
meta: {
description:
"The group name, which affects when the action runs (for example, when the threshold is met or when the alert is recovered). Each rule type has a list of valid action group names. If you don't need to group actions, set to `default`.",
},
})
),
id: schema.string({
meta: { description: 'The identifier for the connector saved object.' },
}),
params: schema.recordOf(schema.string(), schema.any(), {
defaultValue: {},
meta: {
description:
'The parameters for the action, which are sent to the connector. The `params` are handled as Mustache templates and passed a default set of context.',
},
}),
frequency: schema.maybe(actionFrequencySchema),
uuid: schema.maybe(
schema.string({
meta: { description: 'A universally unique identifier (UUID) for the action.' },
})
),
alerts_filter: schema.maybe(actionAlertsFilterSchema),
use_alert_data_for_template: schema.maybe(
schema.boolean({
meta: {
description: 'Indicates whether to use alert data as a template.',
},
})
),
},
{
meta: { description: 'An action that runs under defined conditions.' },
}
);
export const updateBodySchema = schema.object({
name: schema.string(),
tags: schema.arrayOf(schema.string(), { defaultValue: [] }),
schedule: schema.object({
interval: schema.string({ validate: validateDurationV1 }),
name: schema.string({
meta: {
description:
'The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.',
},
}),
tags: schema.arrayOf(
schema.string({
meta: {
description: 'The tags for the rule.',
},
}),
{ defaultValue: [] }
),
schedule: schema.object({
interval: schema.string({
validate: validateDurationV1,
meta: { description: 'The interval is specified in seconds, minutes, hours, or days.' },
}),
}),
throttle: schema.maybe(
schema.nullable(
schema.string({
validate: validateDurationV1,
meta: {
description:
'Use the `throttle` property in the action `frequency` object instead. The throttle interval, which defines how often an alert generates repeated actions. NOTE: You cannot specify the throttle interval at both the rule and action level. If you set it at the rule level then update the rule in Kibana, it is automatically changed to use action-specific values.',
},
})
)
),
params: schema.recordOf(schema.string(), schema.any(), {
defaultValue: {},
meta: { description: 'The parameters for the rule.' },
}),
throttle: schema.maybe(schema.nullable(schema.string({ validate: validateDurationV1 }))),
params: schema.recordOf(schema.string(), schema.any(), { defaultValue: {} }),
actions: schema.arrayOf(actionSchema, { defaultValue: [] }),
notify_when: schema.maybe(schema.nullable(notifyWhenSchemaV1)),
alert_delay: schema.maybe(alertDelaySchemaV1),
});
export const updateParamsSchema = schema.object({
id: schema.string(),
id: schema.string({
meta: {
description: 'The identifier for the rule.',
},
}),
});

View file

@ -17,9 +17,19 @@ import {
} from '../../common/constants/v1';
import { validateNotifyWhenV1 } from '../../validation';
export const ruleParamsSchema = schema.recordOf(schema.string(), schema.maybe(schema.any()));
export const actionParamsSchema = schema.recordOf(schema.string(), schema.maybe(schema.any()));
export const mappedParamsSchema = schema.recordOf(schema.string(), schema.maybe(schema.any()));
export const ruleParamsSchema = schema.recordOf(schema.string(), schema.maybe(schema.any()), {
meta: { description: 'The parameters for the rule.' },
});
export const actionParamsSchema = schema.recordOf(schema.string(), schema.maybe(schema.any()), {
meta: {
description:
'The parameters for the action, which are sent to the connector. The `params` are handled as Mustache templates and passed a default set of context.',
},
});
export const mappedParamsSchema = schema.recordOf(
schema.string({ meta: { description: 'The mapped parameters for the rule.' } }),
schema.maybe(schema.any())
);
export const notifyWhenSchema = schema.oneOf(
[
@ -37,156 +47,404 @@ export const notifyWhenSchema = schema.oneOf(
);
const intervalScheduleSchema = schema.object({
interval: schema.string(),
interval: schema.string({
meta: { description: 'The interval is specified in seconds, minutes, hours, or days.' },
}),
});
const actionFrequencySchema = schema.object({
summary: schema.boolean(),
summary: schema.boolean({ meta: { description: 'Indicates whether the action is a summary.' } }),
notify_when: notifyWhenSchema,
throttle: schema.nullable(schema.string()),
});
const actionAlertsFilterSchema = schema.object({
query: schema.maybe(alertsFilterQuerySchemaV1),
timeframe: schema.maybe(
schema.object({
days: schema.arrayOf(
schema.oneOf([
schema.literal(1),
schema.literal(2),
schema.literal(3),
schema.literal(4),
schema.literal(5),
schema.literal(6),
schema.literal(7),
])
),
hours: schema.object({
start: schema.string(),
end: schema.string(),
}),
timezone: schema.string(),
throttle: schema.nullable(
schema.string({
meta: {
description: `The throttle interval, which defines how often an alert generates repeated actions. It is specified in seconds, minutes, hours, or days and is applicable only if 'notify_when' is set to 'onThrottleInterval'. NOTE: You cannot specify the throttle interval at both the rule and action level. The recommended method is to set it for each action. If you set it at the rule level then update the rule in Kibana, it is automatically changed to use action-specific values.`,
},
})
),
});
const actionAlertsFilterSchema = schema.object(
{
query: schema.maybe(alertsFilterQuerySchemaV1),
timeframe: schema.maybe(
schema.object({
days: schema.arrayOf(
schema.oneOf([
schema.literal(1),
schema.literal(2),
schema.literal(3),
schema.literal(4),
schema.literal(5),
schema.literal(6),
schema.literal(7),
]),
{
meta: {
description:
'Defines the days of the week that the action can run, represented as an array of numbers. For example, `1` represents Monday. An empty array is equivalent to specifying all the days of the week.',
},
}
),
hours: schema.object({
start: schema.string({
meta: {
description: 'The start of the time frame in 24-hour notation (`hh:mm`).',
},
}),
end: schema.string({
meta: {
description: 'The end of the time frame in 24-hour notation (`hh:mm`).',
},
}),
}),
timezone: schema.string({
meta: {
description:
'The ISO time zone for the `hours` values. Values such as `UTC` and `UTC+1` also work but lack built-in daylight savings time support and are not recommended.',
},
}),
})
),
},
{
meta: {
description: 'Defines a period that limits whether the action runs.',
},
}
);
const actionSchema = schema.object({
uuid: schema.maybe(schema.string()),
group: schema.maybe(schema.string()),
id: schema.string(),
connector_type_id: schema.string(),
uuid: schema.maybe(
schema.string({
meta: { description: 'A universally unique identifier (UUID) for the action.' },
})
),
group: schema.maybe(
schema.string({
meta: {
description:
"The group name, which affects when the action runs (for example, when the threshold is met or when the alert is recovered). Each rule type has a list of valid action group names. If you don't need to group actions, set to `default`.",
},
})
),
id: schema.string({
meta: { description: 'The identifier for the connector saved object.' },
}),
connector_type_id: schema.string({
meta: {
description:
'The type of connector. This property appears in responses but cannot be set in requests.',
},
}),
params: actionParamsSchema,
frequency: schema.maybe(actionFrequencySchema),
alerts_filter: schema.maybe(actionAlertsFilterSchema),
use_alert_data_for_template: schema.maybe(schema.boolean()),
use_alert_data_for_template: schema.maybe(
schema.boolean({
meta: { description: 'Indicates whether to use alert data as a template.' },
})
),
});
export const ruleExecutionStatusSchema = schema.object({
status: schema.oneOf([
schema.literal(ruleExecutionStatusValuesV1.OK),
schema.literal(ruleExecutionStatusValuesV1.ACTIVE),
schema.literal(ruleExecutionStatusValuesV1.ERROR),
schema.literal(ruleExecutionStatusValuesV1.WARNING),
schema.literal(ruleExecutionStatusValuesV1.PENDING),
schema.literal(ruleExecutionStatusValuesV1.UNKNOWN),
]),
last_execution_date: schema.string(),
last_duration: schema.maybe(schema.number()),
status: schema.oneOf(
[
schema.literal(ruleExecutionStatusValuesV1.OK),
schema.literal(ruleExecutionStatusValuesV1.ACTIVE),
schema.literal(ruleExecutionStatusValuesV1.ERROR),
schema.literal(ruleExecutionStatusValuesV1.WARNING),
schema.literal(ruleExecutionStatusValuesV1.PENDING),
schema.literal(ruleExecutionStatusValuesV1.UNKNOWN),
],
{
meta: {
description: 'Status of rule execution.',
},
}
),
last_execution_date: schema.string({
meta: {
description: 'The date and time when rule was executed last.',
},
}),
last_duration: schema.maybe(
schema.number({
meta: {
description: 'Duration of last execution of the rule.',
},
})
),
error: schema.maybe(
schema.object({
reason: schema.oneOf([
schema.literal(ruleExecutionStatusErrorReasonV1.READ),
schema.literal(ruleExecutionStatusErrorReasonV1.DECRYPT),
schema.literal(ruleExecutionStatusErrorReasonV1.EXECUTE),
schema.literal(ruleExecutionStatusErrorReasonV1.UNKNOWN),
schema.literal(ruleExecutionStatusErrorReasonV1.LICENSE),
schema.literal(ruleExecutionStatusErrorReasonV1.TIMEOUT),
schema.literal(ruleExecutionStatusErrorReasonV1.DISABLED),
schema.literal(ruleExecutionStatusErrorReasonV1.VALIDATE),
]),
message: schema.string(),
reason: schema.oneOf(
[
schema.literal(ruleExecutionStatusErrorReasonV1.READ),
schema.literal(ruleExecutionStatusErrorReasonV1.DECRYPT),
schema.literal(ruleExecutionStatusErrorReasonV1.EXECUTE),
schema.literal(ruleExecutionStatusErrorReasonV1.UNKNOWN),
schema.literal(ruleExecutionStatusErrorReasonV1.LICENSE),
schema.literal(ruleExecutionStatusErrorReasonV1.TIMEOUT),
schema.literal(ruleExecutionStatusErrorReasonV1.DISABLED),
schema.literal(ruleExecutionStatusErrorReasonV1.VALIDATE),
],
{
meta: {
description: 'Reason for error.',
},
}
),
message: schema.string({
meta: {
description: 'Error message.',
},
}),
})
),
warning: schema.maybe(
schema.object({
reason: schema.oneOf([
schema.literal(ruleExecutionStatusWarningReasonV1.MAX_EXECUTABLE_ACTIONS),
schema.literal(ruleExecutionStatusWarningReasonV1.MAX_ALERTS),
schema.literal(ruleExecutionStatusWarningReasonV1.MAX_QUEUED_ACTIONS),
]),
message: schema.string(),
reason: schema.oneOf(
[
schema.literal(ruleExecutionStatusWarningReasonV1.MAX_EXECUTABLE_ACTIONS),
schema.literal(ruleExecutionStatusWarningReasonV1.MAX_ALERTS),
schema.literal(ruleExecutionStatusWarningReasonV1.MAX_QUEUED_ACTIONS),
],
{
meta: {
description: 'Reason for warning.',
},
}
),
message: schema.string({
meta: {
description: 'Warning message.',
},
}),
})
),
});
export const ruleLastRunSchema = schema.object({
outcome: schema.oneOf([
schema.literal(ruleLastRunOutcomeValuesV1.SUCCEEDED),
schema.literal(ruleLastRunOutcomeValuesV1.WARNING),
schema.literal(ruleLastRunOutcomeValuesV1.FAILED),
]),
outcome_order: schema.maybe(schema.number()),
outcome: schema.oneOf(
[
schema.literal(ruleLastRunOutcomeValuesV1.SUCCEEDED),
schema.literal(ruleLastRunOutcomeValuesV1.WARNING),
schema.literal(ruleLastRunOutcomeValuesV1.FAILED),
],
{
meta: {
description:
'Outcome of last run of the rule. Value could be succeeded, warning or failed.',
},
}
),
outcome_order: schema.maybe(
schema.number({
meta: {
description: 'Order of the outcome.',
},
})
),
warning: schema.maybe(
schema.nullable(
schema.oneOf([
schema.literal(ruleExecutionStatusErrorReasonV1.READ),
schema.literal(ruleExecutionStatusErrorReasonV1.DECRYPT),
schema.literal(ruleExecutionStatusErrorReasonV1.EXECUTE),
schema.literal(ruleExecutionStatusErrorReasonV1.UNKNOWN),
schema.literal(ruleExecutionStatusErrorReasonV1.LICENSE),
schema.literal(ruleExecutionStatusErrorReasonV1.TIMEOUT),
schema.literal(ruleExecutionStatusErrorReasonV1.DISABLED),
schema.literal(ruleExecutionStatusErrorReasonV1.VALIDATE),
schema.literal(ruleExecutionStatusWarningReasonV1.MAX_EXECUTABLE_ACTIONS),
schema.literal(ruleExecutionStatusWarningReasonV1.MAX_ALERTS),
schema.literal(ruleExecutionStatusWarningReasonV1.MAX_QUEUED_ACTIONS),
])
schema.oneOf(
[
schema.literal(ruleExecutionStatusErrorReasonV1.READ),
schema.literal(ruleExecutionStatusErrorReasonV1.DECRYPT),
schema.literal(ruleExecutionStatusErrorReasonV1.EXECUTE),
schema.literal(ruleExecutionStatusErrorReasonV1.UNKNOWN),
schema.literal(ruleExecutionStatusErrorReasonV1.LICENSE),
schema.literal(ruleExecutionStatusErrorReasonV1.TIMEOUT),
schema.literal(ruleExecutionStatusErrorReasonV1.DISABLED),
schema.literal(ruleExecutionStatusErrorReasonV1.VALIDATE),
schema.literal(ruleExecutionStatusWarningReasonV1.MAX_EXECUTABLE_ACTIONS),
schema.literal(ruleExecutionStatusWarningReasonV1.MAX_ALERTS),
schema.literal(ruleExecutionStatusWarningReasonV1.MAX_QUEUED_ACTIONS),
],
{
meta: {
description: 'Warning of last rule execution.',
},
}
)
)
),
outcome_msg: schema.maybe(
schema.nullable(
schema.arrayOf(
schema.string({
meta: {
description: 'Outcome message generated during last rule run.',
},
})
)
)
),
outcome_msg: schema.maybe(schema.nullable(schema.arrayOf(schema.string()))),
alerts_count: schema.object({
active: schema.maybe(schema.nullable(schema.number())),
new: schema.maybe(schema.nullable(schema.number())),
recovered: schema.maybe(schema.nullable(schema.number())),
ignored: schema.maybe(schema.nullable(schema.number())),
active: schema.maybe(
schema.nullable(
schema.number({
meta: {
description: 'Number of active alerts during last run.',
},
})
)
),
new: schema.maybe(
schema.nullable(
schema.number({
meta: {
description: 'Number of new alerts during last run.',
},
})
)
),
recovered: schema.maybe(
schema.nullable(
schema.number({
meta: {
description: 'Number of recovered alerts during last run.',
},
})
)
),
ignored: schema.maybe(
schema.nullable(
schema.number({
meta: {
description: 'Number of ignored alerts during last run.',
},
})
)
),
}),
});
export const monitoringSchema = schema.object({
run: schema.object({
history: schema.arrayOf(
schema.object({
success: schema.boolean(),
timestamp: schema.number(),
duration: schema.maybe(schema.number()),
outcome: schema.maybe(ruleLastRunSchema),
})
export const monitoringSchema = schema.object(
{
run: schema.object(
{
history: schema.arrayOf(
schema.object({
success: schema.boolean({
meta: { description: 'Indicates whether the rule run was successful.' },
}),
timestamp: schema.number({ meta: { description: 'Time of rule run.' } }),
duration: schema.maybe(
schema.number({ meta: { description: 'Duration of the rule run.' } })
),
outcome: schema.maybe(ruleLastRunSchema),
}),
{ meta: { description: 'History of the rule run.' } }
),
calculated_metrics: schema.object(
{
p50: schema.maybe(schema.number()),
p95: schema.maybe(schema.number()),
p99: schema.maybe(schema.number()),
success_ratio: schema.number(),
},
{
meta: {
description: 'Calculation of different percentiles and success ratio.',
},
}
),
last_run: schema.object({
timestamp: schema.string({
meta: { description: 'Time of the most recent rule run.' },
}),
metrics: schema.object({
duration: schema.maybe(
schema.number({
meta: { description: 'Duration of most recent rule run.' },
})
),
total_search_duration_ms: schema.maybe(
schema.nullable(
schema.number({
meta: {
description:
'Total time spent performing Elasticsearch searches as measured by Kibana; includes network latency and time spent serializing or deserializing the request and response.',
},
})
)
),
total_indexing_duration_ms: schema.maybe(
schema.nullable(
schema.number({
meta: {
description:
'Total time spent indexing documents during last rule run in milliseconds.',
},
})
)
),
total_alerts_detected: schema.maybe(
schema.nullable(
schema.number({
meta: { description: 'Total number of alerts detected during last rule run.' },
})
)
),
total_alerts_created: schema.maybe(
schema.nullable(
schema.number({
meta: {
description: 'Total number of alerts created during last rule run.',
},
})
)
),
gap_duration_s: schema.maybe(
schema.nullable(
schema.number({
meta: {
description: 'Duration in seconds of rule run gap.',
},
})
)
),
}),
}),
},
{
meta: {
description: 'Rule run details.',
},
}
),
calculated_metrics: schema.object({
p50: schema.maybe(schema.number()),
p95: schema.maybe(schema.number()),
p99: schema.maybe(schema.number()),
success_ratio: schema.number(),
}),
last_run: schema.object({
timestamp: schema.string(),
metrics: schema.object({
duration: schema.maybe(schema.number()),
total_search_duration_ms: schema.maybe(schema.nullable(schema.number())),
total_indexing_duration_ms: schema.maybe(schema.nullable(schema.number())),
total_alerts_detected: schema.maybe(schema.nullable(schema.number())),
total_alerts_created: schema.maybe(schema.nullable(schema.number())),
gap_duration_s: schema.maybe(schema.nullable(schema.number())),
}),
}),
}),
});
},
{
meta: {
description: 'Monitoring details of the rule.',
},
}
);
export const ruleSnoozeScheduleSchema = schema.object({
id: schema.maybe(schema.string()),
duration: schema.number(),
id: schema.maybe(
schema.string({
meta: {
description: 'Identifier of the rule snooze schedule.',
},
})
),
duration: schema.number({
meta: {
description: 'Duration of the rule snooze schedule.',
},
}),
rRule: rRuleResponseSchemaV1,
skipRecurrences: schema.maybe(schema.arrayOf(schema.string())),
skipRecurrences: schema.maybe(
schema.arrayOf(
schema.string({
meta: {
description: 'Skips recurrence of rule on this date.',
},
})
)
),
});
export const alertDelaySchema = schema.object(
@ -204,37 +462,167 @@ export const alertDelaySchema = schema.object(
);
export const ruleResponseSchema = schema.object({
id: schema.string(),
enabled: schema.boolean(),
name: schema.string(),
tags: schema.arrayOf(schema.string()),
rule_type_id: schema.string(),
consumer: schema.string(),
id: schema.string({
meta: {
description: 'The identifier for the rule.',
},
}),
enabled: schema.boolean({
meta: {
description:
'Indicates whether you want to run the rule on an interval basis after it is created.',
},
}),
name: schema.string({
meta: {
description: ' The name of the rule.',
},
}),
tags: schema.arrayOf(
schema.string({
meta: { description: 'The tags for the rule.' },
})
),
rule_type_id: schema.string({
meta: { description: 'The rule type identifier.' },
}),
consumer: schema.string({
meta: {
description:
'The name of the application or feature that owns the rule. For example: `alerts`, `apm`, `discover`, `infrastructure`, `logs`, `metrics`, `ml`, `monitoring`, `securitySolution`, `siem`, `stackAlerts`, or `uptime`.',
},
}),
schedule: intervalScheduleSchema,
actions: schema.arrayOf(actionSchema),
params: ruleParamsSchema,
mapped_params: schema.maybe(mappedParamsSchema),
scheduled_task_id: schema.maybe(schema.string()),
created_by: schema.nullable(schema.string()),
updated_by: schema.nullable(schema.string()),
created_at: schema.string(),
updated_at: schema.string(),
api_key_owner: schema.nullable(schema.string()),
api_key_created_by_user: schema.maybe(schema.nullable(schema.boolean())),
throttle: schema.maybe(schema.nullable(schema.string())),
mute_all: schema.boolean(),
scheduled_task_id: schema.maybe(
schema.string({
meta: {
description: 'Identifier of the scheduled task.',
},
})
),
created_by: schema.nullable(
schema.string({
meta: {
description: 'The identifier for the user that created the rule.',
},
})
),
updated_by: schema.nullable(
schema.string({
meta: {
description: 'The identifier for the user that updated this rule most recently.',
},
})
),
created_at: schema.string({
meta: {
description: 'The date and time that the rule was created.',
},
}),
updated_at: schema.string({
meta: {
description: 'The date and time that the rule was updated most recently.',
},
}),
api_key_owner: schema.nullable(
schema.string({
meta: {
description:
'The owner of the API key that is associated with the rule and used to run background tasks.',
},
})
),
api_key_created_by_user: schema.maybe(
schema.nullable(
schema.boolean({
meta: {
description:
'Indicates whether the API key that is associated with the rule was created by the user.',
},
})
)
),
throttle: schema.maybe(
schema.nullable(
schema.string({
meta: {
description:
'Deprecated in 8.13.0. Use the `throttle` property in the action `frequency` object instead. The throttle interval, which defines how often an alert generates repeated actions. NOTE: You cannot specify the throttle interval at both the rule and action level. If you set it at the rule level then update the rule in Kibana, it is automatically changed to use action-specific values.',
deprecated: true,
},
})
)
),
mute_all: schema.boolean({
meta: {
description: 'Indicates whether all alerts are muted.',
},
}),
notify_when: schema.maybe(schema.nullable(notifyWhenSchema)),
muted_alert_ids: schema.arrayOf(schema.string()),
muted_alert_ids: schema.arrayOf(
schema.string({
meta: {
description: 'List of identifiers of muted alerts. ',
},
})
),
execution_status: ruleExecutionStatusSchema,
monitoring: schema.maybe(monitoringSchema),
snooze_schedule: schema.maybe(schema.arrayOf(ruleSnoozeScheduleSchema)),
active_snoozes: schema.maybe(schema.arrayOf(schema.string())),
is_snoozed_until: schema.maybe(schema.nullable(schema.string())),
active_snoozes: schema.maybe(
schema.arrayOf(
schema.string({
meta: {
description: `List of active snoozes for the rule.`,
},
})
)
),
is_snoozed_until: schema.maybe(
schema.nullable(
schema.string({
meta: {
description: 'The date when the rule will no longer be snoozed.',
},
})
)
),
last_run: schema.maybe(schema.nullable(ruleLastRunSchema)),
next_run: schema.maybe(schema.nullable(schema.string())),
revision: schema.number(),
running: schema.maybe(schema.nullable(schema.boolean())),
view_in_app_relative_url: schema.maybe(schema.nullable(schema.string())),
next_run: schema.maybe(
schema.nullable(
schema.string({
meta: {
description: 'Date and time of the next run of the rule.',
},
})
)
),
revision: schema.number({
meta: {
description: 'The rule revision number.',
},
}),
running: schema.maybe(
schema.nullable(
schema.boolean({
meta: {
description: 'Indicates whether the rule is running.',
},
})
)
),
view_in_app_relative_url: schema.maybe(
schema.nullable(
schema.string({
meta: {
description: 'Relative URL to view rule in the app.',
},
})
)
),
alert_delay: schema.maybe(alertDelaySchema),
});

View file

@ -22,7 +22,7 @@ import {
createBodySchemaV1,
createParamsSchemaV1,
} from '../../../../../common/routes/rule/apis/create';
import type { RuleParamsV1 } from '../../../../../common/routes/rule/response';
import { RuleParamsV1, ruleResponseSchemaV1 } from '../../../../../common/routes/rule/response';
import { Rule } from '../../../../application/rule/types';
import { transformCreateBodyV1 } from './transforms';
import { transformRuleToRuleResponseV1 } from '../../transforms';
@ -37,8 +37,16 @@ export const createRuleRoute = ({ router, licenseState, usageCounter }: RouteOpt
summary: `Create a rule`,
},
validate: {
body: createBodySchemaV1,
params: createParamsSchemaV1,
request: {
body: createBodySchemaV1,
params: createParamsSchemaV1,
},
response: {
200: {
body: () => ruleResponseSchemaV1,
description: 'Indicates a successful call.',
},
},
},
},
handleDisabledApiKeysError(

View file

@ -26,7 +26,14 @@ export const deleteRuleRoute = (
summary: `Delete a rule`,
},
validate: {
params: deleteRuleRequestParamsSchemaV1,
request: {
params: deleteRuleRequestParamsSchemaV1,
},
response: {
204: {
description: 'Indicates a successful call.',
},
},
},
},
router.handleLegacyErrors(

View file

@ -14,7 +14,7 @@ import type {
FindRulesRequestQueryV1,
FindRulesResponseV1,
} from '../../../../../common/routes/rule/apis/find';
import type { RuleParamsV1 } from '../../../../../common/routes/rule/response';
import { RuleParamsV1, ruleResponseSchemaV1 } from '../../../../../common/routes/rule/response';
import {
AlertingRequestHandlerContext,
BASE_ALERTING_API_PATH,
@ -43,10 +43,18 @@ const buildFindRulesRoute = ({
path,
options: {
access: 'public',
summary: `Get rules`,
summary: `Get information about rules.`,
},
validate: {
query: findRulesRequestQuerySchemaV1,
request: {
query: findRulesRequestQuerySchemaV1,
},
response: {
200: {
body: () => ruleResponseSchemaV1,
description: 'Indicates a successful call.',
},
},
},
},
router.handleLegacyErrors(

View file

@ -8,7 +8,7 @@
import { IRouter, RouteConfigOptions, RouteMethod } from '@kbn/core/server';
import { ILicenseState } from '../../../../lib';
import { verifyAccessAndContext } from '../../../lib';
import type { RuleParamsV1 } from '../../../../../common/routes/rule/response';
import { RuleParamsV1, ruleResponseSchemaV1 } from '../../../../../common/routes/rule/response';
import { Rule } from '../../../../application/rule/types';
import {
AlertingRequestHandlerContext,
@ -42,7 +42,15 @@ const buildGetRuleRoute = ({
path,
options,
validate: {
params: getRuleRequestParamsSchemaV1,
request: {
params: getRuleRequestParamsSchemaV1,
},
response: {
200: {
body: () => ruleResponseSchemaV1,
description: 'Indicates a successful call.',
},
},
},
},
router.handleLegacyErrors(

View file

@ -26,7 +26,14 @@ export const muteAlertRoute = (
summary: `Mute an alert`,
},
validate: {
params: muteAlertParamsSchemaV1,
request: {
params: muteAlertParamsSchemaV1,
},
response: {
204: {
description: 'Indicates a successful call.',
},
},
},
},
router.handleLegacyErrors(

View file

@ -17,7 +17,7 @@ import {
updateBodySchemaV1,
updateParamsSchemaV1,
} from '../../../../../common/routes/rule/apis/update';
import type { RuleParamsV1 } from '../../../../../common/routes/rule/response';
import { RuleParamsV1, ruleResponseSchemaV1 } from '../../../../../common/routes/rule/response';
import { AlertingRequestHandlerContext, BASE_ALERTING_API_PATH } from '../../../../types';
import { Rule } from '../../../../application/rule/types';
import { transformUpdateBodyV1 } from './transforms';
@ -36,8 +36,16 @@ export const updateRuleRoute = (
summary: `Update a rule`,
},
validate: {
body: updateBodySchemaV1,
params: updateParamsSchemaV1,
request: {
body: updateBodySchemaV1,
params: updateParamsSchemaV1,
},
response: {
200: {
body: () => ruleResponseSchemaV1,
description: 'Indicates a successful call.',
},
},
},
},
handleDisabledApiKeysError(

View file

@ -13,8 +13,16 @@ import { RewriteRequestCase, verifyAccessAndContext } from './lib';
import { AlertingRequestHandlerContext, BASE_ALERTING_API_PATH } from '../types';
const paramSchema = schema.object({
rule_id: schema.string(),
alert_id: schema.string(),
rule_id: schema.string({
meta: {
description: 'The identifier for the rule.',
},
}),
alert_id: schema.string({
meta: {
description: 'The identifier for the alert.',
},
}),
});
const rewriteParamsReq: RewriteRequestCase<MuteOptions> = ({