[7.x] Alerting plugin migrate to Kibana platform (#57635) (#57921)

* resolved conflicts

* Delete codeowners file

* Revert merge conflicts with old version of utility.ts file
This commit is contained in:
Yuliia Naumenko 2020-02-19 11:29:02 -08:00 committed by GitHub
parent 71401c62df
commit 2366d0debd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
175 changed files with 2942 additions and 1934 deletions

View file

@ -3,7 +3,7 @@
"paths": {
"xpack.actions": "plugins/actions",
"xpack.advancedUiActions": "plugins/advanced_ui_actions",
"xpack.alerting": "legacy/plugins/alerting",
"xpack.alerting": "plugins/alerting",
"xpack.triggersActionsUI": "plugins/triggers_actions_ui",
"xpack.apm": ["legacy/plugins/apm", "plugins/apm"],
"xpack.beatsManagement": "legacy/plugins/beats_management",

View file

@ -4,43 +4,4 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { Legacy } from 'kibana';
import { Root } from 'joi';
import { init } from './server';
import mappings from './mappings.json';
export {
AlertingPlugin,
AlertsClient,
AlertType,
AlertExecutorOptions,
PluginSetupContract,
PluginStartContract,
} from './server';
export function alerting(kibana: any) {
return new kibana.Plugin({
id: 'alerting',
configPrefix: 'xpack.alerting',
require: ['kibana', 'elasticsearch', 'actions', 'task_manager', 'encryptedSavedObjects'],
isEnabled(config: Legacy.KibanaConfig) {
return (
config.get('xpack.alerting.enabled') === true &&
config.get('xpack.actions.enabled') === true &&
config.get('xpack.encryptedSavedObjects.enabled') === true &&
config.get('xpack.task_manager.enabled') === true
);
},
config(Joi: Root) {
return Joi.object()
.keys({
enabled: Joi.boolean().default(true),
})
.default();
},
init,
uiExports: {
mappings,
},
});
}
export * from './server';

View file

@ -1,31 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { extendRouteWithLicenseCheck } from './extend_route_with_license_check';
import { LicenseState } from './lib/license_state';
jest.mock('./lib/license_state', () => ({
verifyApiAccessFactory: () => {},
}));
describe('extendRouteWithLicenseCheck', () => {
describe('#actionsextendRouteWithLicenseCheck', () => {
let licenseState: jest.Mocked<LicenseState>;
test('extends route object with license, if config property already exists', () => {
const newRoute = extendRouteWithLicenseCheck(
{ config: { someTestProperty: 'test' } },
licenseState
);
expect(newRoute.config.pre.length > 0);
});
test('extends route object with license check under options.pre', () => {
const newRoute = extendRouteWithLicenseCheck(
{ options: { someProperty: 'test' } },
licenseState
);
expect(newRoute.options.pre.length > 0);
});
});
});

View file

@ -1,19 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { LicenseState, verifyApiAccessFactory } from './lib/license_state';
export function extendRouteWithLicenseCheck(route: any, licenseState: LicenseState) {
const verifyApiAccessPreRouting = verifyApiAccessFactory(licenseState);
const key = route.options ? 'options' : 'config';
return {
...route,
[key]: {
...route[key],
pre: [verifyApiAccessPreRouting],
},
};
}

View file

@ -4,10 +4,32 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { AlertsClient as AlertsClientClass } from './alerts_client';
import { Legacy } from 'kibana';
import { Root } from 'joi';
import mappings from './mappings.json';
export type AlertsClient = PublicMethodsOf<AlertsClientClass>;
export { init } from './init';
export { AlertType, AlertingPlugin, AlertExecutorOptions } from './types';
export { PluginSetupContract, PluginStartContract } from './plugin';
export function alerting(kibana: any) {
return new kibana.Plugin({
id: 'alerting',
configPrefix: 'xpack.alerting',
require: ['kibana', 'elasticsearch', 'actions', 'task_manager', 'encryptedSavedObjects'],
isEnabled(config: Legacy.KibanaConfig) {
return (
config.get('xpack.alerting.enabled') === true &&
config.get('xpack.actions.enabled') === true &&
config.get('xpack.encryptedSavedObjects.enabled') === true &&
config.get('xpack.task_manager.enabled') === true
);
},
config(Joi: Root) {
return Joi.object()
.keys({
enabled: Joi.boolean().default(true),
})
.default();
},
uiExports: {
mappings,
},
});
}

View file

@ -1,28 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { Server, shim } from './shim';
import { Plugin } from './plugin';
import { AlertingPlugin } from './types';
export async function init(server: Server) {
const { initializerContext, coreSetup, coreStart, pluginsSetup, pluginsStart } = shim(server);
const plugin = new Plugin(initializerContext);
const setupContract = await plugin.setup(coreSetup, pluginsSetup);
const startContract = plugin.start(coreStart, pluginsStart);
server.decorate('request', 'getAlertsClient', function() {
return startContract.getAlertsClientWithRequest(this);
});
const exposedFunctions: AlertingPlugin = {
setup: setupContract,
start: startContract,
};
server.expose(exposedFunctions);
}

View file

@ -1,176 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import Hapi from 'hapi';
import { Services } from './types';
import { AlertsClient } from './alerts_client';
import { AlertTypeRegistry } from './alert_type_registry';
import { TaskRunnerFactory } from './task_runner';
import { AlertsClientFactory } from './alerts_client_factory';
import { LicenseState } from './lib/license_state';
import { IClusterClient, KibanaRequest, Logger } from '../../../../../src/core/server';
import {
AlertingPluginInitializerContext,
AlertingCoreSetup,
AlertingCoreStart,
AlertingPluginsSetup,
AlertingPluginsStart,
} from './shim';
import {
createAlertRoute,
deleteAlertRoute,
findAlertRoute,
getAlertRoute,
getAlertStateRoute,
listAlertTypesRoute,
updateAlertRoute,
enableAlertRoute,
disableAlertRoute,
updateApiKeyRoute,
muteAllAlertRoute,
unmuteAllAlertRoute,
muteAlertInstanceRoute,
unmuteAlertInstanceRoute,
} from './routes';
import { extendRouteWithLicenseCheck } from './extend_route_with_license_check';
export interface PluginSetupContract {
registerType: AlertTypeRegistry['register'];
}
export interface PluginStartContract {
listTypes: AlertTypeRegistry['list'];
getAlertsClientWithRequest(request: Hapi.Request): PublicMethodsOf<AlertsClient>;
}
export class Plugin {
private readonly logger: Logger;
private alertTypeRegistry?: AlertTypeRegistry;
private readonly taskRunnerFactory: TaskRunnerFactory;
private adminClient?: IClusterClient;
private serverBasePath?: string;
private licenseState: LicenseState | null = null;
private isESOUsingEphemeralEncryptionKey?: boolean;
constructor(initializerContext: AlertingPluginInitializerContext) {
this.logger = initializerContext.logger.get('plugins', 'alerting');
this.taskRunnerFactory = new TaskRunnerFactory();
}
public async setup(
core: AlertingCoreSetup,
plugins: AlertingPluginsSetup
): Promise<PluginSetupContract> {
this.adminClient = core.elasticsearch.adminClient;
this.licenseState = new LicenseState(plugins.licensing.license$);
this.isESOUsingEphemeralEncryptionKey =
plugins.encryptedSavedObjects.usingEphemeralEncryptionKey;
if (this.isESOUsingEphemeralEncryptionKey) {
this.logger.warn(
'APIs are disabled due to the Encrypted Saved Objects plugin using an ephemeral encryption key. Please set xpack.encryptedSavedObjects.encryptionKey in kibana.yml.'
);
}
// Encrypted attributes
plugins.encryptedSavedObjects.registerType({
type: 'alert',
attributesToEncrypt: new Set(['apiKey']),
attributesToExcludeFromAAD: new Set([
'scheduledTaskId',
'muteAll',
'mutedInstanceIds',
'updatedBy',
]),
});
const alertTypeRegistry = new AlertTypeRegistry({
taskManager: plugins.taskManager,
taskRunnerFactory: this.taskRunnerFactory,
});
this.alertTypeRegistry = alertTypeRegistry;
this.serverBasePath = core.http.basePath.serverBasePath;
// Register routes
core.http.route(extendRouteWithLicenseCheck(createAlertRoute, this.licenseState));
core.http.route(extendRouteWithLicenseCheck(deleteAlertRoute, this.licenseState));
core.http.route(extendRouteWithLicenseCheck(findAlertRoute, this.licenseState));
core.http.route(extendRouteWithLicenseCheck(getAlertRoute, this.licenseState));
core.http.route(extendRouteWithLicenseCheck(getAlertStateRoute, this.licenseState));
core.http.route(extendRouteWithLicenseCheck(listAlertTypesRoute, this.licenseState));
core.http.route(extendRouteWithLicenseCheck(updateAlertRoute, this.licenseState));
core.http.route(extendRouteWithLicenseCheck(enableAlertRoute, this.licenseState));
core.http.route(extendRouteWithLicenseCheck(disableAlertRoute, this.licenseState));
core.http.route(extendRouteWithLicenseCheck(updateApiKeyRoute, this.licenseState));
core.http.route(extendRouteWithLicenseCheck(muteAllAlertRoute, this.licenseState));
core.http.route(extendRouteWithLicenseCheck(unmuteAllAlertRoute, this.licenseState));
core.http.route(extendRouteWithLicenseCheck(muteAlertInstanceRoute, this.licenseState));
core.http.route(extendRouteWithLicenseCheck(unmuteAlertInstanceRoute, this.licenseState));
return {
registerType: alertTypeRegistry.register.bind(alertTypeRegistry),
};
}
public start(core: AlertingCoreStart, plugins: AlertingPluginsStart): PluginStartContract {
const { adminClient, serverBasePath, isESOUsingEphemeralEncryptionKey } = this;
function spaceIdToNamespace(spaceId?: string): string | undefined {
const spacesPlugin = plugins.spaces();
return spacesPlugin && spaceId ? spacesPlugin.spaceIdToNamespace(spaceId) : undefined;
}
const alertsClientFactory = new AlertsClientFactory({
alertTypeRegistry: this.alertTypeRegistry!,
logger: this.logger,
taskManager: plugins.taskManager,
securityPluginSetup: plugins.security,
encryptedSavedObjectsPlugin: plugins.encryptedSavedObjects,
spaceIdToNamespace,
getSpaceId(request: Hapi.Request) {
const spacesPlugin = plugins.spaces();
return spacesPlugin ? spacesPlugin.getSpaceId(request) : undefined;
},
});
this.taskRunnerFactory.initialize({
logger: this.logger,
getServices(rawRequest: Hapi.Request): Services {
const request = KibanaRequest.from(rawRequest);
return {
callCluster: (...args) => adminClient!.asScoped(request).callAsCurrentUser(...args),
// rawRequest is actually a fake request, converting it to KibanaRequest causes issue in SO access
savedObjectsClient: core.savedObjects.getScopedSavedObjectsClient(rawRequest as any),
};
},
spaceIdToNamespace,
executeAction: plugins.actions.execute,
encryptedSavedObjectsPlugin: plugins.encryptedSavedObjects,
getBasePath(spaceId?: string): string {
const spacesPlugin = plugins.spaces();
return spacesPlugin && spaceId ? spacesPlugin.getBasePath(spaceId) : serverBasePath!;
},
});
return {
listTypes: this.alertTypeRegistry!.list.bind(this.alertTypeRegistry!),
getAlertsClientWithRequest: (request: Hapi.Request) => {
if (isESOUsingEphemeralEncryptionKey === true) {
throw new Error(
`Unable to create alerts client due to the Encrypted Saved Objects plugin using an ephemeral encryption key. Please set xpack.encryptedSavedObjects.encryptionKey in kibana.yml`
);
}
return alertsClientFactory!.create(KibanaRequest.from(request), request);
},
};
}
public stop() {
if (this.licenseState) {
this.licenseState.clean();
}
}
}

View file

@ -1,52 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import Hapi from 'hapi';
import { alertsClientMock } from '../alerts_client.mock';
import { alertTypeRegistryMock } from '../alert_type_registry.mock';
const defaultConfig = {
'kibana.index': '.kibana',
};
export function createMockServer(config: Record<string, any> = defaultConfig) {
const server = new Hapi.Server({
port: 0,
});
const alertsClient = alertsClientMock.create();
const alertTypeRegistry = alertTypeRegistryMock.create();
server.config = () => {
return {
get(key: string) {
return config[key];
},
has(key: string) {
return config.hasOwnProperty(key);
},
};
};
server.register({
name: 'alerting',
register(pluginServer: Hapi.Server) {
pluginServer.expose({
setup: {
registerType: alertTypeRegistry.register,
},
start: {
listTypes: alertTypeRegistry.list,
},
});
},
});
server.decorate('request', 'getAlertsClient', () => alertsClient);
server.decorate('request', 'getBasePath', () => '/s/default');
return { server, alertsClient, alertTypeRegistry };
}

View file

@ -1,136 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { omit } from 'lodash';
import { createMockServer } from './_mock_server';
import { createAlertRoute } from './create';
const { server, alertsClient } = createMockServer();
server.route(createAlertRoute);
const mockedAlert = {
alertTypeId: '1',
consumer: 'bar',
name: 'abc',
schedule: { interval: '10s' },
tags: ['foo'],
params: {
bar: true,
},
throttle: '30s',
actions: [
{
group: 'default',
id: '2',
params: {
foo: true,
},
},
],
};
beforeEach(() => jest.resetAllMocks());
test('creates an alert with proper parameters', async () => {
const request = {
method: 'POST',
url: '/api/alert',
payload: mockedAlert,
};
const createdAt = new Date();
const updatedAt = new Date();
alertsClient.create.mockResolvedValueOnce({
...mockedAlert,
enabled: true,
muteAll: false,
createdBy: '',
updatedBy: '',
apiKey: '',
apiKeyOwner: '',
mutedInstanceIds: [],
createdAt,
updatedAt,
id: '123',
actions: [
{
...mockedAlert.actions[0],
actionTypeId: 'test',
},
],
});
const { payload, statusCode } = await server.inject(request);
expect(statusCode).toBe(200);
const response = JSON.parse(payload);
expect(new Date(response.createdAt)).toEqual(createdAt);
expect(omit(response, 'createdAt', 'updatedAt')).toMatchInlineSnapshot(`
Object {
"actions": Array [
Object {
"actionTypeId": "test",
"group": "default",
"id": "2",
"params": Object {
"foo": true,
},
},
],
"alertTypeId": "1",
"apiKey": "",
"apiKeyOwner": "",
"consumer": "bar",
"createdBy": "",
"enabled": true,
"id": "123",
"muteAll": false,
"mutedInstanceIds": Array [],
"name": "abc",
"params": Object {
"bar": true,
},
"schedule": Object {
"interval": "10s",
},
"tags": Array [
"foo",
],
"throttle": "30s",
"updatedBy": "",
}
`);
expect(alertsClient.create).toHaveBeenCalledTimes(1);
expect(alertsClient.create.mock.calls[0]).toMatchInlineSnapshot(`
Array [
Object {
"data": Object {
"actions": Array [
Object {
"group": "default",
"id": "2",
"params": Object {
"foo": true,
},
},
],
"alertTypeId": "1",
"consumer": "bar",
"enabled": true,
"name": "abc",
"params": Object {
"bar": true,
},
"schedule": Object {
"interval": "10s",
},
"tags": Array [
"foo",
],
"throttle": "30s",
},
},
]
`);
});

View file

@ -1,72 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import Hapi from 'hapi';
import Joi from 'joi';
import { getDurationSchema } from '../lib';
import { IntervalSchedule } from '../types';
interface ScheduleRequest extends Hapi.Request {
payload: {
enabled: boolean;
name: string;
tags: string[];
alertTypeId: string;
consumer: string;
schedule: IntervalSchedule;
actions: Array<{
group: string;
id: string;
params: Record<string, any>;
}>;
params: Record<string, any>;
throttle: string | null;
};
}
export const createAlertRoute = {
method: 'POST',
path: '/api/alert',
options: {
tags: ['access:alerting-all'],
validate: {
options: {
abortEarly: false,
},
payload: Joi.object()
.keys({
enabled: Joi.boolean().default(true),
name: Joi.string().required(),
tags: Joi.array()
.items(Joi.string())
.default([]),
alertTypeId: Joi.string().required(),
consumer: Joi.string().required(),
throttle: getDurationSchema().default(null),
schedule: Joi.object()
.keys({
interval: getDurationSchema().required(),
})
.required(),
params: Joi.object().required(),
actions: Joi.array()
.items(
Joi.object().keys({
group: Joi.string().required(),
id: Joi.string().required(),
params: Joi.object().required(),
})
)
.required(),
})
.required(),
},
},
async handler(request: ScheduleRequest) {
const alertsClient = request.getAlertsClient!();
return await alertsClient.create({ data: request.payload });
},
};

View file

@ -1,33 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { createMockServer } from './_mock_server';
import { deleteAlertRoute } from './delete';
const { server, alertsClient } = createMockServer();
server.route(deleteAlertRoute);
beforeEach(() => jest.resetAllMocks());
test('deletes an alert with proper parameters', async () => {
const request = {
method: 'DELETE',
url: '/api/alert/1',
};
alertsClient.delete.mockResolvedValueOnce({});
const { payload, statusCode } = await server.inject(request);
expect(statusCode).toBe(204);
expect(payload).toEqual('');
expect(alertsClient.delete).toHaveBeenCalledTimes(1);
expect(alertsClient.delete.mock.calls[0]).toMatchInlineSnapshot(`
Array [
Object {
"id": "1",
},
]
`);
});

View file

@ -1,35 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import Hapi from 'hapi';
import Joi from 'joi';
interface DeleteRequest extends Hapi.Request {
params: {
id: string;
};
}
export const deleteAlertRoute = {
method: 'DELETE',
path: '/api/alert/{id}',
config: {
tags: ['access:alerting-all'],
validate: {
params: Joi.object()
.keys({
id: Joi.string().required(),
})
.required(),
},
},
async handler(request: DeleteRequest, h: Hapi.ResponseToolkit) {
const { id } = request.params;
const alertsClient = request.getAlertsClient!();
await alertsClient.delete({ id });
return h.response().code(204);
},
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { createMockServer } from './_mock_server';
import { disableAlertRoute } from './disable';
const { server, alertsClient } = createMockServer();
server.route(disableAlertRoute);
test('disables an alert', async () => {
const request = {
method: 'POST',
url: '/api/alert/1/_disable',
};
const { statusCode } = await server.inject(request);
expect(statusCode).toBe(204);
expect(alertsClient.disable).toHaveBeenCalledWith({ id: '1' });
});

View file

@ -1,23 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import Hapi from 'hapi';
export const disableAlertRoute = {
method: 'POST',
path: '/api/alert/{id}/_disable',
config: {
tags: ['access:alerting-all'],
response: {
emptyStatusCode: 204,
},
},
async handler(request: Hapi.Request, h: Hapi.ResponseToolkit) {
const alertsClient = request.getAlertsClient!();
await alertsClient.disable({ id: request.params.id });
return h.response();
},
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { createMockServer } from './_mock_server';
import { enableAlertRoute } from './enable';
const { server, alertsClient } = createMockServer();
server.route(enableAlertRoute);
test('enables an alert', async () => {
const request = {
method: 'POST',
url: '/api/alert/1/_enable',
};
const { statusCode } = await server.inject(request);
expect(statusCode).toBe(204);
expect(alertsClient.enable).toHaveBeenCalledWith({ id: '1' });
});

View file

@ -1,23 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import Hapi from 'hapi';
export const enableAlertRoute = {
method: 'POST',
path: '/api/alert/{id}/_enable',
config: {
tags: ['access:alerting-all'],
response: {
emptyStatusCode: 204,
},
},
async handler(request: Hapi.Request, h: Hapi.ResponseToolkit) {
const alertsClient = request.getAlertsClient!();
await alertsClient.enable({ id: request.params.id });
return h.response();
},
};

View file

@ -1,63 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { createMockServer } from './_mock_server';
import { findAlertRoute } from './find';
const { server, alertsClient } = createMockServer();
server.route(findAlertRoute);
beforeEach(() => jest.resetAllMocks());
test('sends proper arguments to alert find function', async () => {
const request = {
method: 'GET',
url:
'/api/alert/_find?' +
'per_page=1&' +
'page=1&' +
'search=text*&' +
'default_search_operator=AND&' +
'search_fields=description&' +
'sort_field=description&' +
'fields=description',
};
const expectedResult = {
page: 1,
perPage: 1,
total: 0,
data: [],
};
alertsClient.find.mockResolvedValueOnce(expectedResult);
const { payload, statusCode } = await server.inject(request);
expect(statusCode).toBe(200);
const response = JSON.parse(payload);
expect(response).toEqual(expectedResult);
expect(alertsClient.find).toHaveBeenCalledTimes(1);
expect(alertsClient.find.mock.calls[0]).toMatchInlineSnapshot(`
Array [
Object {
"options": Object {
"defaultSearchOperator": "AND",
"fields": Array [
"description",
],
"filter": undefined,
"hasReference": undefined,
"page": 1,
"perPage": 1,
"search": "text*",
"searchFields": Array [
"description",
],
"sortField": "description",
},
},
]
`);
});

View file

@ -1,86 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import Joi from 'joi';
import Hapi from 'hapi';
import { WithoutQueryAndParams } from '../types';
interface FindRequest extends WithoutQueryAndParams<Hapi.Request> {
query: {
per_page: number;
page: number;
search?: string;
default_search_operator: 'AND' | 'OR';
search_fields?: string[];
sort_field?: string;
has_reference?: {
type: string;
id: string;
};
fields?: string[];
filter?: string;
};
}
export const findAlertRoute = {
method: 'GET',
path: '/api/alert/_find',
config: {
tags: ['access:alerting-read'],
validate: {
query: Joi.object()
.keys({
per_page: Joi.number()
.min(0)
.default(20),
page: Joi.number()
.min(1)
.default(1),
search: Joi.string()
.allow('')
.optional(),
default_search_operator: Joi.string()
.valid('OR', 'AND')
.default('OR'),
search_fields: Joi.array()
.items(Joi.string())
.single(),
sort_field: Joi.string(),
has_reference: Joi.object()
.keys({
type: Joi.string().required(),
id: Joi.string().required(),
})
.optional(),
fields: Joi.array()
.items(Joi.string())
.single(),
filter: Joi.string()
.allow('')
.optional(),
})
.default(),
},
},
async handler(request: FindRequest) {
const { query } = request;
const alertsClient = request.getAlertsClient!();
return await alertsClient.find({
options: {
perPage: query.per_page,
page: query.page,
search: query.search,
defaultSearchOperator: query.default_search_operator,
searchFields: query.search_fields,
sortField: query.sort_field,
hasReference: query.has_reference,
fields: query.fields,
filter: query.filter,
},
});
},
};

View file

@ -1,68 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { createMockServer } from './_mock_server';
import { getAlertRoute } from './get';
const { server, alertsClient } = createMockServer();
server.route(getAlertRoute);
const mockedAlert = {
id: '1',
alertTypeId: '1',
schedule: { interval: '10s' },
params: {
bar: true,
},
createdAt: new Date(),
updatedAt: new Date(),
actions: [
{
group: 'default',
id: '2',
actionTypeId: 'test',
params: {
foo: true,
},
},
],
consumer: 'bar',
name: 'abc',
tags: ['foo'],
enabled: true,
muteAll: false,
createdBy: '',
updatedBy: '',
apiKey: '',
apiKeyOwner: '',
throttle: '30s',
mutedInstanceIds: [],
};
beforeEach(() => jest.resetAllMocks());
test('calls get with proper parameters', async () => {
const request = {
method: 'GET',
url: '/api/alert/1',
};
alertsClient.get.mockResolvedValueOnce(mockedAlert);
const { payload, statusCode } = await server.inject(request);
expect(statusCode).toBe(200);
const { createdAt, updatedAt, ...response } = JSON.parse(payload);
expect({ createdAt: new Date(createdAt), updatedAt: new Date(updatedAt), ...response }).toEqual(
mockedAlert
);
expect(alertsClient.get).toHaveBeenCalledTimes(1);
expect(alertsClient.get.mock.calls[0]).toMatchInlineSnapshot(`
Array [
Object {
"id": "1",
},
]
`);
});

View file

@ -1,34 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import Joi from 'joi';
import Hapi from 'hapi';
interface GetRequest extends Hapi.Request {
params: {
id: string;
};
}
export const getAlertRoute = {
method: 'GET',
path: `/api/alert/{id}`,
options: {
tags: ['access:alerting-read'],
validate: {
params: Joi.object()
.keys({
id: Joi.string().required(),
})
.required(),
},
},
async handler(request: GetRequest) {
const { id } = request.params;
const alertsClient = request.getAlertsClient!();
return await alertsClient.get({ id });
},
};

View file

@ -1,73 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { createMockServer } from './_mock_server';
import { getAlertStateRoute } from './get_alert_state';
import { SavedObjectsErrorHelpers } from 'src/core/server';
const { server, alertsClient } = createMockServer();
server.route(getAlertStateRoute);
const mockedAlertState = {
alertTypeState: {
some: 'value',
},
alertInstances: {
first_instance: {
state: {},
meta: {
lastScheduledActions: {
group: 'first_group',
date: new Date(),
},
},
},
second_instance: {},
},
};
beforeEach(() => jest.resetAllMocks());
test('gets alert state', async () => {
const request = {
method: 'GET',
url: '/api/alert/1/state',
};
alertsClient.getAlertState.mockResolvedValueOnce(mockedAlertState);
const { statusCode } = await server.inject(request);
expect(statusCode).toBe(200);
expect(alertsClient.getAlertState).toHaveBeenCalledWith({ id: '1' });
});
test('returns NO-CONTENT when alert exists but has no task state yet', async () => {
const request = {
method: 'GET',
url: '/api/alert/1/state',
};
alertsClient.getAlertState.mockResolvedValueOnce(undefined);
const { statusCode } = await server.inject(request);
expect(statusCode).toBe(204);
expect(alertsClient.getAlertState).toHaveBeenCalledWith({ id: '1' });
});
test('returns NOT-FOUND when alert is not found', async () => {
const request = {
method: 'GET',
url: '/api/alert/1/state',
};
alertsClient.getAlertState.mockRejectedValue(
SavedObjectsErrorHelpers.createGenericNotFoundError('alert', '1')
);
const { statusCode } = await server.inject(request);
expect(statusCode).toBe(404);
expect(alertsClient.getAlertState).toHaveBeenCalledWith({ id: '1' });
});

View file

@ -1,35 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import Joi from 'joi';
import Hapi from 'hapi';
interface GetAlertStateRequest extends Hapi.Request {
params: {
id: string;
};
}
export const getAlertStateRoute = {
method: 'GET',
path: '/api/alert/{id}/state',
options: {
tags: ['access:alerting-read'],
validate: {
params: Joi.object()
.keys({
id: Joi.string().required(),
})
.required(),
},
},
async handler(request: GetAlertStateRequest, h: Hapi.ResponseToolkit) {
const { id } = request.params;
const alertsClient = request.getAlertsClient!();
const state = await alertsClient.getAlertState({ id });
return state ? state : h.response().code(204);
},
};

View file

@ -1,28 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { createMockServer } from './_mock_server';
import { listAlertTypesRoute } from './list_alert_types';
const { server, alertTypeRegistry } = createMockServer();
server.route(listAlertTypesRoute);
beforeEach(() => jest.resetAllMocks());
test('calls the list function', async () => {
const request = {
method: 'GET',
url: '/api/alert/types',
};
alertTypeRegistry.list.mockReturnValueOnce([]);
const { payload, statusCode } = await server.inject(request);
expect(statusCode).toBe(200);
const response = JSON.parse(payload);
expect(response).toEqual([]);
expect(alertTypeRegistry.list).toHaveBeenCalledTimes(1);
expect(alertTypeRegistry.list.mock.calls[0]).toMatchInlineSnapshot(`Array []`);
});

View file

@ -1,18 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import Hapi from 'hapi';
export const listAlertTypesRoute = {
method: 'GET',
path: `/api/alert/types`,
config: {
tags: ['access:alerting-read'],
},
async handler(request: Hapi.Request) {
return request.server.plugins.alerting!.start.listTypes();
},
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { createMockServer } from './_mock_server';
import { muteAllAlertRoute } from './mute_all';
const { server, alertsClient } = createMockServer();
server.route(muteAllAlertRoute);
test('mutes an alert', async () => {
const request = {
method: 'POST',
url: '/api/alert/1/_mute_all',
};
const { statusCode } = await server.inject(request);
expect(statusCode).toBe(204);
expect(alertsClient.muteAll).toHaveBeenCalledWith({ id: '1' });
});

View file

@ -1,29 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import Hapi from 'hapi';
interface MuteAllRequest extends Hapi.Request {
params: {
id: string;
};
}
export const muteAllAlertRoute = {
method: 'POST',
path: '/api/alert/{id}/_mute_all',
config: {
tags: ['access:alerting-all'],
response: {
emptyStatusCode: 204,
},
},
async handler(request: MuteAllRequest, h: Hapi.ResponseToolkit) {
const alertsClient = request.getAlertsClient!();
await alertsClient.muteAll(request.params);
return h.response();
},
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { createMockServer } from './_mock_server';
import { muteAlertInstanceRoute } from './mute_instance';
const { server, alertsClient } = createMockServer();
server.route(muteAlertInstanceRoute);
test('mutes an alert instance', async () => {
const request = {
method: 'POST',
url: '/api/alert/1/alert_instance/2/_mute',
};
const { statusCode } = await server.inject(request);
expect(statusCode).toBe(204);
expect(alertsClient.muteInstance).toHaveBeenCalledWith({ alertId: '1', alertInstanceId: '2' });
});

View file

@ -1,30 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import Hapi from 'hapi';
interface MuteInstanceRequest extends Hapi.Request {
params: {
alertId: string;
alertInstanceId: string;
};
}
export const muteAlertInstanceRoute = {
method: 'POST',
path: '/api/alert/{alertId}/alert_instance/{alertInstanceId}/_mute',
config: {
tags: ['access:alerting-all'],
response: {
emptyStatusCode: 204,
},
},
async handler(request: MuteInstanceRequest, h: Hapi.ResponseToolkit) {
const alertsClient = request.getAlertsClient!();
await alertsClient.muteInstance(request.params);
return h.response();
},
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { createMockServer } from './_mock_server';
import { unmuteAllAlertRoute } from './unmute_all';
const { server, alertsClient } = createMockServer();
server.route(unmuteAllAlertRoute);
test('unmutes an alert', async () => {
const request = {
method: 'POST',
url: '/api/alert/1/_unmute_all',
};
const { statusCode } = await server.inject(request);
expect(statusCode).toBe(204);
expect(alertsClient.unmuteAll).toHaveBeenCalledWith({ id: '1' });
});

View file

@ -1,29 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import Hapi from 'hapi';
interface UnmuteAllRequest extends Hapi.Request {
params: {
id: string;
};
}
export const unmuteAllAlertRoute = {
method: 'POST',
path: '/api/alert/{id}/_unmute_all',
config: {
tags: ['access:alerting-all'],
response: {
emptyStatusCode: 204,
},
},
async handler(request: UnmuteAllRequest, h: Hapi.ResponseToolkit) {
const alertsClient = request.getAlertsClient!();
await alertsClient.unmuteAll(request.params);
return h.response();
},
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { createMockServer } from './_mock_server';
import { unmuteAlertInstanceRoute } from './unmute_instance';
const { server, alertsClient } = createMockServer();
server.route(unmuteAlertInstanceRoute);
test('unmutes an alert instance', async () => {
const request = {
method: 'POST',
url: '/api/alert/1/alert_instance/2/_unmute',
};
const { statusCode } = await server.inject(request);
expect(statusCode).toBe(204);
expect(alertsClient.unmuteInstance).toHaveBeenCalledWith({ alertId: '1', alertInstanceId: '2' });
});

View file

@ -1,30 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import Hapi from 'hapi';
interface UnmuteInstanceRequest extends Hapi.Request {
params: {
alertId: string;
alertInstanceId: string;
};
}
export const unmuteAlertInstanceRoute = {
method: 'POST',
path: '/api/alert/{alertId}/alert_instance/{alertInstanceId}/_unmute',
config: {
tags: ['access:alerting-all'],
response: {
emptyStatusCode: 204,
},
},
async handler(request: UnmuteInstanceRequest, h: Hapi.ResponseToolkit) {
const alertsClient = request.getAlertsClient!();
await alertsClient.unmuteInstance(request.params);
return h.response();
},
};

View file

@ -1,98 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { createMockServer } from './_mock_server';
import { updateAlertRoute } from './update';
const { server, alertsClient } = createMockServer();
server.route(updateAlertRoute);
beforeEach(() => jest.resetAllMocks());
const mockedResponse = {
id: '1',
alertTypeId: '1',
tags: ['foo'],
schedule: { interval: '12s' },
params: {
otherField: false,
},
createdAt: new Date(),
updatedAt: new Date(),
actions: [
{
group: 'default',
id: '2',
actionTypeId: 'test',
params: {
baz: true,
},
},
],
};
test('calls the update function with proper parameters', async () => {
const request = {
method: 'PUT',
url: '/api/alert/1',
payload: {
throttle: null,
name: 'abc',
tags: ['bar'],
schedule: { interval: '12s' },
params: {
otherField: false,
},
actions: [
{
group: 'default',
id: '2',
params: {
baz: true,
},
},
],
},
};
alertsClient.update.mockResolvedValueOnce(mockedResponse);
const { payload, statusCode } = await server.inject(request);
expect(statusCode).toBe(200);
const { createdAt, updatedAt, ...response } = JSON.parse(payload);
expect({ createdAt: new Date(createdAt), updatedAt: new Date(updatedAt), ...response }).toEqual(
mockedResponse
);
expect(alertsClient.update).toHaveBeenCalledTimes(1);
expect(alertsClient.update.mock.calls[0]).toMatchInlineSnapshot(`
Array [
Object {
"data": Object {
"actions": Array [
Object {
"group": "default",
"id": "2",
"params": Object {
"baz": true,
},
},
],
"name": "abc",
"params": Object {
"otherField": false,
},
"schedule": Object {
"interval": "12s",
},
"tags": Array [
"bar",
],
"throttle": null,
},
"id": "1",
},
]
`);
});

View file

@ -1,73 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import Joi from 'joi';
import Hapi from 'hapi';
import { getDurationSchema } from '../lib';
import { IntervalSchedule } from '../types';
interface UpdateRequest extends Hapi.Request {
params: {
id: string;
};
payload: {
alertTypeId: string;
name: string;
tags: string[];
schedule: IntervalSchedule;
actions: Array<{
group: string;
id: string;
params: Record<string, any>;
}>;
params: Record<string, any>;
throttle: string | null;
};
}
export const updateAlertRoute = {
method: 'PUT',
path: '/api/alert/{id}',
options: {
tags: ['access:alerting-all'],
validate: {
options: {
abortEarly: false,
},
payload: Joi.object()
.keys({
throttle: getDurationSchema()
.required()
.allow(null),
name: Joi.string().required(),
tags: Joi.array()
.items(Joi.string())
.required(),
schedule: Joi.object()
.keys({
interval: getDurationSchema().required(),
})
.required(),
params: Joi.object().required(),
actions: Joi.array()
.items(
Joi.object().keys({
group: Joi.string().required(),
id: Joi.string().required(),
params: Joi.object().required(),
})
)
.required(),
})
.required(),
},
},
async handler(request: UpdateRequest) {
const { id } = request.params;
const alertsClient = request.getAlertsClient!();
return await alertsClient.update({ id, data: request.payload });
},
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { createMockServer } from './_mock_server';
import { updateApiKeyRoute } from './update_api_key';
const { server, alertsClient } = createMockServer();
server.route(updateApiKeyRoute);
test('updates api key for an alert', async () => {
const request = {
method: 'POST',
url: '/api/alert/1/_update_api_key',
};
const { statusCode } = await server.inject(request);
expect(statusCode).toBe(204);
expect(alertsClient.updateApiKey).toHaveBeenCalledWith({ id: '1' });
});

View file

@ -1,23 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import Hapi from 'hapi';
export const updateApiKeyRoute = {
method: 'POST',
path: '/api/alert/{id}/_update_api_key',
config: {
tags: ['access:alerting-all'],
response: {
emptyStatusCode: 204,
},
},
async handler(request: Hapi.Request, h: Hapi.ResponseToolkit) {
const alertsClient = request.getAlertsClient!();
await alertsClient.updateApiKey({ id: request.params.id });
return h.response();
},
};

View file

@ -1,145 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import Hapi from 'hapi';
import { Legacy } from 'kibana';
import { LegacySpacesPlugin as SpacesPluginStartContract } from '../../spaces';
import {
TaskManagerStartContract,
TaskManagerSetupContract,
} from '../../../../plugins/task_manager/server';
import { getTaskManagerSetup, getTaskManagerStart } from '../../task_manager/server';
import { XPackMainPlugin } from '../../xpack_main/server/xpack_main';
import KbnServer from '../../../../../src/legacy/server/kbn_server';
import {
EncryptedSavedObjectsPluginSetup,
EncryptedSavedObjectsPluginStart,
} from '../../../../plugins/encrypted_saved_objects/server';
import { SecurityPluginSetup } from '../../../../plugins/security/server';
import {
CoreSetup,
LoggerFactory,
SavedObjectsLegacyService,
} from '../../../../../src/core/server';
import {
ActionsPlugin,
PluginSetupContract as ActionsPluginSetupContract,
PluginStartContract as ActionsPluginStartContract,
} from '../../../../plugins/actions/server';
import { LicensingPluginSetup } from '../../../../plugins/licensing/server';
// Extend PluginProperties to indicate which plugins are guaranteed to exist
// due to being marked as dependencies
interface Plugins extends Hapi.PluginProperties {
actions: ActionsPlugin;
}
export interface Server extends Legacy.Server {
plugins: Plugins;
}
/**
* Shim what we're thinking setup and start contracts will look like
*/
export type SecurityPluginSetupContract = Pick<SecurityPluginSetup, '__legacyCompat'>;
export type SecurityPluginStartContract = Pick<SecurityPluginSetup, 'authc'>;
export type XPackMainPluginSetupContract = Pick<XPackMainPlugin, 'registerFeature'>;
/**
* New platform interfaces
*/
export interface AlertingPluginInitializerContext {
logger: LoggerFactory;
}
export interface AlertingCoreSetup {
elasticsearch: CoreSetup['elasticsearch'];
http: {
route: (route: Hapi.ServerRoute) => void;
basePath: {
serverBasePath: string;
};
};
}
export interface AlertingCoreStart {
savedObjects: SavedObjectsLegacyService;
}
export interface AlertingPluginsSetup {
security?: SecurityPluginSetupContract;
taskManager: TaskManagerSetupContract;
actions: ActionsPluginSetupContract;
xpack_main: XPackMainPluginSetupContract;
encryptedSavedObjects: EncryptedSavedObjectsPluginSetup;
licensing: LicensingPluginSetup;
}
export interface AlertingPluginsStart {
actions: ActionsPluginStartContract;
security?: SecurityPluginStartContract;
spaces: () => SpacesPluginStartContract | undefined;
encryptedSavedObjects: EncryptedSavedObjectsPluginStart;
taskManager: TaskManagerStartContract;
}
/**
* Shim
*
* @param server Hapi server instance
*/
export function shim(
server: Server
): {
initializerContext: AlertingPluginInitializerContext;
coreSetup: AlertingCoreSetup;
coreStart: AlertingCoreStart;
pluginsSetup: AlertingPluginsSetup;
pluginsStart: AlertingPluginsStart;
} {
const newPlatform = ((server as unknown) as KbnServer).newPlatform;
const initializerContext: AlertingPluginInitializerContext = {
logger: newPlatform.coreContext.logger,
};
const coreSetup: AlertingCoreSetup = {
elasticsearch: newPlatform.setup.core.elasticsearch,
http: {
route: server.route.bind(server),
basePath: newPlatform.setup.core.http.basePath,
},
};
const coreStart: AlertingCoreStart = {
savedObjects: server.savedObjects,
};
const pluginsSetup: AlertingPluginsSetup = {
security: newPlatform.setup.plugins.security as SecurityPluginSetupContract | undefined,
taskManager: getTaskManagerSetup(server)!,
actions: newPlatform.setup.plugins.actions as ActionsPluginSetupContract,
xpack_main: server.plugins.xpack_main,
encryptedSavedObjects: newPlatform.setup.plugins
.encryptedSavedObjects as EncryptedSavedObjectsPluginSetup,
licensing: newPlatform.setup.plugins.licensing as LicensingPluginSetup,
};
const pluginsStart: AlertingPluginsStart = {
security: newPlatform.setup.plugins.security as SecurityPluginStartContract | undefined,
actions: newPlatform.start.plugins.actions as ActionsPluginStartContract,
// TODO: Currently a function because it's an optional dependency that
// initializes after this function is called
spaces: () => server.plugins.spaces,
encryptedSavedObjects: newPlatform.start.plugins
.encryptedSavedObjects as EncryptedSavedObjectsPluginStart,
taskManager: getTaskManagerStart(server)!,
};
return {
initializerContext,
coreSetup,
coreStart,
pluginsSetup,
pluginsStart,
};
}

View file

@ -109,15 +109,16 @@ export const monitoring = (kibana: LegacyPluginApi): LegacyPluginSpec => {
};
const legacyPlugins = plugins as Partial<typeof plugins> & { infra?: InfraPlugin };
const { xpack_main, elasticsearch, infra, alerting } = legacyPlugins;
const { xpack_main, elasticsearch, infra } = legacyPlugins;
const {
core: coreSetup,
plugins: { usageCollection, licensing },
plugins: { usageCollection, licensing, alerting },
} = server.newPlatform.setup;
const pluginsSetup: PluginsSetup = {
usageCollection,
licensing,
alerting,
};
const __LEGACY: LegacySetup = {
@ -126,7 +127,6 @@ export const monitoring = (kibana: LegacyPluginApi): LegacyPluginSpec => {
xpack_main,
elasticsearch,
infra,
alerting,
},
};

View file

@ -19,7 +19,7 @@ import {
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } from 'ui/documentation_links';
import { Alert } from '../../../../alerting/server/types';
import { Alert } from '../../../../../../plugins/alerting/common';
import { getSetupModeState, addSetupModeCallback, toggleSetupMode } from '../../lib/setup_mode';
import { NUMBER_OF_MIGRATED_ALERTS, ALERT_TYPE_PREFIX } from '../../../common/constants';
import { AlertsConfiguration } from './configuration';

View file

@ -11,9 +11,8 @@ import {
MONITORING_CONFIG_ALERTING_EMAIL_ADDRESS,
} from '../../common/constants';
import { Logger } from 'src/core/server';
import { AlertServices } from '../../../alerting/server/types';
import { AlertServices, AlertInstance } from '../../../../../plugins/alerting/server';
import { savedObjectsClientMock } from 'src/core/server/mocks';
import { AlertInstance } from '../../../alerting/server/alert_instance';
import {
AlertState,
AlertClusterState,

View file

@ -10,7 +10,7 @@ import { Legacy } from 'kibana';
import { Logger } from 'src/core/server';
import { i18n } from '@kbn/i18n';
import { ALERT_TYPE_LICENSE_EXPIRATION, INDEX_PATTERN_ELASTICSEARCH } from '../../common/constants';
import { AlertType } from '../../../alerting';
import { AlertType } from '../../../../../plugins/alerting/server';
import { fetchLicenses } from '../lib/alerts/fetch_licenses';
import { fetchDefaultEmailAddress } from '../lib/alerts/fetch_default_email_address';
import { fetchClusters } from '../lib/alerts/fetch_clusters';

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { Moment } from 'moment';
import { AlertExecutorOptions } from '../../../alerting';
import { AlertExecutorOptions } from '../../../../../plugins/alerting/server';
export interface AlertLicense {
status: string;

View file

@ -5,7 +5,7 @@
*/
import { Moment } from 'moment-timezone';
import { i18n } from '@kbn/i18n';
import { AlertInstance } from '../../../../alerting/server/alert_instance';
import { AlertInstance } from '../../../../../../plugins/alerting/server';
import { AlertLicense } from '../../alerts/types';
const RESOLVED_SUBJECT = i18n.translate(

View file

@ -34,7 +34,7 @@ export class Plugin {
} = __LEGACY;
const config = monitoringConfig();
const { usageCollection, licensing } = pluginsSetup;
const { usageCollection, licensing, alerting } = pluginsSetup;
registerMonitoringCollection();
/*
* Register collector objects for stats to show up in the APIs
@ -152,7 +152,7 @@ export class Plugin {
};
});
if (KIBANA_ALERTING_ENABLED && plugins.alerting) {
if (KIBANA_ALERTING_ENABLED && alerting) {
// this is not ready right away but we need to register alerts right away
async function getMonitoringCluster() {
const configs = config.get('xpack.monitoring.elasticsearch');
@ -174,7 +174,7 @@ export class Plugin {
function getLogger(contexts) {
return logger.get('plugins', LOGGING_TAG, ...contexts);
}
plugins.alerting.setup.registerType(
alerting.registerType(
getLicenseExpiration(
hapiServer,
getMonitoringCluster,

View file

@ -152,7 +152,6 @@ export const siem = (kibana: any) => {
const initializerContext = { ...coreContext, env };
const __legacy = {
config: server.config,
alerting: server.plugins.alerting,
route: server.route.bind(server),
};

View file

@ -152,8 +152,8 @@ logging.events:
```
See these two README.md's pages for more references on the alerting and actions API:
https://github.com/elastic/kibana/blob/master/x-pack/legacy/plugins/alerting/README.md
https://github.com/elastic/kibana/tree/master/x-pack/legacy/plugins/actions
https://github.com/elastic/kibana/blob/master/x-pack/plugins/alerting/README.md
https://github.com/elastic/kibana/tree/master/x-pack/plugins/actions
### Signals API

View file

@ -8,7 +8,7 @@ import {
elasticsearchServiceMock,
savedObjectsClientMock,
} from '../../../../../../../../../src/core/server/mocks';
import { alertsClientMock } from '../../../../../../alerting/server/alerts_client.mock';
import { alertsClientMock } from '../../../../../../../../plugins/alerting/server/mocks';
import { ActionsClient } from '../../../../../../../../plugins/actions/server';
import { actionsClientMock } from '../../../../../../../../plugins/actions/server/mocks';
import { GetScopedClients } from '../../../../services';

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { Alert } from '../../../../../alerting/common';
import { Alert } from '../../../../../../../plugins/alerting/common';
import { APP_ID, SIGNALS_ID } from '../../../../common/constants';
import { CreateRuleParams } from './types';
import { addTags } from './add_tags';

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { FindResult } from '../../../../../alerting/server/alerts_client';
import { FindResult } from '../../../../../../../plugins/alerting/server';
import { SIGNALS_ID } from '../../../../common/constants';
import { FindRuleParams } from './types';

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { alertsClientMock } from '../../../../../alerting/server/alerts_client.mock';
import { alertsClientMock } from '../../../../../../../plugins/alerting/server/mocks';
import {
getResult,
getFindResultWithSingleHit,

View file

@ -5,7 +5,7 @@
*/
import { INTERNAL_IMMUTABLE_KEY } from '../../../../common/constants';
import { AlertsClient } from '../../../../../alerting';
import { AlertsClient } from '../../../../../../../plugins/alerting/server';
import { RuleAlertType, isAlertTypes } from './types';
import { findRules } from './find_rules';

View file

@ -4,12 +4,12 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { alertsClientMock } from '../../../../../alerting/server/alerts_client.mock';
import {
getResult,
getFindResultWithSingleHit,
FindHit,
} from '../routes/__mocks__/request_responses';
import { alertsClientMock } from '../../../../../../../plugins/alerting/server/mocks';
import { getExportAll } from './get_export_all';
describe('getExportAll', () => {

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { AlertsClient } from '../../../../../alerting';
import { AlertsClient } from '../../../../../../../plugins/alerting/server';
import { getNonPackagedRules } from './get_existing_prepackaged_rules';
import { getExportDetailsNdjson } from './get_export_details_ndjson';
import { transformAlertsToRules, transformRulesToNdjson } from '../routes/rules/utils';

View file

@ -4,13 +4,13 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { alertsClientMock } from '../../../../../alerting/server/alerts_client.mock';
import { getExportByObjectIds, getRulesFromObjects, RulesErrors } from './get_export_by_object_ids';
import {
getResult,
getFindResultWithSingleHit,
FindHit,
} from '../routes/__mocks__/request_responses';
import { alertsClientMock } from '../../../../../../../plugins/alerting/server/mocks';
describe('get_export_by_object_ids', () => {
describe('getExportByObjectIds', () => {

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { AlertsClient } from '../../../../../alerting';
import { AlertsClient } from '../../../../../../../plugins/alerting/server';
import { getExportDetailsNdjson } from './get_export_details_ndjson';
import { isAlertType } from '../rules/types';
import { readRules } from './read_rules';

View file

@ -4,9 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { Alert } from '../../../../../../../plugins/alerting/common';
import { ActionsClient } from '../../../../../../../plugins/actions/server';
import { AlertsClient } from '../../../../../alerting';
import { Alert } from '../../../../../alerting/server/types';
import { AlertsClient } from '../../../../../../../plugins/alerting/server';
import { createRules } from './create_rules';
import { PrepackagedRules } from '../types';

View file

@ -5,7 +5,7 @@
*/
import { defaults } from 'lodash/fp';
import { PartialAlert } from '../../../../../alerting/server/types';
import { PartialAlert } from '../../../../../../../plugins/alerting/server';
import { readRules } from './read_rules';
import { PatchRuleParams, IRuleSavedAttributesSavedObjectAttributes } from './types';
import { addTags } from './add_tags';

View file

@ -4,8 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { alertsClientMock } from '../../../../../alerting/server/alerts_client.mock';
import { readRules } from './read_rules';
import { alertsClientMock } from '../../../../../../../plugins/alerting/server/mocks';
import { getResult, getFindResultWithSingleHit } from '../routes/__mocks__/request_responses';
describe('read_rules', () => {

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { SanitizedAlert } from '../../../../../alerting/common';
import { SanitizedAlert } from '../../../../../../../plugins/alerting/common';
import { INTERNAL_RULE_ID_KEY } from '../../../../common/constants';
import { findRules } from './find_rules';
import { ReadRuleParams, isAlertType } from './types';

View file

@ -13,12 +13,12 @@ import {
SavedObjectsFindResponse,
SavedObjectsClientContract,
} from 'kibana/server';
import { AlertsClient } from '../../../../../../../plugins/alerting/server';
import { Alert } from '../../../../../../../plugins/alerting/common';
import { SIGNALS_ID } from '../../../../common/constants';
import { LegacyRequest } from '../../../types';
import { AlertsClient } from '../../../../../alerting/server';
import { ActionsClient } from '../../../../../../../plugins/actions/server';
import { RuleAlertParams, RuleTypeParams, RuleAlertParamsRest } from '../types';
import { Alert } from '../../../../../alerting/server/types';
export type PatchRuleAlertParamsRest = Partial<RuleAlertParamsRest> & {
id: string | undefined;

View file

@ -6,7 +6,7 @@
import { SavedObjectsClientContract } from 'kibana/server';
import { ActionsClient } from '../../../../../../../plugins/actions/server';
import { AlertsClient } from '../../../../../alerting';
import { AlertsClient } from '../../../../../../../plugins/alerting/server';
import { patchRules } from './patch_rules';
import { PrepackagedRules } from '../types';

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { PartialAlert } from '../../../../../alerting/server/types';
import { PartialAlert } from '../../../../../../../plugins/alerting/server';
import { readRules } from './read_rules';
import { IRuleSavedAttributesSavedObjectAttributes, UpdateRuleParams } from './types';
import { addTags } from './add_tags';

View file

@ -10,7 +10,7 @@ set -e
./check_env_variables.sh
# Example: ./get_alert_instances.sh
# https://github.com/elastic/kibana/blob/master/x-pack/legacy/plugins/alerting/README.md#get-apialert_find-find-alerts
# https://github.com/elastic/kibana/blob/master/x-pack/plugins/alerting/README.md#get-apialert_find-find-alerts
curl -s -k \
-u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \
-X GET ${KIBANA_URL}${SPACE_URL}/api/alert/_find \

View file

@ -10,7 +10,7 @@ set -e
./check_env_variables.sh
# Example: ./get_alert_types.sh
# https://github.com/elastic/kibana/blob/master/x-pack/legacy/plugins/alerting/README.md#get-apialerttypes-list-alert-types
# https://github.com/elastic/kibana/blob/master/x-pack/plugins/alerting/README.md#get-apialerttypes-list-alert-types
curl -s -k \
-u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \
-X GET ${KIBANA_URL}${SPACE_URL}/api/alert/types \

View file

@ -6,8 +6,8 @@
import { getQueryFilter, getFilter } from './get_filter';
import { savedObjectsClientMock } from 'src/core/server/mocks';
import { AlertServices } from '../../../../../alerting/server/types';
import { PartialFilter } from '../types';
import { AlertServices } from '../../../../../../../plugins/alerting/server';
describe('get_filter', () => {
let savedObjectsClient = savedObjectsClientMock.create();

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { AlertServices } from '../../../../../alerting/server/types';
import { AlertServices } from '../../../../../../../plugins/alerting/server';
import { assertUnreachable } from '../../../utils/build_query';
import {
Filter,

View file

@ -6,9 +6,9 @@
import { savedObjectsClientMock } from 'src/core/server/mocks';
import { DEFAULT_INDEX_KEY } from '../../../../common/constants';
import { AlertServices } from '../../../../../alerting/server/types';
import { getInputIndex } from './get_input_output_index';
import { defaultIndexPattern } from '../../../../default_index_pattern';
import { AlertServices } from '../../../../../../../plugins/alerting/server';
describe('get_input_output_index', () => {
let savedObjectsClient = savedObjectsClientMock.create();

View file

@ -4,8 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { AlertServices } from '../../../../../../../plugins/alerting/server';
import { defaultIndexPattern } from '../../../../default_index_pattern';
import { AlertServices } from '../../../../../alerting/server/types';
import { DEFAULT_INDEX_KEY } from '../../../../common/constants';
export const getInputIndex = async (

View file

@ -4,8 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { AlertServices } from '../../../../../../../plugins/alerting/server';
import { RuleTypeParams } from '../types';
import { AlertServices } from '../../../../../alerting/server/types';
import { Logger } from '../../../../../../../../src/core/server';
import { singleSearchAfter } from './single_search_after';
import { singleBulkCreate } from './single_bulk_create';

View file

@ -6,7 +6,7 @@
import { countBy, isEmpty } from 'lodash';
import { performance } from 'perf_hooks';
import { AlertServices } from '../../../../../alerting/server/types';
import { AlertServices } from '../../../../../../../plugins/alerting/server';
import { SignalSearchResponse, BulkResponse } from './types';
import { RuleTypeParams } from '../types';
import { generateId } from './utils';

View file

@ -4,8 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { AlertServices } from '../../../../../../../plugins/alerting/server';
import { RuleTypeParams } from '../types';
import { AlertServices } from '../../../../../alerting/server/types';
import { Logger } from '../../../../../../../../src/core/server';
import { SignalSearchResponse } from './types';
import { buildEventsSearchQuery } from './build_events_query';

View file

@ -7,7 +7,11 @@
import { RuleAlertParams, OutputRuleAlertRest } from '../types';
import { SearchResponse } from '../../types';
import { LegacyRequest } from '../../../types';
import { AlertType, State, AlertExecutorOptions } from '../../../../../alerting/server/types';
import {
AlertType,
State,
AlertExecutorOptions,
} from '../../../../../../../plugins/alerting/server';
export interface SignalsParams {
signalIds: string[] | undefined | null;

View file

@ -7,7 +7,7 @@ import { createHash } from 'crypto';
import moment from 'moment';
import dateMath from '@elastic/datemath';
import { parseDuration } from '../../../../../alerting/server/lib';
import { parseDuration } from '../../../../../../../plugins/alerting/server';
export const generateId = (
docIndex: string,

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { alertsClientMock } from '../../../../../alerting/server/alerts_client.mock';
import { alertsClientMock } from '../../../../../../../plugins/alerting/server/mocks';
import { getResult, getFindResultWithMultiHits } from '../routes/__mocks__/request_responses';
import { INTERNAL_RULE_ID_KEY, INTERNAL_IDENTIFIER } from '../../../../common/constants';
import { readRawTags, readTags, convertTagsToSet, convertToTags, isTags } from './read_tags';

View file

@ -6,7 +6,7 @@
import { has } from 'lodash/fp';
import { INTERNAL_IDENTIFIER } from '../../../../common/constants';
import { AlertsClient } from '../../../../../alerting';
import { AlertsClient } from '../../../../../../../plugins/alerting/server';
import { findRules } from '../rules/find_rules';
export interface TagType {

View file

@ -6,6 +6,10 @@
import { i18n } from '@kbn/i18n';
import {
PluginStartContract as AlertingStart,
PluginSetupContract as AlertingSetup,
} from '../../../../plugins/alerting/server';
import {
CoreSetup,
CoreStart,
@ -38,10 +42,12 @@ export interface SetupPlugins {
features: FeaturesSetup;
security: SecuritySetup;
spaces?: SpacesSetup;
alerting: AlertingSetup;
}
export interface StartPlugins {
actions: ActionsStart;
alerting: AlertingStart;
}
export class Plugin {
@ -130,13 +136,13 @@ export class Plugin {
},
});
if (__legacy.alerting != null) {
if (plugins.alerting != null) {
const type = signalRulesAlertType({
logger: this.logger,
version: this.context.env.packageInfo.version,
});
if (isAlertExecutor(type)) {
__legacy.alerting.setup.registerType(type);
plugins.alerting.registerType(type);
}
}
@ -145,7 +151,7 @@ export class Plugin {
}
public start(core: CoreStart, plugins: StartPlugins) {
this.clients.start(core.savedObjects, plugins.actions);
this.clients.start(core.savedObjects, plugins.actions, plugins.alerting);
this.legacyInitRoutes!(this.clients.createGetScoped());
}

View file

@ -6,6 +6,7 @@
import { coreMock, httpServerMock } from '../../../../../../src/core/server/mocks';
import { actionsMock } from '../../../../../plugins/actions/server/mocks';
import { alertsMock } from '../../../../../plugins/alerting/server/mocks';
import { ClientsService } from './clients';
@ -16,13 +17,14 @@ describe('ClientsService', () => {
const clients = new ClientsService();
const actions = actionsMock.createStart();
const alerting = alertsMock.createStart();
const { elasticsearch } = coreMock.createSetup();
const { savedObjects } = coreMock.createStart();
const request = httpServerMock.createRawRequest();
const spacesService = undefined;
clients.setup(elasticsearch.dataClient, spacesService);
clients.start(savedObjects, actions);
clients.start(savedObjects, actions, alerting);
const { spacesClient } = await clients.createGetScoped()(request);
expect(spacesClient.getSpaceId()).toEqual('default');

View file

@ -12,23 +12,23 @@ import {
SavedObjectsClientContract,
} from '../../../../../../src/core/server';
import { ActionsClient } from '../../../../../plugins/actions/server';
import { AlertsClient } from '../../../../../legacy/plugins/alerting/server';
import { AlertsClient } from '../../../../../plugins/alerting/server';
import { SpacesServiceSetup } from '../../../../../plugins/spaces/server';
import { CoreStart, StartPlugins } from '../plugin';
export interface Clients {
actionsClient?: ActionsClient;
alertsClient?: AlertsClient;
clusterClient: IScopedClusterClient;
spacesClient: { getSpaceId: () => string };
savedObjectsClient: SavedObjectsClientContract;
}
interface LegacyClients {
alertsClient?: AlertsClient;
}
export type GetScopedClients = (request: LegacyRequest) => Promise<Clients & LegacyClients>;
export type GetScopedClients = (request: LegacyRequest) => Promise<Clients>;
export class ClientsService {
private actions?: StartPlugins['actions'];
private alerting?: StartPlugins['alerting'];
private clusterClient?: IClusterClient;
private savedObjects?: CoreStart['savedObjects'];
private spacesService?: SpacesServiceSetup;
@ -38,9 +38,14 @@ export class ClientsService {
this.spacesService = spacesService;
}
public start(savedObjects: CoreStart['savedObjects'], actions: StartPlugins['actions']) {
public start(
savedObjects: CoreStart['savedObjects'],
actions: StartPlugins['actions'],
alerting: StartPlugins['alerting']
) {
this.savedObjects = savedObjects;
this.actions = actions;
this.alerting = alerting;
}
public createGetScoped(): GetScopedClients {
@ -52,7 +57,7 @@ export class ClientsService {
const kibanaRequest = KibanaRequest.from(request);
return {
alertsClient: request.getAlertsClient?.(),
alertsClient: await this.alerting?.getAlertsClientWithRequest?.(kibanaRequest),
actionsClient: await this.actions?.getActionsClientWithRequest?.(kibanaRequest),
clusterClient: this.clusterClient!.asScoped(kibanaRequest),
savedObjectsClient: this.savedObjects!.getScopedClient(kibanaRequest),

View file

@ -12,7 +12,7 @@ import {
IKibanaResponse,
KibanaResponseFactory,
} from 'kibana/server';
import { FindOptions } from '../../../../legacy/plugins/alerting/server/alerts_client';
import { FindOptions } from '../../../alerting/server';
import { LicenseState } from '../lib/license_state';
import { verifyApiAccess } from '../lib/license_api_access';

View file

@ -77,7 +77,7 @@ Note that the `manage_own_api_key` cluster privilege is not enough - it can be u
### Methods
**server.plugins.alerting.setup.registerType(options)**
**server.newPlatform.setup.plugins.alerting.registerType(options)**
The following table describes the properties of the `options` object.
@ -119,7 +119,7 @@ This example receives server and threshold as parameters. It will read the CPU u
```
import { schema } from '@kbn/config-schema';
...
server.plugins.alerting.setup.registerType({
server.newPlatform.setup.plugins.alerting.registerType({
id: 'my-alert-type',
name: 'My alert type',
validate: {
@ -178,7 +178,7 @@ server.plugins.alerting.setup.registerType({
This example only receives threshold as a parameter. It will read the CPU usage of all the servers and schedule individual actions if the reading for a server is greater than the threshold. This is a better implementation than above as only one query is performed for all the servers instead of one query per server.
```
server.plugins.alerting.setup.registerType({
server.newPlatform.setup.plugins.alerting.registerType({
id: 'my-alert-type',
name: 'My alert type',
validate: {

View file

@ -0,0 +1,10 @@
{
"id": "alerting",
"server": true,
"version": "8.0.0",
"kibanaVersion": "kibana",
"configPath": ["xpack", "alerting"],
"requiredPlugins": ["licensing", "taskManager", "encryptedSavedObjects", "actions"],
"optionalPlugins": ["spaces", "security"],
"ui": false
}

View file

@ -6,7 +6,7 @@
import { TaskRunnerFactory } from './task_runner';
import { AlertTypeRegistry } from './alert_type_registry';
import { taskManagerMock } from '../../../../plugins/task_manager/server/task_manager.mock';
import { taskManagerMock } from '../../../plugins/task_manager/server/task_manager.mock';
const taskManager = taskManagerMock.setup();
const alertTypeRegistryParams = {

View file

@ -6,7 +6,7 @@
import Boom from 'boom';
import { i18n } from '@kbn/i18n';
import { RunContext, TaskManagerSetupContract } from '../../../../plugins/task_manager/server';
import { RunContext, TaskManagerSetupContract } from '../../../plugins/task_manager/server';
import { TaskRunnerFactory } from './task_runner';
import { AlertType } from './types';

View file

@ -6,13 +6,13 @@
import uuid from 'uuid';
import { schema } from '@kbn/config-schema';
import { AlertsClient } from './alerts_client';
import { savedObjectsClientMock, loggingServiceMock } from '../../../../../src/core/server/mocks';
import { taskManagerMock } from '../../../../plugins/task_manager/server/task_manager.mock';
import { savedObjectsClientMock, loggingServiceMock } from '../../../../src/core/server/mocks';
import { taskManagerMock } from '../../../plugins/task_manager/server/task_manager.mock';
import { alertTypeRegistryMock } from './alert_type_registry.mock';
import { TaskStatus } from '../../../../plugins/task_manager/server';
import { TaskStatus } from '../../../plugins/task_manager/server';
import { IntervalSchedule } from './types';
import { resolvable } from './test_utils';
import { encryptedSavedObjectsMock } from '../../../../plugins/encrypted_saved_objects/server/mocks';
import { encryptedSavedObjectsMock } from '../../../plugins/encrypted_saved_objects/server/mocks';
const taskManager = taskManagerMock.start();
const alertTypeRegistry = alertTypeRegistryMock.create();

View file

@ -29,9 +29,9 @@ import {
InvalidateAPIKeyParams,
CreateAPIKeyResult as SecurityPluginCreateAPIKeyResult,
InvalidateAPIKeyResult as SecurityPluginInvalidateAPIKeyResult,
} from '../../../../plugins/security/server';
import { EncryptedSavedObjectsPluginStart } from '../../../../plugins/encrypted_saved_objects/server';
import { TaskManagerStartContract } from '../../../../plugins/task_manager/server';
} from '../../../plugins/security/server';
import { EncryptedSavedObjectsPluginStart } from '../../../plugins/encrypted_saved_objects/server';
import { TaskManagerStartContract } from '../../../plugins/task_manager/server';
import { taskInstanceToAlertTaskInstance } from './task_runner/alert_task_instance';
type NormalizedAlertAction = Omit<AlertAction, 'actionTypeId'>;

View file

@ -5,23 +5,23 @@
*/
import { Request } from 'hapi';
import { AlertsClientFactory, ConstructorOpts } from './alerts_client_factory';
import { AlertsClientFactory, AlertsClientFactoryOpts } from './alerts_client_factory';
import { alertTypeRegistryMock } from './alert_type_registry.mock';
import { taskManagerMock } from '../../../../plugins/task_manager/server/task_manager.mock';
import { KibanaRequest } from '../../../../../src/core/server';
import { loggingServiceMock } from '../../../../../src/core/server/mocks';
import { encryptedSavedObjectsMock } from '../../../../plugins/encrypted_saved_objects/server/mocks';
import { taskManagerMock } from '../../../plugins/task_manager/server/task_manager.mock';
import { KibanaRequest } from '../../../../src/core/server';
import { loggingServiceMock, savedObjectsClientMock } from '../../../../src/core/server/mocks';
import { encryptedSavedObjectsMock } from '../../../plugins/encrypted_saved_objects/server/mocks';
jest.mock('./alerts_client');
const savedObjectsClient = jest.fn();
const savedObjectsClient = savedObjectsClientMock.create();
const securityPluginSetup = {
authc: {
createAPIKey: jest.fn(),
getCurrentUser: jest.fn(),
},
};
const alertsClientFactoryParams: jest.Mocked<ConstructorOpts> = {
const alertsClientFactoryParams: jest.Mocked<AlertsClientFactoryOpts> = {
logger: loggingServiceMock.create().get(),
taskManager: taskManagerMock.start(),
alertTypeRegistry: alertTypeRegistryMock.create(),
@ -52,8 +52,9 @@ beforeEach(() => {
});
test('creates an alerts client with proper constructor arguments', async () => {
const factory = new AlertsClientFactory(alertsClientFactoryParams);
factory.create(KibanaRequest.from(fakeRequest), fakeRequest);
const factory = new AlertsClientFactory();
factory.initialize(alertsClientFactoryParams);
factory.create(KibanaRequest.from(fakeRequest), savedObjectsClient);
expect(jest.requireMock('./alerts_client').AlertsClient).toHaveBeenCalledWith({
savedObjectsClient,
@ -70,8 +71,9 @@ test('creates an alerts client with proper constructor arguments', async () => {
});
test('getUserName() returns null when security is disabled', async () => {
const factory = new AlertsClientFactory(alertsClientFactoryParams);
factory.create(KibanaRequest.from(fakeRequest), fakeRequest);
const factory = new AlertsClientFactory();
factory.initialize(alertsClientFactoryParams);
factory.create(KibanaRequest.from(fakeRequest), savedObjectsClient);
const constructorCall = jest.requireMock('./alerts_client').AlertsClient.mock.calls[0][0];
const userNameResult = await constructorCall.getUserName();
@ -79,11 +81,12 @@ test('getUserName() returns null when security is disabled', async () => {
});
test('getUserName() returns a name when security is enabled', async () => {
const factory = new AlertsClientFactory({
const factory = new AlertsClientFactory();
factory.initialize({
...alertsClientFactoryParams,
securityPluginSetup: securityPluginSetup as any,
});
factory.create(KibanaRequest.from(fakeRequest), fakeRequest);
factory.create(KibanaRequest.from(fakeRequest), savedObjectsClient);
const constructorCall = jest.requireMock('./alerts_client').AlertsClient.mock.calls[0][0];
securityPluginSetup.authc.getCurrentUser.mockReturnValueOnce({ username: 'bob' });
@ -92,8 +95,9 @@ test('getUserName() returns a name when security is enabled', async () => {
});
test('createAPIKey() returns { apiKeysEnabled: false } when security is disabled', async () => {
const factory = new AlertsClientFactory(alertsClientFactoryParams);
factory.create(KibanaRequest.from(fakeRequest), fakeRequest);
const factory = new AlertsClientFactory();
factory.initialize(alertsClientFactoryParams);
factory.create(KibanaRequest.from(fakeRequest), savedObjectsClient);
const constructorCall = jest.requireMock('./alerts_client').AlertsClient.mock.calls[0][0];
const createAPIKeyResult = await constructorCall.createAPIKey();
@ -101,8 +105,9 @@ test('createAPIKey() returns { apiKeysEnabled: false } when security is disabled
});
test('createAPIKey() returns { apiKeysEnabled: false } when security is enabled but ES security is disabled', async () => {
const factory = new AlertsClientFactory(alertsClientFactoryParams);
factory.create(KibanaRequest.from(fakeRequest), fakeRequest);
const factory = new AlertsClientFactory();
factory.initialize(alertsClientFactoryParams);
factory.create(KibanaRequest.from(fakeRequest), savedObjectsClient);
const constructorCall = jest.requireMock('./alerts_client').AlertsClient.mock.calls[0][0];
securityPluginSetup.authc.createAPIKey.mockResolvedValueOnce(null);
@ -111,11 +116,12 @@ test('createAPIKey() returns { apiKeysEnabled: false } when security is enabled
});
test('createAPIKey() returns an API key when security is enabled', async () => {
const factory = new AlertsClientFactory({
const factory = new AlertsClientFactory();
factory.initialize({
...alertsClientFactoryParams,
securityPluginSetup: securityPluginSetup as any,
});
factory.create(KibanaRequest.from(fakeRequest), fakeRequest);
factory.create(KibanaRequest.from(fakeRequest), savedObjectsClient);
const constructorCall = jest.requireMock('./alerts_client').AlertsClient.mock.calls[0][0];
securityPluginSetup.authc.createAPIKey.mockResolvedValueOnce({ api_key: '123', id: 'abc' });
@ -127,11 +133,12 @@ test('createAPIKey() returns an API key when security is enabled', async () => {
});
test('createAPIKey() throws when security plugin createAPIKey throws an error', async () => {
const factory = new AlertsClientFactory({
const factory = new AlertsClientFactory();
factory.initialize({
...alertsClientFactoryParams,
securityPluginSetup: securityPluginSetup as any,
});
factory.create(KibanaRequest.from(fakeRequest), fakeRequest);
factory.create(KibanaRequest.from(fakeRequest), savedObjectsClient);
const constructorCall = jest.requireMock('./alerts_client').AlertsClient.mock.calls[0][0];
securityPluginSetup.authc.createAPIKey.mockRejectedValueOnce(new Error('TLS disabled'));

Some files were not shown because too many files have changed in this diff Show more