Add ability to name alerts (#49035)

* Ability to name alerts

* Fix RawAlert TypeScript interface

* Update docs
This commit is contained in:
Mike Côté 2019-11-01 13:35:17 -04:00 committed by GitHub
parent 568b8d3992
commit bfdf61714e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 63 additions and 20 deletions

View file

@ -198,6 +198,7 @@ Payload:
|Property|Description|Type|
|---|---|---|
|enabled|Indicate if you want the alert to start executing on an interval basis after it has been created.|boolean|
|name|A name 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|
|alertTypeParams|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|
@ -242,6 +243,7 @@ Payload:
|Property|Description|Type|
|---|---|---|
|interval|The interval in seconds, minutes, hours or days the alert should execute. Example: `10s`, `5m`, `1h`, `1d`.|string|
|name|A name to reference and search in the future.|string|
|alertTypeParams|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:<br> - `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.<br>- `id` (string): The id of the action saved object to execute.<br>- `params` (object): There 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|

View file

@ -4,6 +4,9 @@
"enabled": {
"type": "boolean"
},
"name": {
"type": "text"
},
"alertTypeId": {
"type": "keyword"
},

View file

@ -43,6 +43,7 @@ const mockedDate = new Date('2019-02-12T21:01:22.479Z');
function getMockData(overwrites: Record<string, any> = {}) {
return {
enabled: true,
name: 'abc',
alertTypeId: '123',
interval: '10s',
throttle: null,
@ -172,6 +173,7 @@ describe('create()', () => {
"interval": "10s",
"muteAll": false,
"mutedInstanceIds": Array [],
"name": "abc",
"throttle": null,
"updatedBy": "elastic",
}
@ -504,6 +506,7 @@ describe('create()', () => {
},
],
alertTypeId: '123',
name: 'abc',
alertTypeParams: { bar: true },
apiKey: Buffer.from('123:abc').toString('base64'),
apiKeyOwner: 'elastic',
@ -1173,6 +1176,7 @@ describe('update()', () => {
id: '1',
data: {
interval: '10s',
name: 'abc',
alertTypeParams: {
bar: true,
},
@ -1230,6 +1234,7 @@ describe('update()', () => {
"apiKeyOwner": null,
"enabled": true,
"interval": "10s",
"name": "abc",
"scheduledTaskId": "task-123",
"updatedBy": "elastic",
}
@ -1304,6 +1309,7 @@ describe('update()', () => {
id: '1',
data: {
interval: '10s',
name: 'abc',
alertTypeParams: {
bar: true,
},
@ -1362,6 +1368,7 @@ describe('update()', () => {
"apiKeyOwner": "elastic",
"enabled": true,
"interval": "10s",
"name": "abc",
"scheduledTaskId": "task-123",
"updatedBy": "elastic",
}
@ -1406,6 +1413,7 @@ describe('update()', () => {
id: '1',
data: {
interval: '10s',
name: 'abc',
alertTypeParams: {
bar: true,
},

View file

@ -72,6 +72,7 @@ interface CreateOptions {
interface UpdateOptions {
id: string;
data: {
name: string;
interval: string;
actions: AlertAction[];
alertTypeParams: Record<string, any>;

View file

@ -12,6 +12,7 @@ server.route(createAlertRoute);
const mockedAlert = {
alertTypeId: '1',
name: 'abc',
interval: '10s',
alertTypeParams: {
bar: true,
@ -44,24 +45,25 @@ test('creates an alert with proper parameters', async () => {
expect(statusCode).toBe(200);
const response = JSON.parse(payload);
expect(response).toMatchInlineSnapshot(`
Object {
"actions": Array [
Object {
"actions": Array [
Object {
"group": "default",
"id": "2",
"params": Object {
"foo": true,
},
},
],
"alertTypeId": "1",
"alertTypeParams": Object {
"bar": true,
"group": "default",
"id": "2",
"params": Object {
"foo": true,
},
"id": "123",
"interval": "10s",
}
`);
},
],
"alertTypeId": "1",
"alertTypeParams": Object {
"bar": true,
},
"id": "123",
"interval": "10s",
"name": "abc",
}
`);
expect(alertsClient.create).toHaveBeenCalledTimes(1);
expect(alertsClient.create.mock.calls[0]).toMatchInlineSnapshot(`
Array [
@ -82,6 +84,7 @@ test('creates an alert with proper parameters', async () => {
},
"enabled": true,
"interval": "10s",
"name": "abc",
"throttle": null,
},
},
@ -107,6 +110,7 @@ test('creates an alert with proper parameters', async () => {
},
"enabled": true,
"interval": "10s",
"name": "abc",
"throttle": null,
},
},

View file

@ -12,6 +12,7 @@ import { getDurationSchema } from '../lib';
interface ScheduleRequest extends Hapi.Request {
payload: {
enabled: boolean;
name: string;
alertTypeId: string;
interval: string;
actions: AlertAction[];
@ -32,6 +33,7 @@ export const createAlertRoute = {
payload: Joi.object()
.keys({
enabled: Joi.boolean().default(true),
name: Joi.string().required(),
alertTypeId: Joi.string().required(),
throttle: getDurationSchema().default(null),
interval: getDurationSchema().required(),

View file

@ -36,6 +36,7 @@ test('calls the update function with proper parameters', async () => {
url: '/api/alert/1',
payload: {
throttle: null,
name: 'abc',
interval: '12s',
alertTypeParams: {
otherField: false,
@ -75,6 +76,7 @@ test('calls the update function with proper parameters', async () => {
"otherField": false,
},
"interval": "12s",
"name": "abc",
"throttle": null,
},
"id": "1",

View file

@ -15,6 +15,7 @@ interface UpdateRequest extends Hapi.Request {
};
payload: {
alertTypeId: string;
name: string;
interval: string;
actions: AlertAction[];
alertTypeParams: Record<string, any>;
@ -36,6 +37,7 @@ export const updateAlertRoute = {
throttle: getDurationSchema()
.required()
.allow(null),
name: Joi.string().required(),
interval: getDurationSchema().required(),
alertTypeParams: Joi.object().required(),
actions: Joi.array()

View file

@ -60,6 +60,7 @@ export interface RawAlertAction extends SavedObjectAttributes {
export interface Alert {
enabled: boolean;
name: string;
alertTypeId: string;
interval: string;
actions: AlertAction[];
@ -76,6 +77,7 @@ export interface Alert {
export interface RawAlert extends SavedObjectAttributes {
enabled: boolean;
name: string;
alertTypeId: string;
interval: string;
actions: RawAlertAction[];

View file

@ -124,6 +124,7 @@ export const createSignals = async ({
return alertsClient.create({
data: {
name: 'SIEM Alert',
alertTypeId: SIGNALS_ID,
alertTypeParams: {
description,

View file

@ -84,6 +84,7 @@ export const updateSignal = async ({
return alertsClient.update({
id: signal.id,
data: {
name: 'SIEM Alert',
interval: calculateInterval(interval, signal.interval),
actions,
alertTypeParams: nextAlertTypeParams,

View file

@ -178,6 +178,7 @@ export class AlertUtils {
}
const response = await request.send({
enabled: true,
name: 'abc',
interval: '1m',
throttle: '1m',
alertTypeId: 'test.always-firing',

View file

@ -7,6 +7,7 @@
export function getTestAlertData(overwrites = {}) {
return {
enabled: true,
name: 'abc',
alertTypeId: 'test.noop',
interval: '10s',
throttle: '1m',

View file

@ -54,6 +54,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) {
objectRemover.add(space.id, response.body.id, 'alert');
expect(response.body).to.eql({
id: response.body.id,
name: 'abc',
actions: [],
enabled: true,
alertTypeId: 'test.noop',
@ -171,10 +172,10 @@ export default function createAlertTests({ getService }: FtrProviderContext) {
statusCode: 400,
error: 'Bad Request',
message:
'child "alertTypeId" fails because ["alertTypeId" is required]. child "interval" fails because ["interval" is required]. child "alertTypeParams" fails because ["alertTypeParams" is required]. child "actions" fails because ["actions" is required]',
'child "name" fails because ["name" is required]. child "alertTypeId" fails because ["alertTypeId" is required]. child "interval" fails because ["interval" is required]. child "alertTypeParams" fails because ["alertTypeParams" is required]. child "actions" fails because ["actions" is required]',
validation: {
source: 'payload',
keys: ['alertTypeId', 'interval', 'alertTypeParams', 'actions'],
keys: ['name', 'alertTypeId', 'interval', 'alertTypeParams', 'actions'],
},
});
break;

View file

@ -56,6 +56,7 @@ export default function createFindTests({ getService }: FtrProviderContext) {
const match = response.body.data.find((obj: any) => obj.id === createdAlert.id);
expect(match).to.eql({
id: createdAlert.id,
name: 'abc',
alertTypeId: 'test.noop',
interval: '10s',
enabled: true,
@ -111,6 +112,7 @@ export default function createFindTests({ getService }: FtrProviderContext) {
const match = response.body.data.find((obj: any) => obj.id === createdAlert.id);
expect(match).to.eql({
id: createdAlert.id,
name: 'abc',
alertTypeId: 'test.noop',
interval: '10s',
enabled: true,

View file

@ -50,6 +50,7 @@ export default function createGetTests({ getService }: FtrProviderContext) {
expect(response.statusCode).to.eql(200);
expect(response.body).to.eql({
id: createdAlert.id,
name: 'abc',
alertTypeId: 'test.noop',
interval: '10s',
enabled: true,

View file

@ -31,6 +31,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) {
objectRemover.add(space.id, createdAlert.id, 'alert');
const updatedData = {
name: 'bcd',
alertTypeParams: {
foo: true,
},
@ -89,6 +90,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) {
.set('kbn-xsrf', 'foo')
.auth(user.username, user.password)
.send({
name: 'bcd',
alertTypeParams: {
foo: true,
},
@ -134,6 +136,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) {
.set('kbn-xsrf', 'foo')
.auth(user.username, user.password)
.send({
name: 'bcd',
throttle: '1m',
alertTypeId: '1',
alertTypeParams: {
@ -197,10 +200,10 @@ export default function createUpdateTests({ getService }: FtrProviderContext) {
statusCode: 400,
error: 'Bad Request',
message:
'child "throttle" fails because ["throttle" is required]. child "interval" fails because ["interval" is required]. child "alertTypeParams" fails because ["alertTypeParams" is required]. child "actions" fails because ["actions" is required]',
'child "throttle" fails because ["throttle" is required]. child "name" fails because ["name" is required]. child "interval" fails because ["interval" is required]. child "alertTypeParams" fails because ["alertTypeParams" is required]. child "actions" fails because ["actions" is required]',
validation: {
source: 'payload',
keys: ['throttle', 'interval', 'alertTypeParams', 'actions'],
keys: ['throttle', 'name', 'interval', 'alertTypeParams', 'actions'],
},
});
break;
@ -229,6 +232,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) {
.set('kbn-xsrf', 'foo')
.auth(user.username, user.password)
.send({
name: 'bcd',
interval: '10s',
throttle: '1m',
alertTypeParams: {},

View file

@ -36,6 +36,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) {
objectRemover.add(Spaces.space1.id, response.body.id, 'alert');
expect(response.body).to.eql({
id: response.body.id,
name: 'abc',
actions: [],
enabled: true,
alertTypeId: 'test.noop',

View file

@ -39,6 +39,7 @@ export default function createFindTests({ getService }: FtrProviderContext) {
const match = response.body.data.find((obj: any) => obj.id === createdAlert.id);
expect(match).to.eql({
id: createdAlert.id,
name: 'abc',
alertTypeId: 'test.noop',
interval: '10s',
enabled: true,

View file

@ -33,6 +33,7 @@ export default function createGetTests({ getService }: FtrProviderContext) {
expect(response.statusCode).to.eql(200);
expect(response.body).to.eql({
id: createdAlert.id,
name: 'abc',
alertTypeId: 'test.noop',
interval: '10s',
enabled: true,

View file

@ -26,6 +26,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) {
objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert');
const updatedData = {
name: 'bcd',
alertTypeParams: {
foo: true,
},
@ -63,6 +64,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) {
.put(`${getUrlPrefix(Spaces.other.id)}/api/alert/${createdAlert.id}`)
.set('kbn-xsrf', 'foo')
.send({
name: 'bcd',
alertTypeParams: {
foo: true,
},