mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[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.
This commit is contained in:
parent
30e41c5d8f
commit
9fe7229357
53 changed files with 587 additions and 628 deletions
3
.github/CODEOWNERS
vendored
3
.github/CODEOWNERS
vendored
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
];
|
||||
};
|
||||
|
|
|
@ -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<LegacyPluginSpec> {
|
||||
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);
|
||||
}
|
|
@ -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';
|
|
@ -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<LegacyPluginSpec> {
|
||||
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);
|
||||
}
|
|
@ -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';
|
||||
|
||||
|
|
|
@ -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<LegacyPluginSpec> {
|
||||
return new kibana.Plugin({
|
||||
id: 'task_manager',
|
||||
|
@ -58,7 +43,7 @@ export function taskManager(kibana: LegacyPluginApi): ArrayOrItem<LegacyPluginSp
|
|||
server.expose(
|
||||
createLegacyApi(
|
||||
getTaskManagerSetup(server)!
|
||||
.registerLegacyAPI({})
|
||||
.registerLegacyAPI()
|
||||
.then((taskManagerPlugin: TaskManager) => {
|
||||
// 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<LegacyPluginSp
|
|||
)
|
||||
);
|
||||
},
|
||||
uiExports: {
|
||||
mappings,
|
||||
migrations,
|
||||
savedObjectSchemas,
|
||||
},
|
||||
} as Legacy.PluginSpecOptions);
|
||||
}
|
||||
|
|
|
@ -1,34 +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 { resolve } from 'path';
|
||||
|
||||
export function triggersActionsUI(kibana: any) {
|
||||
return new kibana.Plugin({
|
||||
id: 'triggers_actions_ui',
|
||||
configPrefix: 'xpack.triggers_actions_ui',
|
||||
isEnabled(config: Legacy.KibanaConfig) {
|
||||
return (
|
||||
config.get('xpack.triggers_actions_ui.enabled') &&
|
||||
(config.get('xpack.actions.enabled') || config.get('xpack.alerting.enabled'))
|
||||
);
|
||||
},
|
||||
publicDir: resolve(__dirname, 'public'),
|
||||
require: ['kibana'],
|
||||
config(Joi: Root) {
|
||||
return Joi.object()
|
||||
.keys({
|
||||
enabled: Joi.boolean().default(true),
|
||||
})
|
||||
.default();
|
||||
},
|
||||
uiExports: {
|
||||
styleSheetPaths: resolve(__dirname, 'public/index.scss'),
|
||||
},
|
||||
});
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
// Imported EUI
|
||||
@import 'src/legacy/ui/public/styles/_styling_constants';
|
|
@ -53,6 +53,7 @@ import {
|
|||
} from './routes';
|
||||
import { IEventLogger, IEventLogService } from '../../event_log/server';
|
||||
import { initializeActionsTelemetry, scheduleActionsTelemetry } from './usage/task';
|
||||
import { setupSavedObjects } from './saved_objects';
|
||||
|
||||
const EVENT_LOG_PROVIDER = 'actions';
|
||||
export const EVENT_LOG_ACTIONS = {
|
||||
|
@ -133,19 +134,7 @@ export class ActionsPlugin implements Plugin<Promise<PluginSetupContract>, 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({
|
||||
|
|
42
x-pack/plugins/actions/server/saved_objects/index.ts
Normal file
42
x-pack/plugins/actions/server/saved_objects/index.ts
Normal file
|
@ -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']),
|
||||
});
|
||||
}
|
|
@ -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({
|
||||
|
|
33
x-pack/plugins/alerting/server/saved_objects/index.ts
Normal file
33
x-pack/plugins/alerting/server/saved_objects/index.ts
Normal file
|
@ -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',
|
||||
]),
|
||||
});
|
||||
}
|
|
@ -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';
|
||||
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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<TaskManager>;
|
||||
registerLegacyAPI: () => Promise<TaskManager>;
|
||||
} & Pick<TaskManager, 'addMiddleware' | 'registerTaskDefinitions'>;
|
||||
|
||||
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<TaskManagerSetupContract> {
|
||||
const logger = this.initContext.logger.get('taskManager');
|
||||
const config$ = this.initContext.config.create<TaskManagerConfig>();
|
||||
const config = await this.initContext.config
|
||||
.create<TaskManagerConfig>()
|
||||
.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) => {
|
||||
|
|
23
x-pack/plugins/task_manager/server/saved_objects/index.ts
Normal file
23
x-pack/plugins/task_manager/server/saved_objects/index.ts
Normal file
|
@ -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,
|
||||
});
|
||||
}
|
|
@ -240,7 +240,7 @@ export class TaskManager {
|
|||
* @param taskDefinitions - The Kibana task definitions dictionary
|
||||
*/
|
||||
public registerTaskDefinitions(taskDefinitions: TaskDictionary<TaskDefinition>) {
|
||||
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`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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())}`,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -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({
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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<string, any> = {
|
||||
headers: null,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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')}`,
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"id": "sample_task_plugin",
|
||||
"version": "1.0.0",
|
||||
"kibanaVersion": "kibana",
|
||||
"configPath": ["xpack"],
|
||||
"requiredPlugins": ["taskManager"],
|
||||
"server": true,
|
||||
"ui": false
|
||||
}
|
|
@ -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": {}
|
||||
}
|
|
@ -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();
|
|
@ -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<TaskManagerStartContract>,
|
||||
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<any, any, any, any>,
|
||||
res: KibanaResponseFactory
|
||||
): Promise<IKibanaResponse<any>> {
|
||||
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<any, any, any, any>,
|
||||
res: KibanaResponseFactory
|
||||
): Promise<IKibanaResponse<any>> {
|
||||
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<any, any, any, any>,
|
||||
res: KibanaResponseFactory
|
||||
): Promise<IKibanaResponse<any>> {
|
||||
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<any, any, any, any>,
|
||||
res: KibanaResponseFactory
|
||||
): Promise<IKibanaResponse<any>> {
|
||||
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<any, any, any, any>,
|
||||
res: KibanaResponseFactory
|
||||
): Promise<IKibanaResponse<any>> {
|
||||
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<any, any, any, any>,
|
||||
res: KibanaResponseFactory
|
||||
): Promise<IKibanaResponse<any>> {
|
||||
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<any, any, any, any>,
|
||||
res: KibanaResponseFactory
|
||||
): Promise<IKibanaResponse<any>> {
|
||||
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 });
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
|
@ -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<void, void, SampleTaskManagerFixtureSetupDeps, SampleTaskManagerFixtureStartDeps> {
|
||||
taskManagerStart$: Subject<TaskManagerStartContract> = new Subject<TaskManagerStartContract>();
|
||||
taskManagerStart: Promise<TaskManagerStartContract> = 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<Record<string, unknown>> {
|
||||
return new Promise(resolve => {
|
||||
emitter.once(event, data => resolve(data || {}));
|
||||
});
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue