From 9fe722935738de887d8fa244d556cc41e55a38bd Mon Sep 17 00:00:00 2001 From: Gidi Meir Morris Date: Wed, 29 Apr 2020 15:46:54 +0100 Subject: [PATCH] [Alerting] migrates all remaining plugins to new platform (#64335) Completes the migration of all Alerting Services plugins onto the Kibana Platform It includes: 1. Actions plugin 2. Alerting plugin 3. Task Manager plugin 4. Triggers UI plugin And touches the Uptime and Siem plugins as their use of the Task Manager relied on some of the legacy lifecycle to work (registering AlertTypes and Telemetry tasks after the Start stage has already began). The fix was simply to moves these registrations to the Setup stage. --- .github/CODEOWNERS | 3 - x-pack/index.js | 6 - x-pack/legacy/plugins/actions/server/index.ts | 38 --- x-pack/legacy/plugins/alerting/index.ts | 7 - .../legacy/plugins/alerting/server/index.ts | 40 --- .../plugins/monitoring/common/constants.ts | 2 +- .../plugins/task_manager/server/index.ts | 22 +- .../plugins/triggers_actions_ui/index.ts | 34 --- .../triggers_actions_ui/public/index.scss | 2 - x-pack/plugins/actions/server/plugin.ts | 15 +- .../actions/server/saved_objects/index.ts | 42 +++ .../server/saved_objects}/mappings.json | 0 x-pack/plugins/alerting/server/plugin.ts | 13 +- .../alerting/server/saved_objects/index.ts | 33 +++ .../server/saved_objects}/mappings.json | 0 x-pack/plugins/monitoring/common/constants.ts | 2 +- .../scripts/get_action_instances.sh | 2 +- .../scripts/get_action_types.sh | 2 +- x-pack/plugins/task_manager/server/plugin.ts | 21 +- .../server/saved_objects/index.ts | 23 ++ .../server/saved_objects}/mappings.json | 0 .../server/saved_objects}/migrations.ts | 0 .../task_manager/server/task_manager.ts | 8 +- .../builtin_action_types/servicenow.ts | 2 +- .../actions/builtin_action_types/slack.ts | 2 +- .../actions/builtin_action_types/webhook.ts | 2 +- .../alerting_api_integration/common/config.ts | 5 +- .../common/fixtures/plugins/aad/index.ts | 2 +- .../{actions => actions_simulators}/README.md | 0 .../{actions => actions_simulators}/index.ts | 2 +- .../package.json | 0 .../pagerduty_simulation.ts | 0 .../servicenow_simulation.ts | 0 .../slack_simulation.ts | 0 .../webhook_simulation.ts | 0 .../common/fixtures/plugins/alerts/index.ts | 4 +- .../fixtures/plugins/task_manager/index.ts | 2 +- .../actions/builtin_action_types/pagerduty.ts | 2 +- .../builtin_action_types/servicenow.ts | 2 +- .../actions/builtin_action_types/slack.ts | 2 +- .../actions/builtin_action_types/webhook.ts | 2 +- .../actions/builtin_action_types/webhook.ts | 2 +- .../common/config.ts | 1 - x-pack/test/functional_with_es_ssl/config.ts | 2 - .../plugins/sample_task_plugin/kibana.json | 9 + .../plugins/sample_task_plugin/package.json | 18 ++ .../sample_task_plugin/server}/index.ts | 4 +- .../sample_task_plugin/server/init_routes.ts | 252 ++++++++++++++++++ .../sample_task_plugin/server/plugin.ts | 164 ++++++++++++ .../plugins/task_manager/index.js | 150 ----------- .../plugins/task_manager/init_routes.js | 236 ---------------- .../plugins/task_manager/package.json | 12 - .../task_manager/task_manager_integration.js | 21 +- 53 files changed, 587 insertions(+), 628 deletions(-) delete mode 100644 x-pack/legacy/plugins/actions/server/index.ts delete mode 100644 x-pack/legacy/plugins/alerting/index.ts delete mode 100644 x-pack/legacy/plugins/alerting/server/index.ts delete mode 100644 x-pack/legacy/plugins/triggers_actions_ui/index.ts delete mode 100644 x-pack/legacy/plugins/triggers_actions_ui/public/index.scss create mode 100644 x-pack/plugins/actions/server/saved_objects/index.ts rename x-pack/{legacy/plugins/actions/server => plugins/actions/server/saved_objects}/mappings.json (100%) create mode 100644 x-pack/plugins/alerting/server/saved_objects/index.ts rename x-pack/{legacy/plugins/alerting/server => plugins/alerting/server/saved_objects}/mappings.json (100%) create mode 100644 x-pack/plugins/task_manager/server/saved_objects/index.ts rename x-pack/{legacy/plugins/task_manager/server => plugins/task_manager/server/saved_objects}/mappings.json (100%) rename x-pack/{legacy/plugins/task_manager/server => plugins/task_manager/server/saved_objects}/migrations.ts (100%) rename x-pack/test/alerting_api_integration/common/fixtures/plugins/{actions => actions_simulators}/README.md (100%) rename x-pack/test/alerting_api_integration/common/fixtures/plugins/{actions => actions_simulators}/index.ts (98%) rename x-pack/test/alerting_api_integration/common/fixtures/plugins/{actions => actions_simulators}/package.json (100%) rename x-pack/test/alerting_api_integration/common/fixtures/plugins/{actions => actions_simulators}/pagerduty_simulation.ts (100%) rename x-pack/test/alerting_api_integration/common/fixtures/plugins/{actions => actions_simulators}/servicenow_simulation.ts (100%) rename x-pack/test/alerting_api_integration/common/fixtures/plugins/{actions => actions_simulators}/slack_simulation.ts (100%) rename x-pack/test/alerting_api_integration/common/fixtures/plugins/{actions => actions_simulators}/webhook_simulation.ts (100%) create mode 100644 x-pack/test/plugin_api_integration/plugins/sample_task_plugin/kibana.json create mode 100644 x-pack/test/plugin_api_integration/plugins/sample_task_plugin/package.json rename x-pack/{legacy/plugins/actions => test/plugin_api_integration/plugins/sample_task_plugin/server}/index.ts (65%) create mode 100644 x-pack/test/plugin_api_integration/plugins/sample_task_plugin/server/init_routes.ts create mode 100644 x-pack/test/plugin_api_integration/plugins/sample_task_plugin/server/plugin.ts delete mode 100644 x-pack/test/plugin_api_integration/plugins/task_manager/index.js delete mode 100644 x-pack/test/plugin_api_integration/plugins/task_manager/init_routes.js delete mode 100644 x-pack/test/plugin_api_integration/plugins/task_manager/package.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 9e74daa13513d..a97400ee09c0e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -166,8 +166,6 @@ /x-pack/plugins/telemetry_collection_xpack/ @elastic/pulse # Kibana Alerting Services -/x-pack/legacy/plugins/alerting/ @elastic/kibana-alerting-services -/x-pack/legacy/plugins/actions/ @elastic/kibana-alerting-services /x-pack/plugins/alerting/ @elastic/kibana-alerting-services /x-pack/plugins/actions/ @elastic/kibana-alerting-services /x-pack/plugins/event_log/ @elastic/kibana-alerting-services @@ -175,7 +173,6 @@ /x-pack/test/alerting_api_integration/ @elastic/kibana-alerting-services /x-pack/test/plugin_api_integration/plugins/task_manager/ @elastic/kibana-alerting-services /x-pack/test/plugin_api_integration/test_suites/task_manager/ @elastic/kibana-alerting-services -/x-pack/legacy/plugins/triggers_actions_ui/ @elastic/kibana-alerting-services /x-pack/plugins/triggers_actions_ui/ @elastic/kibana-alerting-services /x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/ @elastic/kibana-alerting-services /x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/ @elastic/kibana-alerting-services diff --git a/x-pack/index.js b/x-pack/index.js index a4142e24e4aeb..cfadddac3994a 100644 --- a/x-pack/index.js +++ b/x-pack/index.js @@ -17,10 +17,7 @@ import { canvas } from './legacy/plugins/canvas'; import { infra } from './legacy/plugins/infra'; import { taskManager } from './legacy/plugins/task_manager'; import { encryptedSavedObjects } from './legacy/plugins/encrypted_saved_objects'; -import { actions } from './legacy/plugins/actions'; -import { alerting } from './legacy/plugins/alerting'; import { ingestManager } from './legacy/plugins/ingest_manager'; -import { triggersActionsUI } from './legacy/plugins/triggers_actions_ui'; module.exports = function(kibana) { return [ @@ -37,9 +34,6 @@ module.exports = function(kibana) { infra(kibana), taskManager(kibana), encryptedSavedObjects(kibana), - actions(kibana), - alerting(kibana), ingestManager(kibana), - triggersActionsUI(kibana), ]; }; diff --git a/x-pack/legacy/plugins/actions/server/index.ts b/x-pack/legacy/plugins/actions/server/index.ts deleted file mode 100644 index 63dd6f99f9c24..0000000000000 --- a/x-pack/legacy/plugins/actions/server/index.ts +++ /dev/null @@ -1,38 +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; - * you may not use this file except in compliance with the Elastic License. - */ -import { Root } from 'joi'; -import { Legacy } from 'kibana'; -import mappings from './mappings.json'; -import { - LegacyPluginApi, - LegacyPluginSpec, - ArrayOrItem, -} from '../../../../../src/legacy/plugin_discovery/types'; - -export function actions(kibana: LegacyPluginApi): ArrayOrItem { - return new kibana.Plugin({ - id: 'actions', - configPrefix: 'xpack.actions', - config(Joi: Root) { - return Joi.object({ - enabled: Joi.boolean().default(true), - }) - .unknown(true) - .default(); - }, - require: ['kibana', 'elasticsearch'], - isEnabled(config: Legacy.KibanaConfig) { - return ( - config.get('xpack.encryptedSavedObjects.enabled') === true && - config.get('xpack.actions.enabled') === true && - config.get('xpack.task_manager.enabled') === true - ); - }, - uiExports: { - mappings, - }, - } as Legacy.PluginSpecOptions); -} diff --git a/x-pack/legacy/plugins/alerting/index.ts b/x-pack/legacy/plugins/alerting/index.ts deleted file mode 100644 index 0d0a698841269..0000000000000 --- a/x-pack/legacy/plugins/alerting/index.ts +++ /dev/null @@ -1,7 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -export * from './server'; diff --git a/x-pack/legacy/plugins/alerting/server/index.ts b/x-pack/legacy/plugins/alerting/server/index.ts deleted file mode 100644 index 065af7dedebd9..0000000000000 --- a/x-pack/legacy/plugins/alerting/server/index.ts +++ /dev/null @@ -1,40 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { Legacy } from 'kibana'; -import { Root } from 'joi'; -import mappings from './mappings.json'; -import { - LegacyPluginApi, - LegacyPluginSpec, - ArrayOrItem, -} from '../../../../../src/legacy/plugin_discovery/types'; - -export function alerting(kibana: LegacyPluginApi): ArrayOrItem { - return new kibana.Plugin({ - id: 'alerting', - configPrefix: 'xpack.alerting', - require: ['kibana', 'elasticsearch', 'actions', 'task_manager', 'encryptedSavedObjects'], - isEnabled(config: Legacy.KibanaConfig) { - return ( - config.get('xpack.alerting.enabled') === true && - config.get('xpack.actions.enabled') === true && - config.get('xpack.encryptedSavedObjects.enabled') === true && - config.get('xpack.task_manager.enabled') === true - ); - }, - config(Joi: Root) { - return Joi.object() - .keys({ - enabled: Joi.boolean().default(true), - }) - .default(); - }, - uiExports: { - mappings, - }, - } as Legacy.PluginSpecOptions); -} diff --git a/x-pack/legacy/plugins/monitoring/common/constants.ts b/x-pack/legacy/plugins/monitoring/common/constants.ts index 3a4c7b71dcd03..36030e1fa7f2a 100644 --- a/x-pack/legacy/plugins/monitoring/common/constants.ts +++ b/x-pack/legacy/plugins/monitoring/common/constants.ts @@ -251,7 +251,7 @@ export const ALERT_TYPES = [ALERT_TYPE_LICENSE_EXPIRATION, ALERT_TYPE_CLUSTER_ST /** * Matches the id for the built-in in email action type - * See x-pack/legacy/plugins/actions/server/builtin_action_types/email.ts + * See x-pack/plugins/actions/server/builtin_action_types/email.ts */ export const ALERT_ACTION_TYPE_EMAIL = '.email'; diff --git a/x-pack/legacy/plugins/task_manager/server/index.ts b/x-pack/legacy/plugins/task_manager/server/index.ts index 3ea687f7003f4..a3167920efa06 100644 --- a/x-pack/legacy/plugins/task_manager/server/index.ts +++ b/x-pack/legacy/plugins/task_manager/server/index.ts @@ -6,8 +6,6 @@ import { Root } from 'joi'; import { Legacy } from 'kibana'; -import mappings from './mappings.json'; -import { migrations } from './migrations'; import { createLegacyApi, getTaskManagerSetup } from './legacy'; export { LegacyTaskManagerApi, getTaskManagerSetup, getTaskManagerStart } from './legacy'; @@ -21,19 +19,6 @@ import { ArrayOrItem, } from '../../../../../src/legacy/plugin_discovery/types'; -const savedObjectSchemas = { - task: { - hidden: true, - isNamespaceAgnostic: true, - convertToAliasScript: `ctx._id = ctx._source.type + ':' + ctx._id`, - // legacy config is marked as any in core, no choice here - // eslint-disable-next-line @typescript-eslint/no-explicit-any - indexPattern(config: any) { - return config.get('xpack.task_manager.index'); - }, - }, -}; - export function taskManager(kibana: LegacyPluginApi): ArrayOrItem { return new kibana.Plugin({ id: 'task_manager', @@ -58,7 +43,7 @@ export function taskManager(kibana: LegacyPluginApi): ArrayOrItem { // we can't tell the Kibana Platform Task Manager plugin to // to wait to `start` as that happens before legacy plugins @@ -77,10 +62,5 @@ export function taskManager(kibana: LegacyPluginApi): ArrayOrItem, Plugi ); } - // Encrypted attributes - // - `secrets` properties will be encrypted - // - `config` will be included in AAD - // - everything else excluded from AAD - plugins.encryptedSavedObjects.registerType({ - type: 'action', - attributesToEncrypt: new Set(['secrets']), - attributesToExcludeFromAAD: new Set(['name']), - }); - plugins.encryptedSavedObjects.registerType({ - type: 'action_task_params', - attributesToEncrypt: new Set(['apiKey']), - }); + setupSavedObjects(core.savedObjects, plugins.encryptedSavedObjects); plugins.eventLog.registerProviderActions(EVENT_LOG_PROVIDER, Object.values(EVENT_LOG_ACTIONS)); this.eventLogger = plugins.eventLog.getLogger({ diff --git a/x-pack/plugins/actions/server/saved_objects/index.ts b/x-pack/plugins/actions/server/saved_objects/index.ts new file mode 100644 index 0000000000000..dbd7925f96871 --- /dev/null +++ b/x-pack/plugins/actions/server/saved_objects/index.ts @@ -0,0 +1,42 @@ +/* + * 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 { SavedObjectsServiceSetup } from 'kibana/server'; +import mappings from './mappings.json'; +import { EncryptedSavedObjectsPluginSetup } from '../../../encrypted_saved_objects/server'; + +export function setupSavedObjects( + savedObjects: SavedObjectsServiceSetup, + encryptedSavedObjects: EncryptedSavedObjectsPluginSetup +) { + savedObjects.registerType({ + name: 'action', + hidden: false, + namespaceType: 'single', + mappings: mappings.action, + }); + + // Encrypted attributes + // - `secrets` properties will be encrypted + // - `config` will be included in AAD + // - everything else excluded from AAD + encryptedSavedObjects.registerType({ + type: 'action', + attributesToEncrypt: new Set(['secrets']), + attributesToExcludeFromAAD: new Set(['name']), + }); + + savedObjects.registerType({ + name: 'action_task_params', + hidden: false, + namespaceType: 'single', + mappings: mappings.action_task_params, + }); + encryptedSavedObjects.registerType({ + type: 'action_task_params', + attributesToEncrypt: new Set(['apiKey']), + }); +} diff --git a/x-pack/legacy/plugins/actions/server/mappings.json b/x-pack/plugins/actions/server/saved_objects/mappings.json similarity index 100% rename from x-pack/legacy/plugins/actions/server/mappings.json rename to x-pack/plugins/actions/server/saved_objects/mappings.json diff --git a/x-pack/plugins/alerting/server/plugin.ts b/x-pack/plugins/alerting/server/plugin.ts index c03d3506a051d..8cdde2eeb9877 100644 --- a/x-pack/plugins/alerting/server/plugin.ts +++ b/x-pack/plugins/alerting/server/plugin.ts @@ -58,6 +58,7 @@ import { Services } from './types'; import { registerAlertsUsageCollector } from './usage'; import { initializeAlertingTelemetry, scheduleAlertingTelemetry } from './usage/task'; import { IEventLogger, IEventLogService } from '../../event_log/server'; +import { setupSavedObjects } from './saved_objects'; const EVENT_LOG_PROVIDER = 'alerting'; export const EVENT_LOG_ACTIONS = { @@ -134,17 +135,7 @@ export class AlertingPlugin { ); } - // Encrypted attributes - plugins.encryptedSavedObjects.registerType({ - type: 'alert', - attributesToEncrypt: new Set(['apiKey']), - attributesToExcludeFromAAD: new Set([ - 'scheduledTaskId', - 'muteAll', - 'mutedInstanceIds', - 'updatedBy', - ]), - }); + setupSavedObjects(core.savedObjects, plugins.encryptedSavedObjects); plugins.eventLog.registerProviderActions(EVENT_LOG_PROVIDER, Object.values(EVENT_LOG_ACTIONS)); this.eventLogger = plugins.eventLog.getLogger({ diff --git a/x-pack/plugins/alerting/server/saved_objects/index.ts b/x-pack/plugins/alerting/server/saved_objects/index.ts new file mode 100644 index 0000000000000..4efec2fe55ef0 --- /dev/null +++ b/x-pack/plugins/alerting/server/saved_objects/index.ts @@ -0,0 +1,33 @@ +/* + * 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 { SavedObjectsServiceSetup } from 'kibana/server'; +import mappings from './mappings.json'; +import { EncryptedSavedObjectsPluginSetup } from '../../../encrypted_saved_objects/server'; + +export function setupSavedObjects( + savedObjects: SavedObjectsServiceSetup, + encryptedSavedObjects: EncryptedSavedObjectsPluginSetup +) { + savedObjects.registerType({ + name: 'alert', + hidden: false, + namespaceType: 'single', + mappings: mappings.alert, + }); + + // Encrypted attributes + encryptedSavedObjects.registerType({ + type: 'alert', + attributesToEncrypt: new Set(['apiKey']), + attributesToExcludeFromAAD: new Set([ + 'scheduledTaskId', + 'muteAll', + 'mutedInstanceIds', + 'updatedBy', + ]), + }); +} diff --git a/x-pack/legacy/plugins/alerting/server/mappings.json b/x-pack/plugins/alerting/server/saved_objects/mappings.json similarity index 100% rename from x-pack/legacy/plugins/alerting/server/mappings.json rename to x-pack/plugins/alerting/server/saved_objects/mappings.json diff --git a/x-pack/plugins/monitoring/common/constants.ts b/x-pack/plugins/monitoring/common/constants.ts index edd6142455dfb..eeed7b4d5acf6 100644 --- a/x-pack/plugins/monitoring/common/constants.ts +++ b/x-pack/plugins/monitoring/common/constants.ts @@ -245,7 +245,7 @@ export const ALERT_TYPES = [ALERT_TYPE_LICENSE_EXPIRATION, ALERT_TYPE_CLUSTER_ST /** * Matches the id for the built-in in email action type - * See x-pack/legacy/plugins/actions/server/builtin_action_types/email.ts + * See x-pack/plugins/actions/server/builtin_action_types/email.ts */ export const ALERT_ACTION_TYPE_EMAIL = '.email'; diff --git a/x-pack/plugins/siem/server/lib/detection_engine/scripts/get_action_instances.sh b/x-pack/plugins/siem/server/lib/detection_engine/scripts/get_action_instances.sh index 750c5574f4a72..2028216e6770f 100755 --- a/x-pack/plugins/siem/server/lib/detection_engine/scripts/get_action_instances.sh +++ b/x-pack/plugins/siem/server/lib/detection_engine/scripts/get_action_instances.sh @@ -10,7 +10,7 @@ set -e ./check_env_variables.sh # Example: ./get_action_instances.sh -# https://github.com/elastic/kibana/blob/master/x-pack/legacy/plugins/actions/README.md#get-apiaction_find-find-actions +# https://github.com/elastic/kibana/blob/master/x-pack/plugins/actions/README.md#get-apiaction_find-find-actions curl -s -k \ -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ -X GET ${KIBANA_URL}${SPACE_URL}/api/action/_getAll \ diff --git a/x-pack/plugins/siem/server/lib/detection_engine/scripts/get_action_types.sh b/x-pack/plugins/siem/server/lib/detection_engine/scripts/get_action_types.sh index 8d8cbdd70a803..c587e9a204182 100755 --- a/x-pack/plugins/siem/server/lib/detection_engine/scripts/get_action_types.sh +++ b/x-pack/plugins/siem/server/lib/detection_engine/scripts/get_action_types.sh @@ -10,7 +10,7 @@ set -e ./check_env_variables.sh # Example: ./get_action_types.sh -# https://github.com/elastic/kibana/blob/master/x-pack/legacy/plugins/actions/README.md +# https://github.com/elastic/kibana/blob/master/x-pack/plugins/actions/README.md curl -s -k \ -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ -X GET ${KIBANA_URL}${SPACE_URL}/api/action/types \ diff --git a/x-pack/plugins/task_manager/server/plugin.ts b/x-pack/plugins/task_manager/server/plugin.ts index a70fbdb18c30b..0f6e3fc31d96d 100644 --- a/x-pack/plugins/task_manager/server/plugin.ts +++ b/x-pack/plugins/task_manager/server/plugin.ts @@ -12,11 +12,10 @@ import { TaskManager } from './task_manager'; import { createTaskManager } from './create_task_manager'; import { TaskManagerConfig } from './config'; import { Middleware } from './lib/middleware'; +import { setupSavedObjects } from './saved_objects'; -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface PluginLegacyDependencies {} export type TaskManagerSetupContract = { - registerLegacyAPI: (legacyDependencies: PluginLegacyDependencies) => Promise; + registerLegacyAPI: () => Promise; } & Pick; export type TaskManagerStartContract = Pick< @@ -35,12 +34,18 @@ export class TaskManagerPlugin this.currentConfig = {} as TaskManagerConfig; } - public setup(core: CoreSetup, plugins: unknown): TaskManagerSetupContract { + public async setup(core: CoreSetup, plugins: unknown): Promise { const logger = this.initContext.logger.get('taskManager'); - const config$ = this.initContext.config.create(); + const config = await this.initContext.config + .create() + .pipe(first()) + .toPromise(); + + setupSavedObjects(core.savedObjects, config); + return { - registerLegacyAPI: once((__LEGACY: PluginLegacyDependencies) => { - config$.subscribe(async config => { + registerLegacyAPI: once(() => { + (async () => { const [{ savedObjects, elasticsearch }] = await core.getStartServices(); const savedObjectsRepository = savedObjects.createInternalRepository(['task']); this.legacyTaskManager$.next( @@ -53,7 +58,7 @@ export class TaskManagerPlugin }) ); this.legacyTaskManager$.complete(); - }); + })(); return this.taskManager; }), addMiddleware: (middleware: Middleware) => { diff --git a/x-pack/plugins/task_manager/server/saved_objects/index.ts b/x-pack/plugins/task_manager/server/saved_objects/index.ts new file mode 100644 index 0000000000000..0ad9021cd7f39 --- /dev/null +++ b/x-pack/plugins/task_manager/server/saved_objects/index.ts @@ -0,0 +1,23 @@ +/* + * 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 { SavedObjectsServiceSetup } from 'kibana/server'; +import mappings from './mappings.json'; +import { TaskManagerConfig } from '../config.js'; + +export function setupSavedObjects( + savedObjects: SavedObjectsServiceSetup, + config: TaskManagerConfig +) { + savedObjects.registerType({ + name: 'task', + namespaceType: 'agnostic', + hidden: true, + convertToAliasScript: `ctx._id = ctx._source.type + ':' + ctx._id`, + mappings: mappings.task, + indexPattern: config.index, + }); +} diff --git a/x-pack/legacy/plugins/task_manager/server/mappings.json b/x-pack/plugins/task_manager/server/saved_objects/mappings.json similarity index 100% rename from x-pack/legacy/plugins/task_manager/server/mappings.json rename to x-pack/plugins/task_manager/server/saved_objects/mappings.json diff --git a/x-pack/legacy/plugins/task_manager/server/migrations.ts b/x-pack/plugins/task_manager/server/saved_objects/migrations.ts similarity index 100% rename from x-pack/legacy/plugins/task_manager/server/migrations.ts rename to x-pack/plugins/task_manager/server/saved_objects/migrations.ts diff --git a/x-pack/plugins/task_manager/server/task_manager.ts b/x-pack/plugins/task_manager/server/task_manager.ts index 24ceea0fe71ef..2a45a599120dd 100644 --- a/x-pack/plugins/task_manager/server/task_manager.ts +++ b/x-pack/plugins/task_manager/server/task_manager.ts @@ -240,7 +240,7 @@ export class TaskManager { * @param taskDefinitions - The Kibana task definitions dictionary */ public registerTaskDefinitions(taskDefinitions: TaskDictionary) { - this.assertUninitialized('register task definitions'); + this.assertUninitialized('register task definitions', Object.keys(taskDefinitions).join(', ')); const duplicate = Object.keys(taskDefinitions).find(k => !!this.definitions[k]); if (duplicate) { throw new Error(`Task ${duplicate} is already defined!`); @@ -360,9 +360,11 @@ export class TaskManager { * @param {string} message shown if task manager is already initialized * @returns void */ - private assertUninitialized(message: string) { + private assertUninitialized(message: string, context?: string) { if (this.isStarted) { - throw new Error(`Cannot ${message} after the task manager is initialized!`); + throw new Error( + `${context ? `[${context}] ` : ''}Cannot ${message} after the task manager is initialized` + ); } } } diff --git a/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/servicenow.ts b/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/servicenow.ts index a7551ad7e2fad..1244657ed9988 100644 --- a/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/servicenow.ts +++ b/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/servicenow.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { getExternalServiceSimulatorPath, ExternalServiceSimulator, -} from '../../../../common/fixtures/plugins/actions'; +} from '../../../../common/fixtures/plugins/actions_simulators'; // node ../scripts/functional_test_runner.js --grep "Actions.servicenddd" --config=test/alerting_api_integration/security_and_spaces/config.ts diff --git a/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/slack.ts b/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/slack.ts index 46258e41d5d69..4151deab45213 100644 --- a/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/slack.ts +++ b/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/slack.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { getExternalServiceSimulatorPath, ExternalServiceSimulator, -} from '../../../../common/fixtures/plugins/actions'; +} from '../../../../common/fixtures/plugins/actions_simulators'; // eslint-disable-next-line import/no-default-export export default function slackTest({ getService }: FtrProviderContext) { diff --git a/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/webhook.ts b/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/webhook.ts index 338610e9243a4..bae6dada48fb7 100644 --- a/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/webhook.ts +++ b/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/webhook.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { getExternalServiceSimulatorPath, ExternalServiceSimulator, -} from '../../../../common/fixtures/plugins/actions'; +} from '../../../../common/fixtures/plugins/actions_simulators'; // eslint-disable-next-line import/no-default-export export default function webhookTest({ getService }: FtrProviderContext) { diff --git a/x-pack/test/alerting_api_integration/common/config.ts b/x-pack/test/alerting_api_integration/common/config.ts index 457b7621e84bd..870ed3cf0cc0f 100644 --- a/x-pack/test/alerting_api_integration/common/config.ts +++ b/x-pack/test/alerting_api_integration/common/config.ts @@ -8,7 +8,7 @@ import path from 'path'; import { CA_CERT_PATH } from '@kbn/dev-utils'; import { FtrConfigProviderContext } from '@kbn/test/types/ftr'; import { services } from './services'; -import { getAllExternalServiceSimulatorPaths } from './fixtures/plugins/actions'; +import { getAllExternalServiceSimulatorPaths } from './fixtures/plugins/actions_simulators'; interface CreateTestConfigOptions { license: string; @@ -75,7 +75,6 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions) 'some.non.existent.com', ])}`, `--xpack.actions.enabledActionTypes=${JSON.stringify(enabledActionTypes)}`, - '--xpack.alerting.enabled=true', '--xpack.eventLog.logEntries=true', `--xpack.actions.preconfigured=${JSON.stringify([ { @@ -124,7 +123,7 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions) ])}`, ...disabledPlugins.map(key => `--xpack.${key}.enabled=false`), `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'alerts')}`, - `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'actions')}`, + `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'actions_simulators')}`, `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'task_manager')}`, `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'aad')}`, `--server.xsrf.whitelist=${JSON.stringify(getAllExternalServiceSimulatorPaths())}`, diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/index.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/index.ts index 05139213b76b9..400aec7e11c8d 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/index.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/index.ts @@ -21,7 +21,7 @@ interface CheckAADRequest extends Hapi.Request { // eslint-disable-next-line import/no-default-export export default function(kibana: any) { return new kibana.Plugin({ - require: ['actions', 'alerting', 'encryptedSavedObjects'], + require: ['encryptedSavedObjects'], name: 'aad-fixtures', init(server: Legacy.Server) { const newPlatform = ((server as unknown) as KbnServer).newPlatform; diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/README.md b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/README.md similarity index 100% rename from x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/README.md rename to x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/README.md diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/index.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/index.ts similarity index 98% rename from x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/index.ts rename to x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/index.ts index 019b15cc1862a..45edd4c092da9 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/index.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/index.ts @@ -36,7 +36,7 @@ export function getAllExternalServiceSimulatorPaths(): string[] { // eslint-disable-next-line import/no-default-export export default function(kibana: any) { return new kibana.Plugin({ - require: ['xpack_main', 'actions'], + require: ['xpack_main'], name: NAME, init: (server: Hapi.Server) => { // this action is specifically NOT enabled in ../../config.ts diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/package.json b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/package.json similarity index 100% rename from x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/package.json rename to x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/package.json diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/pagerduty_simulation.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/pagerduty_simulation.ts similarity index 100% rename from x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/pagerduty_simulation.ts rename to x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/pagerduty_simulation.ts diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/servicenow_simulation.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/servicenow_simulation.ts similarity index 100% rename from x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/servicenow_simulation.ts rename to x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/servicenow_simulation.ts diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/slack_simulation.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/slack_simulation.ts similarity index 100% rename from x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/slack_simulation.ts rename to x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/slack_simulation.ts diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/webhook_simulation.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/webhook_simulation.ts similarity index 100% rename from x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/webhook_simulation.ts rename to x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/webhook_simulation.ts diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/index.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/index.ts index 43d533ad3ae14..1a47addf36ab3 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/index.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/index.ts @@ -11,8 +11,8 @@ import { ActionTypeExecutorOptions, ActionType } from '../../../../../../plugins // eslint-disable-next-line import/no-default-export export default function(kibana: any) { return new kibana.Plugin({ - require: ['xpack_main', 'actions', 'alerting', 'elasticsearch'], - name: 'alerts', + require: ['xpack_main', 'elasticsearch'], + name: 'alerts-fixture', init(server: any) { const clusterClient = server.newPlatform.start.core.elasticsearch.legacy.client; server.plugins.xpack_main.registerFeature({ diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager/index.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager/index.ts index 29708f86b0a9b..ac32f05805e4a 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager/index.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager/index.ts @@ -31,7 +31,7 @@ const taskByIdQuery = (id: string) => ({ export default function(kibana: any) { return new kibana.Plugin({ name: 'taskManagerHelpers', - require: ['elasticsearch', 'task_manager'], + require: ['elasticsearch'], config(Joi: any) { return Joi.object({ diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/pagerduty.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/pagerduty.ts index eeb0818b5fbab..4c76ebfb93b0b 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/pagerduty.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/pagerduty.ts @@ -11,7 +11,7 @@ import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { getExternalServiceSimulatorPath, ExternalServiceSimulator, -} from '../../../../common/fixtures/plugins/actions'; +} from '../../../../common/fixtures/plugins/actions_simulators'; // eslint-disable-next-line import/no-default-export export default function pagerdutyTest({ getService }: FtrProviderContext) { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/servicenow.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/servicenow.ts index 054f8f6141817..399ae0f27f5b1 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/servicenow.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/servicenow.ts @@ -11,7 +11,7 @@ import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { getExternalServiceSimulatorPath, ExternalServiceSimulator, -} from '../../../../common/fixtures/plugins/actions'; +} from '../../../../common/fixtures/plugins/actions_simulators'; // node ../scripts/functional_test_runner.js --grep "servicenow" --config=test/alerting_api_integration/security_and_spaces/config.ts diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/slack.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/slack.ts index e00589b7e85b7..386254e49c19c 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/slack.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/slack.ts @@ -11,7 +11,7 @@ import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { getExternalServiceSimulatorPath, ExternalServiceSimulator, -} from '../../../../common/fixtures/plugins/actions'; +} from '../../../../common/fixtures/plugins/actions_simulators'; // eslint-disable-next-line import/no-default-export export default function slackTest({ getService }: FtrProviderContext) { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/webhook.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/webhook.ts index fd996ea4507ba..9b66326fa6157 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/webhook.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/webhook.ts @@ -10,7 +10,7 @@ import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { getExternalServiceSimulatorPath, ExternalServiceSimulator, -} from '../../../../common/fixtures/plugins/actions'; +} from '../../../../common/fixtures/plugins/actions_simulators'; const defaultValues: Record = { headers: null, diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/actions/builtin_action_types/webhook.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/builtin_action_types/webhook.ts index 5122a74d53b72..112149a32649a 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/actions/builtin_action_types/webhook.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/builtin_action_types/webhook.ts @@ -10,7 +10,7 @@ import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { getExternalServiceSimulatorPath, ExternalServiceSimulator, -} from '../../../../common/fixtures/plugins/actions'; +} from '../../../../common/fixtures/plugins/actions_simulators'; // eslint-disable-next-line import/no-default-export export default function webhookTest({ getService }: FtrProviderContext) { diff --git a/x-pack/test/detection_engine_api_integration/common/config.ts b/x-pack/test/detection_engine_api_integration/common/config.ts index e89352118990a..1e6600c7cd2c0 100644 --- a/x-pack/test/detection_engine_api_integration/common/config.ts +++ b/x-pack/test/detection_engine_api_integration/common/config.ts @@ -78,7 +78,6 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions) 'some.non.existent.com', ])}`, `--xpack.actions.enabledActionTypes=${JSON.stringify(enabledActionTypes)}`, - '--xpack.alerting.enabled=true', '--xpack.eventLog.logEntries=true', ...disabledPlugins.map(key => `--xpack.${key}.enabled=false`), `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'alerts')}`, diff --git a/x-pack/test/functional_with_es_ssl/config.ts b/x-pack/test/functional_with_es_ssl/config.ts index a620b1d953376..71b22a336f6b9 100644 --- a/x-pack/test/functional_with_es_ssl/config.ts +++ b/x-pack/test/functional_with_es_ssl/config.ts @@ -50,8 +50,6 @@ export default async function({ readConfigFile }: FtrConfigProviderContext) { `--elasticsearch.hosts=https://${servers.elasticsearch.hostname}:${servers.elasticsearch.port}`, `--elasticsearch.ssl.certificateAuthorities=${CA_CERT_PATH}`, `--plugin-path=${join(__dirname, 'fixtures', 'plugins', 'alerts')}`, - '--xpack.actions.enabled=true', - '--xpack.alerting.enabled=true', `--xpack.actions.preconfigured=${JSON.stringify([ { id: 'my-slack1', diff --git a/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/kibana.json b/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/kibana.json new file mode 100644 index 0000000000000..416ef7fa34591 --- /dev/null +++ b/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/kibana.json @@ -0,0 +1,9 @@ +{ + "id": "sample_task_plugin", + "version": "1.0.0", + "kibanaVersion": "kibana", + "configPath": ["xpack"], + "requiredPlugins": ["taskManager"], + "server": true, + "ui": false +} diff --git a/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/package.json b/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/package.json new file mode 100644 index 0000000000000..c8d47decd94c1 --- /dev/null +++ b/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/package.json @@ -0,0 +1,18 @@ +{ + "name": "sample_task_plugin", + "version": "1.0.0", + "kibana": { + "version": "kibana", + "templateVersion": "1.0.0" + }, + "main": "target/test/plugin_api_integration/plugins/sample_task_plugin", + "scripts": { + "kbn": "node ../../../../../scripts/kbn.js", + "build": "rm -rf './target' && tsc" + }, + "devDependencies": { + "typescript": "3.7.2" + }, + "license": "Apache-2.0", + "dependencies": {} +} diff --git a/x-pack/legacy/plugins/actions/index.ts b/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/server/index.ts similarity index 65% rename from x-pack/legacy/plugins/actions/index.ts rename to x-pack/test/plugin_api_integration/plugins/sample_task_plugin/server/index.ts index 276d1ea3accea..77233f463734a 100644 --- a/x-pack/legacy/plugins/actions/index.ts +++ b/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/server/index.ts @@ -4,4 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -export * from './server/'; +import { SampleTaskManagerFixturePlugin } from './plugin'; + +export const plugin = () => new SampleTaskManagerFixturePlugin(); diff --git a/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/server/init_routes.ts b/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/server/init_routes.ts new file mode 100644 index 0000000000000..1fee2decbcba9 --- /dev/null +++ b/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/server/init_routes.ts @@ -0,0 +1,252 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { + RequestHandlerContext, + KibanaRequest, + KibanaResponseFactory, + IKibanaResponse, + IRouter, + CoreSetup, +} from 'kibana/server'; +import { EventEmitter } from 'events'; +import { TaskManagerStartContract } from '../../../../../plugins/task_manager/server'; + +const scope = 'testing'; +const taskManagerQuery = { + bool: { + filter: { + bool: { + must: [ + { + term: { + 'task.scope': scope, + }, + }, + ], + }, + }, + }, +}; + +export function initRoutes( + router: IRouter, + core: CoreSetup, + taskManagerStart: Promise, + taskTestingEvents: EventEmitter +) { + async function ensureIndexIsRefreshed() { + return await core.elasticsearch.adminClient.callAsInternalUser('indices.refresh', { + index: '.kibana_task_manager', + }); + } + + router.post( + { + path: `/api/sample_tasks/schedule`, + validate: { + body: schema.object({ + task: schema.object({ + taskType: schema.string(), + schedule: schema.maybe( + schema.object({ + interval: schema.string(), + }) + ), + interval: schema.maybe(schema.string()), + params: schema.recordOf(schema.string(), schema.any(), { defaultValue: {} }), + state: schema.recordOf(schema.string(), schema.any(), { defaultValue: {} }), + id: schema.maybe(schema.string()), + }), + }), + }, + }, + async function( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise> { + try { + const taskManager = await taskManagerStart; + const { task: taskFields } = req.body; + const task = { + ...taskFields, + scope: [scope], + }; + + const taskResult = await taskManager.schedule(task, { req }); + + return res.ok({ body: taskResult }); + } catch (err) { + return res.internalError({ body: err }); + } + } + ); + + router.post( + { + path: `/api/sample_tasks/run_now`, + validate: { + body: schema.object({ + task: schema.object({ + id: schema.string({}), + }), + }), + }, + }, + async function( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise> { + const { + task: { id }, + } = req.body; + try { + const taskManager = await taskManagerStart; + return res.ok({ body: await taskManager.runNow(id) }); + } catch (err) { + return res.ok({ body: { id, error: `${err}` } }); + } + } + ); + + router.post( + { + path: `/api/sample_tasks/ensure_scheduled`, + validate: { + body: schema.object({ + task: schema.object({ + taskType: schema.string(), + params: schema.object({}), + state: schema.maybe(schema.object({})), + id: schema.maybe(schema.string()), + }), + }), + }, + }, + async function( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise> { + try { + const { task: taskFields } = req.body; + const task = { + ...taskFields, + scope: [scope], + }; + + const taskManager = await taskManagerStart; + const taskResult = await taskManager.ensureScheduled(task, { req }); + + return res.ok({ body: taskResult }); + } catch (err) { + return res.ok({ body: err }); + } + } + ); + + router.post( + { + path: `/api/sample_tasks/event`, + validate: { + body: schema.object({ + event: schema.string(), + data: schema.recordOf(schema.string(), schema.any(), { defaultValue: {} }), + }), + }, + }, + async function( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise> { + try { + const { event, data } = req.body; + taskTestingEvents.emit(event, data); + return res.ok({ body: event }); + } catch (err) { + return res.ok({ body: err }); + } + } + ); + + router.get( + { + path: `/api/sample_tasks`, + validate: {}, + }, + async function( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise> { + try { + const taskManager = await taskManagerStart; + return res.ok({ + body: await taskManager.fetch({ + query: taskManagerQuery, + }), + }); + } catch (err) { + return res.ok({ body: err }); + } + } + ); + + router.get( + { + path: `/api/sample_tasks/task/{taskId}`, + validate: { + params: schema.object({ + taskId: schema.string(), + }), + }, + }, + async function( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise> { + try { + await ensureIndexIsRefreshed(); + const taskManager = await taskManagerStart; + return res.ok({ body: await taskManager.get(req.params.taskId) }); + } catch (err) { + return res.ok({ body: err }); + } + return res.ok({ body: {} }); + } + ); + + router.delete( + { + path: `/api/sample_tasks`, + validate: {}, + }, + async function( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise> { + try { + let tasksFound = 0; + const taskManager = await taskManagerStart; + do { + const { docs: tasks } = await taskManager.fetch({ + query: taskManagerQuery, + }); + tasksFound = tasks.length; + await Promise.all(tasks.map(task => taskManager.remove(task.id))); + } while (tasksFound > 0); + return res.ok({ body: 'OK' }); + } catch (err) { + return res.ok({ body: err }); + } + } + ); +} diff --git a/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/server/plugin.ts b/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/server/plugin.ts new file mode 100644 index 0000000000000..508d58b8f0ca9 --- /dev/null +++ b/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/server/plugin.ts @@ -0,0 +1,164 @@ +/* + * 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 { Plugin, CoreSetup, CoreStart } from 'kibana/server'; +import { EventEmitter } from 'events'; +import { Subject } from 'rxjs'; +import { first } from 'rxjs/operators'; +import { initRoutes } from './init_routes'; +import { + TaskManagerSetupContract, + TaskManagerStartContract, + ConcreteTaskInstance, +} from '../../../../../plugins/task_manager/server'; +import { DEFAULT_MAX_WORKERS } from '../../../../../plugins/task_manager/server/config'; + +// this plugin's dependendencies +export interface SampleTaskManagerFixtureSetupDeps { + taskManager: TaskManagerSetupContract; +} +export interface SampleTaskManagerFixtureStartDeps { + taskManager: TaskManagerStartContract; +} + +export class SampleTaskManagerFixturePlugin + implements + Plugin { + taskManagerStart$: Subject = new Subject(); + taskManagerStart: Promise = this.taskManagerStart$ + .pipe(first()) + .toPromise(); + + public setup(core: CoreSetup, { taskManager }: SampleTaskManagerFixtureSetupDeps) { + const taskTestingEvents = new EventEmitter(); + taskTestingEvents.setMaxListeners(DEFAULT_MAX_WORKERS * 2); + + const defaultSampleTaskConfig = { + timeout: '1m', + // This task allows tests to specify its behavior (whether it reschedules itself, whether it errors, etc) + // taskInstance.params has the following optional fields: + // nextRunMilliseconds: number - If specified, the run method will return a runAt that is now + nextRunMilliseconds + // failWith: string - If specified, the task will throw an error with the specified message + // failOn: number - If specified, the task will only throw the `failWith` error when `count` equals to the failOn value + // waitForParams : boolean - should the task stall ands wait to receive params asynchronously before using the default params + // waitForEvent : string - if provided, the task will stall (after completing the run) and wait for an asyn event before completing + createTaskRunner: ({ taskInstance }: { taskInstance: ConcreteTaskInstance }) => ({ + async run() { + const { params, state, id } = taskInstance; + const prevState = state || { count: 0 }; + + const count = (prevState.count || 0) + 1; + + const runParams = { + ...params, + // if this task requires custom params provided async - wait for them + ...(params.waitForParams ? await once(taskTestingEvents, id) : {}), + }; + + if (runParams.failWith) { + if (!runParams.failOn || (runParams.failOn && count === runParams.failOn)) { + throw new Error(runParams.failWith); + } + } + + await core.elasticsearch.adminClient.callAsInternalUser('index', { + index: '.kibana_task_manager_test_result', + body: { + type: 'task', + taskId: taskInstance.id, + params: JSON.stringify(runParams), + state: JSON.stringify(state), + ranAt: new Date(), + }, + refresh: true, + }); + + // Stall task run until a certain event is triggered + if (runParams.waitForEvent) { + await once(taskTestingEvents, runParams.waitForEvent); + } + + return { + state: { count }, + runAt: millisecondsFromNow(runParams.nextRunMilliseconds), + }; + }, + }), + }; + + taskManager.registerTaskDefinitions({ + sampleTask: { + ...defaultSampleTaskConfig, + type: 'sampleTask', + title: 'Sample Task', + description: 'A sample task for testing the task_manager.', + }, + singleAttemptSampleTask: { + ...defaultSampleTaskConfig, + type: 'singleAttemptSampleTask', + title: 'Failing Sample Task', + description: + 'A sample task for testing the task_manager that fails on the first attempt to run.', + // fail after the first failed run + maxAttempts: 1, + }, + }); + + taskManager.addMiddleware({ + async beforeSave({ taskInstance, ...opts }) { + const modifiedInstance = { + ...taskInstance, + params: { + originalParams: taskInstance.params, + superFly: 'My middleware param!', + }, + }; + + return { + ...opts, + taskInstance: modifiedInstance, + }; + }, + + async beforeRun({ taskInstance, ...opts }) { + return { + ...opts, + taskInstance: { + ...taskInstance, + params: taskInstance.params.originalParams, + }, + }; + }, + + async beforeMarkRunning(context) { + return context; + }, + }); + initRoutes(core.http.createRouter(), core, this.taskManagerStart, taskTestingEvents); + } + + public start(core: CoreStart, { taskManager }: SampleTaskManagerFixtureStartDeps) { + this.taskManagerStart$.next(taskManager); + this.taskManagerStart$.complete(); + } + public stop() {} +} + +function millisecondsFromNow(ms: number) { + if (!ms) { + return; + } + + const dt = new Date(); + dt.setTime(dt.getTime() + ms); + return dt; +} + +const once = function(emitter: EventEmitter, event: string): Promise> { + return new Promise(resolve => { + emitter.once(event, data => resolve(data || {})); + }); +}; diff --git a/x-pack/test/plugin_api_integration/plugins/task_manager/index.js b/x-pack/test/plugin_api_integration/plugins/task_manager/index.js deleted file mode 100644 index e5b645367b8b7..0000000000000 --- a/x-pack/test/plugin_api_integration/plugins/task_manager/index.js +++ /dev/null @@ -1,150 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -const { DEFAULT_MAX_WORKERS } = require('../../../../plugins/task_manager/server/config.ts'); -const { EventEmitter } = require('events'); - -import { initRoutes } from './init_routes'; - -const once = function(emitter, event) { - return new Promise(resolve => { - emitter.once(event, data => resolve(data || {})); - }); -}; - -export default function TaskTestingAPI(kibana) { - const taskTestingEvents = new EventEmitter(); - taskTestingEvents.setMaxListeners(DEFAULT_MAX_WORKERS * 2); - - return new kibana.Plugin({ - name: 'sampleTask', - require: ['elasticsearch', 'task_manager'], - - config(Joi) { - return Joi.object({ - enabled: Joi.boolean().default(true), - }).default(); - }, - - init(server) { - const taskManager = { - ...server.newPlatform.setup.plugins.taskManager, - ...server.newPlatform.start.plugins.taskManager, - }; - const legacyTaskManager = server.plugins.task_manager; - - const defaultSampleTaskConfig = { - timeout: '1m', - // This task allows tests to specify its behavior (whether it reschedules itself, whether it errors, etc) - // taskInstance.params has the following optional fields: - // nextRunMilliseconds: number - If specified, the run method will return a runAt that is now + nextRunMilliseconds - // failWith: string - If specified, the task will throw an error with the specified message - // failOn: number - If specified, the task will only throw the `failWith` error when `count` equals to the failOn value - // waitForParams : boolean - should the task stall ands wait to receive params asynchronously before using the default params - // waitForEvent : string - if provided, the task will stall (after completing the run) and wait for an asyn event before completing - createTaskRunner: ({ taskInstance }) => ({ - async run() { - const { params, state, id } = taskInstance; - const prevState = state || { count: 0 }; - - const count = (prevState.count || 0) + 1; - - const runParams = { - ...params, - // if this task requires custom params provided async - wait for them - ...(params.waitForParams ? await once(taskTestingEvents, id) : {}), - }; - - if (runParams.failWith) { - if (!runParams.failOn || (runParams.failOn && count === runParams.failOn)) { - throw new Error(runParams.failWith); - } - } - - const callCluster = server.plugins.elasticsearch.getCluster('admin') - .callWithInternalUser; - await callCluster('index', { - index: '.kibana_task_manager_test_result', - body: { - type: 'task', - taskId: taskInstance.id, - params: JSON.stringify(runParams), - state: JSON.stringify(state), - ranAt: new Date(), - }, - refresh: true, - }); - - // Stall task run until a certain event is triggered - if (runParams.waitForEvent) { - await once(taskTestingEvents, runParams.waitForEvent); - } - - return { - state: { count }, - runAt: millisecondsFromNow(runParams.nextRunMilliseconds), - }; - }, - }), - }; - - taskManager.registerTaskDefinitions({ - sampleTask: { - ...defaultSampleTaskConfig, - title: 'Sample Task', - description: 'A sample task for testing the task_manager.', - }, - singleAttemptSampleTask: { - ...defaultSampleTaskConfig, - title: 'Failing Sample Task', - description: - 'A sample task for testing the task_manager that fails on the first attempt to run.', - // fail after the first failed run - maxAttempts: 1, - }, - }); - - taskManager.addMiddleware({ - async beforeSave({ taskInstance, ...opts }) { - const modifiedInstance = { - ...taskInstance, - params: { - originalParams: taskInstance.params, - superFly: 'My middleware param!', - }, - }; - - return { - ...opts, - taskInstance: modifiedInstance, - }; - }, - - async beforeRun({ taskInstance, ...opts }) { - return { - ...opts, - taskInstance: { - ...taskInstance, - params: taskInstance.params.originalParams, - }, - }; - }, - }); - - initRoutes(server, taskManager, legacyTaskManager, taskTestingEvents); - }, - }); -} - -function millisecondsFromNow(ms) { - if (!ms) { - return; - } - - const dt = new Date(); - dt.setTime(dt.getTime() + ms); - return dt; -} diff --git a/x-pack/test/plugin_api_integration/plugins/task_manager/init_routes.js b/x-pack/test/plugin_api_integration/plugins/task_manager/init_routes.js deleted file mode 100644 index 785fbed341423..0000000000000 --- a/x-pack/test/plugin_api_integration/plugins/task_manager/init_routes.js +++ /dev/null @@ -1,236 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import Joi from 'joi'; - -const scope = 'testing'; -const taskManagerQuery = { - bool: { - filter: { - bool: { - must: [ - { - term: { - 'task.scope': scope, - }, - }, - ], - }, - }, - }, -}; - -export function initRoutes(server, taskManager, legacyTaskManager, taskTestingEvents) { - const callCluster = server.plugins.elasticsearch.getCluster('admin').callWithInternalUser; - - async function ensureIndexIsRefreshed() { - return await callCluster('indices.refresh', { - index: '.kibana_task_manager', - }); - } - - server.route({ - path: '/api/sample_tasks/schedule', - method: 'POST', - config: { - validate: { - payload: Joi.object({ - task: Joi.object({ - taskType: Joi.string().required(), - schedule: Joi.object({ - interval: Joi.string(), - }).optional(), - interval: Joi.string().optional(), - params: Joi.object().required(), - state: Joi.object().optional(), - id: Joi.string().optional(), - }), - }), - }, - }, - async handler(request) { - try { - const { task: taskFields } = request.payload; - const task = { - ...taskFields, - scope: [scope], - }; - - const taskResult = await taskManager.schedule(task, { request }); - - return taskResult; - } catch (err) { - return err; - } - }, - }); - - /* - Schedule using legacy Api - */ - server.route({ - path: '/api/sample_tasks/schedule_legacy', - method: 'POST', - config: { - validate: { - payload: Joi.object({ - task: Joi.object({ - taskType: Joi.string().required(), - schedule: Joi.object({ - interval: Joi.string(), - }).optional(), - interval: Joi.string().optional(), - params: Joi.object().required(), - state: Joi.object().optional(), - id: Joi.string().optional(), - }), - }), - }, - }, - async handler(request) { - try { - const { task: taskFields } = request.payload; - const task = { - ...taskFields, - scope: [scope], - }; - - const taskResult = await legacyTaskManager.schedule(task, { request }); - - return taskResult; - } catch (err) { - return err; - } - }, - }); - - server.route({ - path: '/api/sample_tasks/run_now', - method: 'POST', - config: { - validate: { - payload: Joi.object({ - task: Joi.object({ - id: Joi.string().optional(), - }), - }), - }, - }, - async handler(request) { - const { - task: { id }, - } = request.payload; - try { - return await taskManager.runNow(id); - } catch (err) { - return { id, error: `${err}` }; - } - }, - }); - - server.route({ - path: '/api/sample_tasks/ensure_scheduled', - method: 'POST', - config: { - validate: { - payload: Joi.object({ - task: Joi.object({ - taskType: Joi.string().required(), - params: Joi.object().required(), - state: Joi.object().optional(), - id: Joi.string().optional(), - }), - }), - }, - }, - async handler(request) { - try { - const { task: taskFields } = request.payload; - const task = { - ...taskFields, - scope: [scope], - }; - - const taskResult = await taskManager.ensureScheduled(task, { request }); - - return taskResult; - } catch (err) { - return err; - } - }, - }); - - server.route({ - path: '/api/sample_tasks/event', - method: 'POST', - config: { - validate: { - payload: Joi.object({ - event: Joi.string().required(), - data: Joi.object() - .optional() - .default({}), - }), - }, - }, - async handler(request) { - try { - const { event, data } = request.payload; - taskTestingEvents.emit(event, data); - return { event }; - } catch (err) { - return err; - } - }, - }); - - server.route({ - path: '/api/sample_tasks', - method: 'GET', - async handler() { - try { - return taskManager.fetch({ - query: taskManagerQuery, - }); - } catch (err) { - return err; - } - }, - }); - - server.route({ - path: '/api/sample_tasks/task/{taskId}', - method: 'GET', - async handler(request) { - try { - await ensureIndexIsRefreshed(); - return await taskManager.get(request.params.taskId); - } catch (err) { - return err; - } - }, - }); - - server.route({ - path: '/api/sample_tasks', - method: 'DELETE', - async handler() { - try { - let tasksFound = 0; - do { - const { docs: tasks } = await taskManager.fetch({ - query: taskManagerQuery, - }); - tasksFound = tasks.length; - await Promise.all(tasks.map(task => taskManager.remove(task.id))); - } while (tasksFound > 0); - return 'OK'; - } catch (err) { - return err; - } - }, - }); -} diff --git a/x-pack/test/plugin_api_integration/plugins/task_manager/package.json b/x-pack/test/plugin_api_integration/plugins/task_manager/package.json deleted file mode 100644 index ec63c512e9cd7..0000000000000 --- a/x-pack/test/plugin_api_integration/plugins/task_manager/package.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "sample_task_plugin", - "version": "1.0.0", - "kibana": { - "version": "kibana", - "templateVersion": "1.0.0" - }, - "license": "Apache-2.0", - "dependencies": { - "joi": "^13.5.2" - } -} diff --git a/x-pack/test/plugin_api_integration/test_suites/task_manager/task_manager_integration.js b/x-pack/test/plugin_api_integration/test_suites/task_manager/task_manager_integration.js index e8f976d5ae6e3..00cefa42711c9 100644 --- a/x-pack/test/plugin_api_integration/test_suites/task_manager/task_manager_integration.js +++ b/x-pack/test/plugin_api_integration/test_suites/task_manager/task_manager_integration.js @@ -11,7 +11,7 @@ import supertestAsPromised from 'supertest-as-promised'; const { task: { properties: taskManagerIndexMapping }, -} = require('../../../../legacy/plugins/task_manager/server/mappings.json'); +} = require('../../../../plugins/task_manager/server/saved_objects/mappings.json'); const { DEFAULT_MAX_WORKERS, @@ -90,15 +90,6 @@ export default function({ getService }) { .then(response => response.body); } - function scheduleTaskUsingLegacyApi(task) { - return supertest - .post('/api/sample_tasks/schedule_legacy') - .set('kbn-xsrf', 'xxx') - .send({ task }) - .expect(200) - .then(response => response.body); - } - function runTaskNow(task) { return supertest .post('/api/sample_tasks/run_now') @@ -587,15 +578,5 @@ export default function({ getService }) { expect(getTaskById(tasks, longRunningTask.id).state.count).to.eql(1); }); }); - - it('should retain the legacy api until v8.0.0', async () => { - const result = await scheduleTaskUsingLegacyApi({ - id: 'task-with-legacy-api', - taskType: 'sampleTask', - params: {}, - }); - - expect(result.id).to.be('task-with-legacy-api'); - }); }); }