* [Alerts][License] Define minimum license required for each alert type (#84997) * Define minimum license required for each alert type * fixed typechecks * fixed tests * fixed tests * fixed due to comments * fixed due to comments * removed file * removed casting to LicenseType * [Alerts][License] Add license checks to alerts HTTP APIs and execution (#85223) * [Alerts][License] Add license checks to alerts HTTP APIs and execution * fixed typechecks * resolved conflicts * resolved conflicts * added router tests * fixed typechecks * added license check support for alert task running * fixed typechecks * added integration tests * fixed due to comments * fixed due to comments * fixed tests * fixed typechecks * [Alerting UI][License] Disable alert types in UI when the license doesn't support it. (#85496) * [Alerting UI][License] Disable alert types in UI when the license doesn't support it. * fixed typechecks * added licensing for alert list and details page * fixed multy select menu * fixed due to comments * fixed due to comments * fixed due to comments * fixed typechecks * fixed license error message * fixed license error message * fixed typechecks * fixed license error message Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
184 lines
6.3 KiB
TypeScript
184 lines
6.3 KiB
TypeScript
/*
|
|
* 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 Boom from '@hapi/boom';
|
|
import { i18n } from '@kbn/i18n';
|
|
import { RunContext, TaskManagerSetupContract } from '../../task_manager/server';
|
|
import { ActionType as CommonActionType } from '../common';
|
|
import { ActionsConfigurationUtilities } from './actions_config';
|
|
import { LicensingPluginSetup } from '../../licensing/server';
|
|
import {
|
|
ExecutorError,
|
|
getActionTypeFeatureUsageName,
|
|
TaskRunnerFactory,
|
|
ILicenseState,
|
|
} from './lib';
|
|
import {
|
|
ActionType,
|
|
PreConfiguredAction,
|
|
ActionTypeConfig,
|
|
ActionTypeSecrets,
|
|
ActionTypeParams,
|
|
} from './types';
|
|
|
|
export interface ActionTypeRegistryOpts {
|
|
licensing: LicensingPluginSetup;
|
|
taskManager: TaskManagerSetupContract;
|
|
taskRunnerFactory: TaskRunnerFactory;
|
|
actionsConfigUtils: ActionsConfigurationUtilities;
|
|
licenseState: ILicenseState;
|
|
preconfiguredActions: PreConfiguredAction[];
|
|
}
|
|
|
|
export class ActionTypeRegistry {
|
|
private readonly taskManager: TaskManagerSetupContract;
|
|
private readonly actionTypes: Map<string, ActionType> = new Map();
|
|
private readonly taskRunnerFactory: TaskRunnerFactory;
|
|
private readonly actionsConfigUtils: ActionsConfigurationUtilities;
|
|
private readonly licenseState: ILicenseState;
|
|
private readonly preconfiguredActions: PreConfiguredAction[];
|
|
private readonly licensing: LicensingPluginSetup;
|
|
|
|
constructor(constructorParams: ActionTypeRegistryOpts) {
|
|
this.taskManager = constructorParams.taskManager;
|
|
this.taskRunnerFactory = constructorParams.taskRunnerFactory;
|
|
this.actionsConfigUtils = constructorParams.actionsConfigUtils;
|
|
this.licenseState = constructorParams.licenseState;
|
|
this.preconfiguredActions = constructorParams.preconfiguredActions;
|
|
this.licensing = constructorParams.licensing;
|
|
}
|
|
|
|
/**
|
|
* Returns if the action type registry has the given action type registered
|
|
*/
|
|
public has(id: string) {
|
|
return this.actionTypes.has(id);
|
|
}
|
|
|
|
/**
|
|
* Throws error if action type is not enabled.
|
|
*/
|
|
public ensureActionTypeEnabled(id: string) {
|
|
this.actionsConfigUtils.ensureActionTypeEnabled(id);
|
|
// Important to happen last because the function will notify of feature usage at the
|
|
// same time and it shouldn't notify when the action type isn't enabled
|
|
this.licenseState.ensureLicenseForActionType(this.get(id));
|
|
}
|
|
|
|
/**
|
|
* Returns true if action type is enabled in the config and a valid license is used.
|
|
*/
|
|
public isActionTypeEnabled(
|
|
id: string,
|
|
options: { notifyUsage: boolean } = { notifyUsage: false }
|
|
) {
|
|
return (
|
|
this.actionsConfigUtils.isActionTypeEnabled(id) &&
|
|
this.licenseState.isLicenseValidForActionType(this.get(id), options).isValid === true
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Returns true if action type is enabled or it is a preconfigured action type.
|
|
*/
|
|
public isActionExecutable(
|
|
actionId: string,
|
|
actionTypeId: string,
|
|
options: { notifyUsage: boolean } = { notifyUsage: false }
|
|
) {
|
|
const actionTypeEnabled = this.isActionTypeEnabled(actionTypeId, options);
|
|
return (
|
|
actionTypeEnabled ||
|
|
(!actionTypeEnabled &&
|
|
this.preconfiguredActions.find(
|
|
(preconfiguredAction) => preconfiguredAction.id === actionId
|
|
) !== undefined)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Registers an action type to the action type registry
|
|
*/
|
|
public register<
|
|
Config extends ActionTypeConfig = ActionTypeConfig,
|
|
Secrets extends ActionTypeSecrets = ActionTypeSecrets,
|
|
Params extends ActionTypeParams = ActionTypeParams,
|
|
ExecutorResultData = void
|
|
>(actionType: ActionType<Config, Secrets, Params, ExecutorResultData>) {
|
|
if (this.has(actionType.id)) {
|
|
throw new Error(
|
|
i18n.translate(
|
|
'xpack.actions.actionTypeRegistry.register.duplicateActionTypeErrorMessage',
|
|
{
|
|
defaultMessage: 'Action type "{id}" is already registered.',
|
|
values: {
|
|
id: actionType.id,
|
|
},
|
|
}
|
|
)
|
|
);
|
|
}
|
|
this.actionTypes.set(actionType.id, { ...actionType } as ActionType);
|
|
this.taskManager.registerTaskDefinitions({
|
|
[`actions:${actionType.id}`]: {
|
|
title: actionType.name,
|
|
maxAttempts: actionType.maxAttempts || 1,
|
|
getRetry(attempts: number, error: unknown) {
|
|
if (error instanceof ExecutorError) {
|
|
return error.retry == null ? false : error.retry;
|
|
}
|
|
// Don't retry other kinds of errors
|
|
return false;
|
|
},
|
|
createTaskRunner: (context: RunContext) => this.taskRunnerFactory.create(context),
|
|
},
|
|
});
|
|
// No need to notify usage on basic action types
|
|
if (actionType.minimumLicenseRequired !== 'basic') {
|
|
this.licensing.featureUsage.register(
|
|
getActionTypeFeatureUsageName(actionType as ActionType),
|
|
actionType.minimumLicenseRequired
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns an action type, throws if not registered
|
|
*/
|
|
public get<
|
|
Config extends ActionTypeConfig = ActionTypeConfig,
|
|
Secrets extends ActionTypeSecrets = ActionTypeSecrets,
|
|
Params extends ActionTypeParams = ActionTypeParams,
|
|
ExecutorResultData = void
|
|
>(id: string): ActionType<Config, Secrets, Params, ExecutorResultData> {
|
|
if (!this.has(id)) {
|
|
throw Boom.badRequest(
|
|
i18n.translate('xpack.actions.actionTypeRegistry.get.missingActionTypeErrorMessage', {
|
|
defaultMessage: 'Action type "{id}" is not registered.',
|
|
values: {
|
|
id,
|
|
},
|
|
})
|
|
);
|
|
}
|
|
return this.actionTypes.get(id)! as ActionType<Config, Secrets, Params, ExecutorResultData>;
|
|
}
|
|
|
|
/**
|
|
* Returns a list of registered action types [{ id, name, enabled }]
|
|
*/
|
|
public list(): CommonActionType[] {
|
|
return Array.from(this.actionTypes).map(([actionTypeId, actionType]) => ({
|
|
id: actionTypeId,
|
|
name: actionType.name,
|
|
minimumLicenseRequired: actionType.minimumLicenseRequired,
|
|
enabled: this.isActionTypeEnabled(actionTypeId),
|
|
enabledInConfig: this.actionsConfigUtils.isActionTypeEnabled(actionTypeId),
|
|
enabledInLicense: !!this.licenseState.isLicenseValidForActionType(actionType).isValid,
|
|
}));
|
|
}
|
|
}
|