diff --git a/x-pack/legacy/plugins/alerting/README.md b/x-pack/legacy/plugins/alerting/README.md index 85dbd75e141743..0b4024be395488 100644 --- a/x-pack/legacy/plugins/alerting/README.md +++ b/x-pack/legacy/plugins/alerting/README.md @@ -200,7 +200,7 @@ Payload: |name|A name to reference and search in the future.|string| |tags|A list of keywords to reference and search in the future.|string[]| |alertTypeId|The id value of the alert type you want to call when the alert is scheduled to execute.|string| -|interval|The interval in seconds, minutes, hours or days the alert should execute. Example: `10s`, `5m`, `1h`, `1d`.|string| +|schedule|The schedule specifying when this alert should run, using one of the available schedule formats specified under _Schedule Formats_ below|object| |params|The parameters to pass in to the alert type executor `params` value. This will also validate against the alert type params validator if defined.|object| |actions|Array of the following:
- `group` (string): We support grouping actions in the scenario of escalations or different types of alert instances. If you don't need this, feel free to use `default` as a value.
- `id` (string): The id of the action saved object to execute.
- `params` (object): The map to the `params` the action type will receive. In order to help apply context to strings, we handle them as mustache templates and pass in a default set of context. (see templating actions).|array| @@ -242,7 +242,7 @@ Payload: |Property|Description|Type| |---|---|---| -|interval|The interval in seconds, minutes, hours or days the alert should execute. Example: `10s`, `5m`, `1h`, `1d`.|string| +|schedule|The schedule specifying when this alert should be run, using one of the available schedule formats specified under _Schedule Formats_ below|object| |name|A name to reference and search in the future.|string| |tags|A list of keywords to reference and search in the future.|string[]| |params|The parameters to pass in to the alert type executor `params` value. This will also validate against the alert type params validator if defined.|object| @@ -304,6 +304,14 @@ Params: |---|---|---| |id|The id of the alert you're trying to update the API key for. System will use user in request context to generate an API key for.|string| +##### Schedule Formats +A schedule is structured such that the key specifies the format you wish to use and its value specifies the schedule. + +We currently support the _Interval format_ which specifies the interval in seconds, minutes, hours or days at which the alert should execute. +Example: `{ interval: "10s" }`, `{ interval: "5m" }`, `{ interval: "1h" }`, `{ interval: "1d" }`. + +There are plans to support multiple other schedule formats in the near fuiture. + ## Alert instance factory **alertInstanceFactory(id)** diff --git a/x-pack/legacy/plugins/alerting/mappings.json b/x-pack/legacy/plugins/alerting/mappings.json index 7a7446602351d5..95361871160315 100644 --- a/x-pack/legacy/plugins/alerting/mappings.json +++ b/x-pack/legacy/plugins/alerting/mappings.json @@ -13,8 +13,12 @@ "alertTypeId": { "type": "keyword" }, - "interval": { - "type": "keyword" + "schedule": { + "properties": { + "interval": { + "type": "keyword" + } + } }, "actions": { "type": "nested", diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts index 37eb6a9b21d447..b07dad68da72d4 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.test.ts @@ -47,7 +47,7 @@ function getMockData(overwrites: Record = {}) { name: 'abc', tags: ['foo'], alertTypeId: '123', - interval: '10s', + schedule: { interval: '10s' }, throttle: null, params: { bar: true, @@ -92,7 +92,7 @@ describe('create()', () => { type: 'alert', attributes: { alertTypeId: '123', - interval: '10s', + schedule: { interval: '10s' }, params: { bar: true, }, @@ -157,10 +157,12 @@ describe('create()', () => { ], "alertTypeId": "123", "id": "1", - "interval": "10s", "params": Object { "bar": true, }, + "schedule": Object { + "interval": "10s", + }, "scheduledTaskId": "task-123", } `); @@ -184,13 +186,15 @@ describe('create()', () => { "apiKeyOwner": undefined, "createdBy": "elastic", "enabled": true, - "interval": "10s", "muteAll": false, "mutedInstanceIds": Array [], "name": "abc", "params": Object { "bar": true, }, + "schedule": Object { + "interval": "10s", + }, "tags": Array [ "foo", ], @@ -298,7 +302,7 @@ describe('create()', () => { type: 'alert', attributes: { alertTypeId: '123', - interval: '10s', + schedule: { interval: '10s' }, params: { bar: true, }, @@ -399,10 +403,12 @@ describe('create()', () => { ], "alertTypeId": "123", "id": "1", - "interval": "10s", "params": Object { "bar": true, }, + "schedule": Object { + "interval": "10s", + }, "scheduledTaskId": "task-123", } `); @@ -445,7 +451,7 @@ describe('create()', () => { attributes: { enabled: false, alertTypeId: '123', - interval: 10000, + schedule: { interval: 10000 }, params: { bar: true, }, @@ -484,10 +490,12 @@ describe('create()', () => { "alertTypeId": "123", "enabled": false, "id": "1", - "interval": 10000, "params": Object { "bar": true, }, + "schedule": Object { + "interval": 10000, + }, } `); expect(savedObjectsClient.create).toHaveBeenCalledTimes(1); @@ -585,7 +593,7 @@ describe('create()', () => { type: 'alert', attributes: { alertTypeId: '123', - interval: '10s', + schedule: { interval: '10s' }, params: { bar: true, }, @@ -648,7 +656,7 @@ describe('create()', () => { type: 'alert', attributes: { alertTypeId: '123', - interval: '10s', + schedule: { interval: '10s' }, params: { bar: true, }, @@ -722,7 +730,7 @@ describe('create()', () => { type: 'alert', attributes: { alertTypeId: '123', - interval: '10s', + schedule: { interval: '10s' }, params: { bar: true, }, @@ -794,7 +802,7 @@ describe('create()', () => { createdBy: 'elastic', updatedBy: 'elastic', enabled: true, - interval: '10s', + schedule: { interval: '10s' }, throttle: null, muteAll: false, mutedInstanceIds: [], @@ -820,7 +828,7 @@ describe('enable()', () => { id: '1', type: 'alert', attributes: { - interval: '10s', + schedule: { interval: '10s' }, alertTypeId: '2', enabled: false, }, @@ -846,7 +854,7 @@ describe('enable()', () => { 'alert', '1', { - interval: '10s', + schedule: { interval: '10s' }, alertTypeId: '2', enabled: true, scheduledTaskId: 'task-123', @@ -879,7 +887,7 @@ describe('enable()', () => { id: '1', type: 'alert', attributes: { - interval: '10s', + schedule: { interval: '10s' }, alertTypeId: '2', enabled: true, }, @@ -897,7 +905,7 @@ describe('enable()', () => { id: '1', type: 'alert', attributes: { - interval: '10s', + schedule: { interval: '10s' }, alertTypeId: '2', enabled: false, }, @@ -927,7 +935,7 @@ describe('enable()', () => { 'alert', '1', { - interval: '10s', + schedule: { interval: '10s' }, alertTypeId: '2', enabled: true, scheduledTaskId: 'task-123', @@ -962,7 +970,7 @@ describe('disable()', () => { id: '1', type: 'alert', attributes: { - interval: '10s', + schedule: { interval: '10s' }, alertTypeId: '2', enabled: true, scheduledTaskId: 'task-123', @@ -976,7 +984,7 @@ describe('disable()', () => { 'alert', '1', { - interval: '10s', + schedule: { interval: '10s' }, alertTypeId: '2', apiKey: null, apiKeyOwner: null, @@ -997,7 +1005,7 @@ describe('disable()', () => { id: '1', type: 'alert', attributes: { - interval: '10s', + schedule: { interval: '10s' }, alertTypeId: '2', enabled: false, scheduledTaskId: 'task-123', @@ -1060,7 +1068,7 @@ describe('muteInstance()', () => { id: '1', type: 'alert', attributes: { - interval: '10s', + schedule: { interval: '10s' }, alertTypeId: '2', enabled: true, scheduledTaskId: 'task-123', @@ -1088,7 +1096,7 @@ describe('muteInstance()', () => { id: '1', type: 'alert', attributes: { - interval: '10s', + schedule: { interval: '10s' }, alertTypeId: '2', enabled: true, scheduledTaskId: 'task-123', @@ -1107,7 +1115,7 @@ describe('muteInstance()', () => { id: '1', type: 'alert', attributes: { - interval: '10s', + schedule: { interval: '10s' }, alertTypeId: '2', enabled: true, scheduledTaskId: 'task-123', @@ -1129,7 +1137,7 @@ describe('unmuteInstance()', () => { id: '1', type: 'alert', attributes: { - interval: '10s', + schedule: { interval: '10s' }, alertTypeId: '2', enabled: true, scheduledTaskId: 'task-123', @@ -1157,7 +1165,7 @@ describe('unmuteInstance()', () => { id: '1', type: 'alert', attributes: { - interval: '10s', + schedule: { interval: '10s' }, alertTypeId: '2', enabled: true, scheduledTaskId: 'task-123', @@ -1176,7 +1184,7 @@ describe('unmuteInstance()', () => { id: '1', type: 'alert', attributes: { - interval: '10s', + schedule: { interval: '10s' }, alertTypeId: '2', enabled: true, scheduledTaskId: 'task-123', @@ -1199,7 +1207,7 @@ describe('get()', () => { type: 'alert', attributes: { alertTypeId: '123', - interval: '10s', + schedule: { interval: '10s' }, params: { bar: true, }, @@ -1235,10 +1243,12 @@ describe('get()', () => { ], "alertTypeId": "123", "id": "1", - "interval": "10s", "params": Object { "bar": true, }, + "schedule": Object { + "interval": "10s", + }, } `); expect(savedObjectsClient.get).toHaveBeenCalledTimes(1); @@ -1257,7 +1267,7 @@ describe('get()', () => { type: 'alert', attributes: { alertTypeId: '123', - interval: '10s', + schedule: { interval: '10s' }, params: { bar: true, }, @@ -1292,7 +1302,7 @@ describe('find()', () => { type: 'alert', attributes: { alertTypeId: '123', - interval: '10s', + schedule: { interval: '10s' }, params: { bar: true, }, @@ -1332,10 +1342,12 @@ describe('find()', () => { ], "alertTypeId": "123", "id": "1", - "interval": "10s", "params": Object { "bar": true, }, + "schedule": Object { + "interval": "10s", + }, }, ], "page": 1, @@ -1362,7 +1374,7 @@ describe('delete()', () => { type: 'alert', attributes: { alertTypeId: '123', - interval: '10s', + schedule: { interval: '10s' }, params: { bar: true, }, @@ -1443,7 +1455,7 @@ describe('update()', () => { type: 'alert', attributes: { enabled: true, - interval: '10s', + schedule: { interval: '10s' }, params: { bar: true, }, @@ -1470,7 +1482,7 @@ describe('update()', () => { const result = await alertsClient.update({ id: '1', data: { - interval: '10s', + schedule: { interval: '10s' }, name: 'abc', tags: ['foo'], params: { @@ -1501,10 +1513,12 @@ describe('update()', () => { ], "enabled": true, "id": "1", - "interval": "10s", "params": Object { "bar": true, }, + "schedule": Object { + "interval": "10s", + }, "scheduledTaskId": "task-123", } `); @@ -1528,11 +1542,13 @@ describe('update()', () => { "apiKey": null, "apiKeyOwner": null, "enabled": true, - "interval": "10s", "name": "abc", "params": Object { "bar": true, }, + "schedule": Object { + "interval": "10s", + }, "scheduledTaskId": "task-123", "tags": Array [ "foo", @@ -1598,7 +1614,7 @@ describe('update()', () => { type: 'alert', attributes: { enabled: true, - interval: '10s', + schedule: { interval: '10s' }, params: { bar: true, }, @@ -1651,7 +1667,7 @@ describe('update()', () => { const result = await alertsClient.update({ id: '1', data: { - interval: '10s', + schedule: { interval: '10s' }, name: 'abc', tags: ['foo'], params: { @@ -1712,10 +1728,12 @@ describe('update()', () => { ], "enabled": true, "id": "1", - "interval": "10s", "params": Object { "bar": true, }, + "schedule": Object { + "interval": "10s", + }, "scheduledTaskId": "task-123", } `); @@ -1771,7 +1789,7 @@ describe('update()', () => { type: 'alert', attributes: { enabled: true, - interval: '10s', + schedule: { interval: '10s' }, params: { bar: true, }, @@ -1799,7 +1817,7 @@ describe('update()', () => { const result = await alertsClient.update({ id: '1', data: { - interval: '10s', + schedule: { interval: '10s' }, name: 'abc', tags: ['foo'], params: { @@ -1831,10 +1849,12 @@ describe('update()', () => { "apiKey": "MTIzOmFiYw==", "enabled": true, "id": "1", - "interval": "10s", "params": Object { "bar": true, }, + "schedule": Object { + "interval": "10s", + }, "scheduledTaskId": "task-123", } `); @@ -1858,11 +1878,13 @@ describe('update()', () => { "apiKey": "MTIzOmFiYw==", "apiKeyOwner": "elastic", "enabled": true, - "interval": "10s", "name": "abc", "params": Object { "bar": true, }, + "schedule": Object { + "interval": "10s", + }, "scheduledTaskId": "task-123", "tags": Array [ "foo", @@ -1909,7 +1931,7 @@ describe('update()', () => { alertsClient.update({ id: '1', data: { - interval: '10s', + schedule: { interval: '10s' }, name: 'abc', tags: ['foo'], params: { @@ -1939,7 +1961,7 @@ describe('updateApiKey()', () => { id: '1', type: 'alert', attributes: { - interval: '10s', + schedule: { interval: '10s' }, alertTypeId: '2', enabled: true, }, @@ -1956,7 +1978,7 @@ describe('updateApiKey()', () => { 'alert', '1', { - interval: '10s', + schedule: { interval: '10s' }, alertTypeId: '2', enabled: true, apiKey: Buffer.from('123:abc').toString('base64'), diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.ts index 27fda9871e6854..578daa445b6ffe 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.ts @@ -8,7 +8,14 @@ import Boom from 'boom'; import { omit } from 'lodash'; import { i18n } from '@kbn/i18n'; import { Logger, SavedObjectsClientContract, SavedObjectReference } from 'src/core/server'; -import { Alert, RawAlert, AlertTypeRegistry, AlertAction, AlertType } from './types'; +import { + Alert, + RawAlert, + AlertTypeRegistry, + AlertAction, + AlertType, + IntervalSchedule, +} from './types'; import { TaskManagerStartContract } from './shim'; import { validateAlertTypeParams } from './lib'; import { CreateAPIKeyResult as SecurityPluginCreateAPIKeyResult } from '../../../../plugins/security/server'; @@ -82,7 +89,7 @@ interface UpdateOptions { data: { name: string; tags: string[]; - interval: string; + schedule: IntervalSchedule; actions: NormalizedAlertAction[]; params: Record; }; @@ -145,11 +152,7 @@ export class AlertsClient { if (data.enabled) { let scheduledTask; try { - scheduledTask = await this.scheduleAlert( - createdAlert.id, - rawAlert.alertTypeId, - rawAlert.interval - ); + scheduledTask = await this.scheduleAlert(createdAlert.id, rawAlert.alertTypeId); } catch (e) { // Cleanup data, something went wrong scheduling the task try { @@ -259,11 +262,7 @@ export class AlertsClient { const { attributes, version } = await this.savedObjectsClient.get('alert', id); if (attributes.enabled === false) { const apiKey = await this.createAPIKey(); - const scheduledTask = await this.scheduleAlert( - id, - attributes.alertTypeId, - attributes.interval - ); + const scheduledTask = await this.scheduleAlert(id, attributes.alertTypeId); const username = await this.getUserName(); await this.savedObjectsClient.update( 'alert', @@ -364,7 +363,7 @@ export class AlertsClient { } } - private async scheduleAlert(id: string, alertTypeId: string, interval: string) { + private async scheduleAlert(id: string, alertTypeId: string) { return await this.taskManager.schedule({ taskType: `alerting:${alertTypeId}`, params: { diff --git a/x-pack/legacy/plugins/alerting/server/lib/get_next_run_at.test.ts b/x-pack/legacy/plugins/alerting/server/lib/get_next_run_at.test.ts index 852e412689b35c..1c4d8a42d2830e 100644 --- a/x-pack/legacy/plugins/alerting/server/lib/get_next_run_at.test.ts +++ b/x-pack/legacy/plugins/alerting/server/lib/get_next_run_at.test.ts @@ -15,12 +15,12 @@ const mockedNow = new Date('2019-06-03T18:55:25.982Z'); test('Adds interface to given date when result is > Date.now()', () => { const currentRunAt = new Date('2019-06-03T18:55:23.982Z'); - const result = getNextRunAt(currentRunAt, '10s'); + const result = getNextRunAt(currentRunAt, { interval: '10s' }); expect(result).toEqual(new Date('2019-06-03T18:55:33.982Z')); }); test('Uses Date.now() when the result would of been a date in the past', () => { const currentRunAt = new Date('2019-06-03T18:55:13.982Z'); - const result = getNextRunAt(currentRunAt, '10s'); + const result = getNextRunAt(currentRunAt, { interval: '10s' }); expect(result).toEqual(mockedNow); }); diff --git a/x-pack/legacy/plugins/alerting/server/lib/get_next_run_at.ts b/x-pack/legacy/plugins/alerting/server/lib/get_next_run_at.ts index 901b614b4d68c0..f9867b53729080 100644 --- a/x-pack/legacy/plugins/alerting/server/lib/get_next_run_at.ts +++ b/x-pack/legacy/plugins/alerting/server/lib/get_next_run_at.ts @@ -5,9 +5,10 @@ */ import { parseDuration } from './parse_duration'; +import { IntervalSchedule } from '../types'; -export function getNextRunAt(currentRunAt: Date, interval: string) { - let nextRunAt = currentRunAt.getTime() + parseDuration(interval); +export function getNextRunAt(currentRunAt: Date, schedule: IntervalSchedule) { + let nextRunAt = currentRunAt.getTime() + parseDuration(schedule.interval); if (nextRunAt < Date.now()) { // To prevent returning dates in the past, we'll return now instead nextRunAt = Date.now(); diff --git a/x-pack/legacy/plugins/alerting/server/lib/task_runner_factory.test.ts b/x-pack/legacy/plugins/alerting/server/lib/task_runner_factory.test.ts index c21c419977bbeb..7966f98c749c82 100644 --- a/x-pack/legacy/plugins/alerting/server/lib/task_runner_factory.test.ts +++ b/x-pack/legacy/plugins/alerting/server/lib/task_runner_factory.test.ts @@ -74,7 +74,7 @@ const mockedAlertTypeSavedObject = { attributes: { enabled: true, alertTypeId: '123', - interval: '10s', + schedule: { interval: '10s' }, mutedInstanceIds: [], params: { bar: true, diff --git a/x-pack/legacy/plugins/alerting/server/lib/task_runner_factory.ts b/x-pack/legacy/plugins/alerting/server/lib/task_runner_factory.ts index 051b15fc8dd8f7..fe0979538d04ef 100644 --- a/x-pack/legacy/plugins/alerting/server/lib/task_runner_factory.ts +++ b/x-pack/legacy/plugins/alerting/server/lib/task_runner_factory.ts @@ -20,6 +20,7 @@ import { GetServicesFunction, RawAlert, SpaceIdToNamespaceFunction, + IntervalSchedule, } from '../types'; export interface TaskRunnerContext { @@ -94,7 +95,7 @@ export class TaskRunnerFactory { const services = getServices(fakeRequest); // Ensure API key is still valid and user has access const { - attributes: { params, actions, interval, throttle, muteAll, mutedInstanceIds }, + attributes: { params, actions, schedule, throttle, muteAll, mutedInstanceIds }, references, } = await services.savedObjectsClient.get('alert', alertId); @@ -167,7 +168,13 @@ export class TaskRunnerFactory { }) ); - const nextRunAt = getNextRunAt(new Date(taskInstance.startedAt!), interval); + const nextRunAt = getNextRunAt( + new Date(taskInstance.startedAt!), + // we do not currently have a good way of returning the type + // from SavedObjectsClient, and as we currenrtly require a schedule + // and we only support `interval`, we can cast this safely + schedule as IntervalSchedule + ); return { state: { diff --git a/x-pack/legacy/plugins/alerting/server/routes/create.test.ts b/x-pack/legacy/plugins/alerting/server/routes/create.test.ts index 634a797880812c..a804aff55ad422 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/create.test.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/create.test.ts @@ -13,7 +13,7 @@ server.route(createAlertRoute); const mockedAlert = { alertTypeId: '1', name: 'abc', - interval: '10s', + schedule: { interval: '10s' }, tags: ['foo'], params: { bar: true, @@ -65,11 +65,13 @@ test('creates an alert with proper parameters', async () => { ], "alertTypeId": "1", "id": "123", - "interval": "10s", "name": "abc", "params": Object { "bar": true, }, + "schedule": Object { + "interval": "10s", + }, "tags": Array [ "foo", ], @@ -91,11 +93,13 @@ test('creates an alert with proper parameters', async () => { ], "alertTypeId": "1", "enabled": true, - "interval": "10s", "name": "abc", "params": Object { "bar": true, }, + "schedule": Object { + "interval": "10s", + }, "tags": Array [ "foo", ], diff --git a/x-pack/legacy/plugins/alerting/server/routes/create.ts b/x-pack/legacy/plugins/alerting/server/routes/create.ts index cb5277ae191003..417072f978a922 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/create.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/create.ts @@ -7,6 +7,7 @@ import Hapi from 'hapi'; import Joi from 'joi'; import { getDurationSchema } from '../lib'; +import { IntervalSchedule } from '../types'; interface ScheduleRequest extends Hapi.Request { payload: { @@ -14,7 +15,7 @@ interface ScheduleRequest extends Hapi.Request { name: string; tags: string[]; alertTypeId: string; - interval: string; + schedule: IntervalSchedule; actions: Array<{ group: string; id: string; @@ -43,7 +44,11 @@ export const createAlertRoute = { .default([]), alertTypeId: Joi.string().required(), throttle: getDurationSchema().default(null), - interval: getDurationSchema().required(), + schedule: Joi.object() + .keys({ + interval: getDurationSchema().required(), + }) + .required(), params: Joi.object().required(), actions: Joi.array() .items( diff --git a/x-pack/legacy/plugins/alerting/server/routes/get.test.ts b/x-pack/legacy/plugins/alerting/server/routes/get.test.ts index 4d44ee9dfe6bda..b97762d10c960a 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/get.test.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/get.test.ts @@ -13,7 +13,7 @@ server.route(getAlertRoute); const mockedAlert = { id: '1', alertTypeId: '1', - interval: '10s', + schedule: { interval: '10s' }, params: { bar: true, }, diff --git a/x-pack/legacy/plugins/alerting/server/routes/update.test.ts b/x-pack/legacy/plugins/alerting/server/routes/update.test.ts index 334fb2120319de..8ce9d94140e6dc 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/update.test.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/update.test.ts @@ -16,7 +16,7 @@ const mockedResponse = { id: '1', alertTypeId: '1', tags: ['foo'], - interval: '12s', + schedule: { interval: '12s' }, params: { otherField: false, }, @@ -40,7 +40,7 @@ test('calls the update function with proper parameters', async () => { throttle: null, name: 'abc', tags: ['bar'], - interval: '12s', + schedule: { interval: '12s' }, params: { otherField: false, }, @@ -75,11 +75,13 @@ test('calls the update function with proper parameters', async () => { }, }, ], - "interval": "12s", "name": "abc", "params": Object { "otherField": false, }, + "schedule": Object { + "interval": "12s", + }, "tags": Array [ "bar", ], diff --git a/x-pack/legacy/plugins/alerting/server/routes/update.ts b/x-pack/legacy/plugins/alerting/server/routes/update.ts index 6e8f8557fb24ad..bc55d484656023 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/update.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/update.ts @@ -7,6 +7,7 @@ import Joi from 'joi'; import Hapi from 'hapi'; import { getDurationSchema } from '../lib'; +import { IntervalSchedule } from '../types'; interface UpdateRequest extends Hapi.Request { params: { @@ -16,7 +17,7 @@ interface UpdateRequest extends Hapi.Request { alertTypeId: string; name: string; tags: string[]; - interval: string; + schedule: IntervalSchedule; actions: Array<{ group: string; id: string; @@ -45,7 +46,11 @@ export const updateAlertRoute = { tags: Joi.array() .items(Joi.string()) .required(), - interval: getDurationSchema().required(), + schedule: Joi.object() + .keys({ + interval: getDurationSchema().required(), + }) + .required(), params: Joi.object().required(), actions: Joi.array() .items( diff --git a/x-pack/legacy/plugins/alerting/server/types.ts b/x-pack/legacy/plugins/alerting/server/types.ts index 1bec2632d80822..e06e0c45e20b48 100644 --- a/x-pack/legacy/plugins/alerting/server/types.ts +++ b/x-pack/legacy/plugins/alerting/server/types.ts @@ -60,12 +60,16 @@ export interface RawAlertAction extends SavedObjectAttributes { params: AlertActionParams; } +export interface IntervalSchedule extends SavedObjectAttributes { + interval: string; +} + export interface Alert { enabled: boolean; name: string; tags: string[]; alertTypeId: string; - interval: string; + schedule: IntervalSchedule; actions: AlertAction[]; params: Record; scheduledTaskId?: string; @@ -83,7 +87,7 @@ export interface RawAlert extends SavedObjectAttributes { name: string; tags: string[]; alertTypeId: string; - interval: string; + schedule: SavedObjectAttributes; actions: RawAlertAction[]; params: SavedObjectAttributes; scheduledTaskId?: string; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts index ae205a814daaed..3c5182b5178b37 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts @@ -271,7 +271,7 @@ export const getResult = (): RuleAlertType => ({ references: ['http://www.example.com', 'https://ww.example.com'], version: 1, }, - interval: '5m', + schedule: { interval: '5m' }, enabled: true, actions: [], throttle: null, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts index 88261d872b0eaf..dad22c74398d2d 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts @@ -45,7 +45,7 @@ export const transformAlertToRule = (alert: RuleAlertType): Partial { + it('should handle create alert request appropriately when interval schedule is wrong syntax', async () => { const response = await supertestWithoutAuth .post(`${getUrlPrefix(space.id)}/api/alert`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) - .send(getTestAlertData(getTestAlertData({ interval: '10x' }))); + .send(getTestAlertData(getTestAlertData({ schedule: { interval: '10x' } }))); switch (scenario.id) { case 'no_kibana_privileges at space1': @@ -275,10 +275,15 @@ export default function createAlertTests({ getService }: FtrProviderContext) { statusCode: 400, error: 'Bad Request', message: - 'child "interval" fails because ["interval" with value "10x" fails to match the seconds pattern, "interval" with value "10x" fails to match the minutes pattern, "interval" with value "10x" fails to match the hours pattern, "interval" with value "10x" fails to match the days pattern]', + 'child "schedule" fails because [child "interval" fails because ["interval" with value "10x" fails to match the seconds pattern, "interval" with value "10x" fails to match the minutes pattern, "interval" with value "10x" fails to match the hours pattern, "interval" with value "10x" fails to match the days pattern]]', validation: { source: 'payload', - keys: ['interval', 'interval', 'interval', 'interval'], + keys: [ + 'schedule.interval', + 'schedule.interval', + 'schedule.interval', + 'schedule.interval', + ], }, }); break; @@ -287,12 +292,12 @@ export default function createAlertTests({ getService }: FtrProviderContext) { } }); - it('should handle create alert request appropriately when interval is 0', async () => { + it('should handle create alert request appropriately when interval schedule is 0', async () => { const response = await supertestWithoutAuth .post(`${getUrlPrefix(space.id)}/api/alert`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) - .send(getTestAlertData(getTestAlertData({ interval: '0s' }))); + .send(getTestAlertData(getTestAlertData({ schedule: { interval: '0s' } }))); switch (scenario.id) { case 'no_kibana_privileges at space1': @@ -312,10 +317,15 @@ export default function createAlertTests({ getService }: FtrProviderContext) { statusCode: 400, error: 'Bad Request', message: - 'child "interval" fails because ["interval" with value "0s" fails to match the seconds pattern, "interval" with value "0s" fails to match the minutes pattern, "interval" with value "0s" fails to match the hours pattern, "interval" with value "0s" fails to match the days pattern]', + 'child "schedule" fails because [child "interval" fails because ["interval" with value "0s" fails to match the seconds pattern, "interval" with value "0s" fails to match the minutes pattern, "interval" with value "0s" fails to match the hours pattern, "interval" with value "0s" fails to match the days pattern]]', validation: { source: 'payload', - keys: ['interval', 'interval', 'interval', 'interval'], + keys: [ + 'schedule.interval', + 'schedule.interval', + 'schedule.interval', + 'schedule.interval', + ], }, }); break; diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/find.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/find.ts index 359058f2ac23af..4da6c059c5a5eb 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/find.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/find.ts @@ -59,7 +59,7 @@ export default function createFindTests({ getService }: FtrProviderContext) { name: 'abc', tags: ['foo'], alertTypeId: 'test.noop', - interval: '1m', + schedule: { interval: '1m' }, enabled: true, actions: [], params: {}, @@ -138,7 +138,7 @@ export default function createFindTests({ getService }: FtrProviderContext) { name: 'abc', tags: ['foo'], alertTypeId: 'test.noop', - interval: '1m', + schedule: { interval: '1m' }, enabled: false, actions: [ { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get.ts index 1a8109f6b6b3c6..9c1f7fea932922 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get.ts @@ -53,7 +53,7 @@ export default function createGetTests({ getService }: FtrProviderContext) { name: 'abc', tags: ['foo'], alertTypeId: 'test.noop', - interval: '1m', + schedule: { interval: '1m' }, enabled: true, actions: [], params: {}, diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts index 1b1bcef9ad23ff..0e2ec0f7bc5341 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts @@ -36,7 +36,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { params: { foo: true, }, - interval: '12s', + schedule: { interval: '12s' }, actions: [], throttle: '2m', }; @@ -96,7 +96,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { params: { foo: true, }, - interval: '12s', + schedule: { interval: '12s' }, throttle: '1m', actions: [], }); @@ -145,7 +145,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { params: { foo: true, }, - interval: '12s', + schedule: { interval: '12s' }, actions: [], }); @@ -203,10 +203,10 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { statusCode: 400, error: 'Bad Request', message: - 'child "throttle" fails because ["throttle" is required]. child "name" fails because ["name" is required]. child "tags" fails because ["tags" is required]. child "interval" fails because ["interval" is required]. child "params" fails because ["params" is required]. child "actions" fails because ["actions" is required]', + 'child "throttle" fails because ["throttle" is required]. child "name" fails because ["name" is required]. child "tags" fails because ["tags" is required]. child "schedule" fails because ["schedule" is required]. child "params" fails because ["params" is required]. child "actions" fails because ["actions" is required]', validation: { source: 'payload', - keys: ['throttle', 'name', 'tags', 'interval', 'params', 'actions'], + keys: ['throttle', 'name', 'tags', 'schedule', 'params', 'actions'], }, }); break; @@ -237,7 +237,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { .send({ name: 'bcd', tags: ['bar'], - interval: '1m', + schedule: { interval: '1m' }, throttle: '1m', params: {}, actions: [], @@ -269,12 +269,12 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { } }); - it('should handle update alert request appropriately when interval is wrong syntax', async () => { + it('should handle update alert request appropriately when interval schedule is wrong syntax', async () => { const response = await supertestWithoutAuth .put(`${getUrlPrefix(space.id)}/api/alert/1`) .set('kbn-xsrf', 'foo') .auth(user.username, user.password) - .send(getTestAlertData({ interval: '10x', enabled: undefined })); + .send(getTestAlertData({ schedule: { interval: '10x' }, enabled: undefined })); switch (scenario.id) { case 'no_kibana_privileges at space1': @@ -294,10 +294,16 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { statusCode: 400, error: 'Bad Request', message: - 'child "interval" fails because ["interval" with value "10x" fails to match the seconds pattern, "interval" with value "10x" fails to match the minutes pattern, "interval" with value "10x" fails to match the hours pattern, "interval" with value "10x" fails to match the days pattern]. "alertTypeId" is not allowed', + 'child "schedule" fails because [child "interval" fails because ["interval" with value "10x" fails to match the seconds pattern, "interval" with value "10x" fails to match the minutes pattern, "interval" with value "10x" fails to match the hours pattern, "interval" with value "10x" fails to match the days pattern]]. "alertTypeId" is not allowed', validation: { source: 'payload', - keys: ['interval', 'interval', 'interval', 'interval', 'alertTypeId'], + keys: [ + 'schedule.interval', + 'schedule.interval', + 'schedule.interval', + 'schedule.interval', + 'alertTypeId', + ], }, }); break; diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/alerts.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/alerts.ts index 5fafd8b0bfb610..03e973194b4e2c 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/alerts.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/alerts.ts @@ -123,7 +123,7 @@ export default function alertTests({ getService }: FtrProviderContext) { .set('kbn-xsrf', 'foo') .send( getTestAlertData({ - interval: '1m', + schedule: { interval: '1m' }, alertTypeId: 'test.always-firing', params: { index: ES_TEST_INDEX_NAME, diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/create.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/create.ts index 929905a958abbd..0e9011729eb3ec 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/create.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/create.ts @@ -71,7 +71,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { alertTypeId: 'test.noop', params: {}, createdBy: null, - interval: '1m', + schedule: { interval: '1m' }, scheduledTaskId: response.body.scheduledTaskId, updatedBy: null, throttle: '1m', diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/find.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/find.ts index 0d12af6db79b2b..3fdd9168eb5cb9 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/find.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/find.ts @@ -42,7 +42,7 @@ export default function createFindTests({ getService }: FtrProviderContext) { name: 'abc', tags: ['foo'], alertTypeId: 'test.noop', - interval: '1m', + schedule: { interval: '1m' }, enabled: true, actions: [], params: {}, diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get.ts index 9e4797bcbf7ad2..a49d3478d336db 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get.ts @@ -36,7 +36,7 @@ export default function createGetTests({ getService }: FtrProviderContext) { name: 'abc', tags: ['foo'], alertTypeId: 'test.noop', - interval: '1m', + schedule: { interval: '1m' }, enabled: true, actions: [], params: {}, diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update.ts index a6eccf88d9e269..46822781c0cd31 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update.ts @@ -31,7 +31,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { params: { foo: true, }, - interval: '12s', + schedule: { interval: '12s' }, actions: [], throttle: '1m', }; @@ -71,7 +71,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { params: { foo: true, }, - interval: '12s', + schedule: { interval: '12s' }, actions: [], throttle: '1m', })