[Alerting] fixes to allow pre-configured actions to be executed (#63432)
resolves https://github.com/elastic/kibana/issues/63162 Most of the support for pre-configured actions has already been added to Kibana, except for one small piece. The ability for them to be executed. This PR adds that support.
This commit is contained in:
parent
0abbb1d9c4
commit
7677764c65
|
@ -23,6 +23,7 @@ describe('execute()', () => {
|
|||
actionTypeRegistry: actionTypeRegistryMock.create(),
|
||||
getScopedSavedObjectsClient: jest.fn().mockReturnValueOnce(savedObjectsClient),
|
||||
isESOUsingEphemeralEncryptionKey: false,
|
||||
preconfiguredActions: [],
|
||||
});
|
||||
savedObjectsClient.get.mockResolvedValueOnce({
|
||||
id: '123',
|
||||
|
@ -68,6 +69,68 @@ describe('execute()', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test('schedules the action with all given parameters with a preconfigured action', async () => {
|
||||
const executeFn = createExecuteFunction({
|
||||
getBasePath,
|
||||
taskManager: mockTaskManager,
|
||||
actionTypeRegistry: actionTypeRegistryMock.create(),
|
||||
getScopedSavedObjectsClient: jest.fn().mockReturnValueOnce(savedObjectsClient),
|
||||
isESOUsingEphemeralEncryptionKey: false,
|
||||
preconfiguredActions: [
|
||||
{
|
||||
id: '123',
|
||||
actionTypeId: 'mock-action-preconfigured',
|
||||
config: {},
|
||||
isPreconfigured: true,
|
||||
name: 'x',
|
||||
secrets: {},
|
||||
},
|
||||
],
|
||||
});
|
||||
savedObjectsClient.get.mockResolvedValueOnce({
|
||||
id: '123',
|
||||
type: 'action',
|
||||
attributes: {
|
||||
actionTypeId: 'mock-action',
|
||||
},
|
||||
references: [],
|
||||
});
|
||||
savedObjectsClient.create.mockResolvedValueOnce({
|
||||
id: '234',
|
||||
type: 'action_task_params',
|
||||
attributes: {},
|
||||
references: [],
|
||||
});
|
||||
await executeFn({
|
||||
id: '123',
|
||||
params: { baz: false },
|
||||
spaceId: 'default',
|
||||
apiKey: Buffer.from('123:abc').toString('base64'),
|
||||
});
|
||||
expect(mockTaskManager.schedule).toHaveBeenCalledTimes(1);
|
||||
expect(mockTaskManager.schedule.mock.calls[0]).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Object {
|
||||
"params": Object {
|
||||
"actionTaskParamsId": "234",
|
||||
"spaceId": "default",
|
||||
},
|
||||
"scope": Array [
|
||||
"actions",
|
||||
],
|
||||
"state": Object {},
|
||||
"taskType": "actions:mock-action-preconfigured",
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(savedObjectsClient.get).not.toHaveBeenCalled();
|
||||
expect(savedObjectsClient.create).toHaveBeenCalledWith('action_task_params', {
|
||||
actionId: '123',
|
||||
params: { baz: false },
|
||||
apiKey: Buffer.from('123:abc').toString('base64'),
|
||||
});
|
||||
});
|
||||
|
||||
test('uses API key when provided', async () => {
|
||||
const getScopedSavedObjectsClient = jest.fn().mockReturnValueOnce(savedObjectsClient);
|
||||
const executeFn = createExecuteFunction({
|
||||
|
@ -76,6 +139,7 @@ describe('execute()', () => {
|
|||
getScopedSavedObjectsClient,
|
||||
isESOUsingEphemeralEncryptionKey: false,
|
||||
actionTypeRegistry: actionTypeRegistryMock.create(),
|
||||
preconfiguredActions: [],
|
||||
});
|
||||
savedObjectsClient.get.mockResolvedValueOnce({
|
||||
id: '123',
|
||||
|
@ -125,6 +189,7 @@ describe('execute()', () => {
|
|||
getScopedSavedObjectsClient,
|
||||
isESOUsingEphemeralEncryptionKey: false,
|
||||
actionTypeRegistry: actionTypeRegistryMock.create(),
|
||||
preconfiguredActions: [],
|
||||
});
|
||||
savedObjectsClient.get.mockResolvedValueOnce({
|
||||
id: '123',
|
||||
|
@ -171,6 +236,7 @@ describe('execute()', () => {
|
|||
getScopedSavedObjectsClient,
|
||||
isESOUsingEphemeralEncryptionKey: true,
|
||||
actionTypeRegistry: actionTypeRegistryMock.create(),
|
||||
preconfiguredActions: [],
|
||||
});
|
||||
await expect(
|
||||
executeFn({
|
||||
|
@ -193,6 +259,7 @@ describe('execute()', () => {
|
|||
getScopedSavedObjectsClient,
|
||||
isESOUsingEphemeralEncryptionKey: false,
|
||||
actionTypeRegistry: mockedActionTypeRegistry,
|
||||
preconfiguredActions: [],
|
||||
});
|
||||
mockedActionTypeRegistry.ensureActionTypeEnabled.mockImplementation(() => {
|
||||
throw new Error('Fail');
|
||||
|
|
|
@ -6,7 +6,12 @@
|
|||
|
||||
import { SavedObjectsClientContract } from '../../../../src/core/server';
|
||||
import { TaskManagerStartContract } from '../../task_manager/server';
|
||||
import { GetBasePathFunction, RawAction, ActionTypeRegistryContract } from './types';
|
||||
import {
|
||||
GetBasePathFunction,
|
||||
RawAction,
|
||||
ActionTypeRegistryContract,
|
||||
PreConfiguredAction,
|
||||
} from './types';
|
||||
|
||||
interface CreateExecuteFunctionOptions {
|
||||
taskManager: TaskManagerStartContract;
|
||||
|
@ -14,6 +19,7 @@ interface CreateExecuteFunctionOptions {
|
|||
getBasePath: GetBasePathFunction;
|
||||
isESOUsingEphemeralEncryptionKey: boolean;
|
||||
actionTypeRegistry: ActionTypeRegistryContract;
|
||||
preconfiguredActions: PreConfiguredAction[];
|
||||
}
|
||||
|
||||
export interface ExecuteOptions {
|
||||
|
@ -29,6 +35,7 @@ export function createExecuteFunction({
|
|||
actionTypeRegistry,
|
||||
getScopedSavedObjectsClient,
|
||||
isESOUsingEphemeralEncryptionKey,
|
||||
preconfiguredActions,
|
||||
}: CreateExecuteFunctionOptions) {
|
||||
return async function execute({ id, params, spaceId, apiKey }: ExecuteOptions) {
|
||||
if (isESOUsingEphemeralEncryptionKey === true) {
|
||||
|
@ -61,9 +68,9 @@ export function createExecuteFunction({
|
|||
};
|
||||
|
||||
const savedObjectsClient = getScopedSavedObjectsClient(fakeRequest);
|
||||
const actionSavedObject = await savedObjectsClient.get<RawAction>('action', id);
|
||||
const actionTypeId = await getActionTypeId(id);
|
||||
|
||||
actionTypeRegistry.ensureActionTypeEnabled(actionSavedObject.attributes.actionTypeId);
|
||||
actionTypeRegistry.ensureActionTypeEnabled(actionTypeId);
|
||||
|
||||
const actionTaskParamsRecord = await savedObjectsClient.create('action_task_params', {
|
||||
actionId: id,
|
||||
|
@ -72,7 +79,7 @@ export function createExecuteFunction({
|
|||
});
|
||||
|
||||
await taskManager.schedule({
|
||||
taskType: `actions:${actionSavedObject.attributes.actionTypeId}`,
|
||||
taskType: `actions:${actionTypeId}`,
|
||||
params: {
|
||||
spaceId,
|
||||
actionTaskParamsId: actionTaskParamsRecord.id,
|
||||
|
@ -80,5 +87,15 @@ export function createExecuteFunction({
|
|||
state: {},
|
||||
scope: ['actions'],
|
||||
});
|
||||
|
||||
async function getActionTypeId(actionId: string): Promise<string> {
|
||||
const pcAction = preconfiguredActions.find(action => action.id === actionId);
|
||||
if (pcAction) {
|
||||
return pcAction.actionTypeId;
|
||||
}
|
||||
|
||||
const actionSO = await savedObjectsClient.get<RawAction>('action', actionId);
|
||||
return actionSO.attributes.actionTypeId;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ actionExecutor.initialize({
|
|||
actionTypeRegistry,
|
||||
encryptedSavedObjectsPlugin,
|
||||
eventLogger: eventLoggerMock.create(),
|
||||
preconfiguredActions: [],
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -232,6 +233,7 @@ test('throws an error when passing isESOUsingEphemeralEncryptionKey with value o
|
|||
actionTypeRegistry,
|
||||
encryptedSavedObjectsPlugin,
|
||||
eventLogger: eventLoggerMock.create(),
|
||||
preconfiguredActions: [],
|
||||
});
|
||||
await expect(
|
||||
customActionExecutor.execute(executeParams)
|
||||
|
|
|
@ -11,6 +11,8 @@ import {
|
|||
ActionTypeRegistryContract,
|
||||
GetServicesFunction,
|
||||
RawAction,
|
||||
PreConfiguredAction,
|
||||
Services,
|
||||
} from '../types';
|
||||
import { EncryptedSavedObjectsPluginStart } from '../../../encrypted_saved_objects/server';
|
||||
import { SpacesServiceSetup } from '../../../spaces/server';
|
||||
|
@ -24,6 +26,7 @@ export interface ActionExecutorContext {
|
|||
encryptedSavedObjectsPlugin: EncryptedSavedObjectsPluginStart;
|
||||
actionTypeRegistry: ActionTypeRegistryContract;
|
||||
eventLogger: IEventLogger;
|
||||
preconfiguredActions: PreConfiguredAction[];
|
||||
}
|
||||
|
||||
export interface ExecuteOptions {
|
||||
|
@ -72,28 +75,22 @@ export class ActionExecutor {
|
|||
encryptedSavedObjectsPlugin,
|
||||
actionTypeRegistry,
|
||||
eventLogger,
|
||||
preconfiguredActions,
|
||||
} = this.actionExecutorContext!;
|
||||
|
||||
const services = getServices(request);
|
||||
const spaceId = spaces && spaces.getSpaceId(request);
|
||||
const namespace = spaceId && spaceId !== 'default' ? { namespace: spaceId } : {};
|
||||
|
||||
// Ensure user can read the action before processing
|
||||
const {
|
||||
attributes: { actionTypeId, config, name },
|
||||
} = await services.savedObjectsClient.get<RawAction>('action', actionId);
|
||||
const { actionTypeId, name, config, secrets } = await getActionInfo(
|
||||
services,
|
||||
encryptedSavedObjectsPlugin,
|
||||
preconfiguredActions,
|
||||
actionId,
|
||||
namespace.namespace
|
||||
);
|
||||
|
||||
actionTypeRegistry.ensureActionTypeEnabled(actionTypeId);
|
||||
|
||||
// Only get encrypted attributes here, the remaining attributes can be fetched in
|
||||
// the savedObjectsClient call
|
||||
const {
|
||||
attributes: { secrets },
|
||||
} = await encryptedSavedObjectsPlugin.getDecryptedAsInternalUser<RawAction>(
|
||||
'action',
|
||||
actionId,
|
||||
namespace
|
||||
);
|
||||
const actionType = actionTypeRegistry.get(actionTypeId);
|
||||
|
||||
let validatedParams: Record<string, any>;
|
||||
|
@ -173,3 +170,50 @@ function actionErrorToMessage(result: ActionTypeExecutorResult): string {
|
|||
|
||||
return message;
|
||||
}
|
||||
|
||||
interface ActionInfo {
|
||||
actionTypeId: string;
|
||||
name: string;
|
||||
config: any;
|
||||
secrets: any;
|
||||
}
|
||||
|
||||
async function getActionInfo(
|
||||
services: Services,
|
||||
encryptedSavedObjectsPlugin: EncryptedSavedObjectsPluginStart,
|
||||
preconfiguredActions: PreConfiguredAction[],
|
||||
actionId: string,
|
||||
namespace: string | undefined
|
||||
): Promise<ActionInfo> {
|
||||
// check to see if it's a pre-configured action first
|
||||
const pcAction = preconfiguredActions.find(
|
||||
preconfiguredAction => preconfiguredAction.id === actionId
|
||||
);
|
||||
if (pcAction) {
|
||||
return {
|
||||
actionTypeId: pcAction.actionTypeId,
|
||||
name: pcAction.name,
|
||||
config: pcAction.config,
|
||||
secrets: pcAction.secrets,
|
||||
};
|
||||
}
|
||||
|
||||
// if not pre-configured action, should be a saved object
|
||||
// ensure user can read the action before processing
|
||||
const {
|
||||
attributes: { actionTypeId, config, name },
|
||||
} = await services.savedObjectsClient.get<RawAction>('action', actionId);
|
||||
|
||||
const {
|
||||
attributes: { secrets },
|
||||
} = await encryptedSavedObjectsPlugin.getDecryptedAsInternalUser<RawAction>('action', actionId, {
|
||||
namespace: namespace === 'default' ? undefined : namespace,
|
||||
});
|
||||
|
||||
return {
|
||||
actionTypeId,
|
||||
name,
|
||||
config,
|
||||
secrets,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ const actionExecutorInitializerParams = {
|
|||
actionTypeRegistry,
|
||||
encryptedSavedObjectsPlugin: mockedEncryptedSavedObjectsPlugin,
|
||||
eventLogger: eventLoggerMock.create(),
|
||||
preconfiguredActions: [],
|
||||
};
|
||||
const taskRunnerFactoryInitializerParams = {
|
||||
spaceIdToNamespace,
|
||||
|
|
|
@ -245,6 +245,7 @@ export class ActionsPlugin implements Plugin<Promise<PluginSetupContract>, Plugi
|
|||
getServices: this.getServicesFactory(core.savedObjects),
|
||||
encryptedSavedObjectsPlugin: plugins.encryptedSavedObjects,
|
||||
actionTypeRegistry: actionTypeRegistry!,
|
||||
preconfiguredActions,
|
||||
});
|
||||
|
||||
taskRunnerFactory!.initialize({
|
||||
|
@ -265,6 +266,7 @@ export class ActionsPlugin implements Plugin<Promise<PluginSetupContract>, Plugi
|
|||
getScopedSavedObjectsClient: core.savedObjects.getScopedClient,
|
||||
getBasePath: this.getBasePath,
|
||||
isESOUsingEphemeralEncryptionKey: isESOUsingEphemeralEncryptionKey!,
|
||||
preconfiguredActions,
|
||||
}),
|
||||
isActionTypeEnabled: id => {
|
||||
return this.actionTypeRegistry!.isActionTypeEnabled(id);
|
||||
|
|
|
@ -100,6 +100,27 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions)
|
|||
xyzSecret2: 'credential2',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'preconfigured-es-index-action',
|
||||
actionTypeId: '.index',
|
||||
name: 'preconfigured_es_index_action',
|
||||
config: {
|
||||
index: 'functional-test-actions-index-preconfigured',
|
||||
refresh: true,
|
||||
executionTimeField: 'timestamp',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'preconfigured.test.index-record',
|
||||
actionTypeId: 'test.index-record',
|
||||
name: 'Test:_Preconfigured_Index_Record',
|
||||
config: {
|
||||
unencrypted: 'ignored-but-required',
|
||||
},
|
||||
secrets: {
|
||||
encrypted: 'this-is-also-ignored-and-also-required',
|
||||
},
|
||||
},
|
||||
])}`,
|
||||
...disabledPlugins.map(key => `--xpack.${key}.enabled=false`),
|
||||
`--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'alerts')}`,
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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 expect from '@kbn/expect';
|
||||
|
||||
import { FtrProviderContext } from '../../../../common/ftr_provider_context';
|
||||
|
||||
// from: x-pack/test/alerting_api_integration/common/config.ts
|
||||
const ACTION_ID = 'preconfigured-es-index-action';
|
||||
const ES_TEST_INDEX_NAME = 'functional-test-actions-index-preconfigured';
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default function indexTest({ getService }: FtrProviderContext) {
|
||||
const es = getService('legacyEs');
|
||||
const supertest = getService('supertest');
|
||||
const esArchiver = getService('esArchiver');
|
||||
|
||||
describe('preconfigured index action', () => {
|
||||
after(() => esArchiver.unload('empty_kibana'));
|
||||
beforeEach(() => clearTestIndex(es));
|
||||
|
||||
it('should execute successfully when expected for a single body', async () => {
|
||||
const { body: result } = await supertest
|
||||
.post(`/api/action/${ACTION_ID}/_execute`)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.send({
|
||||
params: {
|
||||
documents: [{ testing: [4, 5, 6] }],
|
||||
},
|
||||
})
|
||||
.expect(200);
|
||||
expect(result.status).to.eql('ok');
|
||||
|
||||
const items = await getTestIndexItems(es);
|
||||
expect(items.length).to.eql(1);
|
||||
|
||||
// check document sans timestamp
|
||||
const document = items[0]._source;
|
||||
const timestamp = document.timestamp;
|
||||
delete document.timestamp;
|
||||
expect(document).to.eql({ testing: [4, 5, 6] });
|
||||
|
||||
// check timestamp
|
||||
const timestampTime = new Date(timestamp).getTime();
|
||||
const timeNow = Date.now();
|
||||
const timeMinuteAgo = timeNow - 1000 * 60;
|
||||
expect(timestampTime).to.be.within(timeMinuteAgo, timeNow);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function clearTestIndex(es: any) {
|
||||
return await es.indices.delete({
|
||||
index: ES_TEST_INDEX_NAME,
|
||||
ignoreUnavailable: true,
|
||||
});
|
||||
}
|
||||
|
||||
async function getTestIndexItems(es: any) {
|
||||
const result = await es.search({
|
||||
index: ES_TEST_INDEX_NAME,
|
||||
});
|
||||
|
||||
return result.hits.hits;
|
||||
}
|
|
@ -68,6 +68,18 @@ export default function getAllActionTests({ getService }: FtrProviderContext) {
|
|||
},
|
||||
referencedByCount: 0,
|
||||
},
|
||||
{
|
||||
id: 'preconfigured-es-index-action',
|
||||
isPreconfigured: true,
|
||||
actionTypeId: '.index',
|
||||
name: 'preconfigured_es_index_action',
|
||||
config: {
|
||||
index: 'functional-test-actions-index-preconfigured',
|
||||
refresh: true,
|
||||
executionTimeField: 'timestamp',
|
||||
},
|
||||
referencedByCount: 0,
|
||||
},
|
||||
{
|
||||
id: 'my-slack1',
|
||||
isPreconfigured: true,
|
||||
|
@ -90,6 +102,16 @@ export default function getAllActionTests({ getService }: FtrProviderContext) {
|
|||
},
|
||||
referencedByCount: 0,
|
||||
},
|
||||
{
|
||||
id: 'preconfigured.test.index-record',
|
||||
isPreconfigured: true,
|
||||
actionTypeId: 'test.index-record',
|
||||
name: 'Test:_Preconfigured_Index_Record',
|
||||
config: {
|
||||
unencrypted: 'ignored-but-required',
|
||||
},
|
||||
referencedByCount: 0,
|
||||
},
|
||||
]);
|
||||
break;
|
||||
default:
|
||||
|
@ -167,6 +189,18 @@ export default function getAllActionTests({ getService }: FtrProviderContext) {
|
|||
},
|
||||
referencedByCount: 1,
|
||||
},
|
||||
{
|
||||
id: 'preconfigured-es-index-action',
|
||||
isPreconfigured: true,
|
||||
actionTypeId: '.index',
|
||||
name: 'preconfigured_es_index_action',
|
||||
config: {
|
||||
index: 'functional-test-actions-index-preconfigured',
|
||||
refresh: true,
|
||||
executionTimeField: 'timestamp',
|
||||
},
|
||||
referencedByCount: 0,
|
||||
},
|
||||
{
|
||||
id: 'my-slack1',
|
||||
isPreconfigured: true,
|
||||
|
@ -189,6 +223,16 @@ export default function getAllActionTests({ getService }: FtrProviderContext) {
|
|||
},
|
||||
referencedByCount: 0,
|
||||
},
|
||||
{
|
||||
id: 'preconfigured.test.index-record',
|
||||
isPreconfigured: true,
|
||||
actionTypeId: 'test.index-record',
|
||||
name: 'Test:_Preconfigured_Index_Record',
|
||||
config: {
|
||||
unencrypted: 'ignored-but-required',
|
||||
},
|
||||
referencedByCount: 0,
|
||||
},
|
||||
]);
|
||||
break;
|
||||
default:
|
||||
|
@ -232,6 +276,18 @@ export default function getAllActionTests({ getService }: FtrProviderContext) {
|
|||
case 'superuser at space1':
|
||||
expect(response.statusCode).to.eql(200);
|
||||
expect(response.body).to.eql([
|
||||
{
|
||||
id: 'preconfigured-es-index-action',
|
||||
isPreconfigured: true,
|
||||
actionTypeId: '.index',
|
||||
name: 'preconfigured_es_index_action',
|
||||
config: {
|
||||
index: 'functional-test-actions-index-preconfigured',
|
||||
refresh: true,
|
||||
executionTimeField: 'timestamp',
|
||||
},
|
||||
referencedByCount: 0,
|
||||
},
|
||||
{
|
||||
id: 'my-slack1',
|
||||
isPreconfigured: true,
|
||||
|
@ -254,6 +310,16 @@ export default function getAllActionTests({ getService }: FtrProviderContext) {
|
|||
},
|
||||
referencedByCount: 0,
|
||||
},
|
||||
{
|
||||
id: 'preconfigured.test.index-record',
|
||||
isPreconfigured: true,
|
||||
actionTypeId: 'test.index-record',
|
||||
name: 'Test:_Preconfigured_Index_Record',
|
||||
config: {
|
||||
unencrypted: 'ignored-but-required',
|
||||
},
|
||||
referencedByCount: 0,
|
||||
},
|
||||
]);
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -11,6 +11,7 @@ export default function actionsTests({ loadTestFile }: FtrProviderContext) {
|
|||
describe('Actions', () => {
|
||||
loadTestFile(require.resolve('./builtin_action_types/email'));
|
||||
loadTestFile(require.resolve('./builtin_action_types/es_index'));
|
||||
loadTestFile(require.resolve('./builtin_action_types/es_index_preconfigured'));
|
||||
loadTestFile(require.resolve('./builtin_action_types/pagerduty'));
|
||||
loadTestFile(require.resolve('./builtin_action_types/server_log'));
|
||||
loadTestFile(require.resolve('./builtin_action_types/servicenow'));
|
||||
|
|
|
@ -165,6 +165,100 @@ instanceStateValue: true
|
|||
}
|
||||
});
|
||||
|
||||
it('should schedule task, run alert and schedule preconfigured actions when appropriate', async () => {
|
||||
const testStart = new Date();
|
||||
const reference = alertUtils.generateReference();
|
||||
const response = await alertUtils.createAlwaysFiringAction({
|
||||
reference,
|
||||
indexRecordActionId: 'preconfigured.test.index-record',
|
||||
});
|
||||
|
||||
switch (scenario.id) {
|
||||
case 'no_kibana_privileges at space1':
|
||||
case 'global_read at space1':
|
||||
case 'space_1_all at space2':
|
||||
expect(response.statusCode).to.eql(404);
|
||||
expect(response.body).to.eql({
|
||||
statusCode: 404,
|
||||
error: 'Not Found',
|
||||
message: 'Not Found',
|
||||
});
|
||||
break;
|
||||
case 'superuser at space1':
|
||||
case 'space_1_all at space1':
|
||||
expect(response.statusCode).to.eql(200);
|
||||
|
||||
// Wait for the action to index a document before disabling the alert and waiting for tasks to finish
|
||||
await esTestIndexTool.waitForDocs('action:test.index-record', reference);
|
||||
|
||||
await taskManagerUtils.waitForAllTasksIdle(testStart);
|
||||
|
||||
const alertId = response.body.id;
|
||||
await alertUtils.disable(alertId);
|
||||
await taskManagerUtils.waitForEmpty(testStart);
|
||||
|
||||
// Ensure only 1 alert executed with proper params
|
||||
const alertSearchResult = await esTestIndexTool.search(
|
||||
'alert:test.always-firing',
|
||||
reference
|
||||
);
|
||||
expect(alertSearchResult.hits.total.value).to.eql(1);
|
||||
expect(alertSearchResult.hits.hits[0]._source).to.eql({
|
||||
source: 'alert:test.always-firing',
|
||||
reference,
|
||||
state: {},
|
||||
params: {
|
||||
index: ES_TEST_INDEX_NAME,
|
||||
reference,
|
||||
},
|
||||
alertInfo: {
|
||||
alertId,
|
||||
spaceId: space.id,
|
||||
namespace: space.id,
|
||||
name: 'abc',
|
||||
tags: ['tag-A', 'tag-B'],
|
||||
createdBy: user.fullName,
|
||||
updatedBy: user.fullName,
|
||||
},
|
||||
});
|
||||
|
||||
// Ensure only 1 action executed with proper params
|
||||
const actionSearchResult = await esTestIndexTool.search(
|
||||
'action:test.index-record',
|
||||
reference
|
||||
);
|
||||
expect(actionSearchResult.hits.total.value).to.eql(1);
|
||||
expect(actionSearchResult.hits.hits[0]._source).to.eql({
|
||||
config: {
|
||||
unencrypted: 'ignored-but-required',
|
||||
},
|
||||
secrets: {
|
||||
encrypted: 'this-is-also-ignored-and-also-required',
|
||||
},
|
||||
params: {
|
||||
index: ES_TEST_INDEX_NAME,
|
||||
reference,
|
||||
message: `
|
||||
alertId: ${alertId},
|
||||
alertName: abc,
|
||||
spaceId: ${space.id},
|
||||
tags: tag-A,tag-B,
|
||||
alertInstanceId: 1,
|
||||
instanceContextValue: true,
|
||||
instanceStateValue: true
|
||||
`.trim(),
|
||||
},
|
||||
reference,
|
||||
source: 'action:test.index-record',
|
||||
});
|
||||
|
||||
await taskManagerUtils.waitForActionTaskParamsToBeCleanedUp(testStart);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`);
|
||||
}
|
||||
});
|
||||
|
||||
it('should pass updated alert params to executor', async () => {
|
||||
const testStart = new Date();
|
||||
// create an alert
|
||||
|
|
|
@ -45,6 +45,18 @@ export default function getAllActionTests({ getService }: FtrProviderContext) {
|
|||
},
|
||||
referencedByCount: 0,
|
||||
},
|
||||
{
|
||||
id: 'preconfigured-es-index-action',
|
||||
isPreconfigured: true,
|
||||
actionTypeId: '.index',
|
||||
name: 'preconfigured_es_index_action',
|
||||
config: {
|
||||
index: 'functional-test-actions-index-preconfigured',
|
||||
refresh: true,
|
||||
executionTimeField: 'timestamp',
|
||||
},
|
||||
referencedByCount: 0,
|
||||
},
|
||||
{
|
||||
id: 'my-slack1',
|
||||
isPreconfigured: true,
|
||||
|
@ -67,6 +79,16 @@ export default function getAllActionTests({ getService }: FtrProviderContext) {
|
|||
},
|
||||
referencedByCount: 0,
|
||||
},
|
||||
{
|
||||
id: 'preconfigured.test.index-record',
|
||||
isPreconfigured: true,
|
||||
actionTypeId: 'test.index-record',
|
||||
name: 'Test:_Preconfigured_Index_Record',
|
||||
config: {
|
||||
unencrypted: 'ignored-but-required',
|
||||
},
|
||||
referencedByCount: 0,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -88,6 +110,18 @@ export default function getAllActionTests({ getService }: FtrProviderContext) {
|
|||
objectRemover.add(Spaces.space1.id, createdAction.id, 'action');
|
||||
|
||||
await supertest.get(`${getUrlPrefix(Spaces.other.id)}/api/action/_getAll`).expect(200, [
|
||||
{
|
||||
id: 'preconfigured-es-index-action',
|
||||
isPreconfigured: true,
|
||||
actionTypeId: '.index',
|
||||
name: 'preconfigured_es_index_action',
|
||||
config: {
|
||||
index: 'functional-test-actions-index-preconfigured',
|
||||
refresh: true,
|
||||
executionTimeField: 'timestamp',
|
||||
},
|
||||
referencedByCount: 0,
|
||||
},
|
||||
{
|
||||
id: 'my-slack1',
|
||||
isPreconfigured: true,
|
||||
|
@ -110,6 +144,16 @@ export default function getAllActionTests({ getService }: FtrProviderContext) {
|
|||
},
|
||||
referencedByCount: 0,
|
||||
},
|
||||
{
|
||||
id: 'preconfigured.test.index-record',
|
||||
isPreconfigured: true,
|
||||
actionTypeId: 'test.index-record',
|
||||
name: 'Test:_Preconfigured_Index_Record',
|
||||
config: {
|
||||
unencrypted: 'ignored-but-required',
|
||||
},
|
||||
referencedByCount: 0,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue