Skip to content

Commit

Permalink
Adds a builtin action to send events to PagerDuty.
Browse files Browse the repository at this point in the history
  • Loading branch information
pmuellr committed Aug 15, 2019
1 parent 3e14b02 commit 7c06057
Show file tree
Hide file tree
Showing 3 changed files with 397 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ import { actionType as serverLogActionType } from './server_log';
import { actionType as slackActionType } from './slack';
import { actionType as emailActionType } from './email';
import { actionType as indexActionType } from './es_index';
import { actionType as pagerDutyActionType } from './pagerduty';

export function registerBuiltInActionTypes(actionTypeRegistry: ActionTypeRegistry) {
actionTypeRegistry.register(serverLogActionType);
actionTypeRegistry.register(slackActionType);
actionTypeRegistry.register(emailActionType);
actionTypeRegistry.register(indexActionType);
actionTypeRegistry.register(pagerDutyActionType);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
/*
* 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 { ActionType, Services } from '../types';
import { ActionTypeRegistry } from '../action_type_registry';
import { taskManagerMock } from '../../../task_manager/task_manager.mock';
import { encryptedSavedObjectsMock } from '../../../encrypted_saved_objects/server/plugin.mock';
import { validateConfig, validateSecrets, validateParams } from '../lib';
import { SavedObjectsClientMock } from '../../../../../../src/core/server/mocks';

import { registerBuiltInActionTypes } from './index';

const ACTION_TYPE_ID = '.pagerduty';
const NO_OP_FN = () => {};

const services: Services = {
log: NO_OP_FN,
callCluster: async (path: string, opts: any) => {},
savedObjectsClient: SavedObjectsClientMock.create(),
};

function getServices(): Services {
return services;
}

let actionTypeRegistry: ActionTypeRegistry;

const mockEncryptedSavedObjectsPlugin = encryptedSavedObjectsMock.create();

beforeAll(() => {
actionTypeRegistry = new ActionTypeRegistry({
getServices,
taskManager: taskManagerMock.create(),
encryptedSavedObjectsPlugin: mockEncryptedSavedObjectsPlugin,
spaceIdToNamespace: jest.fn().mockReturnValue(undefined),
getBasePath: jest.fn().mockReturnValue(undefined),
});
registerBuiltInActionTypes(actionTypeRegistry);
});

beforeEach(() => {
services.log = NO_OP_FN;
});

describe('action is registered', () => {
test('gets registered with builtin actions', () => {
expect(actionTypeRegistry.has(ACTION_TYPE_ID)).toEqual(true);
});
});

describe('get()', () => {
test('returns action type', () => {
const actionType = actionTypeRegistry.get(ACTION_TYPE_ID);
expect(actionType.id).toEqual(ACTION_TYPE_ID);
expect(actionType.name).toEqual('pagerduty');
});
});

describe('validateConfig()', () => {
let actionType: ActionType;

beforeAll(() => {
actionType = actionTypeRegistry.get(ACTION_TYPE_ID);
expect(actionType).toBeTruthy();
});

test('should validate and pass when config is valid', () => {
expect(validateConfig(actionType, {})).toEqual({ apiUrl: null });
expect(validateConfig(actionType, { apiUrl: 'bar' })).toEqual({ apiUrl: 'bar' });
});

test('should validate and throw error when config is invalid', () => {
expect(() => {
validateConfig(actionType, { shouldNotBeHere: true });
}).toThrowErrorMatchingInlineSnapshot(
`"error validating action type config: [shouldNotBeHere]: definition for this key is missing"`
);
expect(() => {
validateConfig(actionType, { apiUrl: false });
}).toThrowErrorMatchingInlineSnapshot(`
"error validating action type config: [apiUrl]: types that failed validation:
- [apiUrl.0]: expected value of type [string] but got [boolean]
- [apiUrl.1]: expected value to equal [null] but got [false]"
`);
});
});

describe('validateSecrets()', () => {
let actionType: ActionType;

beforeAll(() => {
actionType = actionTypeRegistry.get(ACTION_TYPE_ID);
expect(actionType).toBeTruthy();
});

test('should validate and pass when secrets is valid', () => {
const routingKey = '0123456789ABCDEF0123456789ABCDEF';
expect(validateSecrets(actionType, { routingKey })).toEqual({
routingKey,
});
});

test('should validate and throw error when secrets is invalid', () => {
const routingKey = '123456789ABCDEF0123456789ABCDEF'; // 31 chars!
expect(() => {
validateSecrets(actionType, { routingKey });
}).toThrowErrorMatchingInlineSnapshot(
`"error validating action type secrets: [routingKey]: value is [123456789ABCDEF0123456789ABCDEF] but it must have a minimum length of [32]."`
);

expect(() => {
validateSecrets(actionType, { routingKey: false });
}).toThrowErrorMatchingInlineSnapshot(
`"error validating action type secrets: [routingKey]: expected value of type [string] but got [boolean]"`
);

expect(() => {
validateSecrets(actionType, {});
}).toThrowErrorMatchingInlineSnapshot(
`"error validating action type secrets: [routingKey]: expected value of type [string] but got [undefined]"`
);
});
});

describe('validateParams()', () => {
let actionType: ActionType;

beforeAll(() => {
actionType = actionTypeRegistry.get(ACTION_TYPE_ID);
expect(actionType).toBeTruthy();
});

test('should validate and pass when params is valid', () => {
expect(validateParams(actionType, {})).toEqual({
eventAction: 'trigger',
});

const params = {
eventAction: 'trigger',
dedupKey: 'a dedupKey',
summary: 'a summary',
source: 'a source',
severity: 'critical',
timestamp: new Date().toISOString(),
component: 'a component',
group: 'a group',
class: 'a class',
};
expect(validateParams(actionType, params)).toEqual(params);
});

test('should validate and throw error when params is invalid', () => {
expect(() => {
validateParams(actionType, { eventAction: 'ackynollage' });
}).toThrowErrorMatchingInlineSnapshot(`
"error validating action params: [eventAction]: types that failed validation:
- [eventAction.0]: expected value to equal [trigger] but got [ackynollage]
- [eventAction.1]: expected value to equal [resolve] but got [ackynollage]
- [eventAction.2]: expected value to equal [acknowledge] but got [ackynollage]"
`);
});
});

describe('execute()', () => {
test('calls the executor with proper params', async () => {
expect('TBD').toEqual('TBD');
});
});
Loading

0 comments on commit 7c06057

Please sign in to comment.