Simplifying

This commit is contained in:
Ying Mao 2021-03-22 14:20:44 -04:00
parent b9ad6c3f48
commit 4b1b78761e
21 changed files with 121 additions and 226 deletions

View file

@ -403,7 +403,6 @@ describe('create()', () => {
enabled: true,
enabledActionTypes: ['some-not-ignored-action-type'],
allowedHosts: ['*'],
preconfiguredAlertHistoryEsIndex: true,
preconfigured: {},
proxyRejectUnauthorizedCertificates: true,
rejectUnauthorized: true,

View file

@ -16,7 +16,6 @@ const defaultActionsConfig: ActionsConfig = {
enabled: false,
allowedHosts: [],
enabledActionTypes: [],
preconfiguredAlertHistoryEsIndex: true,
preconfigured: {},
proxyRejectUnauthorizedCertificates: true,
rejectUnauthorized: true,

View file

@ -1,27 +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
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import { PreConfiguredAction } from '../../types';
import { ActionTypeId as EsIndexActionTypeId } from '../es_index';
import { AlertHistoryEsIndexConnectorId } from '../../../common';
import { getInitialIndexName } from './types';
export function getAlertHistoryEsIndex(kibanaVersion: string): Readonly<PreConfiguredAction> {
return Object.freeze({
name: i18n.translate('xpack.actions.alertHistoryEsIndexConnector.name', {
defaultMessage: 'Alert History ES Index',
}),
actionTypeId: EsIndexActionTypeId,
id: AlertHistoryEsIndexConnectorId,
isPreconfigured: true,
config: {
index: getInitialIndexName(kibanaVersion),
},
secrets: {},
});
}

View file

@ -1,37 +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
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export const ALERT_HISTORY = 'alert-history';
export const AlertHistoryEsIndexConnectorIndexName = `${ALERT_HISTORY}-index`;
export const AlertHistoryIlmPolicyName = `${ALERT_HISTORY}-policy`;
export const AlertHistoryIlmPolicy = {
policy: {
phases: {
hot: {
actions: {
rollover: {
max_size: '50GB',
max_age: '30d',
},
},
},
delete: {
min_age: '90d',
actions: {
delete: {},
},
},
},
},
};
export const getIndexName = (kibanaVersion: string) => `${ALERT_HISTORY}-${kibanaVersion}`;
export const getInitialIndexName = (kibanaVersion: string) =>
`${getIndexName(kibanaVersion)}-000001`;

View file

@ -11,7 +11,7 @@ import { schema, TypeOf } from '@kbn/config-schema';
import { Logger } from '../../../../../src/core/server';
import { ActionType, ActionTypeExecutorOptions, ActionTypeExecutorResult } from '../types';
import { renderMustacheObject } from '../lib/mustache_renderer';
import { buildAlertHistoryDocument, AlertHistoryEsIndexConnectorId } from '../../common';
import { buildAlertHistoryDocument } from '../../common';
export type ESIndexActionType = ActionType<ActionTypeConfigType, {}, ActionParamsType, unknown>;
export type ESIndexActionTypeExecutorOptions = ActionTypeExecutorOptions<
@ -39,6 +39,7 @@ export type ActionParamsType = TypeOf<typeof ParamsSchema>;
// eventually: https://github.com/elastic/kibana/projects/26#card-24087404
const ParamsSchema = schema.object({
documents: schema.arrayOf(schema.recordOf(schema.string(), schema.any())),
usePreconfiguredSchema: schema.boolean({ defaultValue: false }),
});
export const ActionTypeId = '.index';
@ -111,20 +112,22 @@ async function executor(
function renderParameterTemplates(
params: ActionParamsType,
variables: Record<string, unknown>,
actionId: string
variables: Record<string, unknown>
): ActionParamsType {
const { documents } = renderMustacheObject<ActionParamsType>(params, variables);
const { documents, usePreconfiguredSchema } = renderMustacheObject<ActionParamsType>(
params,
variables
);
if (actionId === AlertHistoryEsIndexConnectorId) {
if (usePreconfiguredSchema) {
const alertHistoryDoc = buildAlertHistoryDocument(variables);
if (!alertHistoryDoc) {
throw new Error(`error creating alert history document for ${actionId} connector`);
throw new Error(`error creating alert history document`);
}
return { documents: [alertHistoryDoc] };
return { documents: [alertHistoryDoc], usePreconfiguredSchema };
}
return { documents };
return { documents, usePreconfiguredSchema };
}
function wrapErr(

View file

@ -20,7 +20,6 @@ describe('config validation', () => {
"*",
],
"preconfigured": Object {},
"preconfiguredAlertHistoryEsIndex": true,
"proxyRejectUnauthorizedCertificates": true,
"rejectUnauthorized": true,
}
@ -60,7 +59,6 @@ describe('config validation', () => {
"secrets": Object {},
},
},
"preconfiguredAlertHistoryEsIndex": true,
"proxyRejectUnauthorizedCertificates": false,
"rejectUnauthorized": false,
}

View file

@ -29,7 +29,6 @@ export const configSchema = schema.object({
defaultValue: [AllowedHosts.Any],
}
),
preconfiguredAlertHistoryEsIndex: schema.boolean({ defaultValue: true }),
preconfigured: schema.recordOf(schema.string(), preconfiguredActionSchema, {
defaultValue: {},
validate: validatePreconfigured,

View file

@ -40,11 +40,10 @@ const createStartMock = () => {
// this is a default renderer that escapes nothing
export function renderActionParameterTemplatesDefault<RecordType>(
actionTypeId: string,
actionId: string,
params: Record<string, unknown>,
variables: Record<string, unknown>
) {
return renderActionParameterTemplates(undefined, actionTypeId, actionId, params, variables);
return renderActionParameterTemplates(undefined, actionTypeId, params, variables);
}
const createServicesMock = () => {

View file

@ -34,7 +34,6 @@ describe('Actions Plugin', () => {
enabled: true,
enabledActionTypes: ['*'],
allowedHosts: ['*'],
preconfiguredAlertHistoryEsIndex: true,
preconfigured: {},
proxyRejectUnauthorizedCertificates: true,
rejectUnauthorized: true,
@ -188,7 +187,6 @@ describe('Actions Plugin', () => {
enabled: true,
enabledActionTypes: ['*'],
allowedHosts: ['*'],
preconfiguredAlertHistoryEsIndex: true,
preconfigured: {
preconfiguredServerLog: {
actionTypeId: '.server-log',
@ -228,15 +226,6 @@ describe('Actions Plugin', () => {
expect(pluginStart.isActionExecutable('preconfiguredServerLog', '.server-log')).toBe(true);
});
it('should handle preconfiguredAlertHistoryEsIndex = true', async () => {
await plugin.setup(coreSetup, pluginsSetup);
const pluginStart = await plugin.start(coreStart, pluginsStart);
expect(
pluginStart.isActionExecutable('preconfigured-alert-history-es-index', '.index')
).toBe(true);
});
it('should not throw error when ESO plugin has encryption key', async () => {
await plugin.setup(coreSetup, {
...pluginsSetup,

View file

@ -68,8 +68,6 @@ import {
} from './authorization/get_authorization_mode_by_source';
import { ensureSufficientLicense } from './lib/ensure_sufficient_license';
import { renderMustacheObject } from './lib/mustache_renderer';
import { getAlertHistoryEsIndex } from './builtin_action_types/alert_history_es_index/alert_history_es_index';
import { createAlertHistoryEsIndex } from './builtin_action_types/alert_history_es_index/create_alert_history_es_index';
const EVENT_LOG_PROVIDER = 'actions';
export const EVENT_LOG_ACTIONS = {
@ -100,7 +98,6 @@ export interface PluginStartContract {
preconfiguredActions: PreConfiguredAction[];
renderActionParameterTemplates<Params extends ActionTypeParams = ActionTypeParams>(
actionTypeId: string,
actionId: string,
params: Params,
variables: Record<string, unknown>
): Params;
@ -142,7 +139,6 @@ export class ActionsPlugin implements Plugin<PluginSetupContract, PluginStartCon
private readonly telemetryLogger: Logger;
private readonly preconfiguredActions: PreConfiguredAction[];
private readonly kibanaIndexConfig: { kibana: { index: string } };
private kibanaVersion: PluginInitializerContext['env']['packageInfo']['version'];
constructor(initContext: PluginInitializerContext) {
this.actionsConfig = initContext.config.get<ActionsConfig>();
@ -150,7 +146,6 @@ export class ActionsPlugin implements Plugin<PluginSetupContract, PluginStartCon
this.telemetryLogger = initContext.logger.get('usage');
this.preconfiguredActions = [];
this.kibanaIndexConfig = initContext.config.legacy.get();
this.kibanaVersion = initContext.env.packageInfo.version;
}
public setup(
@ -183,10 +178,6 @@ export class ActionsPlugin implements Plugin<PluginSetupContract, PluginStartCon
const taskRunnerFactory = new TaskRunnerFactory(actionExecutor);
const actionsConfigUtils = getActionsConfigurationUtilities(this.actionsConfig);
if (this.actionsConfig.preconfiguredAlertHistoryEsIndex) {
this.preconfiguredActions.push(getAlertHistoryEsIndex(this.kibanaVersion));
}
for (const preconfiguredId of Object.keys(this.actionsConfig.preconfigured)) {
this.preconfiguredActions.push({
...this.actionsConfig.preconfigured[preconfiguredId],
@ -364,14 +355,6 @@ export class ActionsPlugin implements Plugin<PluginSetupContract, PluginStartCon
scheduleActionsTelemetry(this.telemetryLogger, plugins.taskManager);
if (this.actionsConfig.preconfiguredAlertHistoryEsIndex) {
createAlertHistoryEsIndex({
client: core.elasticsearch.client.asInternalUser,
kibanaVersion: this.kibanaVersion,
logger: this.logger,
});
}
return {
isActionTypeEnabled: (id, options = { notifyUsage: false }) => {
return this.actionTypeRegistry!.isActionTypeEnabled(id, options);
@ -485,13 +468,12 @@ export class ActionsPlugin implements Plugin<PluginSetupContract, PluginStartCon
export function renderActionParameterTemplates<Params extends ActionTypeParams = ActionTypeParams>(
actionTypeRegistry: ActionTypeRegistry | undefined,
actionTypeId: string,
actionId: string,
params: Params,
variables: Record<string, unknown>
): Params {
const actionType = actionTypeRegistry?.get(actionTypeId);
if (actionType?.renderParameterTemplates) {
return actionType.renderParameterTemplates(params, variables, actionId) as Params;
return actionType.renderParameterTemplates(params, variables) as Params;
} else {
return renderMustacheObject(params, variables);
}

View file

@ -107,11 +107,7 @@ export interface ActionType<
config?: ValidatorType<Config>;
secrets?: ValidatorType<Secrets>;
};
renderParameterTemplates?(
params: Params,
variables: Record<string, unknown>,
actionId?: string
): Params;
renderParameterTemplates?(params: Params, variables: Record<string, unknown>): Params;
executor: ExecutorType<Config, Secrets, Params, ExecutorResultData>;
}

View file

@ -0,0 +1,65 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { contextMock } from './context.mock';
import { initializeEs } from './init';
describe('initializeEs', () => {
let esContext = contextMock.create();
beforeEach(() => {
esContext = contextMock.create();
});
test(`should create ILM policy if it doesn't exist`, async () => {
esContext.esAdapter.doesIlmPolicyExist.mockResolvedValue(false);
await initializeEs(esContext);
expect(esContext.esAdapter.doesIlmPolicyExist).toHaveBeenCalled();
expect(esContext.esAdapter.createIlmPolicy).toHaveBeenCalled();
});
test(`shouldn't create ILM policy if it exists`, async () => {
esContext.esAdapter.doesIlmPolicyExist.mockResolvedValue(true);
await initializeEs(esContext);
expect(esContext.esAdapter.doesIlmPolicyExist).toHaveBeenCalled();
expect(esContext.esAdapter.createIlmPolicy).not.toHaveBeenCalled();
});
test(`should create index template if it doesn't exist`, async () => {
esContext.esAdapter.doesIndexTemplateExist.mockResolvedValue(false);
await initializeEs(esContext);
expect(esContext.esAdapter.doesIndexTemplateExist).toHaveBeenCalled();
expect(esContext.esAdapter.createIndexTemplate).toHaveBeenCalled();
});
test(`shouldn't create index template if it already exists`, async () => {
esContext.esAdapter.doesIndexTemplateExist.mockResolvedValue(true);
await initializeEs(esContext);
expect(esContext.esAdapter.doesIndexTemplateExist).toHaveBeenCalled();
expect(esContext.esAdapter.createIndexTemplate).not.toHaveBeenCalled();
});
test(`should create initial index if it doesn't exist`, async () => {
esContext.esAdapter.doesAliasExist.mockResolvedValue(false);
await initializeEs(esContext);
expect(esContext.esAdapter.doesAliasExist).toHaveBeenCalled();
expect(esContext.esAdapter.createIndex).toHaveBeenCalled();
});
test(`shouldn't create initial index if it already exists`, async () => {
esContext.esAdapter.doesAliasExist.mockResolvedValue(true);
await initializeEs(esContext);
expect(esContext.esAdapter.doesAliasExist).toHaveBeenCalled();
expect(esContext.esAdapter.createIndex).not.toHaveBeenCalled();
});
});

View file

@ -8,76 +8,17 @@
import { ElasticsearchClient, Logger } from 'src/core/server';
import mappings from './mappings.json';
import { getIndexName, AlertHistoryIlmPolicyName, AlertHistoryIlmPolicy } from './types';
function getAlertHistoryIndexTemplate(indexName: string, ilmPolicyName: string) {
function getAlertHistoryIndexTemplate() {
return {
index_patterns: [`${indexName}-*`],
index_patterns: [`alert-history-*`],
settings: {
number_of_shards: 1,
auto_expand_replicas: '0-1',
'index.lifecycle.name': ilmPolicyName,
'index.lifecycle.rollover_alias': indexName,
},
mappings,
};
}
async function doesIlmPolicyExist({
client,
policyName,
}: {
client: ElasticsearchClient;
policyName: string;
}) {
try {
await client.transport.request({
method: 'GET',
path: `/_ilm/policy/${policyName}`,
});
} catch (err) {
if (err.statusCode === 404) {
return false;
} else {
throw new Error(`error checking existence of ilm policy: ${err.message}`);
}
}
return true;
}
async function createIlmPolicy({
client,
policyName,
}: {
client: ElasticsearchClient;
policyName: string;
}) {
try {
await client.transport.request({
method: 'PUT',
path: `/_ilm/policy/${policyName}`,
body: AlertHistoryIlmPolicy,
});
} catch (err) {
throw new Error(`error creating ilm policy: ${err.message}`);
}
}
async function createIlmPolicyIfNotExists({
client,
policyName,
}: {
client: ElasticsearchClient;
policyName: string;
}) {
const ilmPolicyExists = await doesIlmPolicyExist({ client, policyName });
if (!ilmPolicyExists) {
await createIlmPolicy({ client, policyName });
}
}
async function doesIndexTemplateExist({
client,
templateName,
@ -138,27 +79,22 @@ async function createIndexTemplateIfNotExists({
}
}
export async function createAlertHistoryEsIndex({
export async function createAlertHistoryIndexTemplate({
client,
kibanaVersion,
logger,
}: {
client: ElasticsearchClient;
kibanaVersion: string;
logger: Logger;
}) {
try {
const indexName = getIndexName(kibanaVersion);
const ilmPolicyName = AlertHistoryIlmPolicyName;
const indexTemplate = getAlertHistoryIndexTemplate(indexName, ilmPolicyName);
await createIlmPolicyIfNotExists({ client, policyName: ilmPolicyName });
await createIndexTemplateIfNotExists({
client,
templateName: `${indexName}-template`,
template: indexTemplate,
templateName: `alert-history-template`,
template: getAlertHistoryIndexTemplate(),
});
} catch (err) {
logger.error(`Could not initialize alert history index with mappings: ${err.message}.`);
logger.error(
`Could not initialize alert history index template with mappings: ${err.message}.`
);
}
}

View file

@ -21,10 +21,6 @@
},
"id": {
"type": "keyword"
},
"state": {
"type": "object",
"enabled": false
}
}
},

View file

@ -0,0 +1,10 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export const ALERT_HISTORY = 'alert-history';
export const AlertHistoryEsIndexConnectorIndexName = `${ALERT_HISTORY}-index`;

View file

@ -86,6 +86,7 @@ import {
} from './health';
import { AlertsConfig } from './config';
import { getHealth } from './health/get_health';
import { createAlertHistoryIndexTemplate } from './alert_history/create_alert_history_index_template';
export const EVENT_LOG_PROVIDER = 'alerting';
export const EVENT_LOG_ACTIONS = {
@ -384,6 +385,11 @@ export class AlertingPlugin {
: Promise.resolve([]);
});
createAlertHistoryIndexTemplate({
client: core.elasticsearch.client.asInternalUser,
logger: this.logger,
});
scheduleAlertingTelemetry(this.telemetryLogger, plugins.taskManager);
scheduleAlertingHealthCheck(this.logger, this.config, plugins.taskManager);

View file

@ -128,7 +128,6 @@ export function createExecutionHandler<
alertActionSubgroup: actionSubgroup,
context,
actionParams: action.params,
actionId: action.id,
state,
kibanaBaseUrl,
alertParams,

View file

@ -35,7 +35,6 @@ test('skips non string parameters', () => {
state: {},
alertId: '1',
alertType: 'rule-type-id',
actionId: 'action-id',
alertName: 'alert-name',
tags: ['tag-A', 'tag-B'],
spaceId: 'spaceId-A',
@ -71,7 +70,6 @@ test('missing parameters get emptied out', () => {
state: {},
alertId: '1',
alertType: 'rule-type-id',
actionId: 'action-id',
alertName: 'alert-name',
tags: ['tag-A', 'tag-B'],
spaceId: 'spaceId-A',
@ -100,7 +98,6 @@ test('context parameters are passed to templates', () => {
context: { foo: 'fooVal' },
alertId: '1',
alertType: 'rule-type-id',
actionId: 'action-id',
alertName: 'alert-name',
tags: ['tag-A', 'tag-B'],
spaceId: 'spaceId-A',
@ -128,7 +125,6 @@ test('state parameters are passed to templates', () => {
context: {},
alertId: '1',
alertType: 'rule-type-id',
actionId: 'action-id',
alertName: 'alert-name',
tags: ['tag-A', 'tag-B'],
spaceId: 'spaceId-A',
@ -156,7 +152,6 @@ test('alertId is passed to templates', () => {
context: {},
alertId: '1',
alertType: 'rule-type-id',
actionId: 'action-id',
alertName: 'alert-name',
tags: ['tag-A', 'tag-B'],
spaceId: 'spaceId-A',
@ -184,7 +179,6 @@ test('alertName is passed to templates', () => {
context: {},
alertId: '1',
alertType: 'rule-type-id',
actionId: 'action-id',
alertName: 'alert-name',
tags: ['tag-A', 'tag-B'],
spaceId: 'spaceId-A',
@ -212,7 +206,6 @@ test('tags is passed to templates', () => {
context: {},
alertId: '1',
alertType: 'rule-type-id',
actionId: 'action-id',
alertName: 'alert-name',
tags: ['tag-A', 'tag-B'],
spaceId: 'spaceId-A',
@ -240,7 +233,6 @@ test('undefined tags is passed to templates', () => {
context: {},
alertId: '1',
alertType: 'rule-type-id',
actionId: 'action-id',
alertName: 'alert-name',
spaceId: 'spaceId-A',
alertInstanceId: '2',
@ -267,7 +259,6 @@ test('empty tags is passed to templates', () => {
context: {},
alertId: '1',
alertType: 'rule-type-id',
actionId: 'action-id',
alertName: 'alert-name',
tags: [],
spaceId: 'spaceId-A',
@ -295,7 +286,6 @@ test('spaceId is passed to templates', () => {
context: {},
alertId: '1',
alertType: 'rule-type-id',
actionId: 'action-id',
alertName: 'alert-name',
tags: ['tag-A', 'tag-B'],
spaceId: 'spaceId-A',
@ -323,7 +313,6 @@ test('alertInstanceId is passed to templates', () => {
context: {},
alertId: '1',
alertType: 'rule-type-id',
actionId: 'action-id',
alertName: 'alert-name',
tags: ['tag-A', 'tag-B'],
spaceId: 'spaceId-A',
@ -351,7 +340,6 @@ test('alertActionGroup is passed to templates', () => {
context: {},
alertId: '1',
alertType: 'rule-type-id',
actionId: 'action-id',
alertName: 'alert-name',
tags: ['tag-A', 'tag-B'],
spaceId: 'spaceId-A',
@ -379,7 +367,6 @@ test('alertActionGroupName is passed to templates', () => {
context: {},
alertId: '1',
alertType: 'rule-type-id',
actionId: 'action-id',
alertName: 'alert-name',
tags: ['tag-A', 'tag-B'],
spaceId: 'spaceId-A',
@ -407,7 +394,6 @@ test('rule variables are passed to templates', () => {
context: {},
alertId: '1',
alertType: 'rule-type-id',
actionId: 'action-id',
alertName: 'alert-name',
tags: ['tag-A', 'tag-B'],
spaceId: 'spaceId-A',
@ -437,7 +423,6 @@ test('rule alert variables are passed to templates', () => {
context: {},
alertId: '1',
alertType: 'rule-type-id',
actionId: 'action-id',
alertName: 'alert-name',
tags: ['tag-A', 'tag-B'],
spaceId: 'spaceId-A',
@ -467,7 +452,6 @@ test('date is passed to templates', () => {
context: {},
alertId: '1',
alertType: 'rule-type-id',
actionId: 'action-id',
alertName: 'alert-name',
tags: ['tag-A', 'tag-B'],
spaceId: 'spaceId-A',
@ -497,7 +481,6 @@ test('works recursively', () => {
context: { value: 'context' },
alertId: '1',
alertType: 'rule-type-id',
actionId: 'action-id',
alertName: 'alert-name',
tags: ['tag-A', 'tag-B'],
spaceId: 'spaceId-A',
@ -529,7 +512,6 @@ test('works recursively with arrays', () => {
context: { value: 'context' },
alertId: '1',
alertType: 'rule-type-id',
actionId: 'action-id',
alertName: 'alert-name',
tags: ['tag-A', 'tag-B'],
spaceId: 'spaceId-A',

View file

@ -17,7 +17,6 @@ interface TransformActionParamsOptions {
actionsPlugin: ActionsPluginStartContract;
alertId: string;
alertType: string;
actionId: string;
actionTypeId: string;
alertName: string;
spaceId: string;
@ -37,7 +36,6 @@ export function transformActionParams({
actionsPlugin,
alertId,
alertType,
actionId,
actionTypeId,
alertName,
spaceId,
@ -83,10 +81,5 @@ export function transformActionParams({
actionSubgroup: alertActionSubgroup,
},
};
return actionsPlugin.renderActionParameterTemplates(
actionTypeId,
actionId,
actionParams,
variables
);
return actionsPlugin.renderActionParameterTemplates(actionTypeId, actionParams, variables);
}

View file

@ -56,18 +56,25 @@ export function getActionType(): ActionTypeModel<EsIndexConfig, unknown, IndexAc
): GenericValidationResult<IndexActionParams> => {
const errors = {
documents: new Array<string>(),
usePreconfiguredSchema: new Array<string>(),
};
const validationResult = { errors };
if (!actionParams.documents?.length || Object.keys(actionParams.documents[0]).length === 0) {
errors.documents.push(
i18n.translate(
'xpack.triggersActionsUI.components.builtinActionTypes.error.requiredDocumentJson',
{
defaultMessage: 'Document is required and should be a valid JSON object.',
}
)
);
if (!actionParams.usePreconfiguredSchema) {
if (
!actionParams.documents?.length ||
Object.keys(actionParams.documents[0]).length === 0
) {
errors.documents.push(
i18n.translate(
'xpack.triggersActionsUI.components.builtinActionTypes.error.requiredDocumentJson',
{
defaultMessage: 'Document is required and should be a valid JSON object.',
}
)
);
}
}
return validationResult;
},
};

View file

@ -42,6 +42,7 @@ export interface PagerDutyActionParams {
export interface IndexActionParams {
documents: Array<Record<string, any>>;
usePreconfiguredSchema: boolean;
}
export enum ServerLogLevelOptions {