kibana/x-pack/plugins/actions/server/action_type_registry.ts
Yuliia Naumenko 37525f80a0
License checks for alerts plugin (#85649)
* [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>
2020-12-14 19:29:39 -08:00

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,
}));
}
}