Convert alert params schema from joi to config-schema (#41801) (#41824)

This makes alerts and actions use the same mechanism for registering type
validators; using `@kbn/config-schema` instead of `joi`.
This commit is contained in:
Patrick Mueller 2019-07-24 00:07:56 -04:00 committed by GitHub
parent 4fa4f0b5b4
commit eb44e9b99c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 47 additions and 58 deletions

View file

@ -38,7 +38,7 @@ The following table describes the properties of the `options` object.
|---|---|---|
|id|Unique identifier for the alert type. For convention purposes, ids starting with `.` are reserved for built in alert types. We recommend using a convention like `<plugin_id>.mySpecialAlert` for your alert types to avoid conflicting with another plugin.|string|
|name|A user-friendly name for the alert type. These will be displayed in dropdowns when choosing alert types.|string|
|validate.params|When developing an alert type, you can choose to accept a series of parameters. You may also have the parameters validated before they are passed to the `executor` function or created as an alert saved object. In order to do this, provide a joi schema that we will use to validate the `params` attribute.|Joi schema|
|validate.params|When developing an alert type, you can choose to accept a series of parameters. You may also have the parameters validated before they are passed to the `executor` function or created as an alert saved object. In order to do this, provide a `@kbn/config-schema` schema that we will use to validate the `params` attribute.|@kbn/config-schema|
|executor|This is where the code of the alert type lives. This is a function to be called when executing an alert on an interval basis. For full details, see executor section below.|Function|
### Executor
@ -62,16 +62,16 @@ This is the primary function for an alert type. Whenever the alert needs to exec
This example receives server and threshold as parameters. It will read the CPU usage of the server and fire actions if the reading is greater than the threshold.
```
import { schema } from '@kbn/config-schema';
...
server.plugins.alerting.registerType({
id: 'my-alert-type',
name: 'My alert type',
validate: {
params: Joi.object()
.keys({
server: Joi.string().required(),
threshold: Joi.number().min(0).max(1).required(),
})
.required(),
params: schema.object({
server: schema.string(),
threshold: schema.number({ min: 0, max: 1 }),
}),
},
async executor({
scheduledRunAt,
@ -126,11 +126,9 @@ server.plugins.alerting.registerType({
id: 'my-alert-type',
name: 'My alert type',
validate: {
params: Joi.object()
.keys({
threshold: Joi.number().min(0).max(1).required(),
})
.required(),
params: schema.object({
threshold: schema.number({ min: 0, max: 1 }),
}),
},
async executor({
scheduledRunAt,

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import Joi from 'joi';
import { schema } from '@kbn/config-schema';
import { AlertsClient } from './alerts_client';
import { SavedObjectsClientMock } from '../../../../../src/core/server/mocks';
import { taskManagerMock } from '../../task_manager/task_manager.mock';
@ -282,16 +282,15 @@ describe('create()', () => {
id: '123',
name: 'Test',
validate: {
params: Joi.object()
.keys({
param1: Joi.string().required(),
})
.required(),
params: schema.object({
param1: schema.string(),
threshold: schema.number({ min: 0, max: 1 }),
}),
},
async executor() {},
});
await expect(alertsClient.create({ data })).rejects.toThrowErrorMatchingInlineSnapshot(
`"alertTypeParams invalid: child \\"param1\\" fails because [\\"param1\\" is required]"`
`"alertTypeParams invalid: [param1]: expected value of type [string] but got [undefined]"`
);
});
@ -895,11 +894,9 @@ describe('update()', () => {
id: '123',
name: 'Test',
validate: {
params: Joi.object()
.keys({
param1: Joi.string().required(),
})
.required(),
params: schema.object({
param1: schema.string(),
}),
},
async executor() {},
});
@ -934,7 +931,7 @@ describe('update()', () => {
},
})
).rejects.toThrowErrorMatchingInlineSnapshot(
`"alertTypeParams invalid: child \\"param1\\" fails because [\\"param1\\" is required]"`
`"alertTypeParams invalid: [param1]: expected value of type [string] but got [undefined]"`
);
});
});

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import Joi from 'joi';
import { schema } from '@kbn/config-schema';
import { AlertExecutorOptions } from '../types';
import { SavedObjectsClientMock } from '../../../../../../src/core/server/mocks';
import { getCreateTaskRunnerFunction } from './get_create_task_runner_function';
@ -173,17 +173,15 @@ test('validates params before executing the alert type', async () => {
alertType: {
...getCreateTaskRunnerFunctionParams.alertType,
validate: {
params: Joi.object()
.keys({
param1: Joi.string().required(),
})
.required(),
params: schema.object({
param1: schema.string(),
}),
},
},
});
savedObjectsClient.get.mockResolvedValueOnce(mockedAlertTypeSavedObject);
const runner = createTaskRunner({ taskInstance: mockedTaskInstance });
await expect(runner.run()).rejects.toThrowErrorMatchingInlineSnapshot(
`"alertTypeParams invalid: child \\"param1\\" fails because [\\"param1\\" is required]"`
`"alertTypeParams invalid: [param1]: expected value of type [string] but got [undefined]"`
);
});

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import Joi from 'joi';
import { schema } from '@kbn/config-schema';
import { validateAlertTypeParams } from './validate_alert_type_params';
test('should return passed in params when validation not defined', () => {
@ -27,12 +27,10 @@ test('should validate and apply defaults when params is valid', () => {
id: 'my-alert-type',
name: 'My description',
validate: {
params: Joi.object()
.keys({
param1: Joi.string().required(),
param2: Joi.string().default('default-value'),
})
.required(),
params: schema.object({
param1: schema.string(),
param2: schema.string({ defaultValue: 'default-value' }),
}),
},
async executor() {},
},
@ -51,17 +49,15 @@ test('should validate and throw error when params is invalid', () => {
id: 'my-alert-type',
name: 'My description',
validate: {
params: Joi.object()
.keys({
param1: Joi.string().required(),
})
.required(),
params: schema.object({
param1: schema.string(),
}),
},
async executor() {},
},
{}
)
).toThrowErrorMatchingInlineSnapshot(
`"alertTypeParams invalid: child \\"param1\\" fails because [\\"param1\\" is required]"`
`"alertTypeParams invalid: [param1]: expected value of type [string] but got [undefined]"`
);
});

View file

@ -15,9 +15,10 @@ export function validateAlertTypeParams<T extends Record<string, any>>(
if (!validator) {
return params;
}
const { error, value } = validator.validate(params);
if (error) {
throw Boom.badRequest(`alertTypeParams invalid: ${error.message}`);
try {
return validator.validate(params);
} catch (err) {
throw Boom.badRequest(`alertTypeParams invalid: ${err.message}`);
}
return value;
}

View file

@ -40,7 +40,7 @@ export interface AlertType {
id: string;
name: string;
validate?: {
params?: any;
params?: { validate: (object: any) => any };
};
executor: ({ services, params, state }: AlertExecutorOptions) => Promise<State | void>;
}

View file

@ -137,7 +137,8 @@ export default function createAlertTests({ getService }: KibanaFunctionalTestDef
expect(resp.body).to.eql({
statusCode: 400,
error: 'Bad Request',
message: 'alertTypeParams invalid: child "param1" fails because ["param1" is required]',
message:
'alertTypeParams invalid: [param1]: expected value of type [string] but got [undefined]',
});
});
});

View file

@ -159,7 +159,8 @@ export default function createUpdateTests({ getService }: KibanaFunctionalTestDe
expect(resp.body).to.eql({
statusCode: 400,
error: 'Bad Request',
message: 'alertTypeParams invalid: child "param1" fails because ["param1" is required]',
message:
'alertTypeParams invalid: [param1]: expected value of type [string] but got [undefined]',
});
});
});

View file

@ -4,7 +4,6 @@
* you may not use this file except in compliance with the Elastic License.
*/
import Joi from 'joi';
import { schema } from '@kbn/config-schema';
import { AlertExecutorOptions, AlertType } from '../../../../../legacy/plugins/alerting';
import { ActionTypeExecutorOptions, ActionType } from '../../../../../legacy/plugins/actions';
@ -138,11 +137,9 @@ export default function(kibana: any) {
id: 'test.validation',
name: 'Test: Validation',
validate: {
params: Joi.object()
.keys({
param1: Joi.string().required(),
})
.required(),
params: schema.object({
param1: schema.string(),
}),
},
async executor({ services, params, state }: AlertExecutorOptions) {},
};