Skip to content

Commit

Permalink
added getAlertState on AlertClient and exposed on api
Browse files Browse the repository at this point in the history
  • Loading branch information
gmmorris committed Feb 5, 2020
1 parent 91e28e8 commit 45cc53e
Show file tree
Hide file tree
Showing 15 changed files with 614 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const createAlertsClientMock = () => {
const mocked: jest.Mocked<Schema> = {
create: jest.fn(),
get: jest.fn(),
getAlertState: jest.fn(),
find: jest.fn(),
delete: jest.fn(),
update: jest.fn(),
Expand Down
114 changes: 114 additions & 0 deletions x-pack/legacy/plugins/alerting/server/alerts_client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1356,6 +1356,120 @@ describe('get()', () => {
});
});

describe('getAlertState()', () => {
test('calls saved objects client with given params', async () => {
const alertsClient = new AlertsClient(alertsClientParams);
savedObjectsClient.get.mockResolvedValueOnce({
id: '1',
type: 'alert',
attributes: {
alertTypeId: '123',
schedule: { interval: '10s' },
params: {
bar: true,
},
actions: [
{
group: 'default',
actionRef: 'action_0',
params: {
foo: true,
},
},
],
},
references: [
{
name: 'action_0',
type: 'action',
id: '1',
},
],
});

taskManager.get.mockResolvedValueOnce({
id: '1',
taskType: 'alerting:123',
scheduledAt: new Date(),
attempts: 1,
status: TaskStatus.Idle,
runAt: new Date(),
startedAt: null,
retryAt: null,
state: {},
params: {},
ownerId: null,
});

await alertsClient.getAlertState({ id: '1' });
expect(savedObjectsClient.get).toHaveBeenCalledTimes(1);
expect(savedObjectsClient.get.mock.calls[0]).toMatchInlineSnapshot(`
Array [
"alert",
"1",
]
`);
});

test('gets the underlying task from TaskManager', async () => {
const alertsClient = new AlertsClient(alertsClientParams);

const scheduledTaskId = 'task-123';

savedObjectsClient.get.mockResolvedValueOnce({
id: '1',
type: 'alert',
attributes: {
alertTypeId: '123',
schedule: { interval: '10s' },
params: {
bar: true,
},
actions: [
{
group: 'default',
actionRef: 'action_0',
params: {
foo: true,
},
},
],
enabled: true,
scheduledTaskId,
mutedInstanceIds: [],
muteAll: true,
},
references: [
{
name: 'action_0',
type: 'action',
id: '1',
},
],
});

taskManager.get.mockResolvedValueOnce({
id: scheduledTaskId,
taskType: 'alerting:123',
scheduledAt: new Date(),
attempts: 1,
status: TaskStatus.Idle,
runAt: new Date(),
startedAt: null,
retryAt: null,
state: {},
params: {
alertId: '1',
},
ownerId: null,
});

await alertsClient.getAlertState({ id: '1' });
expect(taskManager.get).toHaveBeenCalledTimes(1);
expect(taskManager.get).toHaveBeenCalledWith(scheduledTaskId);
});
});

describe('find()', () => {
test('calls saved objects client with given params', async () => {
const alertsClient = new AlertsClient(alertsClientParams);
Expand Down
12 changes: 12 additions & 0 deletions x-pack/legacy/plugins/alerting/server/alerts_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
} from '../../../../plugins/security/server';
import { EncryptedSavedObjectsPluginStart } from '../../../../plugins/encrypted_saved_objects/server';
import { TaskManagerStartContract } from '../../../../plugins/task_manager/server';
import { AlertTaskState, taskInstanceToAlertTaskInstance } from './task_runner/alert_task_instance';

type NormalizedAlertAction = Omit<AlertAction, 'actionTypeId'>;
export type CreateAPIKeyResult =
Expand Down Expand Up @@ -204,6 +205,17 @@ export class AlertsClient {
return this.getAlertFromRaw(result.id, result.attributes, result.updated_at, result.references);
}

public async getAlertState({ id }: { id: string }): Promise<AlertTaskState | void> {
const alert = await this.get({ id });
if (alert.scheduledTaskId) {
const { state } = taskInstanceToAlertTaskInstance(
await this.taskManager.get(alert.scheduledTaskId),
alert
);
return state;
}
}

public async find({ options = {} }: FindOptions = {}): Promise<FindResult> {
const {
page,
Expand Down
2 changes: 2 additions & 0 deletions x-pack/legacy/plugins/alerting/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
deleteAlertRoute,
findAlertRoute,
getAlertRoute,
getAlertStateRoute,
listAlertTypesRoute,
updateAlertRoute,
enableAlertRoute,
Expand Down Expand Up @@ -90,6 +91,7 @@ export class Plugin {
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));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* 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 './getAlertState';
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' });
});
35 changes: 35 additions & 0 deletions x-pack/legacy/plugins/alerting/server/routes/get_alert_state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* 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);
},
};
1 change: 1 addition & 0 deletions x-pack/legacy/plugins/alerting/server/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export { createAlertRoute } from './create';
export { deleteAlertRoute } from './delete';
export { findAlertRoute } from './find';
export { getAlertRoute } from './get';
export { getAlertStateRoute } from './get_alert_state';
export { listAlertTypesRoute } from './list_alert_types';
export { updateAlertRoute } from './update';
export { enableAlertRoute } from './enable';
Expand Down
Loading

0 comments on commit 45cc53e

Please sign in to comment.