From 8483574d1e6213d17a57e23bccf5927b160d51b2 Mon Sep 17 00:00:00 2001 From: Pete Harverson Date: Wed, 6 May 2020 09:26:58 +0100 Subject: [PATCH 01/23] [ML] Fixes reordering in view by selection when overall cell selected (#65290) --- .../ml/public/application/explorer/hooks/use_selected_cells.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/ml/public/application/explorer/hooks/use_selected_cells.ts b/x-pack/plugins/ml/public/application/explorer/hooks/use_selected_cells.ts index 043b762334da9..a19750494afdc 100644 --- a/x-pack/plugins/ml/public/application/explorer/hooks/use_selected_cells.ts +++ b/x-pack/plugins/ml/public/application/explorer/hooks/use_selected_cells.ts @@ -33,12 +33,13 @@ export const useSelectedCells = (): [ const setSelectedCells = (swimlaneSelectedCells: AppStateSelectedCells) => { const mlExplorerSwimlane = { ...appState.mlExplorerSwimlane }; + if (swimlaneSelectedCells !== undefined) { swimlaneSelectedCells.showTopFieldValues = false; const currentSwimlaneType = selectedCells?.type; const currentShowTopFieldValues = selectedCells?.showTopFieldValues; - const newSwimlaneType = selectedCells?.type; + const newSwimlaneType = swimlaneSelectedCells?.type; if ( (currentSwimlaneType === SWIMLANE_TYPE.OVERALL && From 94127d803a1fe3b2a5aca9a5ded9e35ad2351086 Mon Sep 17 00:00:00 2001 From: Gidi Meir Morris Date: Wed, 6 May 2020 09:57:26 +0100 Subject: [PATCH 02/23] [Alerting] migrates acceptance and functional test fixtures to KP (#64888) This PR migrates the vast majority of Alerting legacy code to the Kibana Platform. This includes: 1. Removed legacy Task Manager 2. Migrates Fixture plugins in Alerting, Triggers UI and Task Manager Perf This does not includes: 1. The PagerDuty simulator due to a lack of support for custom responses in the platform. issue opened. https://github.com/elastic/kibana/issues/65045 2. The Webhooks simulator due to a lack of support for custom authorisation. Requires investigation. --- renovate.json5 | 16 + test/scripts/jenkins_xpack_build_kibana.sh | 2 + x-pack/index.js | 2 - .../plugins/task_manager/server/index.ts | 66 --- .../plugins/task_manager/server/legacy.ts | 58 -- x-pack/package.json | 2 + x-pack/plugins/actions/server/plugin.ts | 14 +- x-pack/plugins/alerting/server/plugin.ts | 14 +- .../apm/server/lib/apm_telemetry/index.ts | 30 +- .../server/create_task_manager.test.ts | 62 --- .../server/create_task_manager.ts | 43 -- x-pack/plugins/task_manager/server/mocks.ts | 1 - x-pack/plugins/task_manager/server/plugin.ts | 62 ++- .../task_manager/server/task_manager.mock.ts | 1 - .../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 | 16 +- .../common/fixtures/plugins/aad/index.ts | 59 -- .../common/fixtures/plugins/aad/kibana.json | 10 + .../common/fixtures/plugins/aad/package.json | 17 +- .../fixtures/plugins/aad/server}/index.ts | 4 +- .../fixtures/plugins/aad/server/plugin.ts | 64 +++ .../plugins/actions_simulators/index.ts | 91 --- .../actions_simulators/jira_simulation.ts | 101 ---- .../plugins/actions_simulators/kibana.json | 9 + .../plugins/actions_simulators/package.json | 19 +- .../pagerduty_simulation.ts | 79 --- .../actions_simulators/{ => server}/README.md | 0 .../actions_simulators/server/index.ts | 9 + .../server/jira_simulation.ts | 116 ++++ .../server/pagerduty_simulation.ts | 86 +++ .../actions_simulators/server/plugin.ts | 95 ++++ .../server/servicenow_simulation.ts | 99 ++++ .../servicenow_simulation.ts | 81 --- .../actions_simulators_legacy/index.ts | 26 + .../actions_simulators_legacy/package.json | 7 + .../slack_simulation.ts | 0 .../webhook_simulation.ts | 0 .../common/fixtures/plugins/alerts/index.ts | 501 ----------------- .../fixtures/plugins/alerts/kibana.json | 10 + .../fixtures/plugins/alerts/package.json | 19 +- .../fixtures/plugins/alerts/server/index.ts | 9 + .../fixtures/plugins/alerts/server/plugin.ts | 516 ++++++++++++++++++ .../fixtures/plugins/task_manager/index.ts | 60 -- .../plugins/task_manager/package.json | 12 - .../plugins/task_manager_fixture/kibana.json | 9 + .../plugins/task_manager_fixture/package.json | 20 + .../task_manager_fixture/server/index.ts | 9 + .../task_manager_fixture/server/plugin.ts | 87 +++ .../actions/builtin_action_types/jira.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 +- x-pack/test/plugin_api_perf/config.js | 2 +- .../plugins/task_manager_performance/index.js | 378 ------------- .../task_manager_performance/init_routes.js | 77 --- .../task_manager_performance/kibana.json | 9 + .../task_manager_performance/package.json | 15 +- .../task_manager_performance/server/index.ts | 9 + .../server/init_routes.ts | 92 ++++ .../task_manager_performance/server/plugin.ts | 404 ++++++++++++++ .../task_manager_performance/server/types.ts | 82 +++ x-pack/typings/hapi.d.ts | 4 +- yarn.lock | 21 +- 67 files changed, 1964 insertions(+), 1760 deletions(-) delete mode 100644 x-pack/legacy/plugins/task_manager/server/index.ts delete mode 100644 x-pack/legacy/plugins/task_manager/server/legacy.ts delete mode 100644 x-pack/plugins/task_manager/server/create_task_manager.test.ts delete mode 100644 x-pack/plugins/task_manager/server/create_task_manager.ts delete mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/index.ts create mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/kibana.json rename x-pack/{legacy/plugins/task_manager => test/alerting_api_integration/common/fixtures/plugins/aad/server}/index.ts (72%) create mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/server/plugin.ts delete mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/index.ts delete mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/jira_simulation.ts create mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/kibana.json delete mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/pagerduty_simulation.ts rename x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/{ => server}/README.md (100%) create mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/index.ts create mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/jira_simulation.ts create mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/pagerduty_simulation.ts create mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/plugin.ts create mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/servicenow_simulation.ts delete mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/servicenow_simulation.ts create mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/index.ts create mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/package.json rename x-pack/test/alerting_api_integration/common/fixtures/plugins/{actions_simulators => actions_simulators_legacy}/slack_simulation.ts (100%) rename x-pack/test/alerting_api_integration/common/fixtures/plugins/{actions_simulators => actions_simulators_legacy}/webhook_simulation.ts (100%) delete mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/index.ts create mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/kibana.json create mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/index.ts create mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/plugin.ts delete mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager/index.ts delete mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager/package.json create mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager_fixture/kibana.json create mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager_fixture/package.json create mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager_fixture/server/index.ts create mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager_fixture/server/plugin.ts delete mode 100644 x-pack/test/plugin_api_perf/plugins/task_manager_performance/index.js delete mode 100644 x-pack/test/plugin_api_perf/plugins/task_manager_performance/init_routes.js create mode 100644 x-pack/test/plugin_api_perf/plugins/task_manager_performance/kibana.json create mode 100644 x-pack/test/plugin_api_perf/plugins/task_manager_performance/server/index.ts create mode 100644 x-pack/test/plugin_api_perf/plugins/task_manager_performance/server/init_routes.ts create mode 100644 x-pack/test/plugin_api_perf/plugins/task_manager_performance/server/plugin.ts create mode 100644 x-pack/test/plugin_api_perf/plugins/task_manager_performance/server/types.ts diff --git a/renovate.json5 b/renovate.json5 index 61b2485ecf44b..c4efa86366bf4 100644 --- a/renovate.json5 +++ b/renovate.json5 @@ -771,6 +771,14 @@ '@types/podium', ], }, + { + groupSlug: 'pretty-ms', + groupName: 'pretty-ms related packages', + packageNames: [ + 'pretty-ms', + '@types/pretty-ms', + ], + }, { groupSlug: 'proper-lockfile', groupName: 'proper-lockfile related packages', @@ -864,6 +872,14 @@ '@types/sinon', ], }, + { + groupSlug: 'stats-lite', + groupName: 'stats-lite related packages', + packageNames: [ + 'stats-lite', + '@types/stats-lite', + ], + }, { groupSlug: 'storybook', groupName: 'storybook related packages', diff --git a/test/scripts/jenkins_xpack_build_kibana.sh b/test/scripts/jenkins_xpack_build_kibana.sh index 962d2794f712f..8dc41639fa946 100755 --- a/test/scripts/jenkins_xpack_build_kibana.sh +++ b/test/scripts/jenkins_xpack_build_kibana.sh @@ -7,7 +7,9 @@ echo " -> building kibana platform plugins" node scripts/build_kibana_platform_plugins \ --scan-dir "$XPACK_DIR/test/plugin_functional/plugins" \ --scan-dir "$XPACK_DIR/test/functional_with_es_ssl/fixtures/plugins" \ + --scan-dir "$XPACK_DIR/test/alerting_api_integration/plugins" \ --scan-dir "$XPACK_DIR/test/plugin_api_integration/plugins" \ + --scan-dir "$XPACK_DIR/test/plugin_api_perf/plugins" \ --verbose; # doesn't persist, also set in kibanaPipeline.groovy diff --git a/x-pack/index.js b/x-pack/index.js index 99b63a49f5793..bac871fcb5414 100644 --- a/x-pack/index.js +++ b/x-pack/index.js @@ -12,7 +12,6 @@ import { dashboardMode } from './legacy/plugins/dashboard_mode'; import { beats } from './legacy/plugins/beats_management'; import { maps } from './legacy/plugins/maps'; import { spaces } from './legacy/plugins/spaces'; -import { taskManager } from './legacy/plugins/task_manager'; import { encryptedSavedObjects } from './legacy/plugins/encrypted_saved_objects'; import { ingestManager } from './legacy/plugins/ingest_manager'; @@ -26,7 +25,6 @@ module.exports = function(kibana) { dashboardMode(kibana), beats(kibana), maps(kibana), - taskManager(kibana), encryptedSavedObjects(kibana), ingestManager(kibana), ]; diff --git a/x-pack/legacy/plugins/task_manager/server/index.ts b/x-pack/legacy/plugins/task_manager/server/index.ts deleted file mode 100644 index a3167920efa06..0000000000000 --- a/x-pack/legacy/plugins/task_manager/server/index.ts +++ /dev/null @@ -1,66 +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 { createLegacyApi, getTaskManagerSetup } from './legacy'; -export { LegacyTaskManagerApi, getTaskManagerSetup, getTaskManagerStart } from './legacy'; - -// Once all plugins are migrated to NP, this can be removed -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { TaskManager } from '../../../../plugins/task_manager/server/task_manager'; -import { - LegacyPluginApi, - LegacyPluginSpec, - ArrayOrItem, -} from '../../../../../src/legacy/plugin_discovery/types'; - -export function taskManager(kibana: LegacyPluginApi): ArrayOrItem { - return new kibana.Plugin({ - id: 'task_manager', - require: ['kibana', 'elasticsearch', 'xpack_main'], - configPrefix: 'xpack.task_manager', - config(Joi: Root) { - return Joi.object({ - enabled: Joi.boolean().default(true), - index: Joi.string() - .description('The name of the index used to store task information.') - .default('.kibana_task_manager') - .invalid(['.tasks']), - }) - .unknown(true) - .default(); - }, - init(server: Legacy.Server) { - /* - * We must expose the New Platform Task Manager Plugin via the legacy Api - * as removing it now would be a breaking change - we'll remove this in v8.0.0 - */ - server.expose( - createLegacyApi( - getTaskManagerSetup(server)! - .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 - // instead we will start the internal Task Manager plugin when - // all legacy plugins have finished initializing - // Once all plugins are migrated to NP, this can be removed - - // the typing for the lagcy server isn't quite correct, so - // we'll bypase it for now - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (this as any).kbnServer.afterPluginsInit(() => { - taskManagerPlugin.start(); - }); - return taskManagerPlugin; - }) - ) - ); - }, - } as Legacy.PluginSpecOptions); -} diff --git a/x-pack/legacy/plugins/task_manager/server/legacy.ts b/x-pack/legacy/plugins/task_manager/server/legacy.ts deleted file mode 100644 index 0d50828004a94..0000000000000 --- a/x-pack/legacy/plugins/task_manager/server/legacy.ts +++ /dev/null @@ -1,58 +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 { Server } from 'src/legacy/server/kbn_server'; -import { - TaskManagerSetupContract, - TaskManagerStartContract, -} from '../../../../plugins/task_manager/server'; - -import { Middleware } from '../../../../plugins/task_manager/server/lib/middleware.js'; -import { - TaskDictionary, - TaskInstanceWithDeprecatedFields, - TaskInstanceWithId, - TaskDefinition, -} from '../../../../plugins/task_manager/server/task.js'; -import { SearchOpts } from '../../../../plugins/task_manager/server/task_store.js'; - -// Once all plugins are migrated to NP and we can remove Legacy TaskManager in version 8.0.0, -// this can be removed -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { TaskManager } from '../../../../plugins/task_manager/server/task_manager'; - -export type LegacyTaskManagerApi = Pick< - TaskManagerSetupContract, - 'addMiddleware' | 'registerTaskDefinitions' -> & - TaskManagerStartContract; - -export function getTaskManagerSetup(server: Server): TaskManagerSetupContract | undefined { - return server?.newPlatform?.setup?.plugins?.taskManager as TaskManagerSetupContract; -} - -export function getTaskManagerStart(server: Server): TaskManagerStartContract | undefined { - return server?.newPlatform?.start?.plugins?.taskManager as TaskManagerStartContract; -} - -export function createLegacyApi(legacyTaskManager: Promise): LegacyTaskManagerApi { - return { - addMiddleware: (middleware: Middleware) => { - legacyTaskManager.then((tm: TaskManager) => tm.addMiddleware(middleware)); - }, - registerTaskDefinitions: (taskDefinitions: TaskDictionary) => { - legacyTaskManager.then((tm: TaskManager) => tm.registerTaskDefinitions(taskDefinitions)); - }, - fetch: (opts: SearchOpts) => legacyTaskManager.then((tm: TaskManager) => tm.fetch(opts)), - get: (id: string) => legacyTaskManager.then((tm: TaskManager) => tm.get(id)), - remove: (id: string) => legacyTaskManager.then((tm: TaskManager) => tm.remove(id)), - schedule: (taskInstance: TaskInstanceWithDeprecatedFields, options?: object) => - legacyTaskManager.then((tm: TaskManager) => tm.schedule(taskInstance, options)), - runNow: (taskId: string) => legacyTaskManager.then((tm: TaskManager) => tm.runNow(taskId)), - ensureScheduled: (taskInstance: TaskInstanceWithId, options?: object) => - legacyTaskManager.then((tm: TaskManager) => tm.ensureScheduled(taskInstance, options)), - }; -} diff --git a/x-pack/package.json b/x-pack/package.json index be6f436fd3ff7..3a3a0a94fa9ea 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -115,6 +115,8 @@ "@types/uuid": "^3.4.4", "@types/xml-crypto": "^1.4.0", "@types/xml2js": "^0.4.5", + "@types/stats-lite": "^2.2.0", + "@types/pretty-ms": "^5.0.0", "@welldone-software/why-did-you-render": "^4.0.0", "abab": "^1.0.4", "axios": "^0.19.0", diff --git a/x-pack/plugins/actions/server/plugin.ts b/x-pack/plugins/actions/server/plugin.ts index a6cc1fb5463bb..f14df794bbf47 100644 --- a/x-pack/plugins/actions/server/plugin.ts +++ b/x-pack/plugins/actions/server/plugin.ts @@ -177,15 +177,15 @@ export class ActionsPlugin implements Plugin, Plugi const usageCollection = plugins.usageCollection; if (usageCollection) { + initializeActionsTelemetry( + this.telemetryLogger, + plugins.taskManager, + core, + await this.kibanaIndex + ); + core.getStartServices().then(async ([, startPlugins]) => { registerActionsUsageCollector(usageCollection, startPlugins.taskManager); - - initializeActionsTelemetry( - this.telemetryLogger, - plugins.taskManager, - core, - await this.kibanaIndex - ); }); } diff --git a/x-pack/plugins/alerting/server/plugin.ts b/x-pack/plugins/alerting/server/plugin.ts index 8cdde2eeb9877..7bd515616a3c1 100644 --- a/x-pack/plugins/alerting/server/plugin.ts +++ b/x-pack/plugins/alerting/server/plugin.ts @@ -152,15 +152,15 @@ export class AlertingPlugin { const usageCollection = plugins.usageCollection; if (usageCollection) { + initializeAlertingTelemetry( + this.telemetryLogger, + core, + plugins.taskManager, + await this.kibanaIndex + ); + core.getStartServices().then(async ([, startPlugins]) => { registerAlertsUsageCollector(usageCollection, startPlugins.taskManager); - - initializeAlertingTelemetry( - this.telemetryLogger, - core, - plugins.taskManager, - await this.kibanaIndex - ); }); } diff --git a/x-pack/plugins/apm/server/lib/apm_telemetry/index.ts b/x-pack/plugins/apm/server/lib/apm_telemetry/index.ts index 3eb61bb130725..c4b5dc868c37e 100644 --- a/x-pack/plugins/apm/server/lib/apm_telemetry/index.ts +++ b/x-pack/plugins/apm/server/lib/apm_telemetry/index.ts @@ -38,6 +38,21 @@ export async function createApmTelemetry({ taskManager: TaskManagerSetupContract; logger: Logger; }) { + taskManager.registerTaskDefinitions({ + [APM_TELEMETRY_TASK_NAME]: { + title: 'Collect APM telemetry', + type: APM_TELEMETRY_TASK_NAME, + createTaskRunner: () => { + return { + run: async () => { + await collectAndStore(); + }, + cancel: async () => {} + }; + } + } + }); + const savedObjectsClient = await getInternalSavedObjectsClient(core); const collectAndStore = async () => { @@ -79,21 +94,6 @@ export async function createApmTelemetry({ ); }; - taskManager.registerTaskDefinitions({ - [APM_TELEMETRY_TASK_NAME]: { - title: 'Collect APM telemetry', - type: APM_TELEMETRY_TASK_NAME, - createTaskRunner: () => { - return { - run: async () => { - await collectAndStore(); - }, - cancel: async () => {} - }; - } - } - }); - const collector = usageCollector.makeUsageCollector({ type: 'apm', fetch: async () => { diff --git a/x-pack/plugins/task_manager/server/create_task_manager.test.ts b/x-pack/plugins/task_manager/server/create_task_manager.test.ts deleted file mode 100644 index 133cfcac4c046..0000000000000 --- a/x-pack/plugins/task_manager/server/create_task_manager.test.ts +++ /dev/null @@ -1,62 +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 { createTaskManager, LegacyDeps } from './create_task_manager'; -import { mockLogger } from './test_utils'; -import { CoreSetup, SavedObjectsSerializer, UuidServiceSetup } from '../../../../src/core/server'; -import { - savedObjectsRepositoryMock, - savedObjectsTypeRegistryMock, -} from '../../../../src/core/server/mocks'; - -jest.mock('./task_manager'); - -describe('createTaskManager', () => { - const uuid: UuidServiceSetup = { - getInstanceUuid() { - return 'some-uuid'; - }, - }; - const mockCoreSetup = { - uuid, - } as CoreSetup; - - const getMockLegacyDeps = (): LegacyDeps => ({ - config: {}, - savedObjectsSerializer: new SavedObjectsSerializer(savedObjectsTypeRegistryMock.create()), - elasticsearch: { - callAsInternalUser: jest.fn(), - }, - savedObjectsRepository: savedObjectsRepositoryMock.create(), - logger: mockLogger(), - }); - - beforeEach(() => { - jest.resetAllMocks(); - }); - - test('exposes the underlying TaskManager', async () => { - const mockLegacyDeps = getMockLegacyDeps(); - const setupResult = createTaskManager(mockCoreSetup, mockLegacyDeps); - expect(setupResult).toMatchInlineSnapshot(` - TaskManager { - "addMiddleware": [MockFunction], - "assertUninitialized": [MockFunction], - "attemptToRun": [MockFunction], - "ensureScheduled": [MockFunction], - "fetch": [MockFunction], - "get": [MockFunction], - "registerTaskDefinitions": [MockFunction], - "remove": [MockFunction], - "runNow": [MockFunction], - "schedule": [MockFunction], - "start": [MockFunction], - "stop": [MockFunction], - "waitUntilStarted": [MockFunction], - } - `); - }); -}); diff --git a/x-pack/plugins/task_manager/server/create_task_manager.ts b/x-pack/plugins/task_manager/server/create_task_manager.ts deleted file mode 100644 index 7ab6acba7976d..0000000000000 --- a/x-pack/plugins/task_manager/server/create_task_manager.ts +++ /dev/null @@ -1,43 +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 { - IClusterClient, - SavedObjectsSerializer, - CoreSetup, - ISavedObjectsRepository, -} from '../../../../src/core/server'; -import { TaskManager } from './task_manager'; -import { Logger } from './types'; -import { TaskManagerConfig } from './config'; - -export interface LegacyDeps { - config: unknown; - elasticsearch: Pick; - savedObjectsRepository: ISavedObjectsRepository; - savedObjectsSerializer: SavedObjectsSerializer; - logger: Logger; -} - -export function createTaskManager( - core: CoreSetup, - { - logger, - config, - elasticsearch: { callAsInternalUser }, - savedObjectsRepository, - savedObjectsSerializer, - }: LegacyDeps -) { - return new TaskManager({ - taskManagerId: core.uuid.getInstanceUuid(), - config: config as TaskManagerConfig, - savedObjectsRepository, - serializer: savedObjectsSerializer, - callAsInternalUser, - logger, - }); -} diff --git a/x-pack/plugins/task_manager/server/mocks.ts b/x-pack/plugins/task_manager/server/mocks.ts index 8ec05dd1bd401..4a78a0b49001b 100644 --- a/x-pack/plugins/task_manager/server/mocks.ts +++ b/x-pack/plugins/task_manager/server/mocks.ts @@ -8,7 +8,6 @@ import { TaskManagerSetupContract, TaskManagerStartContract } from './plugin'; const createSetupMock = () => { const mock: jest.Mocked = { - registerLegacyAPI: jest.fn(), addMiddleware: jest.fn(), registerTaskDefinitions: jest.fn(), }; diff --git a/x-pack/plugins/task_manager/server/plugin.ts b/x-pack/plugins/task_manager/server/plugin.ts index 0f6e3fc31d96d..4295dbf912c4c 100644 --- a/x-pack/plugins/task_manager/server/plugin.ts +++ b/x-pack/plugins/task_manager/server/plugin.ts @@ -3,20 +3,19 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { PluginInitializerContext, Plugin, CoreSetup } from 'src/core/server'; +import { PluginInitializerContext, Plugin, CoreSetup, CoreStart } from 'src/core/server'; import { Subject } from 'rxjs'; import { first } from 'rxjs/operators'; -import { once } from 'lodash'; import { TaskDictionary, TaskDefinition } from './task'; 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'; -export type TaskManagerSetupContract = { - registerLegacyAPI: () => Promise; -} & Pick; +export type TaskManagerSetupContract = Pick< + TaskManager, + 'addMiddleware' | 'registerTaskDefinitions' +>; export type TaskManagerStartContract = Pick< TaskManager, @@ -28,39 +27,24 @@ export class TaskManagerPlugin legacyTaskManager$: Subject = new Subject(); taskManager: Promise = this.legacyTaskManager$.pipe(first()).toPromise(); currentConfig: TaskManagerConfig; + taskManagerId?: string; + config?: TaskManagerConfig; constructor(private readonly initContext: PluginInitializerContext) { this.initContext = initContext; this.currentConfig = {} as TaskManagerConfig; } - public async setup(core: CoreSetup, plugins: unknown): Promise { - const logger = this.initContext.logger.get('taskManager'); - const config = await this.initContext.config + public async setup(core: CoreSetup): Promise { + this.config = await this.initContext.config .create() .pipe(first()) .toPromise(); - setupSavedObjects(core.savedObjects, config); + setupSavedObjects(core.savedObjects, this.config); + this.taskManagerId = core.uuid.getInstanceUuid(); return { - registerLegacyAPI: once(() => { - (async () => { - const [{ savedObjects, elasticsearch }] = await core.getStartServices(); - const savedObjectsRepository = savedObjects.createInternalRepository(['task']); - this.legacyTaskManager$.next( - createTaskManager(core, { - logger, - config, - elasticsearch: elasticsearch.legacy.client, - savedObjectsRepository, - savedObjectsSerializer: savedObjects.createSerializer(), - }) - ); - this.legacyTaskManager$.complete(); - })(); - return this.taskManager; - }), addMiddleware: (middleware: Middleware) => { this.taskManager.then(tm => tm.addMiddleware(middleware)); }, @@ -70,7 +54,29 @@ export class TaskManagerPlugin }; } - public start(): TaskManagerStartContract { + public start({ savedObjects, elasticsearch }: CoreStart): TaskManagerStartContract { + const logger = this.initContext.logger.get('taskManager'); + const savedObjectsRepository = savedObjects.createInternalRepository(['task']); + + this.legacyTaskManager$.next( + new TaskManager({ + taskManagerId: this.taskManagerId!, + config: this.config!, + savedObjectsRepository, + serializer: savedObjects.createSerializer(), + callAsInternalUser: elasticsearch.legacy.client.callAsInternalUser, + logger, + }) + ); + this.legacyTaskManager$.complete(); + + // we need to "drain" any calls made to the seup API + // before `starting` TaskManager. This is a legacy relic + // of the old API that should be resolved once we split + // Task manager into two services, setup and start, instead + // of the single instance of TaskManager + this.taskManager.then(tm => tm.start()); + return { fetch: (...args) => this.taskManager.then(tm => tm.fetch(...args)), get: (...args) => this.taskManager.then(tm => tm.get(...args)), diff --git a/x-pack/plugins/task_manager/server/task_manager.mock.ts b/x-pack/plugins/task_manager/server/task_manager.mock.ts index 1be1a81cdeb68..1fc626e7d58d6 100644 --- a/x-pack/plugins/task_manager/server/task_manager.mock.ts +++ b/x-pack/plugins/task_manager/server/task_manager.mock.ts @@ -11,7 +11,6 @@ export const taskManagerMock = { const mocked: jest.Mocked = { registerTaskDefinitions: jest.fn(), addMiddleware: jest.fn(), - registerLegacyAPI: jest.fn(), ...overrides, }; return mocked; 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 1244657ed9988..0bb98a540c4e8 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_simulators'; +} from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; // 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 4151deab45213..15b7f4f8b3386 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_simulators'; +} from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; // 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 bae6dada48fb7..e3ba075d27de2 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_simulators'; +} from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; // 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 72a2774e672f1..d6b5b40d99d99 100644 --- a/x-pack/test/alerting_api_integration/common/config.ts +++ b/x-pack/test/alerting_api_integration/common/config.ts @@ -5,10 +5,11 @@ */ import path from 'path'; +import fs from 'fs'; 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_simulators'; +import { getAllExternalServiceSimulatorPaths } from './fixtures/plugins/actions_simulators/server/plugin'; interface CreateTestConfigOptions { license: string; @@ -48,6 +49,11 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions) protocol: ssl ? 'https' : 'http', }, }; + // Find all folders in ./plugins since we treat all them as plugin folder + const allFiles = fs.readdirSync(path.resolve(__dirname, 'fixtures', 'plugins')); + const plugins = allFiles.filter(file => + fs.statSync(path.resolve(__dirname, 'fixtures', 'plugins', file)).isDirectory() + ); return { testFiles: [require.resolve(`../${name}/tests/`)], @@ -123,10 +129,10 @@ 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_simulators')}`, - `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'task_manager')}`, - `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'aad')}`, + ...plugins.map( + pluginDir => + `--plugin-path=${path.resolve(__dirname, 'fixtures', 'plugins', pluginDir)}` + ), `--server.xsrf.whitelist=${JSON.stringify(getAllExternalServiceSimulatorPaths())}`, ...(ssl ? [ 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 deleted file mode 100644 index 400aec7e11c8d..0000000000000 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/index.ts +++ /dev/null @@ -1,59 +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'; -import Hapi from 'hapi'; -import { Legacy } from 'kibana'; -import KbnServer from '../../../../../../../src/legacy/server/kbn_server'; -import { EncryptedSavedObjectsPluginStart } from '../../../../../../plugins/encrypted_saved_objects/server'; - -interface CheckAADRequest extends Hapi.Request { - payload: { - spaceId?: string; - type: string; - id: string; - }; -} - -// eslint-disable-next-line import/no-default-export -export default function(kibana: any) { - return new kibana.Plugin({ - require: ['encryptedSavedObjects'], - name: 'aad-fixtures', - init(server: Legacy.Server) { - const newPlatform = ((server as unknown) as KbnServer).newPlatform; - const esoPlugin = newPlatform.start.plugins - .encryptedSavedObjects as EncryptedSavedObjectsPluginStart; - - server.route({ - method: 'POST', - path: '/api/check_aad', - options: { - validate: { - payload: Joi.object() - .keys({ - spaceId: Joi.string().optional(), - type: Joi.string().required(), - id: Joi.string().required(), - }) - .required(), - }, - }, - handler: (async (request: CheckAADRequest) => { - let namespace: string | undefined; - const spacesPlugin = server.plugins.spaces; - if (spacesPlugin && request.payload.spaceId) { - namespace = spacesPlugin.spaceIdToNamespace(request.payload.spaceId); - } - await esoPlugin.getDecryptedAsInternalUser(request.payload.type, request.payload.id, { - namespace, - }); - return { success: true }; - }) as Hapi.Lifecycle.Method, - }); - }, - }); -} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/kibana.json b/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/kibana.json new file mode 100644 index 0000000000000..9a7bedbb5c6d5 --- /dev/null +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/kibana.json @@ -0,0 +1,10 @@ +{ + "id": "aad-fixtures", + "version": "1.0.0", + "kibanaVersion": "kibana", + "configPath": ["xpack"], + "requiredPlugins": ["taskManager", "encryptedSavedObjects"], + "optionalPlugins": ["spaces"], + "server": true, + "ui": false +} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/package.json b/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/package.json index f5d174c18a209..128b75aaa0509 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/package.json +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/package.json @@ -1,7 +1,20 @@ { "name": "aad-fixtures", - "version": "0.0.0", + "version": "1.0.0", "kibana": { - "version": "kibana" + "version": "kibana", + "templateVersion": "1.0.0" + }, + "main": "target/test/plugin_api_integration/plugins/aad", + "scripts": { + "kbn": "node ../../../../../scripts/kbn.js", + "build": "rm -rf './target' && tsc" + }, + "devDependencies": { + "typescript": "3.7.2" + }, + "license": "Apache-2.0", + "dependencies": { + "joi": "^13.5.2" } } diff --git a/x-pack/legacy/plugins/task_manager/index.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/server/index.ts similarity index 72% rename from x-pack/legacy/plugins/task_manager/index.ts rename to x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/server/index.ts index 276d1ea3accea..54d6de50cff4d 100644 --- a/x-pack/legacy/plugins/task_manager/index.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/server/index.ts @@ -4,4 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -export * from './server/'; +import { FixturePlugin } from './plugin'; + +export const plugin = () => new FixturePlugin(); diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/server/plugin.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/server/plugin.ts new file mode 100644 index 0000000000000..0e9c71d8c20c8 --- /dev/null +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/server/plugin.ts @@ -0,0 +1,64 @@ +/* + * 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, + RequestHandlerContext, + KibanaRequest, + KibanaResponseFactory, + IKibanaResponse, +} from 'kibana/server'; +import { schema } from '@kbn/config-schema'; +import { EncryptedSavedObjectsPluginStart } from '../../../../../../../plugins/encrypted_saved_objects/server'; +import { SpacesPluginSetup } from '../../../../../../../plugins/spaces/server'; + +interface FixtureSetupDeps { + spaces?: SpacesPluginSetup; +} + +interface FixtureStartDeps { + encryptedSavedObjects: EncryptedSavedObjectsPluginStart; +} + +export class FixturePlugin implements Plugin { + public setup(core: CoreSetup, { spaces }: FixtureSetupDeps) { + core.http.createRouter().post( + { + path: '/api/check_aad', + validate: { + body: schema.object({ + spaceId: schema.maybe(schema.string()), + type: schema.string(), + id: schema.string(), + }), + }, + }, + async function( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise> { + try { + let namespace: string | undefined; + const [, { encryptedSavedObjects }] = await core.getStartServices(); + if (spaces && req.body.spaceId) { + namespace = spaces.spacesService.spaceIdToNamespace(req.body.spaceId); + } + await encryptedSavedObjects.getDecryptedAsInternalUser(req.body.type, req.body.id, { + namespace, + }); + return res.ok({ body: { success: true } }); + } catch (err) { + return res.internalError({ body: err }); + } + } + ); + } + + public start() {} + public stop() {} +} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/index.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/index.ts deleted file mode 100644 index 6e7e9e3793778..0000000000000 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/index.ts +++ /dev/null @@ -1,91 +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 Hapi from 'hapi'; -import { PluginSetupContract as ActionsPluginSetupContract } from '../../../../../../plugins/actions/server/plugin'; -import { ActionType } from '../../../../../../plugins/actions/server'; - -import { initPlugin as initPagerduty } from './pagerduty_simulation'; -import { initPlugin as initSlack } from './slack_simulation'; -import { initPlugin as initWebhook } from './webhook_simulation'; -import { initPlugin as initServiceNow } from './servicenow_simulation'; -import { initPlugin as initJira } from './jira_simulation'; - -const NAME = 'actions-FTS-external-service-simulators'; - -export enum ExternalServiceSimulator { - PAGERDUTY = 'pagerduty', - SERVICENOW = 'servicenow', - JIRA = 'jira', - SLACK = 'slack', - WEBHOOK = 'webhook', -} - -export function getExternalServiceSimulatorPath(service: ExternalServiceSimulator): string { - return `/api/_${NAME}/${service}`; -} - -export function getAllExternalServiceSimulatorPaths(): string[] { - const allPaths = Object.values(ExternalServiceSimulator).map(service => - getExternalServiceSimulatorPath(service) - ); - - allPaths.push(`/api/_${NAME}/${ExternalServiceSimulator.SERVICENOW}/api/now/v2/table/incident`); - allPaths.push(`/api/_${NAME}/${ExternalServiceSimulator.JIRA}/rest/api/2/issue`); - return allPaths; -} - -// eslint-disable-next-line import/no-default-export -export default function(kibana: any) { - return new kibana.Plugin({ - require: ['xpack_main'], - name: NAME, - init: (server: Hapi.Server) => { - // this action is specifically NOT enabled in ../../config.ts - const notEnabledActionType: ActionType = { - id: 'test.not-enabled', - name: 'Test: Not Enabled', - minimumLicenseRequired: 'gold', - async executor() { - return { status: 'ok', actionId: '' }; - }, - }; - (server.newPlatform.setup.plugins.actions as ActionsPluginSetupContract).registerType( - notEnabledActionType - ); - server.plugins.xpack_main.registerFeature({ - id: 'actions', - name: 'Actions', - app: ['actions', 'kibana'], - privileges: { - all: { - app: ['actions', 'kibana'], - savedObject: { - all: ['action', 'action_task_params'], - read: [], - }, - ui: [], - api: ['actions-read', 'actions-all'], - }, - read: { - app: ['actions', 'kibana'], - savedObject: { - all: ['action_task_params'], - read: ['action'], - }, - ui: [], - api: ['actions-read'], - }, - }, - }); - - initPagerduty(server, getExternalServiceSimulatorPath(ExternalServiceSimulator.PAGERDUTY)); - initSlack(server, getExternalServiceSimulatorPath(ExternalServiceSimulator.SLACK)); - initWebhook(server, getExternalServiceSimulatorPath(ExternalServiceSimulator.WEBHOOK)); - initServiceNow(server, getExternalServiceSimulatorPath(ExternalServiceSimulator.SERVICENOW)); - initJira(server, getExternalServiceSimulatorPath(ExternalServiceSimulator.JIRA)); - }, - }); -} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/jira_simulation.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/jira_simulation.ts deleted file mode 100644 index 629d0197b2292..0000000000000 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/jira_simulation.ts +++ /dev/null @@ -1,101 +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 Hapi from 'hapi'; - -interface JiraRequest extends Hapi.Request { - payload: { - summary: string; - description?: string; - comments?: string; - }; -} -export function initPlugin(server: Hapi.Server, path: string) { - server.route({ - method: 'POST', - path: `${path}/rest/api/2/issue`, - options: { - auth: false, - }, - handler: createHandler as Hapi.Lifecycle.Method, - }); - - server.route({ - method: 'PUT', - path: `${path}/rest/api/2/issue/{id}`, - options: { - auth: false, - }, - handler: updateHandler as Hapi.Lifecycle.Method, - }); - - server.route({ - method: 'GET', - path: `${path}/rest/api/2/issue/{id}`, - options: { - auth: false, - }, - handler: getHandler as Hapi.Lifecycle.Method, - }); - - server.route({ - method: 'POST', - path: `${path}/rest/api/2/issue/{id}/comment`, - options: { - auth: false, - }, - handler: createCommentHanlder as Hapi.Lifecycle.Method, - }); -} - -// ServiceNow simulator: create a servicenow action pointing here, and you can get -// different responses based on the message posted. See the README.md for -// more info. -function createHandler(request: JiraRequest, h: any) { - return jsonResponse(h, 200, { - id: '123', - key: 'CK-1', - created: '2020-04-27T14:17:45.490Z', - }); -} - -function updateHandler(request: JiraRequest, h: any) { - return jsonResponse(h, 200, { - id: '123', - key: 'CK-1', - created: '2020-04-27T14:17:45.490Z', - updated: '2020-04-27T14:17:45.490Z', - }); -} - -function getHandler(request: JiraRequest, h: any) { - return jsonResponse(h, 200, { - id: '123', - key: 'CK-1', - created: '2020-04-27T14:17:45.490Z', - updated: '2020-04-27T14:17:45.490Z', - summary: 'title', - description: 'description', - }); -} - -function createCommentHanlder(request: JiraRequest, h: any) { - return jsonResponse(h, 200, { - id: '123', - created: '2020-04-27T14:17:45.490Z', - }); -} - -function jsonResponse(h: any, code: number, object?: any) { - if (object == null) { - return h.response('').code(code); - } - - return h - .response(JSON.stringify(object)) - .type('application/json') - .code(code); -} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/kibana.json b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/kibana.json new file mode 100644 index 0000000000000..5f92b9e5479e8 --- /dev/null +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/kibana.json @@ -0,0 +1,9 @@ +{ + "id": "actions_simulators", + "version": "1.0.0", + "kibanaVersion": "kibana", + "configPath": ["xpack"], + "requiredPlugins": ["actions", "features", "encryptedSavedObjects"], + "server": true, + "ui": false +} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/package.json b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/package.json index 7f319f52dee2d..b1076437ef37f 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/package.json +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/package.json @@ -1,7 +1,20 @@ { - "name": "actions-fixtures", - "version": "0.0.0", + "name": "actions_simulators", + "version": "1.0.0", "kibana": { - "version": "kibana" + "version": "kibana", + "templateVersion": "1.0.0" + }, + "main": "target/test/plugin_api_integration/plugins/actions_simulators", + "scripts": { + "kbn": "node ../../../../../scripts/kbn.js", + "build": "rm -rf './target' && tsc" + }, + "devDependencies": { + "typescript": "3.7.2" + }, + "license": "Apache-2.0", + "dependencies": { + "joi": "^13.5.2" } } diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/pagerduty_simulation.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/pagerduty_simulation.ts deleted file mode 100644 index 1de1476fc4ff2..0000000000000 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/pagerduty_simulation.ts +++ /dev/null @@ -1,79 +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'; -import Hapi from 'hapi'; - -interface PagerdutyRequest extends Hapi.Request { - payload: { - dedup_key: string; - payload: { - summary: string; - }; - }; -} - -export function initPlugin(server: Hapi.Server, path: string) { - server.route({ - method: 'POST', - path, - options: { - auth: false, - validate: { - options: { abortEarly: false }, - payload: Joi.object() - .unknown(true) - .keys({ - dedup_key: Joi.string(), - payload: Joi.object() - .unknown(true) - .keys({ - summary: Joi.string(), - }), - }), - }, - }, - handler: pagerdutyHandler as Hapi.Lifecycle.Method, - }); -} -// Pagerduty simulator: create an action pointing here, and you can get -// different responses based on the message posted. See the README.md for -// more info. -function pagerdutyHandler(request: PagerdutyRequest, h: any) { - const body = request.payload; - let dedupKey = body && body.dedup_key; - const summary = body && body.payload && body.payload.summary; - - if (dedupKey == null) { - dedupKey = `kibana-ft-simulator-dedup-key-${new Date().toISOString()}`; - } - - switch (summary) { - case 'respond-with-429': - return jsonResponse(h, 429); - case 'respond-with-502': - return jsonResponse(h, 502); - case 'respond-with-418': - return jsonResponse(h, 418); - } - - return jsonResponse(h, 202, { - status: 'success', - message: 'Event processed', - dedup_key: dedupKey, - }); -} - -function jsonResponse(h: any, code: number, object?: any) { - if (object == null) { - return h.response('').code(code); - } - - return h - .response(JSON.stringify(object)) - .type('application/json') - .code(code); -} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/README.md b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/README.md similarity index 100% rename from x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/README.md rename to x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/README.md diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/index.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/index.ts new file mode 100644 index 0000000000000..54d6de50cff4d --- /dev/null +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/index.ts @@ -0,0 +1,9 @@ +/* + * 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 { FixturePlugin } from './plugin'; + +export const plugin = () => new FixturePlugin(); diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/jira_simulation.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/jira_simulation.ts new file mode 100644 index 0000000000000..8a55cf6b35652 --- /dev/null +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/jira_simulation.ts @@ -0,0 +1,116 @@ +/* + * 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. + */ + +/* + * 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 { + RequestHandlerContext, + KibanaRequest, + KibanaResponseFactory, + IKibanaResponse, + IRouter, +} from 'kibana/server'; + +export function initPlugin(router: IRouter, path: string) { + router.post( + { + path: `${path}/rest/api/2/issue`, + options: { + authRequired: false, + }, + validate: {}, + }, + async function( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise> { + return jsonResponse(res, 200, { + id: '123', + key: 'CK-1', + created: '2020-04-27T14:17:45.490Z', + }); + } + ); + + router.put( + { + path: `${path}/rest/api/2/issue/{id}`, + options: { + authRequired: false, + }, + validate: {}, + }, + async function( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise> { + return jsonResponse(res, 200, { + id: '123', + key: 'CK-1', + created: '2020-04-27T14:17:45.490Z', + updated: '2020-04-27T14:17:45.490Z', + }); + } + ); + + router.get( + { + path: `${path}/rest/api/2/issue/{id}`, + options: { + authRequired: false, + }, + validate: {}, + }, + async function( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise> { + return jsonResponse(res, 200, { + id: '123', + key: 'CK-1', + created: '2020-04-27T14:17:45.490Z', + updated: '2020-04-27T14:17:45.490Z', + summary: 'title', + description: 'description', + }); + } + ); + + router.post( + { + path: `${path}/rest/api/2/issue/{id}/comment`, + options: { + authRequired: false, + }, + validate: {}, + }, + async function( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise> { + return jsonResponse(res, 200, { + id: '123', + created: '2020-04-27T14:17:45.490Z', + }); + } + ); +} + +function jsonResponse( + res: KibanaResponseFactory, + code: number, + object: Record = {} +) { + return res.custom>({ body: object, statusCode: code }); +} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/pagerduty_simulation.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/pagerduty_simulation.ts new file mode 100644 index 0000000000000..83022ec0e3260 --- /dev/null +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/pagerduty_simulation.ts @@ -0,0 +1,86 @@ +/* + * 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, +} from 'kibana/server'; + +export function initPlugin(router: IRouter, path: string) { + router.post( + { + path, + options: { + authRequired: false, + }, + validate: { + body: schema.object( + { + dedup_key: schema.string(), + payload: schema.object( + { + summary: schema.string(), + }, + { + unknowns: 'allow', + } + ), + }, + { + unknowns: 'allow', + } + ), + }, + }, + // Pagerduty simulator: create an action pointing here, and you can get + // different responses based on the message posted. See the README.md for + // more info. + async function( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise> { + const { body } = req; + let dedupKey = body && body.dedup_key; + const summary = body && body.payload && body.payload.summary; + + if (dedupKey == null) { + dedupKey = `kibana-ft-simulator-dedup-key-${new Date().toISOString()}`; + } + + switch (summary) { + case 'respond-with-429': + return jsonErrorResponse(res, 429, new Error(summary)); + case 'respond-with-502': + return jsonErrorResponse(res, 502, new Error(summary)); + case 'respond-with-418': + return jsonErrorResponse(res, 418, new Error(summary)); + } + + return jsonResponse(res, 202, { + status: 'success', + message: 'Event processed', + dedup_key: dedupKey, + }); + } + ); +} + +function jsonResponse( + res: KibanaResponseFactory, + code: number, + object: Record = {} +) { + return res.custom>({ body: object, statusCode: code }); +} + +function jsonErrorResponse(res: KibanaResponseFactory, code: number, object: Error) { + return res.custom({ body: object, statusCode: code }); +} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/plugin.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/plugin.ts new file mode 100644 index 0000000000000..efb219fc8e717 --- /dev/null +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/plugin.ts @@ -0,0 +1,95 @@ +/* + * 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, IRouter } from 'kibana/server'; +import { EncryptedSavedObjectsPluginStart } from '../../../../../../../plugins/encrypted_saved_objects/server'; +import { PluginSetupContract as FeaturesPluginSetup } from '../../../../../../../plugins/features/server'; +import { PluginSetupContract as ActionsPluginSetupContract } from '../../../../../../../plugins/actions/server/plugin'; +import { ActionType } from '../../../../../../../plugins/actions/server'; +import { initPlugin as initPagerduty } from './pagerduty_simulation'; +import { initPlugin as initServiceNow } from './servicenow_simulation'; +import { initPlugin as initJira } from './jira_simulation'; + +export const NAME = 'actions-FTS-external-service-simulators'; + +export enum ExternalServiceSimulator { + PAGERDUTY = 'pagerduty', + SERVICENOW = 'servicenow', + SLACK = 'slack', + JIRA = 'jira', + WEBHOOK = 'webhook', +} + +export function getExternalServiceSimulatorPath(service: ExternalServiceSimulator): string { + return `/api/_${NAME}/${service}`; +} + +export function getAllExternalServiceSimulatorPaths(): string[] { + const allPaths = Object.values(ExternalServiceSimulator).map(service => + getExternalServiceSimulatorPath(service) + ); + allPaths.push(`/api/_${NAME}/${ExternalServiceSimulator.SERVICENOW}/api/now/v2/table/incident`); + allPaths.push(`/api/_${NAME}/${ExternalServiceSimulator.JIRA}/rest/api/2/issue`); + return allPaths; +} + +interface FixtureSetupDeps { + actions: ActionsPluginSetupContract; + features: FeaturesPluginSetup; +} + +interface FixtureStartDeps { + encryptedSavedObjects: EncryptedSavedObjectsPluginStart; +} + +export class FixturePlugin implements Plugin { + public setup(core: CoreSetup, { features, actions }: FixtureSetupDeps) { + // this action is specifically NOT enabled in ../../config.ts + const notEnabledActionType: ActionType = { + id: 'test.not-enabled', + name: 'Test: Not Enabled', + minimumLicenseRequired: 'gold', + async executor() { + return { status: 'ok', actionId: '' }; + }, + }; + actions.registerType(notEnabledActionType); + features.registerFeature({ + id: 'actions', + name: 'Actions', + app: ['actions', 'kibana'], + privileges: { + all: { + app: ['actions', 'kibana'], + savedObject: { + all: ['action', 'action_task_params'], + read: [], + }, + ui: [], + api: ['actions-read', 'actions-all'], + }, + read: { + app: ['actions', 'kibana'], + savedObject: { + all: ['action_task_params'], + read: ['action'], + }, + ui: [], + api: ['actions-read'], + }, + }, + }); + + const router: IRouter = core.http.createRouter(); + + initPagerduty(router, getExternalServiceSimulatorPath(ExternalServiceSimulator.PAGERDUTY)); + initServiceNow(router, getExternalServiceSimulatorPath(ExternalServiceSimulator.SERVICENOW)); + initJira(router, getExternalServiceSimulatorPath(ExternalServiceSimulator.JIRA)); + } + + public start() {} + public stop() {} +} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/servicenow_simulation.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/servicenow_simulation.ts new file mode 100644 index 0000000000000..4bf8216aed26f --- /dev/null +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/servicenow_simulation.ts @@ -0,0 +1,99 @@ +/* + * 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, +} from 'kibana/server'; + +export function initPlugin(router: IRouter, path: string) { + router.post( + { + path: `${path}/api/now/v2/table/incident`, + options: { + authRequired: false, + }, + validate: { + body: schema.object({ + short_description: schema.string(), + description: schema.maybe(schema.string()), + comments: schema.maybe(schema.string()), + }), + }, + }, + // ServiceNow simulator: create a servicenow action pointing here, and you can get + // different responses based on the message posted. See the README.md for + // more info. + async function( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise> { + return jsonResponse(res, 200, { + result: { sys_id: '123', number: 'INC01', sys_created_on: '2020-03-10 12:24:20' }, + }); + } + ); + + router.patch( + { + path: `${path}/api/now/v2/table/incident/{id}`, + options: { + authRequired: false, + }, + validate: {}, + }, + async function( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise> { + return jsonResponse(res, 200, { + result: { sys_id: '123', number: 'INC01', sys_updated_on: '2020-03-10 12:24:20' }, + }); + } + ); + + router.get( + { + path: `${path}/api/now/v2/table/incident/{id}`, + options: { + authRequired: false, + }, + validate: {}, + }, + async function( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise> { + return jsonResponse(res, 200, { + result: { + sys_id: '123', + number: 'INC01', + sys_created_on: '2020-03-10 12:24:20', + short_description: 'title', + description: 'description', + }, + }); + } + ); +} + +function jsonResponse(res: KibanaResponseFactory, code: number, object?: Record) { + if (object == null) { + return res.custom({ + statusCode: code, + body: '', + }); + } + + return res.custom>({ body: object, statusCode: code }); +} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/servicenow_simulation.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/servicenow_simulation.ts deleted file mode 100644 index cc9521369a47d..0000000000000 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/servicenow_simulation.ts +++ /dev/null @@ -1,81 +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 Hapi from 'hapi'; - -interface ServiceNowRequest extends Hapi.Request { - payload: { - short_description: string; - description?: string; - comments?: string; - }; -} -export function initPlugin(server: Hapi.Server, path: string) { - server.route({ - method: 'POST', - path: `${path}/api/now/v2/table/incident`, - options: { - auth: false, - }, - handler: createHandler as Hapi.Lifecycle.Method, - }); - - server.route({ - method: 'PATCH', - path: `${path}/api/now/v2/table/incident/{id}`, - options: { - auth: false, - }, - handler: updateHandler as Hapi.Lifecycle.Method, - }); - - server.route({ - method: 'GET', - path: `${path}/api/now/v2/table/incident/{id}`, - options: { - auth: false, - }, - handler: getHandler as Hapi.Lifecycle.Method, - }); -} - -// ServiceNow simulator: create a servicenow action pointing here, and you can get -// different responses based on the message posted. See the README.md for -// more info. -function createHandler(request: ServiceNowRequest, h: any) { - return jsonResponse(h, 200, { - result: { sys_id: '123', number: 'INC01', sys_created_on: '2020-03-10 12:24:20' }, - }); -} - -function updateHandler(request: ServiceNowRequest, h: any) { - return jsonResponse(h, 200, { - result: { sys_id: '123', number: 'INC01', sys_updated_on: '2020-03-10 12:24:20' }, - }); -} - -function getHandler(request: ServiceNowRequest, h: any) { - return jsonResponse(h, 200, { - result: { - sys_id: '123', - number: 'INC01', - sys_created_on: '2020-03-10 12:24:20', - short_description: 'title', - description: 'description', - }, - }); -} - -function jsonResponse(h: any, code: number, object?: any) { - if (object == null) { - return h.response('').code(code); - } - - return h - .response(JSON.stringify(object)) - .type('application/json') - .code(code); -} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/index.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/index.ts new file mode 100644 index 0000000000000..4219d99b6c43b --- /dev/null +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/index.ts @@ -0,0 +1,26 @@ +/* + * 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 Hapi from 'hapi'; +import { + getExternalServiceSimulatorPath, + NAME, + ExternalServiceSimulator, +} from '../actions_simulators/server/plugin'; + +import { initPlugin as initWebhook } from './webhook_simulation'; +import { initPlugin as initSlack } from './slack_simulation'; + +// eslint-disable-next-line import/no-default-export +export default function(kibana: any) { + return new kibana.Plugin({ + require: ['xpack_main'], + name: `${NAME}-legacy`, + init: (server: Hapi.Server) => { + initWebhook(server, getExternalServiceSimulatorPath(ExternalServiceSimulator.WEBHOOK)); + initSlack(server, getExternalServiceSimulatorPath(ExternalServiceSimulator.SLACK)); + }, + }); +} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/package.json b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/package.json new file mode 100644 index 0000000000000..644cd77d3be75 --- /dev/null +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/package.json @@ -0,0 +1,7 @@ +{ + "name": "actions-fixtures-legacy", + "version": "0.0.0", + "kibana": { + "version": "kibana" + } +} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/slack_simulation.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/slack_simulation.ts similarity index 100% rename from x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/slack_simulation.ts rename to x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/slack_simulation.ts diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/webhook_simulation.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/webhook_simulation.ts similarity index 100% rename from x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/webhook_simulation.ts rename to x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/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 deleted file mode 100644 index 1a47addf36ab3..0000000000000 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/index.ts +++ /dev/null @@ -1,501 +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 { times } from 'lodash'; -import { schema } from '@kbn/config-schema'; -import { AlertExecutorOptions, AlertType } from '../../../../../../plugins/alerting/server'; -import { ActionTypeExecutorOptions, ActionType } from '../../../../../../plugins/actions/server'; - -// eslint-disable-next-line import/no-default-export -export default function(kibana: any) { - return new kibana.Plugin({ - require: ['xpack_main', 'elasticsearch'], - name: 'alerts-fixture', - init(server: any) { - const clusterClient = server.newPlatform.start.core.elasticsearch.legacy.client; - server.plugins.xpack_main.registerFeature({ - id: 'alerting', - name: 'Alerting', - app: ['alerting', 'kibana'], - privileges: { - all: { - app: ['alerting', 'kibana'], - savedObject: { - all: ['alert'], - read: [], - }, - ui: [], - api: ['alerting-read', 'alerting-all'], - }, - read: { - app: ['alerting', 'kibana'], - savedObject: { - all: [], - read: ['alert'], - }, - ui: [], - api: ['alerting-read'], - }, - }, - }); - - // Action types - const noopActionType: ActionType = { - id: 'test.noop', - name: 'Test: Noop', - minimumLicenseRequired: 'gold', - async executor() { - return { status: 'ok', actionId: '' }; - }, - }; - const indexRecordActionType: ActionType = { - id: 'test.index-record', - name: 'Test: Index Record', - minimumLicenseRequired: 'gold', - validate: { - params: schema.object({ - index: schema.string(), - reference: schema.string(), - message: schema.string(), - }), - config: schema.object({ - unencrypted: schema.string(), - }), - secrets: schema.object({ - encrypted: schema.string(), - }), - }, - async executor({ config, secrets, params, services, actionId }: ActionTypeExecutorOptions) { - await services.callCluster('index', { - index: params.index, - refresh: 'wait_for', - body: { - params, - config, - secrets, - reference: params.reference, - source: 'action:test.index-record', - }, - }); - return { status: 'ok', actionId }; - }, - }; - const failingActionType: ActionType = { - id: 'test.failing', - name: 'Test: Failing', - minimumLicenseRequired: 'gold', - validate: { - params: schema.object({ - index: schema.string(), - reference: schema.string(), - }), - }, - async executor({ config, secrets, params, services }: ActionTypeExecutorOptions) { - await services.callCluster('index', { - index: params.index, - refresh: 'wait_for', - body: { - params, - config, - secrets, - reference: params.reference, - source: 'action:test.failing', - }, - }); - throw new Error(`expected failure for ${params.index} ${params.reference}`); - }, - }; - const rateLimitedActionType: ActionType = { - id: 'test.rate-limit', - name: 'Test: Rate Limit', - minimumLicenseRequired: 'gold', - maxAttempts: 2, - validate: { - params: schema.object({ - index: schema.string(), - reference: schema.string(), - retryAt: schema.number(), - }), - }, - async executor({ config, params, services }: ActionTypeExecutorOptions) { - await services.callCluster('index', { - index: params.index, - refresh: 'wait_for', - body: { - params, - config, - reference: params.reference, - source: 'action:test.rate-limit', - }, - }); - return { - status: 'error', - retry: new Date(params.retryAt), - actionId: '', - }; - }, - }; - const authorizationActionType: ActionType = { - id: 'test.authorization', - name: 'Test: Authorization', - minimumLicenseRequired: 'gold', - validate: { - params: schema.object({ - callClusterAuthorizationIndex: schema.string(), - savedObjectsClientType: schema.string(), - savedObjectsClientId: schema.string(), - index: schema.string(), - reference: schema.string(), - }), - }, - async executor({ params, services, actionId }: ActionTypeExecutorOptions) { - // Call cluster - let callClusterSuccess = false; - let callClusterError; - try { - await services.callCluster('index', { - index: params.callClusterAuthorizationIndex, - refresh: 'wait_for', - body: { - param1: 'test', - }, - }); - callClusterSuccess = true; - } catch (e) { - callClusterError = e; - } - // Call scoped cluster - const callScopedCluster = services.getScopedCallCluster(clusterClient); - let callScopedClusterSuccess = false; - let callScopedClusterError; - try { - await callScopedCluster('index', { - index: params.callClusterAuthorizationIndex, - refresh: 'wait_for', - body: { - param1: 'test', - }, - }); - callScopedClusterSuccess = true; - } catch (e) { - callScopedClusterError = e; - } - // Saved objects client - let savedObjectsClientSuccess = false; - let savedObjectsClientError; - try { - await services.savedObjectsClient.get( - params.savedObjectsClientType, - params.savedObjectsClientId - ); - savedObjectsClientSuccess = true; - } catch (e) { - savedObjectsClientError = e; - } - // Save the result - await services.callCluster('index', { - index: params.index, - refresh: 'wait_for', - body: { - state: { - callClusterSuccess, - callClusterError, - callScopedClusterSuccess, - callScopedClusterError, - savedObjectsClientSuccess, - savedObjectsClientError, - }, - params, - reference: params.reference, - source: 'action:test.authorization', - }, - }); - return { - actionId, - status: 'ok', - }; - }, - }; - server.newPlatform.setup.plugins.actions.registerType(noopActionType); - server.newPlatform.setup.plugins.actions.registerType(indexRecordActionType); - server.newPlatform.setup.plugins.actions.registerType(failingActionType); - server.newPlatform.setup.plugins.actions.registerType(rateLimitedActionType); - server.newPlatform.setup.plugins.actions.registerType(authorizationActionType); - - // Alert types - const alwaysFiringAlertType: AlertType = { - id: 'test.always-firing', - name: 'Test: Always Firing', - actionGroups: [ - { id: 'default', name: 'Default' }, - { id: 'other', name: 'Other' }, - ], - defaultActionGroupId: 'default', - actionVariables: { - state: [{ name: 'instanceStateValue', description: 'the instance state value' }], - context: [{ name: 'instanceContextValue', description: 'the instance context value' }], - }, - async executor(alertExecutorOptions: AlertExecutorOptions) { - const { - services, - params, - state, - alertId, - spaceId, - namespace, - name, - tags, - createdBy, - updatedBy, - } = alertExecutorOptions; - let group = 'default'; - const alertInfo = { alertId, spaceId, namespace, name, tags, createdBy, updatedBy }; - - if (params.groupsToScheduleActionsInSeries) { - const index = state.groupInSeriesIndex || 0; - group = params.groupsToScheduleActionsInSeries[index]; - } - - if (group) { - services - .alertInstanceFactory('1') - .replaceState({ instanceStateValue: true }) - .scheduleActions(group, { - instanceContextValue: true, - }); - } - await services.callCluster('index', { - index: params.index, - refresh: 'wait_for', - body: { - state, - params, - reference: params.reference, - source: 'alert:test.always-firing', - alertInfo, - }, - }); - return { - globalStateValue: true, - groupInSeriesIndex: (state.groupInSeriesIndex || 0) + 1, - }; - }, - }; - // Alert types - const cumulativeFiringAlertType: AlertType = { - id: 'test.cumulative-firing', - name: 'Test: Cumulative Firing', - actionGroups: [ - { id: 'default', name: 'Default' }, - { id: 'other', name: 'Other' }, - ], - defaultActionGroupId: 'default', - async executor(alertExecutorOptions: AlertExecutorOptions) { - const { services, state } = alertExecutorOptions; - const group = 'default'; - - const runCount = (state.runCount || 0) + 1; - - times(runCount, index => { - services - .alertInstanceFactory(`instance-${index}`) - .replaceState({ instanceStateValue: true }) - .scheduleActions(group); - }); - - return { - runCount, - }; - }, - }; - const neverFiringAlertType: AlertType = { - id: 'test.never-firing', - name: 'Test: Never firing', - actionGroups: [ - { - id: 'default', - name: 'Default', - }, - ], - defaultActionGroupId: 'default', - async executor({ services, params, state }: AlertExecutorOptions) { - await services.callCluster('index', { - index: params.index, - refresh: 'wait_for', - body: { - state, - params, - reference: params.reference, - source: 'alert:test.never-firing', - }, - }); - return { - globalStateValue: true, - }; - }, - }; - const failingAlertType: AlertType = { - id: 'test.failing', - name: 'Test: Failing', - actionGroups: [ - { - id: 'default', - name: 'Default', - }, - ], - defaultActionGroupId: 'default', - async executor({ services, params, state }: AlertExecutorOptions) { - await services.callCluster('index', { - index: params.index, - refresh: 'wait_for', - body: { - state, - params, - reference: params.reference, - source: 'alert:test.failing', - }, - }); - throw new Error('Failed to execute alert type'); - }, - }; - const authorizationAlertType: AlertType = { - id: 'test.authorization', - name: 'Test: Authorization', - actionGroups: [ - { - id: 'default', - name: 'Default', - }, - ], - defaultActionGroupId: 'default', - validate: { - params: schema.object({ - callClusterAuthorizationIndex: schema.string(), - savedObjectsClientType: schema.string(), - savedObjectsClientId: schema.string(), - index: schema.string(), - reference: schema.string(), - }), - }, - async executor({ services, params, state }: AlertExecutorOptions) { - // Call cluster - let callClusterSuccess = false; - let callClusterError; - try { - await services.callCluster('index', { - index: params.callClusterAuthorizationIndex, - refresh: 'wait_for', - body: { - param1: 'test', - }, - }); - callClusterSuccess = true; - } catch (e) { - callClusterError = e; - } - // Call scoped cluster - const callScopedCluster = services.getScopedCallCluster(clusterClient); - let callScopedClusterSuccess = false; - let callScopedClusterError; - try { - await callScopedCluster('index', { - index: params.callClusterAuthorizationIndex, - refresh: 'wait_for', - body: { - param1: 'test', - }, - }); - callScopedClusterSuccess = true; - } catch (e) { - callScopedClusterError = e; - } - // Saved objects client - let savedObjectsClientSuccess = false; - let savedObjectsClientError; - try { - await services.savedObjectsClient.get( - params.savedObjectsClientType, - params.savedObjectsClientId - ); - savedObjectsClientSuccess = true; - } catch (e) { - savedObjectsClientError = e; - } - // Save the result - await services.callCluster('index', { - index: params.index, - refresh: 'wait_for', - body: { - state: { - callClusterSuccess, - callClusterError, - callScopedClusterSuccess, - callScopedClusterError, - savedObjectsClientSuccess, - savedObjectsClientError, - }, - params, - reference: params.reference, - source: 'alert:test.authorization', - }, - }); - }, - }; - const validationAlertType: AlertType = { - id: 'test.validation', - name: 'Test: Validation', - actionGroups: [ - { - id: 'default', - name: 'Default', - }, - ], - defaultActionGroupId: 'default', - validate: { - params: schema.object({ - param1: schema.string(), - }), - }, - async executor({ services, params, state }: AlertExecutorOptions) {}, - }; - const noopAlertType: AlertType = { - id: 'test.noop', - name: 'Test: Noop', - actionGroups: [{ id: 'default', name: 'Default' }], - defaultActionGroupId: 'default', - async executor({ services, params, state }: AlertExecutorOptions) {}, - }; - const onlyContextVariablesAlertType: AlertType = { - id: 'test.onlyContextVariables', - name: 'Test: Only Context Variables', - actionGroups: [{ id: 'default', name: 'Default' }], - defaultActionGroupId: 'default', - actionVariables: { - context: [{ name: 'aContextVariable', description: 'this is a context variable' }], - }, - async executor(opts: AlertExecutorOptions) {}, - }; - const onlyStateVariablesAlertType: AlertType = { - id: 'test.onlyStateVariables', - name: 'Test: Only State Variables', - actionGroups: [{ id: 'default', name: 'Default' }], - defaultActionGroupId: 'default', - actionVariables: { - state: [{ name: 'aStateVariable', description: 'this is a state variable' }], - }, - async executor(opts: AlertExecutorOptions) {}, - }; - server.newPlatform.setup.plugins.alerting.registerType(alwaysFiringAlertType); - server.newPlatform.setup.plugins.alerting.registerType(cumulativeFiringAlertType); - server.newPlatform.setup.plugins.alerting.registerType(neverFiringAlertType); - server.newPlatform.setup.plugins.alerting.registerType(failingAlertType); - server.newPlatform.setup.plugins.alerting.registerType(validationAlertType); - server.newPlatform.setup.plugins.alerting.registerType(authorizationAlertType); - server.newPlatform.setup.plugins.alerting.registerType(noopAlertType); - server.newPlatform.setup.plugins.alerting.registerType(onlyContextVariablesAlertType); - server.newPlatform.setup.plugins.alerting.registerType(onlyStateVariablesAlertType); - }, - }); -} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/kibana.json b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/kibana.json new file mode 100644 index 0000000000000..98c57db16c914 --- /dev/null +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/kibana.json @@ -0,0 +1,10 @@ +{ + "id": "alerts-fixtures", + "version": "1.0.0", + "kibanaVersion": "kibana", + "configPath": ["xpack"], + "requiredPlugins": ["taskManager", "features", "actions", "alerting"], + "optionalPlugins": ["spaces"], + "server": true, + "ui": false +} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/package.json b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/package.json index 836fa09855d8f..53abf490ad376 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/package.json +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/package.json @@ -1,7 +1,20 @@ { - "name": "alerts", - "version": "0.0.0", + "name": "alerts-fixtures", + "version": "1.0.0", "kibana": { - "version": "kibana" + "version": "kibana", + "templateVersion": "1.0.0" + }, + "main": "target/test/plugin_api_integration/plugins/alerts", + "scripts": { + "kbn": "node ../../../../../scripts/kbn.js", + "build": "rm -rf './target' && tsc" + }, + "devDependencies": { + "typescript": "3.7.2" + }, + "license": "Apache-2.0", + "dependencies": { + "joi": "^13.5.2" } } diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/index.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/index.ts new file mode 100644 index 0000000000000..54d6de50cff4d --- /dev/null +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/index.ts @@ -0,0 +1,9 @@ +/* + * 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 { FixturePlugin } from './plugin'; + +export const plugin = () => new FixturePlugin(); diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/plugin.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/plugin.ts new file mode 100644 index 0000000000000..347695dd12beb --- /dev/null +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/plugin.ts @@ -0,0 +1,516 @@ +/* + * 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 } from 'kibana/server'; +import { schema } from '@kbn/config-schema'; +import { times } from 'lodash'; +import { PluginSetupContract as ActionsPluginSetup } from '../../../../../../../plugins/actions/server/plugin'; +import { PluginSetupContract as AlertingPluginSetup } from '../../../../../../../plugins/alerting/server/plugin'; +import { EncryptedSavedObjectsPluginStart } from '../../../../../../../plugins/encrypted_saved_objects/server'; +import { PluginSetupContract as FeaturesPluginSetup } from '../../../../../../../plugins/features/server'; +import { ActionType, ActionTypeExecutorOptions } from '../../../../../../../plugins/actions/server'; +import { AlertType, AlertExecutorOptions } from '../../../../../../../plugins/alerting/server'; + +interface FixtureSetupDeps { + features: FeaturesPluginSetup; + actions: ActionsPluginSetup; + alerting: AlertingPluginSetup; +} + +interface FixtureStartDeps { + encryptedSavedObjects: EncryptedSavedObjectsPluginStart; +} + +export class FixturePlugin implements Plugin { + public setup( + core: CoreSetup, + { features, actions, alerting }: FixtureSetupDeps + ) { + const clusterClient = core.elasticsearch.adminClient; + features.registerFeature({ + id: 'alerting', + name: 'Alerting', + app: ['alerting', 'kibana'], + privileges: { + all: { + app: ['alerting', 'kibana'], + savedObject: { + all: ['alert'], + read: [], + }, + ui: [], + api: ['alerting-read', 'alerting-all'], + }, + read: { + app: ['alerting', 'kibana'], + savedObject: { + all: [], + read: ['alert'], + }, + ui: [], + api: ['alerting-read'], + }, + }, + }); + // Action types + const noopActionType: ActionType = { + id: 'test.noop', + name: 'Test: Noop', + minimumLicenseRequired: 'gold', + async executor() { + return { status: 'ok', actionId: '' }; + }, + }; + const indexRecordActionType: ActionType = { + id: 'test.index-record', + name: 'Test: Index Record', + minimumLicenseRequired: 'gold', + validate: { + params: schema.object({ + index: schema.string(), + reference: schema.string(), + message: schema.string(), + }), + config: schema.object({ + unencrypted: schema.string(), + }), + secrets: schema.object({ + encrypted: schema.string(), + }), + }, + async executor({ config, secrets, params, services, actionId }: ActionTypeExecutorOptions) { + await services.callCluster('index', { + index: params.index, + refresh: 'wait_for', + body: { + params, + config, + secrets, + reference: params.reference, + source: 'action:test.index-record', + }, + }); + return { status: 'ok', actionId }; + }, + }; + const failingActionType: ActionType = { + id: 'test.failing', + name: 'Test: Failing', + minimumLicenseRequired: 'gold', + validate: { + params: schema.object({ + index: schema.string(), + reference: schema.string(), + }), + }, + async executor({ config, secrets, params, services }: ActionTypeExecutorOptions) { + await services.callCluster('index', { + index: params.index, + refresh: 'wait_for', + body: { + params, + config, + secrets, + reference: params.reference, + source: 'action:test.failing', + }, + }); + throw new Error(`expected failure for ${params.index} ${params.reference}`); + }, + }; + const rateLimitedActionType: ActionType = { + id: 'test.rate-limit', + name: 'Test: Rate Limit', + minimumLicenseRequired: 'gold', + maxAttempts: 2, + validate: { + params: schema.object({ + index: schema.string(), + reference: schema.string(), + retryAt: schema.number(), + }), + }, + async executor({ config, params, services }: ActionTypeExecutorOptions) { + await services.callCluster('index', { + index: params.index, + refresh: 'wait_for', + body: { + params, + config, + reference: params.reference, + source: 'action:test.rate-limit', + }, + }); + return { + status: 'error', + retry: new Date(params.retryAt), + actionId: '', + }; + }, + }; + const authorizationActionType: ActionType = { + id: 'test.authorization', + name: 'Test: Authorization', + minimumLicenseRequired: 'gold', + validate: { + params: schema.object({ + callClusterAuthorizationIndex: schema.string(), + savedObjectsClientType: schema.string(), + savedObjectsClientId: schema.string(), + index: schema.string(), + reference: schema.string(), + }), + }, + async executor({ params, services, actionId }: ActionTypeExecutorOptions) { + // Call cluster + let callClusterSuccess = false; + let callClusterError; + try { + await services.callCluster('index', { + index: params.callClusterAuthorizationIndex, + refresh: 'wait_for', + body: { + param1: 'test', + }, + }); + callClusterSuccess = true; + } catch (e) { + callClusterError = e; + } + // Call scoped cluster + const callScopedCluster = services.getScopedCallCluster(clusterClient); + let callScopedClusterSuccess = false; + let callScopedClusterError; + try { + await callScopedCluster('index', { + index: params.callClusterAuthorizationIndex, + refresh: 'wait_for', + body: { + param1: 'test', + }, + }); + callScopedClusterSuccess = true; + } catch (e) { + callScopedClusterError = e; + } + // Saved objects client + let savedObjectsClientSuccess = false; + let savedObjectsClientError; + try { + await services.savedObjectsClient.get( + params.savedObjectsClientType, + params.savedObjectsClientId + ); + savedObjectsClientSuccess = true; + } catch (e) { + savedObjectsClientError = e; + } + // Save the result + await services.callCluster('index', { + index: params.index, + refresh: 'wait_for', + body: { + state: { + callClusterSuccess, + callClusterError, + callScopedClusterSuccess, + callScopedClusterError, + savedObjectsClientSuccess, + savedObjectsClientError, + }, + params, + reference: params.reference, + source: 'action:test.authorization', + }, + }); + return { + actionId, + status: 'ok', + }; + }, + }; + actions.registerType(noopActionType); + actions.registerType(indexRecordActionType); + actions.registerType(failingActionType); + actions.registerType(rateLimitedActionType); + actions.registerType(authorizationActionType); + + const alwaysFiringAlertType: AlertType = { + id: 'test.always-firing', + name: 'Test: Always Firing', + actionGroups: [ + { id: 'default', name: 'Default' }, + { id: 'other', name: 'Other' }, + ], + defaultActionGroupId: 'default', + actionVariables: { + state: [{ name: 'instanceStateValue', description: 'the instance state value' }], + context: [{ name: 'instanceContextValue', description: 'the instance context value' }], + }, + async executor(alertExecutorOptions: AlertExecutorOptions) { + const { + services, + params, + state, + alertId, + spaceId, + namespace, + name, + tags, + createdBy, + updatedBy, + } = alertExecutorOptions; + let group = 'default'; + const alertInfo = { alertId, spaceId, namespace, name, tags, createdBy, updatedBy }; + + if (params.groupsToScheduleActionsInSeries) { + const index = state.groupInSeriesIndex || 0; + group = params.groupsToScheduleActionsInSeries[index]; + } + + if (group) { + services + .alertInstanceFactory('1') + .replaceState({ instanceStateValue: true }) + .scheduleActions(group, { + instanceContextValue: true, + }); + } + await services.callCluster('index', { + index: params.index, + refresh: 'wait_for', + body: { + state, + params, + reference: params.reference, + source: 'alert:test.always-firing', + alertInfo, + }, + }); + return { + globalStateValue: true, + groupInSeriesIndex: (state.groupInSeriesIndex || 0) + 1, + }; + }, + }; + // Alert types + const cumulativeFiringAlertType: AlertType = { + id: 'test.cumulative-firing', + name: 'Test: Cumulative Firing', + actionGroups: [ + { id: 'default', name: 'Default' }, + { id: 'other', name: 'Other' }, + ], + defaultActionGroupId: 'default', + async executor(alertExecutorOptions: AlertExecutorOptions) { + const { services, state } = alertExecutorOptions; + const group = 'default'; + + const runCount = (state.runCount || 0) + 1; + + times(runCount, index => { + services + .alertInstanceFactory(`instance-${index}`) + .replaceState({ instanceStateValue: true }) + .scheduleActions(group); + }); + + return { + runCount, + }; + }, + }; + const neverFiringAlertType: AlertType = { + id: 'test.never-firing', + name: 'Test: Never firing', + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', + async executor({ services, params, state }: AlertExecutorOptions) { + await services.callCluster('index', { + index: params.index, + refresh: 'wait_for', + body: { + state, + params, + reference: params.reference, + source: 'alert:test.never-firing', + }, + }); + return { + globalStateValue: true, + }; + }, + }; + const failingAlertType: AlertType = { + id: 'test.failing', + name: 'Test: Failing', + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', + async executor({ services, params, state }: AlertExecutorOptions) { + await services.callCluster('index', { + index: params.index, + refresh: 'wait_for', + body: { + state, + params, + reference: params.reference, + source: 'alert:test.failing', + }, + }); + throw new Error('Failed to execute alert type'); + }, + }; + const authorizationAlertType: AlertType = { + id: 'test.authorization', + name: 'Test: Authorization', + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', + validate: { + params: schema.object({ + callClusterAuthorizationIndex: schema.string(), + savedObjectsClientType: schema.string(), + savedObjectsClientId: schema.string(), + index: schema.string(), + reference: schema.string(), + }), + }, + async executor({ services, params, state }: AlertExecutorOptions) { + // Call cluster + let callClusterSuccess = false; + let callClusterError; + try { + await services.callCluster('index', { + index: params.callClusterAuthorizationIndex, + refresh: 'wait_for', + body: { + param1: 'test', + }, + }); + callClusterSuccess = true; + } catch (e) { + callClusterError = e; + } + // Call scoped cluster + const callScopedCluster = services.getScopedCallCluster(clusterClient); + let callScopedClusterSuccess = false; + let callScopedClusterError; + try { + await callScopedCluster('index', { + index: params.callClusterAuthorizationIndex, + refresh: 'wait_for', + body: { + param1: 'test', + }, + }); + callScopedClusterSuccess = true; + } catch (e) { + callScopedClusterError = e; + } + // Saved objects client + let savedObjectsClientSuccess = false; + let savedObjectsClientError; + try { + await services.savedObjectsClient.get( + params.savedObjectsClientType, + params.savedObjectsClientId + ); + savedObjectsClientSuccess = true; + } catch (e) { + savedObjectsClientError = e; + } + // Save the result + await services.callCluster('index', { + index: params.index, + refresh: 'wait_for', + body: { + state: { + callClusterSuccess, + callClusterError, + callScopedClusterSuccess, + callScopedClusterError, + savedObjectsClientSuccess, + savedObjectsClientError, + }, + params, + reference: params.reference, + source: 'alert:test.authorization', + }, + }); + }, + }; + const validationAlertType: AlertType = { + id: 'test.validation', + name: 'Test: Validation', + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', + validate: { + params: schema.object({ + param1: schema.string(), + }), + }, + async executor({ services, params, state }: AlertExecutorOptions) {}, + }; + const noopAlertType: AlertType = { + id: 'test.noop', + name: 'Test: Noop', + actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', + async executor({ services, params, state }: AlertExecutorOptions) {}, + }; + const onlyContextVariablesAlertType: AlertType = { + id: 'test.onlyContextVariables', + name: 'Test: Only Context Variables', + actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', + actionVariables: { + context: [{ name: 'aContextVariable', description: 'this is a context variable' }], + }, + async executor(opts: AlertExecutorOptions) {}, + }; + const onlyStateVariablesAlertType: AlertType = { + id: 'test.onlyStateVariables', + name: 'Test: Only State Variables', + actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', + actionVariables: { + state: [{ name: 'aStateVariable', description: 'this is a state variable' }], + }, + async executor(opts: AlertExecutorOptions) {}, + }; + alerting.registerType(alwaysFiringAlertType); + alerting.registerType(cumulativeFiringAlertType); + alerting.registerType(neverFiringAlertType); + alerting.registerType(failingAlertType); + alerting.registerType(validationAlertType); + alerting.registerType(authorizationAlertType); + alerting.registerType(noopAlertType); + alerting.registerType(onlyContextVariablesAlertType); + alerting.registerType(onlyStateVariablesAlertType); + } + + public start() {} + public stop() {} +} 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 deleted file mode 100644 index ac32f05805e4a..0000000000000 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager/index.ts +++ /dev/null @@ -1,60 +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 { TaskManagerStartContract } from '../../../../../../plugins/task_manager/server'; - -const taskManagerQuery = (...filters: any[]) => ({ - bool: { - filter: { - bool: { - must: filters, - }, - }, - }, -}); - -const tasksForAlerting = { - term: { - 'task.scope': 'alerting', - }, -}; -const taskByIdQuery = (id: string) => ({ - ids: { - values: [`task:${id}`], - }, -}); - -// eslint-disable-next-line import/no-default-export -export default function(kibana: any) { - return new kibana.Plugin({ - name: 'taskManagerHelpers', - require: ['elasticsearch'], - - config(Joi: any) { - return Joi.object({ - enabled: Joi.boolean().default(true), - }).default(); - }, - - init(server: any) { - const taskManager = server.newPlatform.start.plugins.taskManager as TaskManagerStartContract; - - server.route({ - path: '/api/alerting_tasks/{taskId}', - method: 'GET', - async handler(request: any) { - try { - return taskManager.fetch({ - query: taskManagerQuery(tasksForAlerting, taskByIdQuery(request.params.taskId)), - }); - } catch (err) { - return err; - } - }, - }); - }, - }); -} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager/package.json b/x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager/package.json deleted file mode 100644 index 532b597829561..0000000000000 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager/package.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "alerting_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/alerting_api_integration/common/fixtures/plugins/task_manager_fixture/kibana.json b/x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager_fixture/kibana.json new file mode 100644 index 0000000000000..8f606276998f5 --- /dev/null +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager_fixture/kibana.json @@ -0,0 +1,9 @@ +{ + "id": "task_manager_fixture", + "version": "1.0.0", + "kibanaVersion": "kibana", + "configPath": ["xpack"], + "requiredPlugins": ["taskManager"], + "server": true, + "ui": false +} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager_fixture/package.json b/x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager_fixture/package.json new file mode 100644 index 0000000000000..be3b542ed7b52 --- /dev/null +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager_fixture/package.json @@ -0,0 +1,20 @@ +{ + "name": "task_manager_fixture", + "version": "1.0.0", + "kibana": { + "version": "kibana", + "templateVersion": "1.0.0" + }, + "main": "target/test/plugin_api_integration/plugins/task_manager_fixture", + "scripts": { + "kbn": "node ../../../../../scripts/kbn.js", + "build": "rm -rf './target' && tsc" + }, + "devDependencies": { + "typescript": "3.7.2" + }, + "license": "Apache-2.0", + "dependencies": { + "joi": "^13.5.2" + } +} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager_fixture/server/index.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager_fixture/server/index.ts new file mode 100644 index 0000000000000..77233f463734a --- /dev/null +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager_fixture/server/index.ts @@ -0,0 +1,9 @@ +/* + * 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 { SampleTaskManagerFixturePlugin } from './plugin'; + +export const plugin = () => new SampleTaskManagerFixturePlugin(); diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager_fixture/server/plugin.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager_fixture/server/plugin.ts new file mode 100644 index 0000000000000..18fdd5f9c3ac3 --- /dev/null +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager_fixture/server/plugin.ts @@ -0,0 +1,87 @@ +/* + * 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, + RequestHandlerContext, + KibanaRequest, + KibanaResponseFactory, + IKibanaResponse, +} from 'kibana/server'; +import { Subject } from 'rxjs'; +import { first } from 'rxjs/operators'; +import { schema } from '@kbn/config-schema'; +import { TaskManagerStartContract } from '../../../../../../../plugins/task_manager/server'; + +export interface SampleTaskManagerFixtureStartDeps { + taskManager: TaskManagerStartContract; +} + +const taskManagerQuery = (...filters: any[]) => ({ + bool: { + filter: { + bool: { + must: filters, + }, + }, + }, +}); + +const tasksForAlerting = { + term: { + 'task.scope': 'alerting', + }, +}; +const taskByIdQuery = (id: string) => ({ + ids: { + values: [`task:${id}`], + }, +}); + +export class SampleTaskManagerFixturePlugin + implements Plugin { + taskManagerStart$: Subject = new Subject(); + taskManagerStart: Promise = this.taskManagerStart$ + .pipe(first()) + .toPromise(); + + public setup(core: CoreSetup) { + core.http.createRouter().get( + { + path: '/api/alerting_tasks/{taskId}', + validate: { + params: schema.object({ + taskId: schema.string(), + }), + }, + }, + async ( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise> => { + try { + const taskManager = await this.taskManagerStart; + return res.ok({ + body: await taskManager.fetch({ + query: taskManagerQuery(tasksForAlerting, taskByIdQuery(req.params.taskId)), + }), + }); + } catch (err) { + return res.badRequest({ body: err }); + } + } + ); + } + + public start(core: CoreStart, { taskManager }: SampleTaskManagerFixtureStartDeps) { + this.taskManagerStart$.next(taskManager); + this.taskManagerStart$.complete(); + } + public stop() {} +} diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/jira.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/jira.ts index ed63d25d86aca..c67f7868f7ff0 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/jira.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/jira.ts @@ -11,7 +11,7 @@ import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { getExternalServiceSimulatorPath, ExternalServiceSimulator, -} from '../../../../common/fixtures/plugins/actions_simulators'; +} from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; const mapping = [ { 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 4c76ebfb93b0b..443d3acb7ba1c 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_simulators'; +} from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; // 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 04cd06999f432..c69eead75e278 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_simulators'; +} from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; const mapping = [ { 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 386254e49c19c..e522b8c7b898d 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_simulators'; +} from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; // 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 9b66326fa6157..9c769897d35ee 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_simulators'; +} from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; 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 112149a32649a..22e1284f55aa8 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_simulators'; +} from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; // eslint-disable-next-line import/no-default-export export default function webhookTest({ getService }: FtrProviderContext) { diff --git a/x-pack/test/plugin_api_perf/config.js b/x-pack/test/plugin_api_perf/config.js index 9a7d0071afcc4..9c6d8873b8c84 100644 --- a/x-pack/test/plugin_api_perf/config.js +++ b/x-pack/test/plugin_api_perf/config.js @@ -39,7 +39,7 @@ export default async function({ readConfigFile }) { '..', 'plugin_api_integration', 'plugins', - 'task_manager' + 'sample_task_plugin' )}`, ...plugins.map( pluginDir => `--plugin-path=${path.resolve(__dirname, 'plugins', pluginDir)}` diff --git a/x-pack/test/plugin_api_perf/plugins/task_manager_performance/index.js b/x-pack/test/plugin_api_perf/plugins/task_manager_performance/index.js deleted file mode 100644 index 87e3b3b66a201..0000000000000 --- a/x-pack/test/plugin_api_perf/plugins/task_manager_performance/index.js +++ /dev/null @@ -1,378 +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 uuid from 'uuid'; -import _ from 'lodash'; -import stats from 'stats-lite'; -import prettyMilliseconds from 'pretty-ms'; -import { performance, PerformanceObserver } from 'perf_hooks'; -import { initRoutes } from './init_routes'; - -export default function TaskManagerPerformanceAPI(kibana) { - return new kibana.Plugin({ - name: 'perfTask', - 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 performanceState = resetPerfState({}); - - let lastFlush = new Date(); - function flushPerfStats() { - setTimeout(flushPerfStats, 5000); - const prevFlush = lastFlush; - lastFlush = new Date(); - - const tasks = performanceState.leadTimeQueue.length; - const title = `[Perf${performanceState.capturing ? ' (capturing)' : ''}]`; - const seconds = parseInt((lastFlush - prevFlush) / 1000); - console.log( - `${title} I have processed ${tasks} tasks in the past ${seconds}s (${tasks / - seconds} per second)` - ); - if (tasks > 0) { - const latestAverage = avg(performanceState.leadTimeQueue.splice(0, tasks)).mean; - - performanceState.averagesTakenLeadTime.push(latestAverage); - performanceState.averagesTaken.push(tasks); - if (performanceState.averagesTakenLeadTime.length > 1) { - performanceState.runningAverageLeadTime = avg( - performanceState.averagesTakenLeadTime - ).mean; - performanceState.runningAverageTasksPerSecond = - avg(performanceState.averagesTaken).mean / 5; - } else { - performanceState.runningAverageLeadTime = latestAverage; - performanceState.runningAverageTasksPerSecond = tasks / 5; - } - } - } - - setTimeout(flushPerfStats, 5000); - - const title = 'Perf Test Task'; - - taskManager.registerTaskDefinitions({ - performanceTestTask: { - title, - description: 'A task for stress testing task_manager.', - timeout: '1m', - - createTaskRunner: ({ taskInstance }) => { - return { - async run() { - const { params, state } = taskInstance; - - const counter = state.counter ? state.counter : 1; - - const now = Date.now(); - const leadTime = now - taskInstance.runAt; - performanceState.leadTimeQueue.push(leadTime); - - // schedule to run next cycle as soon as possible - const runAt = calRunAt(params, counter); - - const stateUpdated = { - ...state, - counter: counter + 1, - }; - - if (params.trackExecutionTimeline && state.perf && state.perf.id) { - performance.mark(`perfTask_run_${state.perf.id}_${counter}`); - performance.measure( - 'perfTask.markUntilRun', - `perfTask_markAsRunning_${state.perf.id}_${counter}`, - `perfTask_run_${state.perf.id}_${counter}` - ); - if (counter === 1) { - performance.measure( - 'perfTask.firstRun', - `perfTask_schedule_${state.perf.id}`, - `perfTask_run_${state.perf.id}_${counter}` - ); - performance.measure( - 'perfTask.firstMarkAsRunningTillRan', - `perfTask_markAsRunning_${state.perf.id}_${counter}`, - `perfTask_run_${state.perf.id}_${counter}` - ); - } - } - - return { - state: stateUpdated, - runAt, - }; - }, - }; - }, - }, - }); - - taskManager.addMiddleware({ - async beforeSave({ taskInstance, ...opts }) { - const modifiedInstance = { - ...taskInstance, - }; - - if (taskInstance.params && taskInstance.params.trackExecutionTimeline) { - modifiedInstance.state = modifiedInstance.state || {}; - modifiedInstance.state.perf = modifiedInstance.state.perf || {}; - modifiedInstance.state.perf.id = uuid.v4().replace(/-/gi, '_'); - performance.mark(`perfTask_schedule_${modifiedInstance.state.perf.id}`); - } - - return { - ...opts, - taskInstance: modifiedInstance, - }; - }, - - async beforeMarkRunning({ taskInstance, ...opts }) { - const modifiedInstance = { - ...taskInstance, - }; - - if ( - modifiedInstance.state && - modifiedInstance.state.perf && - modifiedInstance.state.perf.id - ) { - const { counter = 1 } = modifiedInstance.state; - performance.mark(`perfTask_markAsRunning_${modifiedInstance.state.perf.id}_${counter}`); - if (counter === 1) { - performance.measure( - 'perfTask.firstMarkAsRunning', - `perfTask_schedule_${modifiedInstance.state.perf.id}`, - `perfTask_markAsRunning_${modifiedInstance.state.perf.id}_${counter}` - ); - } else if (counter > 1) { - performance.measure( - 'perfTask.runUntilNextMarkAsRunning', - `perfTask_run_${modifiedInstance.state.perf.id}_${counter - 1}`, - `perfTask_markAsRunning_${modifiedInstance.state.perf.id}_${counter}` - ); - } - } - - return { - ...opts, - taskInstance: modifiedInstance, - }; - }, - }); - - const perfApi = { - capture() { - resetPerfState(performanceState); - performanceState.capturing = true; - performance.mark('perfTest.start'); - }, - endCapture() { - return new Promise(resolve => { - performanceState.performance.summarize.push([resolve, perfApi.summarize]); - - performance.mark('perfTest.end'); - performance.measure('perfTest.duration', 'perfTest.start', 'perfTest.end'); - }); - }, - summarize(perfTestDuration) { - const { - runningAverageTasksPerSecond, - runningAverageLeadTime, - performance, - } = performanceState; - - const { - numberOfTasksRanOverall, - elasticsearchApiCalls, - activityDuration, - sleepDuration, - cycles, - claimAvailableTasksNoTasks, - claimAvailableTasksNoAvailableWorkers, - taskPoolAttemptToRun, - taskRunnerMarkTaskAsRunning, - } = performance; - - const perfRes = { - perfTestDuration: prettyMilliseconds(perfTestDuration), - runningAverageTasksPerSecond, - runningAverageLeadTime, - numberOfTasksRanOverall, - claimAvailableTasksNoTasks, - claimAvailableTasksNoAvailableWorkers, - elasticsearchApiCalls: _.mapValues(elasticsearchApiCalls, avg), - sleepDuration: prettyMilliseconds(stats.sum(sleepDuration)), - activityDuration: prettyMilliseconds(stats.sum(activityDuration)), - cycles, - taskPoolAttemptToRun: avg(taskPoolAttemptToRun), - taskRunnerMarkTaskAsRunning: avg(taskRunnerMarkTaskAsRunning), - }; - - resetPerfState(performanceState); - - return perfRes; - }, - }; - - initRoutes(server, perfApi); - }, - }); -} - -function calRunAt(params, counter) { - const runAt = counter === 1 ? new Date(params.startAt) : new Date(); - return runAt.getTime() < params.runUntil ? runAt : undefined; -} - -function avg(items) { - const mode = stats.mode(items); - return { - mean: parseInt(stats.mean(items)), - range: { - min: parseInt(typeof mode === 'number' ? mode : _.min([...mode])), - max: parseInt(typeof mode === 'number' ? mode : _.max([...mode])), - }, - }; -} - -function resetPerfState(target) { - if (target.performanceObserver) { - target.performanceObserver.disconnect(); - } - - const performanceState = Object.assign(target, { - capturing: false, - runningAverageTasksPerSecond: 0, - averagesTaken: [], - runningAverageLeadTime: -1, - averagesTakenLeadTime: [], - leadTimeQueue: [], - performance: { - numberOfTasksRanOverall: 0, - cycles: { - fillPoolStarts: 0, - fillPoolCycles: 0, - fillPoolBail: 0, - claimedOnRerunCycle: 0, - fillPoolBailNoTasks: 0, - }, - claimAvailableTasksNoTasks: 0, - claimAvailableTasksNoAvailableWorkers: 0, - elasticsearchApiCalls: { - timeUntilFirstRun: [], - timeUntilFirstMarkAsRun: [], - firstMarkAsRunningTillRan: [], - timeFromMarkAsRunTillRun: [], - timeFromRunTillNextMarkAsRun: [], - claimAvailableTasks: [], - }, - activityDuration: [], - sleepDuration: [], - taskPollerActivityDurationPreScheduleComplete: [], - taskPoolAttemptToRun: [], - taskRunnerMarkTaskAsRunning: [], - - summarize: [], - }, - }); - - performanceState.performanceObserver = new PerformanceObserver((list, observer) => { - list.getEntries().forEach(entry => { - const { name, duration } = entry; - switch (name) { - // Elasticsearch Api Calls - case 'perfTask.firstRun': - performanceState.performance.elasticsearchApiCalls.timeUntilFirstRun.push(duration); - break; - case 'perfTask.firstMarkAsRunning': - performanceState.performance.elasticsearchApiCalls.timeUntilFirstMarkAsRun.push(duration); - break; - case 'perfTask.firstMarkAsRunningTillRan': - performanceState.performance.elasticsearchApiCalls.firstMarkAsRunningTillRan.push( - duration - ); - break; - case 'perfTask.markUntilRun': - performanceState.performance.elasticsearchApiCalls.timeFromMarkAsRunTillRun.push( - duration - ); - break; - case 'perfTask.runUntilNextMarkAsRunning': - performanceState.performance.elasticsearchApiCalls.timeFromRunTillNextMarkAsRun.push( - duration - ); - break; - case 'claimAvailableTasks': - performanceState.performance.elasticsearchApiCalls.claimAvailableTasks.push(duration); - break; - case 'TaskPoller.sleepDuration': - performanceState.performance.sleepDuration.push(duration); - break; - case 'fillPool.activityDurationUntilNoTasks': - performanceState.performance.activityDuration.push(duration); - break; - case 'fillPool.activityDurationUntilExhaustedCapacity': - performanceState.performance.activityDuration.push(duration); - break; - case 'fillPool.bailExhaustedCapacity': - performanceState.performance.cycles.fillPoolBail++; - break; - case 'fillPool.claimedOnRerunCycle': - performanceState.performance.cycles.claimedOnRerunCycle++; - break; - case 'fillPool.bailNoTasks': - performanceState.performance.cycles.fillPoolBail++; - performanceState.performance.cycles.fillPoolBailNoTasks++; - break; - case 'fillPool.start': - performanceState.performance.cycles.fillPoolStarts++; - break; - case 'fillPool.cycle': - performanceState.performance.cycles.fillPoolCycles++; - break; - break; - case 'claimAvailableTasks.noTasks': - performanceState.performance.claimAvailableTasksNoTasks++; - break; - case 'claimAvailableTasks.noAvailableWorkers': - performanceState.performance.claimAvailableTasksNoAvailableWorkers++; - break; - case 'taskPool.attemptToRun': - performanceState.performance.taskPoolAttemptToRun.push(duration); - break; - case 'taskRunner.markTaskAsRunning': - performanceState.performance.taskRunnerMarkTaskAsRunning.push(duration); - break; - case 'perfTest.duration': - observer.disconnect(); - const { summarize } = performanceState.performance; - if (summarize && summarize.length) { - summarize.splice(0, summarize.length).forEach(([resolve, summarize]) => { - resolve(summarize(duration)); - }); - } - break; - default: - if (name.startsWith('perfTask_run_')) { - performanceState.performance.numberOfTasksRanOverall++; - } - } - }); - }); - performanceState.performanceObserver.observe({ entryTypes: ['measure', 'mark'] }); - - return performanceState; -} diff --git a/x-pack/test/plugin_api_perf/plugins/task_manager_performance/init_routes.js b/x-pack/test/plugin_api_perf/plugins/task_manager_performance/init_routes.js deleted file mode 100644 index 6cd706a6ebecd..0000000000000 --- a/x-pack/test/plugin_api_perf/plugins/task_manager_performance/init_routes.js +++ /dev/null @@ -1,77 +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'; -import { range, chunk } from 'lodash'; - -const scope = 'perf-testing'; -export function initRoutes(server, performanceState) { - const taskManager = { - ...server.newPlatform.setup.plugins.taskManager, - ...server.newPlatform.start.plugins.taskManager, - }; - - server.route({ - path: '/api/perf_tasks', - method: 'POST', - config: { - validate: { - payload: Joi.object({ - tasksToSpawn: Joi.number().required(), - durationInSeconds: Joi.number().required(), - trackExecutionTimeline: Joi.boolean() - .default(false) - .required(), - }), - }, - }, - async handler(request) { - performanceState.capture(); - - const { tasksToSpawn, durationInSeconds, trackExecutionTimeline } = request.payload; - const startAt = millisecondsFromNow(5000).getTime(); - await chunk(range(tasksToSpawn), 200) - .map(chunkOfTasksToSpawn => () => - Promise.all( - chunkOfTasksToSpawn.map(taskIndex => - taskManager.schedule( - { - taskType: 'performanceTestTask', - params: { - startAt, - taskIndex, - trackExecutionTimeline, - runUntil: millisecondsFromNow(durationInSeconds * 1000).getTime(), - }, - scope: [scope], - }, - { request } - ) - ) - ) - ) - .reduce((chain, nextExecutor) => { - return chain.then(() => nextExecutor()); - }, Promise.resolve()); - - return new Promise(resolve => { - setTimeout(() => { - performanceState.endCapture().then(resolve); - }, durationInSeconds * 1000 + 10000 /* wait extra 10s to drain queue */); - }); - }, - }); -} - -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_perf/plugins/task_manager_performance/kibana.json b/x-pack/test/plugin_api_perf/plugins/task_manager_performance/kibana.json new file mode 100644 index 0000000000000..1fa480cd53c48 --- /dev/null +++ b/x-pack/test/plugin_api_perf/plugins/task_manager_performance/kibana.json @@ -0,0 +1,9 @@ +{ + "id": "task_manager_performance", + "version": "1.0.0", + "kibanaVersion": "kibana", + "configPath": ["xpack"], + "requiredPlugins": ["taskManager"], + "server": true, + "ui": false +} diff --git a/x-pack/test/plugin_api_perf/plugins/task_manager_performance/package.json b/x-pack/test/plugin_api_perf/plugins/task_manager_performance/package.json index 7d46d6b0f3cca..9cb3859271d81 100644 --- a/x-pack/test/plugin_api_perf/plugins/task_manager_performance/package.json +++ b/x-pack/test/plugin_api_perf/plugins/task_manager_performance/package.json @@ -1,16 +1,23 @@ { - "name": "perf_task_plugin", + "name": "task_manager_performance", "version": "1.0.0", "kibana": { "version": "kibana", "templateVersion": "1.0.0" }, - "license": "Apache-2.0", + "main": "target/test/plugin_api_perf/plugins/task_manager_performance", + "scripts": { + "kbn": "node ../../../../../scripts/kbn.js", + "build": "rm -rf './target' && tsc" + }, "dependencies": { "lodash": "^4.17.15", "uuid": "3.3.2", - "joi": "^13.5.2", "stats-lite": "2.2.0", "pretty-ms": "5.0.0" - } + }, + "devDependencies": { + "typescript": "3.7.2" + }, + "license": "Apache-2.0" } diff --git a/x-pack/test/plugin_api_perf/plugins/task_manager_performance/server/index.ts b/x-pack/test/plugin_api_perf/plugins/task_manager_performance/server/index.ts new file mode 100644 index 0000000000000..77233f463734a --- /dev/null +++ b/x-pack/test/plugin_api_perf/plugins/task_manager_performance/server/index.ts @@ -0,0 +1,9 @@ +/* + * 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 { SampleTaskManagerFixturePlugin } from './plugin'; + +export const plugin = () => new SampleTaskManagerFixturePlugin(); diff --git a/x-pack/test/plugin_api_perf/plugins/task_manager_performance/server/init_routes.ts b/x-pack/test/plugin_api_perf/plugins/task_manager_performance/server/init_routes.ts new file mode 100644 index 0000000000000..947cc0743e2f8 --- /dev/null +++ b/x-pack/test/plugin_api_perf/plugins/task_manager_performance/server/init_routes.ts @@ -0,0 +1,92 @@ +/* + * 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 { range, chunk } from 'lodash'; +import { + TaskManagerStartContract, + ConcreteTaskInstance, +} from '../../../../../plugins/task_manager/server'; +import { PerfApi, PerfResult } from './types'; + +const scope = 'perf-testing'; + +export function initRoutes( + router: IRouter, + core: CoreSetup, + taskManagerStart: Promise, + performanceApi: PerfApi +) { + router.post( + { + path: '/api/perf_tasks', + validate: { + body: schema.object({ + tasksToSpawn: schema.number(), + durationInSeconds: schema.number(), + trackExecutionTimeline: schema.boolean({ defaultValue: false }), + }), + }, + }, + async function( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise> { + performanceApi.capture(); + + const taskManager = await taskManagerStart; + + const { tasksToSpawn, durationInSeconds, trackExecutionTimeline } = req.body; + const startAt = millisecondsFromNow(5000).getTime(); + await chunk(range(tasksToSpawn), 200) + .map(chunkOfTasksToSpawn => () => + Promise.all( + chunkOfTasksToSpawn.map(async taskIndex => + taskManager.schedule( + { + taskType: 'performanceTestTask', + params: { + startAt, + taskIndex, + trackExecutionTimeline, + runUntil: millisecondsFromNow(durationInSeconds * 1000).getTime(), + }, + state: {}, + scope: [scope], + }, + { request: req } + ) + ) + ) + ) + .reduce((chain, nextExecutor) => { + return chain.then(() => nextExecutor()); + }, Promise.resolve(undefined)); + + return res.ok({ + body: await new Promise(resolve => { + setTimeout(() => { + performanceApi.endCapture().then((perf: PerfResult) => resolve(perf)); + }, durationInSeconds * 1000 + 10000 /* wait extra 10s to drain queue */); + }), + }); + } + ); +} + +function millisecondsFromNow(ms: number): Date { + const dt = new Date(); + dt.setTime(dt.getTime() + ms); + return dt; +} diff --git a/x-pack/test/plugin_api_perf/plugins/task_manager_performance/server/plugin.ts b/x-pack/test/plugin_api_perf/plugins/task_manager_performance/server/plugin.ts new file mode 100644 index 0000000000000..dad17b32b33f4 --- /dev/null +++ b/x-pack/test/plugin_api_perf/plugins/task_manager_performance/server/plugin.ts @@ -0,0 +1,404 @@ +/* + * 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 { Subject } from 'rxjs'; +import { first } from 'rxjs/operators'; + +import uuid from 'uuid'; +import _ from 'lodash'; +import stats from 'stats-lite'; +import prettyMilliseconds from 'pretty-ms'; +import { performance, PerformanceObserver } from 'perf_hooks'; +import { + TaskManagerSetupContract, + TaskManagerStartContract, + ConcreteTaskInstance, +} from '../../../../../plugins/task_manager/server'; +import { PerfState, PerfApi, PerfResult } from './types'; +import { initRoutes } from './init_routes'; + +// 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 performanceState = resetPerfState({}); + + let lastFlush = new Date(); + function flushPerfStats() { + setTimeout(flushPerfStats, 5000); + const prevFlush = lastFlush; + lastFlush = new Date(); + + const tasks = performanceState.leadTimeQueue.length; + const title = `[Perf${performanceState.capturing ? ' (capturing)' : ''}]`; + const seconds = Math.round((lastFlush.getTime() - prevFlush.getTime()) / 1000); + // eslint-disable-next-line no-console + console.log( + `${title} I have processed ${tasks} tasks in the past ${seconds}s (${tasks / + seconds} per second)` + ); + if (tasks > 0) { + const latestAverage = avg(performanceState.leadTimeQueue.splice(0, tasks)).mean; + + performanceState.averagesTakenLeadTime.push(latestAverage); + performanceState.averagesTaken.push(tasks); + if (performanceState.averagesTakenLeadTime.length > 1) { + performanceState.runningAverageLeadTime = avg( + performanceState.averagesTakenLeadTime + ).mean; + performanceState.runningAverageTasksPerSecond = + avg(performanceState.averagesTaken).mean / 5; + } else { + performanceState.runningAverageLeadTime = latestAverage; + performanceState.runningAverageTasksPerSecond = tasks / 5; + } + } + } + + setTimeout(flushPerfStats, 5000); + + const title = 'Perf Test Task'; + + taskManager.registerTaskDefinitions({ + performanceTestTask: { + type: 'performanceTestTask', + title, + description: 'A task for stress testing task_manager.', + timeout: '1m', + + createTaskRunner: ({ taskInstance }: { taskInstance: ConcreteTaskInstance }) => { + return { + async run() { + const { params, state } = taskInstance; + + const counter = state.counter ? state.counter : 1; + + const now = Date.now(); + const leadTime = now - taskInstance.runAt.getTime(); + performanceState.leadTimeQueue.push(leadTime); + + // schedule to run next cycle as soon as possible + const runAt = calRunAt(params, counter); + + const stateUpdated = { + ...state, + counter: counter + 1, + }; + + if (params.trackExecutionTimeline && state.perf && state.perf.id) { + performance.mark(`perfTask_run_${state.perf.id}_${counter}`); + performance.measure( + 'perfTask.markUntilRun', + `perfTask_markAsRunning_${state.perf.id}_${counter}`, + `perfTask_run_${state.perf.id}_${counter}` + ); + if (counter === 1) { + performance.measure( + 'perfTask.firstRun', + `perfTask_schedule_${state.perf.id}`, + `perfTask_run_${state.perf.id}_${counter}` + ); + performance.measure( + 'perfTask.firstMarkAsRunningTillRan', + `perfTask_markAsRunning_${state.perf.id}_${counter}`, + `perfTask_run_${state.perf.id}_${counter}` + ); + } + } + + return { + state: stateUpdated, + runAt, + }; + }, + }; + }, + }, + }); + + taskManager.addMiddleware({ + async beforeSave({ taskInstance, ...opts }) { + const modifiedInstance = { + ...taskInstance, + }; + + if (taskInstance.params && taskInstance.params.trackExecutionTimeline) { + modifiedInstance.state = modifiedInstance.state || {}; + modifiedInstance.state.perf = modifiedInstance.state.perf || {}; + modifiedInstance.state.perf.id = uuid.v4().replace(/-/gi, '_'); + performance.mark(`perfTask_schedule_${modifiedInstance.state.perf.id}`); + } + + return { + ...opts, + taskInstance: modifiedInstance, + }; + }, + + async beforeRun(opts) { + return opts; + }, + + async beforeMarkRunning({ taskInstance, ...opts }) { + const modifiedInstance = { + ...taskInstance, + }; + + if ( + modifiedInstance.state && + modifiedInstance.state.perf && + modifiedInstance.state.perf.id + ) { + const { counter = 1 } = modifiedInstance.state; + performance.mark(`perfTask_markAsRunning_${modifiedInstance.state.perf.id}_${counter}`); + if (counter === 1) { + performance.measure( + 'perfTask.firstMarkAsRunning', + `perfTask_schedule_${modifiedInstance.state.perf.id}`, + `perfTask_markAsRunning_${modifiedInstance.state.perf.id}_${counter}` + ); + } else if (counter > 1) { + performance.measure( + 'perfTask.runUntilNextMarkAsRunning', + `perfTask_run_${modifiedInstance.state.perf.id}_${counter - 1}`, + `perfTask_markAsRunning_${modifiedInstance.state.perf.id}_${counter}` + ); + } + } + + return { + ...opts, + taskInstance: modifiedInstance, + }; + }, + }); + + const perfApi: PerfApi = { + capture() { + resetPerfState(performanceState); + performanceState.capturing = true; + performance.mark('perfTest.start'); + }, + endCapture() { + return new Promise(resolve => { + performanceState.performance.summarize.push([resolve, perfApi.summarize]); + + performance.mark('perfTest.end'); + performance.measure('perfTest.duration', 'perfTest.start', 'perfTest.end'); + }); + }, + summarize(perfTestDuration: number) { + const { + runningAverageTasksPerSecond, + runningAverageLeadTime, + performance: { + numberOfTasksRanOverall, + elasticsearchApiCalls, + activityDuration, + sleepDuration, + cycles, + claimAvailableTasksNoTasks, + claimAvailableTasksNoAvailableWorkers, + taskPoolAttemptToRun, + taskRunnerMarkTaskAsRunning, + }, + } = performanceState; + + const perfRes: PerfResult = { + perfTestDuration: prettyMilliseconds(perfTestDuration), + runningAverageTasksPerSecond, + runningAverageLeadTime, + numberOfTasksRanOverall, + claimAvailableTasksNoTasks, + claimAvailableTasksNoAvailableWorkers, + elasticsearchApiCalls: (_.mapValues( + elasticsearchApiCalls, + avg + ) as unknown) as PerfResult['elasticsearchApiCalls'], + sleepDuration: prettyMilliseconds(stats.sum(sleepDuration)), + activityDuration: prettyMilliseconds(stats.sum(activityDuration)), + cycles, + taskPoolAttemptToRun: avg(taskPoolAttemptToRun), + taskRunnerMarkTaskAsRunning: avg(taskRunnerMarkTaskAsRunning), + }; + + resetPerfState(performanceState); + + return perfRes; + }, + }; + initRoutes(core.http.createRouter(), core, this.taskManagerStart, perfApi); + } + + public start(core: CoreStart, { taskManager }: SampleTaskManagerFixtureStartDeps) { + this.taskManagerStart$.next(taskManager); + this.taskManagerStart$.complete(); + } + public stop() {} +} + +function calRunAt(params: ConcreteTaskInstance['params'], counter: number) { + const runAt = counter === 1 ? new Date(params.startAt) : new Date(); + return runAt.getTime() < params.runUntil ? runAt : undefined; +} + +function avg(items: number[]) { + const mode = stats.mode(items); + return { + mean: Math.round(stats.mean(items)), + range: { + min: Math.round(isNumericArray(mode) ? _.min([...mode]) : mode), + max: Math.round(isNumericArray(mode) ? _.max([...mode]) : mode), + }, + }; +} + +function isNumericArray(mode: unknown): mode is number[] { + return Array.isArray(mode); +} + +function resetPerfState(target: Partial): PerfState { + if (target.performanceObserver) { + target.performanceObserver.disconnect(); + } + + const performanceState = Object.assign(target, { + capturing: false, + runningAverageTasksPerSecond: 0, + averagesTaken: [], + runningAverageLeadTime: -1, + averagesTakenLeadTime: [], + leadTimeQueue: [], + performance: { + numberOfTasksRanOverall: 0, + cycles: { + fillPoolStarts: 0, + fillPoolCycles: 0, + fillPoolBail: 0, + claimedOnRerunCycle: 0, + fillPoolBailNoTasks: 0, + }, + claimAvailableTasksNoTasks: 0, + claimAvailableTasksNoAvailableWorkers: 0, + elasticsearchApiCalls: { + timeUntilFirstRun: [], + timeUntilFirstMarkAsRun: [], + firstMarkAsRunningTillRan: [], + timeFromMarkAsRunTillRun: [], + timeFromRunTillNextMarkAsRun: [], + claimAvailableTasks: [], + }, + activityDuration: [], + sleepDuration: [], + taskPollerActivityDurationPreScheduleComplete: [], + taskPoolAttemptToRun: [], + taskRunnerMarkTaskAsRunning: [], + + summarize: [], + }, + }); + + performanceState.performanceObserver = new PerformanceObserver((list, observer) => { + list.getEntries().forEach(entry => { + const { name, duration } = entry; + switch (name) { + // Elasticsearch Api Calls + case 'perfTask.firstRun': + performanceState.performance.elasticsearchApiCalls.timeUntilFirstRun.push(duration); + break; + case 'perfTask.firstMarkAsRunning': + performanceState.performance.elasticsearchApiCalls.timeUntilFirstMarkAsRun.push(duration); + break; + case 'perfTask.firstMarkAsRunningTillRan': + performanceState.performance.elasticsearchApiCalls.firstMarkAsRunningTillRan.push( + duration + ); + break; + case 'perfTask.markUntilRun': + performanceState.performance.elasticsearchApiCalls.timeFromMarkAsRunTillRun.push( + duration + ); + break; + case 'perfTask.runUntilNextMarkAsRunning': + performanceState.performance.elasticsearchApiCalls.timeFromRunTillNextMarkAsRun.push( + duration + ); + break; + case 'claimAvailableTasks': + performanceState.performance.elasticsearchApiCalls.claimAvailableTasks.push(duration); + break; + case 'TaskPoller.sleepDuration': + performanceState.performance.sleepDuration.push(duration); + break; + case 'fillPool.activityDurationUntilNoTasks': + performanceState.performance.activityDuration.push(duration); + break; + case 'fillPool.activityDurationUntilExhaustedCapacity': + performanceState.performance.activityDuration.push(duration); + break; + case 'fillPool.bailExhaustedCapacity': + performanceState.performance.cycles.fillPoolBail++; + break; + case 'fillPool.claimedOnRerunCycle': + performanceState.performance.cycles.claimedOnRerunCycle++; + break; + case 'fillPool.bailNoTasks': + performanceState.performance.cycles.fillPoolBail++; + performanceState.performance.cycles.fillPoolBailNoTasks++; + break; + case 'fillPool.start': + performanceState.performance.cycles.fillPoolStarts++; + break; + case 'fillPool.cycle': + performanceState.performance.cycles.fillPoolCycles++; + break; + break; + case 'claimAvailableTasks.noTasks': + performanceState.performance.claimAvailableTasksNoTasks++; + break; + case 'claimAvailableTasks.noAvailableWorkers': + performanceState.performance.claimAvailableTasksNoAvailableWorkers++; + break; + case 'taskPool.attemptToRun': + performanceState.performance.taskPoolAttemptToRun.push(duration); + break; + case 'taskRunner.markTaskAsRunning': + performanceState.performance.taskRunnerMarkTaskAsRunning.push(duration); + break; + case 'perfTest.duration': + observer.disconnect(); + const { summarize } = performanceState.performance; + if (summarize && summarize.length) { + summarize.splice(0, summarize.length).forEach(([resolve, callSummarize]) => { + resolve(callSummarize(duration)); + }); + } + break; + default: + if (name.startsWith('perfTask_run_')) { + performanceState.performance.numberOfTasksRanOverall++; + } + } + }); + }); + performanceState.performanceObserver.observe({ entryTypes: ['measure', 'mark'] }); + + return performanceState; +} diff --git a/x-pack/test/plugin_api_perf/plugins/task_manager_performance/server/types.ts b/x-pack/test/plugin_api_perf/plugins/task_manager_performance/server/types.ts new file mode 100644 index 0000000000000..ac5e8cdaba936 --- /dev/null +++ b/x-pack/test/plugin_api_perf/plugins/task_manager_performance/server/types.ts @@ -0,0 +1,82 @@ +/* + * 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 { PerformanceObserver } from 'perf_hooks'; + +export interface Perf { + numberOfTasksRanOverall: number; + cycles: { + fillPoolStarts: number; + fillPoolCycles: number; + fillPoolBail: number; + claimedOnRerunCycle: number; + fillPoolBailNoTasks: number; + }; + claimAvailableTasksNoTasks: number; + claimAvailableTasksNoAvailableWorkers: number; + elasticsearchApiCalls: { + timeUntilFirstRun: number[]; + timeUntilFirstMarkAsRun: number[]; + firstMarkAsRunningTillRan: number[]; + timeFromMarkAsRunTillRun: number[]; + timeFromRunTillNextMarkAsRun: number[]; + claimAvailableTasks: number[]; + }; + activityDuration: number[]; + sleepDuration: number[]; + taskPollerActivityDurationPreScheduleComplete: number[]; + taskPoolAttemptToRun: number[]; + taskRunnerMarkTaskAsRunning: number[]; + + summarize: Array<[(perf: PerfResult) => void, (perfTestDuration: number) => PerfResult]>; +} + +export interface PerfState { + performanceObserver?: PerformanceObserver; + runningAverageTasksPerSecond: number; + averagesTaken: number[]; + runningAverageLeadTime: number; + averagesTakenLeadTime: number[]; + leadTimeQueue: number[]; + performance: Perf; + capturing: boolean; +} + +export interface PerfResult { + perfTestDuration: string; + runningAverageTasksPerSecond: number; + runningAverageLeadTime: number; + numberOfTasksRanOverall: number; + claimAvailableTasksNoTasks: number; + claimAvailableTasksNoAvailableWorkers: number; + elasticsearchApiCalls: { + timeUntilFirstRun: PerfAvg; + timeUntilFirstMarkAsRun: PerfAvg; + firstMarkAsRunningTillRan: PerfAvg; + timeFromMarkAsRunTillRun: PerfAvg; + timeFromRunTillNextMarkAsRun: PerfAvg; + claimAvailableTasks: PerfAvg; + }; + sleepDuration: string; + activityDuration: string; + cycles: Perf['cycles']; + taskPoolAttemptToRun: PerfAvg; + taskRunnerMarkTaskAsRunning: PerfAvg; +} + +export interface PerfApi { + capture: () => void; + endCapture: () => Promise; + summarize: (perfTestDuration: number) => PerfResult; +} + +export interface PerfAvg { + mean: number; + range: { + min: number; + max: number; + }; +} diff --git a/x-pack/typings/hapi.d.ts b/x-pack/typings/hapi.d.ts index 872e042eb1cdb..ed86a961cd1db 100644 --- a/x-pack/typings/hapi.d.ts +++ b/x-pack/typings/hapi.d.ts @@ -10,7 +10,7 @@ import { XPackMainPlugin } from '../legacy/plugins/xpack_main/server/xpack_main' import { SecurityPlugin } from '../legacy/plugins/security'; import { ActionsPlugin, ActionsClient } from '../plugins/actions/server'; import { AlertingPlugin, AlertsClient } from '../plugins/alerting/server'; -import { LegacyTaskManagerApi } from '../legacy/plugins/task_manager/server'; +import { TaskManager } from '../plugins/task_manager/server'; declare module 'hapi' { interface Request { @@ -22,6 +22,6 @@ declare module 'hapi' { security?: SecurityPlugin; actions?: ActionsPlugin; alerting?: AlertingPlugin; - task_manager?: LegacyTaskManagerApi; + task_manager?: TaskManager; } } diff --git a/yarn.lock b/yarn.lock index b28a5b82a8300..1ce919e210e66 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4577,6 +4577,13 @@ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-1.16.1.tgz#328d1c9b54402e44119398bcb6a31b7bbd606d59" integrity sha512-db6pZL5QY3JrlCHBhYQzYDci0xnoDuxfseUuguLRr3JNk+bnCfpkK6p8quiUDyO8A0vbpBKkk59Fw125etrNeA== +"@types/pretty-ms@^5.0.0": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@types/pretty-ms/-/pretty-ms-5.0.1.tgz#f2f0d7be58caf8613d149053d446e0282ae11ff3" + integrity sha512-FFR4uj0p47Yq6JCrOt7DCaiUJIw7t9Vh7wwt3bF6qq99QRqjSH/doEGZsIIgZqhDmwjBObVBkrn0ICm1pY+mPg== + dependencies: + pretty-ms "*" + "@types/prop-types@*": version "15.7.1" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.1.tgz#f1a11e7babb0c3cad68100be381d1e064c68f1f6" @@ -4875,6 +4882,11 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw== +"@types/stats-lite@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@types/stats-lite/-/stats-lite-2.2.0.tgz#bc8190bf9dfa1e16b89eaa2b433c99dff0804de9" + integrity sha512-YV6SS4QC+pbzqjMIV8qVSTDOOazgKBLTVaN+7PfuxELjz/eyzc20KwDVGPrbHt2OcYMA7K2ezLB45Cp6DpNOSQ== + "@types/strip-ansi@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/strip-ansi/-/strip-ansi-3.0.0.tgz#9b63d453a6b54aa849182207711a08be8eea48ae" @@ -22734,7 +22746,7 @@ parse-link-header@^1.0.1: dependencies: xtend "~4.0.1" -parse-ms@^2.0.0: +parse-ms@^2.0.0, parse-ms@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-2.1.0.tgz#348565a753d4391fa524029956b172cb7753097d" integrity sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA== @@ -23495,6 +23507,13 @@ pretty-hrtime@^1.0.0, pretty-hrtime@^1.0.3: resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE= +pretty-ms@*: + version "7.0.0" + resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-7.0.0.tgz#45781273110caf35f55cab21a8a9bd403a233dc0" + integrity sha512-J3aPWiC5e9ZeZFuSeBraGxSkGMOvulSWsxDByOcbD1Pr75YL3LSNIKIb52WXbCLE1sS5s4inBBbryjF4Y05Ceg== + dependencies: + parse-ms "^2.1.0" + pretty-ms@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-4.0.0.tgz#31baf41b94fd02227098aaa03bd62608eb0d6e92" From 6114ebabec0bed854603bf7bb1f27c019dfa498b Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Wed, 6 May 2020 10:58:34 +0200 Subject: [PATCH 03/23] [chore] Improve request cancelation handling in vis embeddable (#65057) --- .../visualizations/public/embeddable/visualize_embeddable.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts b/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts index 89697ecd7ed71..10704514ab8d5 100644 --- a/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts +++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts @@ -340,13 +340,14 @@ export class VisualizeEmbeddable extends Embeddable Date: Wed, 6 May 2020 10:22:40 +0100 Subject: [PATCH 04/23] [ML] Adding daily_model_snapshot_retention_after_days to types and schemas (#65417) --- x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts | 1 + .../plugins/ml/server/routes/schemas/anomaly_detectors_schema.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts b/x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts index bf8e3031db975..bc55c7549c589 100644 --- a/x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts +++ b/x-pack/plugins/ml/common/types/anomaly_detection_jobs/job.ts @@ -26,6 +26,7 @@ export interface Job { groups: string[]; model_plot_config?: ModelPlotConfig; model_snapshot_retention_days?: number; + daily_model_snapshot_retention_after_days?: number; renormalization_window_days?: number; results_index_name?: string; results_retention_days?: number; diff --git a/x-pack/plugins/ml/server/routes/schemas/anomaly_detectors_schema.ts b/x-pack/plugins/ml/server/routes/schemas/anomaly_detectors_schema.ts index 9b86e3e06096e..88b86de322e3c 100644 --- a/x-pack/plugins/ml/server/routes/schemas/anomaly_detectors_schema.ts +++ b/x-pack/plugins/ml/server/routes/schemas/anomaly_detectors_schema.ts @@ -112,6 +112,7 @@ export const anomalyDetectionJobSchema = { model_snapshot_id: schema.maybe(schema.string()), model_snapshot_min_version: schema.maybe(schema.string()), model_snapshot_retention_days: schema.maybe(schema.number()), + daily_model_snapshot_retention_after_days: schema.maybe(schema.number()), renormalization_window_days: schema.maybe(schema.number()), results_index_name: schema.maybe(schema.string()), results_retention_days: schema.maybe(schema.number()), From da28df5b154bd8223124b1814f5b350b842c309d Mon Sep 17 00:00:00 2001 From: Mikhail Shustov Date: Wed, 6 May 2020 11:51:50 +0200 Subject: [PATCH 05/23] add direct build command (#65431) --- src/core/MIGRATION.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/MIGRATION.md b/src/core/MIGRATION.md index 80f12dd78214d..02d46b1583b59 100644 --- a/src/core/MIGRATION.md +++ b/src/core/MIGRATION.md @@ -990,6 +990,9 @@ ls -lh plugins/my_plugin/target/public/ you might see at least one js bundle - `my_plugin.plugin.js`. This is the only artifact loaded by the platform during bootstrap in the browser. The rule of thumb is to keep its size as small as possible. Other lazily loaded parts of your plugin present in the same folder as separate chunks under `{number}.plugin.js` names. If you want to investigate what your plugin bundle consists of you need to run `@kbn/optimizer` with `--profile` flag to get generated [webpack stats file](https://webpack.js.org/api/stats/). +```bash +node scripts/build_kibana_platform_plugins.js --dist --no-examples --profile +``` Many OSS tools are allowing you to analyze generated stats file - [an official tool](http://webpack.github.io/analyse/#modules) from webpack authors - [webpack-visualizer](https://chrisbateman.github.io/webpack-visualizer/) From 81ad646d224ac77feca81701a0bfc3c1436737fc Mon Sep 17 00:00:00 2001 From: Silvia Mitter Date: Wed, 6 May 2020 11:53:01 +0200 Subject: [PATCH 06/23] update apm index pattern (#65424) --- x-pack/plugins/apm/server/tutorial/index_pattern.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/apm/server/tutorial/index_pattern.json b/x-pack/plugins/apm/server/tutorial/index_pattern.json index e0d9595585b88..1d061f9e11e61 100644 --- a/x-pack/plugins/apm/server/tutorial/index_pattern.json +++ b/x-pack/plugins/apm/server/tutorial/index_pattern.json @@ -1,7 +1,7 @@ { "attributes": { "fieldFormatMap": "{\"client.bytes\":{\"id\":\"bytes\"},\"client.nat.port\":{\"id\":\"string\"},\"client.port\":{\"id\":\"string\"},\"destination.bytes\":{\"id\":\"bytes\"},\"destination.nat.port\":{\"id\":\"string\"},\"destination.port\":{\"id\":\"string\"},\"event.duration\":{\"id\":\"duration\",\"params\":{\"inputFormat\":\"nanoseconds\",\"outputFormat\":\"asMilliseconds\",\"outputPrecision\":1}},\"event.sequence\":{\"id\":\"string\"},\"event.severity\":{\"id\":\"string\"},\"http.request.body.bytes\":{\"id\":\"bytes\"},\"http.request.bytes\":{\"id\":\"bytes\"},\"http.response.body.bytes\":{\"id\":\"bytes\"},\"http.response.bytes\":{\"id\":\"bytes\"},\"http.response.status_code\":{\"id\":\"string\"},\"log.syslog.facility.code\":{\"id\":\"string\"},\"log.syslog.priority\":{\"id\":\"string\"},\"network.bytes\":{\"id\":\"bytes\"},\"package.size\":{\"id\":\"string\"},\"process.parent.pgid\":{\"id\":\"string\"},\"process.parent.pid\":{\"id\":\"string\"},\"process.parent.ppid\":{\"id\":\"string\"},\"process.parent.thread.id\":{\"id\":\"string\"},\"process.pgid\":{\"id\":\"string\"},\"process.pid\":{\"id\":\"string\"},\"process.ppid\":{\"id\":\"string\"},\"process.thread.id\":{\"id\":\"string\"},\"server.bytes\":{\"id\":\"bytes\"},\"server.nat.port\":{\"id\":\"string\"},\"server.port\":{\"id\":\"string\"},\"source.bytes\":{\"id\":\"bytes\"},\"source.nat.port\":{\"id\":\"string\"},\"source.port\":{\"id\":\"string\"},\"system.cpu.total.norm.pct\":{\"id\":\"percent\"},\"system.memory.actual.free\":{\"id\":\"bytes\"},\"system.memory.total\":{\"id\":\"bytes\"},\"system.process.cpu.total.norm.pct\":{\"id\":\"percent\"},\"system.process.memory.rss.bytes\":{\"id\":\"bytes\"},\"system.process.memory.size\":{\"id\":\"bytes\"},\"url.port\":{\"id\":\"string\"},\"view spans\":{\"id\":\"url\",\"params\":{\"labelTemplate\":\"View Spans\"}}}", - "fields": "[{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"@timestamp\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"labels\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tags\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.ephemeral_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"as.organization.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.as.organization.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.full_name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.account.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.availability_zone\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.instance.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.instance.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.machine.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.provider\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.region\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"code_signature.exists\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"code_signature.status\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"code_signature.subject_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"code_signature.trusted\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"code_signature.valid\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.image.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.image.tag\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.labels\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.runtime\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.as.organization.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.full_name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.code_signature.exists\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.code_signature.status\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.code_signature.subject_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.code_signature.trusted\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.code_signature.valid\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.pe.company\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.pe.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.pe.file_version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.pe.original_file_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.pe.product\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.class\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.data\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.ttl\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.header_flags\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.op_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.class\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.subdomain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.resolved_ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.response_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"ecs.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":4,\"doc_values\":true,\"indexed\":true,\"name\":\"error.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.stack_trace\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.stack_trace.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.action\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.category\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.created\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.dataset\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.duration\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.end\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.ingested\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.kind\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.module\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.outcome\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.provider\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.risk_score\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.risk_score_norm\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.sequence\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.severity\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.start\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.timezone\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.url\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.accessed\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.attributes\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.code_signature.exists\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.code_signature.status\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.code_signature.subject_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.code_signature.trusted\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.code_signature.valid\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.created\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.ctime\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.device\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.directory\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.drive_letter\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.extension\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.gid\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.group\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.inode\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.mime_type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.mode\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.mtime\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.owner\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.path.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.pe.company\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.pe.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.pe.file_version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.pe.original_file_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.pe.product\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.target_path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.target_path.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.uid\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.architecture\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.hostname\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.full.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.uptime\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.full_name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.body.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.body.content\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.body.content.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.method\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.referrer\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.body.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.body.content\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.body.content.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.status_code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"interface.alias\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"interface.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"interface.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.level\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.logger\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.origin.file.line\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.origin.file.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.origin.function\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.facility.code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.facility.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.priority\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.severity.code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.severity.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.application\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.community_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.direction\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.forwarded_ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.iana_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.inner\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.inner.vlan.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.inner.vlan.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.protocol\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.transport\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.vlan.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.vlan.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.egress\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.egress.interface.alias\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.egress.interface.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.egress.interface.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.egress.vlan.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.egress.vlan.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.egress.zone\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.hostname\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ingress\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ingress.interface.alias\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ingress.interface.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ingress.interface.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ingress.vlan.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ingress.vlan.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ingress.zone\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.full.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.product\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.serial_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.vendor\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"organization.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"organization.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.full.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.architecture\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.build_version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.checksum\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.install_scope\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.installed\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.license\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"pe.company\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"pe.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"pe.file_version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"pe.original_file_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"pe.product\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.args\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.args_count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.code_signature.exists\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.code_signature.status\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.code_signature.subject_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.code_signature.trusted\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.code_signature.valid\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.command_line\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.command_line.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.entity_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.executable\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.executable.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.exit_code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.args\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.args_count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.code_signature.exists\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.code_signature.status\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.code_signature.subject_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.code_signature.trusted\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.code_signature.valid\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.command_line\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.command_line.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.entity_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.executable\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.executable.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.exit_code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.pgid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.pid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.ppid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.start\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.thread.id\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.thread.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.title\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.title.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.uptime\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.working_directory\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.working_directory.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pe.company\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pe.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pe.file_version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pe.original_file_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pe.product\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pgid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.ppid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.start\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.thread.id\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.thread.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.title\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.title.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.uptime\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.working_directory\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.working_directory.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"registry.data.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"registry.data.strings\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"registry.data.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"registry.hive\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"registry.key\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"registry.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"registry.value\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"related.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"related.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"related.user\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.author\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.category\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.license\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.ruleset\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.uuid\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.as.organization.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.full_name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.ephemeral_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.node.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.state\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.as.organization.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.full_name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.framework\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.tactic.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.tactic.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.tactic.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.cipher\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.certificate\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.certificate_chain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.issuer\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.ja3\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.not_after\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.not_before\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.server_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.subject\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.supported_ciphers\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.curve\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.established\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.next_protocol\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.resumed\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.certificate\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.certificate_chain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.issuer\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.ja3s\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.not_after\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.not_before\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.subject\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.version_protocol\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tracing.trace.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tracing.transaction.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.extension\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.fragment\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.full.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.original.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.password\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.query\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.scheme\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.username\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.full_name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.device.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.original.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.full.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vlan.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vlan.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.category\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.classification\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.description.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.enumeration\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.report_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.scanner.vendor\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.score.base\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.score.environmental\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.score.temporal\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.score.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.severity\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.hostname\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"fields\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"timeseries.instance\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.project.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.image.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"docker.container.labels\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.containerized\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.build\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.codename\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.pod.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.pod.uid\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.namespace\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.node.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.labels.*\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.annotations.*\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.replicaset.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.deployment.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.statefulset.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.container.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.container.image\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"processor.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"processor.event\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"timestamp.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"enabled\":false,\"indexed\":false,\"name\":\"http.request.headers\",\"scripted\":false,\"searchable\":false},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.finished\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"enabled\":false,\"indexed\":false,\"name\":\"http.response.headers\",\"scripted\":false,\"searchable\":false},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.environment\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.language.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.language.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.runtime.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.runtime.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.framework.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.framework.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.sampled\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.duration.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.duration.sum.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.self_time.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.self_time.sum.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.breakdown.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.subtype\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.self_time.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.self_time.sum.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"trace.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"parent.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.listening\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.version_major\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"experimental\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.culprit\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.grouping_key\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.module\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":4,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.handled\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.level\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.logger_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.param_message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.cpu.total.norm.pct\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.memory.total\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.memory.actual.free\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.process.cpu.total.norm.pct\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.process.memory.size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.process.memory.rss.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.cpu.ns\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.samples.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.alloc_objects.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.alloc_space.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.inuse_objects.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.inuse_space.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.duration\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.top.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.top.function\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.top.filename\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.top.line\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.stack.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.stack.function\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.stack.filename\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.stack.line\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"sourcemap.service.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"sourcemap.service.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"sourcemap.bundle_filepath\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"view spans\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"child.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.action\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.start.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.duration.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.sync\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.db.link\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.db.rows_affected\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.destination.service.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.destination.service.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.destination.service.resource\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.message.queue.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.message.age.ms\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.duration.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.result\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.marks\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.marks.*.*\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.span_count.dropped\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.message.queue.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.message.age.ms\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_id\",\"scripted\":false,\"searchable\":false,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_index\",\"scripted\":false,\"searchable\":false,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_score\",\"scripted\":false,\"searchable\":false,\"type\":\"number\"}]", + "fields": "[{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"@timestamp\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"labels\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tags\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.ephemeral_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"as.organization.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.as.organization.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.full_name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.account.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.availability_zone\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.instance.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.instance.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.machine.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.provider\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.region\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"code_signature.exists\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"code_signature.status\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"code_signature.subject_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"code_signature.trusted\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"code_signature.valid\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.image.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.image.tag\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.labels\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.runtime\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.as.organization.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.full_name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.code_signature.exists\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.code_signature.status\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.code_signature.subject_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.code_signature.trusted\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.code_signature.valid\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.pe.company\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.pe.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.pe.file_version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.pe.original_file_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dll.pe.product\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.class\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.data\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.ttl\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.header_flags\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.op_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.class\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.subdomain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.resolved_ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.response_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"ecs.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":4,\"doc_values\":true,\"indexed\":true,\"name\":\"error.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.stack_trace\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.stack_trace.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.action\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.category\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.created\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.dataset\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.duration\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.end\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.ingested\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.kind\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.module\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.outcome\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.provider\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.risk_score\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.risk_score_norm\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.sequence\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.severity\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.start\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.timezone\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.url\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.accessed\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.attributes\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.code_signature.exists\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.code_signature.status\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.code_signature.subject_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.code_signature.trusted\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.code_signature.valid\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.created\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.ctime\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.device\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.directory\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.drive_letter\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.extension\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.gid\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.group\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.inode\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.mime_type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.mode\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.mtime\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.owner\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.path.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.pe.company\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.pe.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.pe.file_version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.pe.original_file_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.pe.product\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.target_path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.target_path.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.uid\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.architecture\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.hostname\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.full.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.uptime\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.full_name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.body.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.body.content\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.body.content.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.method\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.referrer\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.body.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.body.content\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.body.content.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.status_code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"interface.alias\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"interface.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"interface.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.level\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.logger\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.origin.file.line\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.origin.file.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.origin.function\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.facility.code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.facility.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.priority\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.severity.code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.severity.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.application\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.community_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.direction\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.forwarded_ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.iana_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.inner\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.inner.vlan.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.inner.vlan.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.protocol\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.transport\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.vlan.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.vlan.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.egress\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.egress.interface.alias\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.egress.interface.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.egress.interface.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.egress.vlan.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.egress.vlan.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.egress.zone\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.hostname\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ingress\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ingress.interface.alias\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ingress.interface.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ingress.interface.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ingress.vlan.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ingress.vlan.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ingress.zone\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.full.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.product\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.serial_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.vendor\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"organization.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"organization.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.full.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.architecture\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.build_version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.checksum\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.install_scope\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.installed\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.license\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"pe.company\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"pe.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"pe.file_version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"pe.original_file_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"pe.product\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.args\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.args_count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.code_signature.exists\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.code_signature.status\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.code_signature.subject_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.code_signature.trusted\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.code_signature.valid\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.command_line\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.command_line.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.entity_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.executable\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.executable.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.exit_code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.args\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.args_count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.code_signature.exists\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.code_signature.status\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.code_signature.subject_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.code_signature.trusted\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.code_signature.valid\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.command_line\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.command_line.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.entity_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.executable\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.executable.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.exit_code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.pgid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.pid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.ppid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.start\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.thread.id\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.thread.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.title\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.title.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.uptime\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.working_directory\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.parent.working_directory.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pe.company\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pe.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pe.file_version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pe.original_file_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pe.product\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pgid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.ppid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.start\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.thread.id\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.thread.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.title\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.title.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.uptime\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.working_directory\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.working_directory.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"registry.data.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"registry.data.strings\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"registry.data.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"registry.hive\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"registry.key\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"registry.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"registry.value\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"related.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"related.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"related.user\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.author\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.category\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.license\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.ruleset\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.uuid\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"rule.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.as.organization.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.full_name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.ephemeral_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.node.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.state\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.as.organization.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.full_name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.framework\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.tactic.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.tactic.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.tactic.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.cipher\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.certificate\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.certificate_chain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.issuer\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.ja3\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.not_after\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.not_before\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.server_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.subject\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.client.supported_ciphers\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.curve\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.established\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.next_protocol\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.resumed\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.certificate\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.certificate_chain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.issuer\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.ja3s\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.not_after\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.not_before\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.server.subject\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tls.version_protocol\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tracing.trace.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tracing.transaction.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.extension\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.fragment\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.full.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.original.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.password\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.query\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.scheme\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.username\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.full_name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.device.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.original.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.full.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vlan.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vlan.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.category\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.classification\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.description.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.enumeration\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.report_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.scanner.vendor\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.score.base\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.score.environmental\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.score.temporal\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.score.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"vulnerability.severity\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.hostname\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"fields\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"timeseries.instance\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.project.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.image.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"docker.container.labels\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.containerized\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.build\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.codename\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.pod.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.pod.uid\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.namespace\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.node.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.labels.*\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.annotations.*\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.replicaset.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.deployment.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.statefulset.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.container.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.container.image\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"processor.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"processor.event\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"timestamp.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"enabled\":false,\"indexed\":false,\"name\":\"http.request.headers\",\"scripted\":false,\"searchable\":false},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.finished\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"enabled\":false,\"indexed\":false,\"name\":\"http.response.headers\",\"scripted\":false,\"searchable\":false},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.environment\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.language.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.language.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.runtime.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.runtime.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.framework.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.framework.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.sampled\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.duration.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.duration.sum.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.self_time.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.self_time.sum.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.breakdown.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.subtype\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.self_time.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.self_time.sum.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"trace.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"parent.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.listening\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.version_major\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"experimental\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.account.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.project.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.culprit\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.grouping_key\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.module\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":4,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.handled\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.level\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.logger_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.param_message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.cpu.total.norm.pct\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.memory.total\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.memory.actual.free\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.process.cpu.total.norm.pct\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.process.memory.size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.process.memory.rss.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.root\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.cpu.ns\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.samples.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.alloc_objects.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.alloc_space.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.inuse_objects.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.inuse_space.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.duration\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.top.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.top.function\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.top.filename\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.top.line\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.stack.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.stack.function\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.stack.filename\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.stack.line\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"sourcemap.service.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"sourcemap.service.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"sourcemap.bundle_filepath\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"view spans\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"child.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.action\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.start.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.duration.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.sync\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.db.link\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.db.rows_affected\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.destination.service.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.destination.service.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.destination.service.resource\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.message.queue.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.message.age.ms\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.duration.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.result\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.marks\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.marks.*.*\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.span_count.dropped\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.message.queue.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.message.age.ms\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.duration.histogram\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_id\",\"scripted\":false,\"searchable\":false,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_index\",\"scripted\":false,\"searchable\":false,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_score\",\"scripted\":false,\"searchable\":false,\"type\":\"number\"}]", "sourceFilters": "[{\"value\":\"sourcemap.sourcemap\"}]", "timeFieldName": "@timestamp" }, From 8a65950de40a7195652879ca92d9b2cd64c798d5 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Wed, 6 May 2020 11:56:58 +0200 Subject: [PATCH 07/23] [ML] Adds docs_per_second to transform edit form. (#65365) Adds an option to edit the docs_per_second option for throttling for transforms. --- .../transform/public/app/common/transform.ts | 4 + .../edit_transform_flyout_form.tsx | 19 +++-- .../use_edit_transform_flyout.test.ts | 45 ++++++++-- .../use_edit_transform_flyout.ts | 82 ++++++++++++++----- 4 files changed, 118 insertions(+), 32 deletions(-) diff --git a/x-pack/plugins/transform/public/app/common/transform.ts b/x-pack/plugins/transform/public/app/common/transform.ts index 41e18ca9d1589..18c53dda0e8a2 100644 --- a/x-pack/plugins/transform/public/app/common/transform.ts +++ b/x-pack/plugins/transform/public/app/common/transform.ts @@ -40,6 +40,10 @@ export interface CreateRequestBody extends PreviewRequestBody { index: IndexName; }; frequency?: string; + settings?: { + max_page_search_size?: number; + docs_per_second?: number; + }; sync?: { time: { field: string; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_flyout_form.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_flyout_form.tsx index 3ea009a9bb6b4..2de8239813b4d 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_flyout_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_flyout_form.tsx @@ -32,14 +32,21 @@ export const EditTransformFlyoutForm: FC = ({ onChange={value => dispatch({ field: 'description', value })} value={formFields.description.value} /> - {/* */} + onChange={value => dispatch({ field: 'docsPerSecond', value })} + value={formFields.docsPerSecond.value} + /> ({ @@ -43,14 +45,21 @@ const getTransformConfigMock = (): TransformPivotConfig => ({ description: 'the-description', }); -const getDescriptionFieldMock = (value = '') => ({ +const getDescriptionFieldMock = (value = ''): FormField => ({ isOptional: true, value, errorMessages: [], validator: 'string', }); -const getFrequencyFieldMock = (value = '') => ({ +const getDocsPerSecondFieldMock = (value = ''): FormField => ({ + isOptional: true, + value, + errorMessages: [], + validator: 'numberAboveZero', +}); + +const getFrequencyFieldMock = (value = ''): FormField => ({ isOptional: true, value, errorMessages: [], @@ -63,6 +72,7 @@ describe('Transform: applyFormFieldsToTransformConfig()', () => { const updateConfig = applyFormFieldsToTransformConfig(transformConfigMock, { description: getDescriptionFieldMock(transformConfigMock.description), + docsPerSecond: getDocsPerSecondFieldMock(), frequency: getFrequencyFieldMock(), }); @@ -70,6 +80,8 @@ describe('Transform: applyFormFieldsToTransformConfig()', () => { // because the Update-Button will be disabled when no form field was changed. expect(Object.keys(updateConfig)).toHaveLength(0); expect(updateConfig.description).toBe(undefined); + // `docs_per_second` is nested under `settings` so we're just checking against that. + expect(updateConfig.settings).toBe(undefined); expect(updateConfig.frequency).toBe(undefined); }); @@ -80,23 +92,28 @@ describe('Transform: applyFormFieldsToTransformConfig()', () => { const updateConfig = applyFormFieldsToTransformConfig(transformConfigMock, { description: getDescriptionFieldMock('the-new-description'), - frequency: getFrequencyFieldMock(undefined), + docsPerSecond: getDocsPerSecondFieldMock('10'), + frequency: getFrequencyFieldMock('1m'), }); - expect(Object.keys(updateConfig)).toHaveLength(1); + expect(Object.keys(updateConfig)).toHaveLength(3); expect(updateConfig.description).toBe('the-new-description'); - expect(updateConfig.frequency).toBe(undefined); + expect(updateConfig.settings?.docs_per_second).toBe(10); + expect(updateConfig.frequency).toBe('1m'); }); test('should only include changed form fields', () => { const transformConfigMock = getTransformConfigMock(); const updateConfig = applyFormFieldsToTransformConfig(transformConfigMock, { description: getDescriptionFieldMock('the-updated-description'), + docsPerSecond: getDocsPerSecondFieldMock(), frequency: getFrequencyFieldMock(), }); expect(Object.keys(updateConfig)).toHaveLength(1); expect(updateConfig.description).toBe('the-updated-description'); + // `docs_per_second` is nested under `settings` so we're just checking against that. + expect(updateConfig.settings).toBe(undefined); expect(updateConfig.frequency).toBe(undefined); }); }); @@ -166,3 +183,21 @@ describe('Transform: frequencyValidator()', () => { expect(frequencyValidator('59m')).toHaveLength(0); }); }); + +describe('Transform: numberValidator()', () => { + test('it should only allow numbers', () => { + // numberValidator() returns an array of error messages so + // an array with a length of 0 means a successful validation. + + // invalid + expect(numberAboveZeroValidator('a-string')).toHaveLength(1); + expect(numberAboveZeroValidator('0s')).toHaveLength(1); + expect(numberAboveZeroValidator('1m')).toHaveLength(1); + expect(numberAboveZeroValidator(-1)).toHaveLength(1); + expect(numberAboveZeroValidator(0)).toHaveLength(1); + + // valid + expect(numberAboveZeroValidator(1)).toHaveLength(0); + expect(numberAboveZeroValidator('1')).toHaveLength(0); + }); +}); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/use_edit_transform_flyout.ts b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/use_edit_transform_flyout.ts index 8c4af7ac252f7..38d91115d212e 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/use_edit_transform_flyout.ts +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/use_edit_transform_flyout.ts @@ -11,29 +11,43 @@ import { i18n } from '@kbn/i18n'; import { TransformPivotConfig } from '../../../../common'; +// A Validator function takes in a value to check and returns an array of error messages. +// If no messages (empty array) get returned, the value is valid. +type Validator = (arg: any) => string[]; + +// Note on the form validation and input components used: +// All inputs use `EuiFieldText` which means all form values will be treated as strings. +// This means we cast other formats like numbers coming from the transform config to strings, +// then revalidate them and cast them again to number before submitting a transform update. +// We do this so we have fine grained control over field validation and the option to +// cast to special values like `null` for disabling `docs_per_second`. +const numberAboveZeroNotValidErrorMessage = i18n.translate( + 'xpack.transform.transformList.editFlyoutFormNumberNotValidErrorMessage', + { + defaultMessage: 'Value needs to be a number above zero.', + } +); +export const numberAboveZeroValidator: Validator = arg => + !isNaN(arg) && parseInt(arg, 10) > 0 ? [] : [numberAboveZeroNotValidErrorMessage]; + +// The way the current form is set up, this validator is just a sanity check, +// it should never trigger an error, because `EuiFieldText` always returns a string. const stringNotValidErrorMessage = i18n.translate( 'xpack.transform.transformList.editFlyoutFormStringNotValidErrorMessage', { defaultMessage: 'Value needs to be of type string.', } ); - -type Validator = (arg: any) => string[]; - -// The way the current form is set up, -// this validator is just a sanity check, -// it should never trigger an error. const stringValidator: Validator = arg => typeof arg === 'string' ? [] : [stringNotValidErrorMessage]; +// Only allow frequencies in the form of 1s/1h etc. const frequencyNotValidErrorMessage = i18n.translate( 'xpack.transform.transformList.editFlyoutFormFrequencyNotValidErrorMessage', { defaultMessage: 'The frequency value is not valid.', } ); - -// Only allow frequencies in the form of 1s/1h etc. export const frequencyValidator: Validator = arg => { if (typeof arg !== 'string' || arg === null) { return [stringNotValidErrorMessage]; @@ -58,23 +72,26 @@ export const frequencyValidator: Validator = arg => { ); }; -interface Validate { - [key: string]: Validator; -} +type Validators = 'string' | 'frequency' | 'numberAboveZero'; + +type Validate = { + [key in Validators]: Validator; +}; const validate: Validate = { string: stringValidator, frequency: frequencyValidator, + numberAboveZero: numberAboveZeroValidator, }; -interface Field { +export interface FormField { errorMessages: string[]; isOptional: boolean; - validator: keyof typeof validate; + validator: keyof Validate; value: string; } -const defaultField: Field = { +const defaultField: FormField = { errorMessages: [], isOptional: true, validator: 'string', @@ -82,9 +99,10 @@ const defaultField: Field = { }; interface EditTransformFlyoutFieldsState { - [key: string]: Field; - description: Field; - frequency: Field; + [key: string]: FormField; + description: FormField; + frequency: FormField; + docsPerSecond: FormField; } export interface EditTransformFlyoutState { @@ -101,10 +119,14 @@ interface Action { } // Some attributes can have a value of `null` to trigger -// a reset to the default value. +// a reset to the default value, or in the case of `docs_per_second` +// `null` is used to disable throttling. interface UpdateTransformPivotConfig { description: string; frequency: string; + settings: { + docs_per_second: number | null; + }; } // Takes in the form configuration and returns a @@ -112,7 +134,7 @@ interface UpdateTransformPivotConfig { // transform update API endpoint. export const applyFormFieldsToTransformConfig = ( config: TransformPivotConfig, - { description, frequency }: EditTransformFlyoutFieldsState + { description, docsPerSecond, frequency }: EditTransformFlyoutFieldsState ): Partial => { const updateConfig: Partial = {}; @@ -132,6 +154,16 @@ export const applyFormFieldsToTransformConfig = ( updateConfig.description = description.value; } + // if the input field was left empty, + // fall back to the default value of `null` + // which will disable throttling. + const docsPerSecondFormValue = + docsPerSecond.value !== '' ? parseInt(docsPerSecond.value, 10) : null; + const docsPerSecondConfigValue = config.settings?.docs_per_second ?? null; + if (docsPerSecondFormValue !== docsPerSecondConfigValue) { + updateConfig.settings = { docs_per_second: docsPerSecondFormValue }; + } + return updateConfig; }; @@ -141,6 +173,11 @@ export const getDefaultState = (config: TransformPivotConfig): EditTransformFlyo formFields: { description: { ...defaultField, value: config?.description ?? '' }, frequency: { ...defaultField, value: config?.frequency ?? '', validator: 'frequency' }, + docsPerSecond: { + ...defaultField, + value: config?.settings?.docs_per_second?.toString() ?? '', + validator: 'numberAboveZero', + }, }, isFormTouched: false, isFormValid: true, @@ -154,10 +191,13 @@ const isFormValid = (fieldsState: EditTransformFlyoutFieldsState) => // Updates a form field with its new value, // runs validation and populates // `errorMessages` if any errors occur. -const formFieldReducer = (state: Field, value: string): Field => { +const formFieldReducer = (state: FormField, value: string): FormField => { return { ...state, - errorMessages: state.isOptional && value.length === 0 ? [] : validate[state.validator](value), + errorMessages: + state.isOptional && typeof value === 'string' && value.length === 0 + ? [] + : validate[state.validator](value), value, }; }; From 4e2b9445761e6cc1adfdf205d277a01f2d57d1b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cau=C3=AA=20Marcondes?= <55978943+cauemarcondes@users.noreply.github.com> Date: Wed, 6 May 2020 11:50:28 +0100 Subject: [PATCH 08/23] [APM] Custom links section inside the Actions menu is showing outside of the menu (#65428) --- .../shared/TransactionActionMenu/TransactionActionMenu.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx index c9376cdc01b5b..4092e0148286e 100644 --- a/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx +++ b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx @@ -27,7 +27,6 @@ import { CustomLink } from './CustomLink'; import { CustomLinkPopover } from './CustomLink/CustomLinkPopover'; import { getSections } from './sections'; import { useLicense } from '../../../hooks/useLicense'; -import { px } from '../../../style/variables'; import { convertFiltersToQuery } from '../../app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/helper'; interface Props { @@ -124,7 +123,7 @@ export const TransactionActionMenu: FunctionComponent = ({ setIsActionPopoverOpen(true)} /> } > -
+
{isCustomLinksPopoverOpen ? ( Date: Wed, 6 May 2020 12:53:43 +0200 Subject: [PATCH 09/23] Fix flaky ServerMetricsCollector integration test (#65420) * fix flaky test * add comment on supertest behavior --- .../metrics/integration_tests/server_collector.test.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/core/server/metrics/integration_tests/server_collector.test.ts b/src/core/server/metrics/integration_tests/server_collector.test.ts index dd5c256cf1600..3b982a06cf06c 100644 --- a/src/core/server/metrics/integration_tests/server_collector.test.ts +++ b/src/core/server/metrics/integration_tests/server_collector.test.ts @@ -185,18 +185,22 @@ describe('ServerMetricsCollector', () => { let metrics = await collector.collect(); expect(metrics.concurrent_connections).toEqual(0); - sendGet('/').end(() => null); + // supertest requests are executed when calling `.then` (or awaiting them). + // however in this test we need to send the request now and await for it later in the code. + // also using `.end` is not possible as it would execute the request twice. + // so the only option is this noop `.then`. + const res1 = sendGet('/').then(res => res); await waitForHits(1); metrics = await collector.collect(); expect(metrics.concurrent_connections).toEqual(1); - sendGet('/').end(() => null); + const res2 = sendGet('/').then(res => res); await waitForHits(2); metrics = await collector.collect(); expect(metrics.concurrent_connections).toEqual(2); waitSubject.next('go'); - await delay(requestWaitDelay); + await Promise.all([res1, res2]); metrics = await collector.collect(); expect(metrics.concurrent_connections).toEqual(0); }); From ced64f43f7edd60b0d0e6a4eee16794f306c89d0 Mon Sep 17 00:00:00 2001 From: Dmitry Lemeshko Date: Wed, 6 May 2020 14:13:52 +0300 Subject: [PATCH 10/23] add tsvb tests to Firefox suite (#65425) --- test/functional/apps/visualize/_tsvb_chart.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/functional/apps/visualize/_tsvb_chart.ts b/test/functional/apps/visualize/_tsvb_chart.ts index 27a06cc05b45c..333aa93b7776d 100644 --- a/test/functional/apps/visualize/_tsvb_chart.ts +++ b/test/functional/apps/visualize/_tsvb_chart.ts @@ -29,6 +29,7 @@ export default function({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['visualize', 'visualBuilder', 'timePicker', 'visChart']); describe('visual builder', function describeIndexTests() { + this.tags('includeFirefox'); beforeEach(async () => { await security.testUser.setRoles(['kibana_admin', 'test_logstash_reader']); await PageObjects.visualize.navigateToNewVisualization(); From 2a32f8f3994f962b3e768d09b83c71d1a380e5fc Mon Sep 17 00:00:00 2001 From: Aleh Zasypkin Date: Wed, 6 May 2020 13:17:42 +0200 Subject: [PATCH 11/23] Sync Kerberos + Anonymous access tests with the latest `security/_authenticate` API (user roles now include roles of anonymous user). (#65421) --- .../anonymous_access.config.ts | 2 +- .../apis/security/kerberos_login.ts | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/x-pack/test/kerberos_api_integration/anonymous_access.config.ts b/x-pack/test/kerberos_api_integration/anonymous_access.config.ts index 90d47ec61a4dc..8b712afe6c4d6 100644 --- a/x-pack/test/kerberos_api_integration/anonymous_access.config.ts +++ b/x-pack/test/kerberos_api_integration/anonymous_access.config.ts @@ -21,7 +21,7 @@ export default async function({ readConfigFile }: FtrConfigProviderContext) { serverArgs: [ ...kerberosAPITestsConfig.get('esTestCluster.serverArgs'), 'xpack.security.authc.anonymous.username=anonymous_user', - 'xpack.security.authc.anonymous.roles=superuser', + 'xpack.security.authc.anonymous.roles=superuser_anonymous', ], }, }; diff --git a/x-pack/test/kerberos_api_integration/apis/security/kerberos_login.ts b/x-pack/test/kerberos_api_integration/apis/security/kerberos_login.ts index fbf9a977e8b1f..e81db7e2b02f3 100644 --- a/x-pack/test/kerberos_api_integration/apis/security/kerberos_login.ts +++ b/x-pack/test/kerberos_api_integration/apis/security/kerberos_login.ts @@ -100,9 +100,7 @@ export default function({ getService }: FtrProviderContext) { }); }); - // Preventing ES Snapshot to be promoted - // https://github.com/elastic/kibana/issues/65114 - describe.skip('finishing SPNEGO', () => { + describe('finishing SPNEGO', () => { it('should properly set cookie and authenticate user', async () => { const response = await supertest .get('/internal/security/me') @@ -120,13 +118,22 @@ export default function({ getService }: FtrProviderContext) { const sessionCookie = request.cookie(cookies[0])!; checkCookieIsSet(sessionCookie); + const isAnonymousAccessEnabled = (config.get( + 'esTestCluster.serverArgs' + ) as string[]).some(setting => setting.startsWith('xpack.security.authc.anonymous')); + + // `superuser_anonymous` role is derived from the enabled anonymous access. + const expectedUserRoles = isAnonymousAccessEnabled + ? ['kibana_admin', 'superuser_anonymous'] + : ['kibana_admin']; + await supertest .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(200, { username: 'tester@TEST.ELASTIC.CO', - roles: ['kibana_admin'], + roles: expectedUserRoles, full_name: null, email: null, metadata: { From a06c02f606637e82d6964dd3be77b8c496f10156 Mon Sep 17 00:00:00 2001 From: patrykkopycinski Date: Wed, 6 May 2020 14:56:09 +0200 Subject: [PATCH 12/23] [SIEM] Eliminate Superfluous Untitled Timelines (#64341) --- x-pack/plugins/siem/common/constants.ts | 2 + .../siem/common/types/timeline/index.ts | 2 + .../timeline_toggle_column.spec.ts | 2 +- .../cypress/integration/url_state.spec.ts | 62 +-- .../siem/cypress/tasks/create_new_case.ts | 1 + .../public/components/events_viewer/index.tsx | 19 +- .../__snapshots__/index.test.tsx.snap | 4 +- .../edit_timeline_batch_actions.tsx | 2 +- .../components/open_timeline/helpers.test.ts | 51 ++- .../components/open_timeline/helpers.ts | 4 + .../components/open_timeline/index.test.tsx | 401 ++++++++---------- .../open_timeline/open_timeline.tsx | 23 +- .../public/components/open_timeline/types.ts | 4 +- .../__snapshots__/index.test.tsx.snap | 82 ++-- .../siem/public/components/timeline/index.tsx | 17 +- .../public/components/top_n/index.test.tsx | 1 + .../siem/public/containers/timeline/api.ts | 20 +- .../siem/public/graphql/introspection.json | 1 + x-pack/plugins/siem/public/graphql/types.ts | 1 + .../siem/public/mock/timeline_results.ts | 2 +- .../components/signals/index.test.tsx | 18 +- .../components/signals/index.tsx | 64 +-- .../siem/public/pages/timelines/index.tsx | 2 +- x-pack/plugins/siem/public/store/epic.ts | 4 +- .../siem/public/store/timeline/actions.ts | 4 + .../siem/public/store/timeline/defaults.ts | 2 +- .../siem/public/store/timeline/epic.ts | 15 +- .../store/timeline/epic_draft_timeline.ts | 110 +++++ .../siem/public/store/timeline/helpers.ts | 39 +- .../siem/public/store/timeline/model.ts | 1 + .../public/store/timeline/reducer.test.ts | 27 +- .../siem/public/store/timeline/reducer.ts | 37 -- .../server/graphql/timeline/schema.gql.ts | 1 + x-pack/plugins/siem/server/graphql/types.ts | 1 + .../server/lib/timeline/default_timeline.ts | 27 ++ .../lib/timeline/default_timeline_headers.ts | 44 ++ .../lib/timeline/pick_saved_timeline.ts | 9 +- .../routes/__mocks__/import_timelines.ts | 23 + .../routes/__mocks__/request_responses.ts | 27 ++ .../draft_clean_timelines_route.test.ts | 114 +++++ .../routes/draft_clean_timelines_route.ts | 86 ++++ .../routes/draft_timelines_route.test.ts | 113 +++++ .../timeline/routes/draft_timelines_route.ts | 80 ++++ .../timeline/routes/export_timelines_route.ts | 2 - .../routes/import_timelines_route.test.ts | 24 +- .../timeline/routes/import_timelines_route.ts | 8 +- .../timeline/routes/utils/export_timelines.ts | 5 + .../siem/server/lib/timeline/saved_object.ts | 62 ++- x-pack/plugins/siem/server/routes/index.ts | 4 + .../es_archives/timeline/data.json.gz | Bin 1775 -> 1827 bytes .../es_archives/timeline/mappings.json | 3 + yarn.lock | 10 +- 52 files changed, 1189 insertions(+), 478 deletions(-) create mode 100644 x-pack/plugins/siem/public/store/timeline/epic_draft_timeline.ts create mode 100644 x-pack/plugins/siem/server/lib/timeline/default_timeline.ts create mode 100644 x-pack/plugins/siem/server/lib/timeline/default_timeline_headers.ts create mode 100644 x-pack/plugins/siem/server/lib/timeline/routes/draft_clean_timelines_route.test.ts create mode 100644 x-pack/plugins/siem/server/lib/timeline/routes/draft_clean_timelines_route.ts create mode 100644 x-pack/plugins/siem/server/lib/timeline/routes/draft_timelines_route.test.ts create mode 100644 x-pack/plugins/siem/server/lib/timeline/routes/draft_timelines_route.ts diff --git a/x-pack/plugins/siem/common/constants.ts b/x-pack/plugins/siem/common/constants.ts index bcf5c78be3644..9bfd89e8bb576 100644 --- a/x-pack/plugins/siem/common/constants.ts +++ b/x-pack/plugins/siem/common/constants.ts @@ -91,6 +91,8 @@ export const DETECTION_ENGINE_RULES_STATUS_URL = `${DETECTION_ENGINE_RULES_URL}/ export const DETECTION_ENGINE_PREPACKAGED_RULES_STATUS_URL = `${DETECTION_ENGINE_RULES_URL}/prepackaged/_status`; export const TIMELINE_URL = '/api/timeline'; +export const TIMELINE_DRAFT_CLEAN_URL = `${TIMELINE_URL}/_draft/clean`; +export const TIMELINE_DRAFT_URL = `${TIMELINE_URL}/_draft`; export const TIMELINE_EXPORT_URL = `${TIMELINE_URL}/_export`; export const TIMELINE_IMPORT_URL = `${TIMELINE_URL}/_import`; diff --git a/x-pack/plugins/siem/common/types/timeline/index.ts b/x-pack/plugins/siem/common/types/timeline/index.ts index 43f66da6109df..e87986fd1bdf2 100644 --- a/x-pack/plugins/siem/common/types/timeline/index.ts +++ b/x-pack/plugins/siem/common/types/timeline/index.ts @@ -136,11 +136,13 @@ const SavedSortRuntimeType = runtimeTypes.partial({ export enum TimelineType { default = 'default', + draft = 'draft', template = 'template', } export const TimelineTypeLiteralRt = runtimeTypes.union([ runtimeTypes.literal(TimelineType.template), + runtimeTypes.literal(TimelineType.draft), runtimeTypes.literal(TimelineType.default), ]); diff --git a/x-pack/plugins/siem/cypress/integration/timeline_toggle_column.spec.ts b/x-pack/plugins/siem/cypress/integration/timeline_toggle_column.spec.ts index 7b2c6f3b55b2e..26006ec5030b6 100644 --- a/x-pack/plugins/siem/cypress/integration/timeline_toggle_column.spec.ts +++ b/x-pack/plugins/siem/cypress/integration/timeline_toggle_column.spec.ts @@ -27,10 +27,10 @@ import { HOSTS_PAGE } from '../urls/navigation'; describe('toggle column in timeline', () => { before(() => { loginAndWaitForPage(HOSTS_PAGE); + openTimeline(); }); beforeEach(() => { - openTimeline(); populateTimeline(); }); diff --git a/x-pack/plugins/siem/cypress/integration/url_state.spec.ts b/x-pack/plugins/siem/cypress/integration/url_state.spec.ts index cd60745b19040..489315a819647 100644 --- a/x-pack/plugins/siem/cypress/integration/url_state.spec.ts +++ b/x-pack/plugins/siem/cypress/integration/url_state.spec.ts @@ -30,7 +30,7 @@ import { openAllHosts } from '../tasks/hosts/main'; import { waitForIpsTableToBeLoaded } from '../tasks/network/flows'; import { clearSearchBar, kqlSearch, navigateFromHeaderTo } from '../tasks/siem_header'; -import { openTimeline } from '../tasks/siem_main'; +import { openTimeline, openTimelineIfClosed } from '../tasks/siem_main'; import { addDescriptionToTimeline, addNameToTimeline, @@ -174,10 +174,11 @@ describe('url state', () => { kqlSearch('source.ip: "10.142.0.9" {enter}'); navigateFromHeaderTo(HOSTS); - cy.get(NETWORK).should( - 'have.attr', - 'href', - "#/link-to/network?query=(language:kuery,query:'source.ip:%20%2210.142.0.9%22%20')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1564691609186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1564691609186)))" + cy.get(NETWORK).should($div => + // @ts-ignore + expect($div[0].attributes.href.value).to.include( + "#/link-to/network?query=(language:kuery,query:'source.ip:%20%2210.142.0.9%22%20')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1564691609186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1564691609186)))" + ) ); }); @@ -187,16 +188,20 @@ describe('url state', () => { openAllHosts(); waitForAllHostsToBeLoaded(); - cy.get(HOSTS).should( - 'have.attr', - 'href', - "#/link-to/hosts?query=(language:kuery,query:'host.name:%20%22siem-kibana%22%20')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1577914409186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1577914409186)))" + cy.get(HOSTS).should($div => + // @ts-ignore + expect($div[0].attributes.href.value).to.include( + "#/link-to/hosts?query=(language:kuery,query:'host.name:%20%22siem-kibana%22%20')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1577914409186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1577914409186)))" + ) ); - cy.get(NETWORK).should( - 'have.attr', - 'href', - "#/link-to/network?query=(language:kuery,query:'host.name:%20%22siem-kibana%22%20')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1577914409186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1577914409186)))" + + cy.get(NETWORK).should($div => + // @ts-ignore + expect($div[0].attributes.href.value).to.include( + "#/link-to/network?query=(language:kuery,query:'host.name:%20%22siem-kibana%22%20')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1577914409186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1577914409186)))" + ) ); + cy.get(HOSTS_NAMES) .first() .invoke('text') @@ -206,24 +211,29 @@ describe('url state', () => { clearSearchBar(); kqlSearch('agent.type: "auditbeat" {enter}'); - cy.get(ANOMALIES_TAB).should( - 'have.attr', - 'href', - "#/hosts/siem-kibana/anomalies?query=(language:kuery,query:'agent.type:%20%22auditbeat%22%20')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1577914409186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1577914409186)))" + cy.get(ANOMALIES_TAB).should($div => + // @ts-ignore + expect($div[0].attributes.href.value).to.include( + "#/hosts/siem-kibana/anomalies?query=(language:kuery,query:'agent.type:%20%22auditbeat%22%20')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1577914409186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1577914409186)))" + ) ); + cy.get(BREADCRUMBS) .eq(1) - .should( - 'have.attr', - 'href', - "#/link-to/hosts?query=(language:kuery,query:'agent.type:%20%22auditbeat%22%20')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1577914409186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1577914409186)))" + .should($div => + // @ts-ignore + expect($div[0].attributes.href.value).to.include( + "#/link-to/hosts?query=(language:kuery,query:'agent.type:%20%22auditbeat%22%20')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1577914409186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1577914409186)))" + ) ); + cy.get(BREADCRUMBS) .eq(2) - .should( - 'have.attr', - 'href', - "#/link-to/hosts/siem-kibana?query=(language:kuery,query:'agent.type:%20%22auditbeat%22%20')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1577914409186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1577914409186)))" + .should($div => + // @ts-ignore + expect($div[0].attributes.href.value).to.include( + "#/link-to/hosts/siem-kibana?query=(language:kuery,query:'agent.type:%20%22auditbeat%22%20')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1577914409186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1577914409186)))" + ) ); }); @@ -236,7 +246,7 @@ describe('url state', () => { it('sets and reads the url state for timeline by id', () => { loginAndWaitForPage(HOSTS_PAGE); - openTimeline(); + openTimelineIfClosed(); executeTimelineKQL('host.name: *'); cy.get(SERVER_SIDE_EVENT_COUNT) diff --git a/x-pack/plugins/siem/cypress/tasks/create_new_case.ts b/x-pack/plugins/siem/cypress/tasks/create_new_case.ts index b7078a1033de8..491fdd84e9b38 100644 --- a/x-pack/plugins/siem/cypress/tasks/create_new_case.ts +++ b/x-pack/plugins/siem/cypress/tasks/create_new_case.ts @@ -32,6 +32,7 @@ export const createNewCase = (newCase: TestCase) => { cy.get(INSERT_TIMELINE_BTN).click({ force: true }); cy.get(TIMELINE_SEARCHBOX).type(`${newCase.timeline.title}{enter}`); cy.get(TIMELINE).should('be.visible'); + cy.wait(300); cy.get(TIMELINE) .eq(1) .click({ force: true }); diff --git a/x-pack/plugins/siem/public/components/events_viewer/index.tsx b/x-pack/plugins/siem/public/components/events_viewer/index.tsx index bc6a1b3b77bfa..5131033d994a1 100644 --- a/x-pack/plugins/siem/public/components/events_viewer/index.tsx +++ b/x-pack/plugins/siem/public/components/events_viewer/index.tsx @@ -16,6 +16,7 @@ import { SubsetTimelineModel, TimelineModel, } from '../../store/timeline/model'; +import { getNewTimeline } from '../../store/timeline/helpers'; import { OnChangeItemsPerPage } from '../timeline/events'; import { Filter } from '../../../../../../src/plugins/data/public'; import { useUiSetting } from '../../lib/kibana'; @@ -44,7 +45,7 @@ const defaultTimelineTypeContext = { }; const StatefulEventsViewerComponent: React.FC = ({ - createTimeline, + addTimeline, columns, dataProviders, deletedEventIds, @@ -75,8 +76,18 @@ const StatefulEventsViewerComponent: React.FC = ({ ); useEffect(() => { - if (createTimeline != null) { - createTimeline({ id, columns, sort, itemsPerPage, showCheckboxes, showRowRenderers }); + if (addTimeline != null) { + addTimeline({ + id, + timeline: getNewTimeline({ + id, + columns, + sort, + itemsPerPage, + showCheckboxes, + showRowRenderers, + }), + }); } return () => { deleteEventQuery({ id, inputId: 'global' }); @@ -180,7 +191,7 @@ const makeMapStateToProps = () => { }; const mapDispatchToProps = { - createTimeline: timelineActions.createTimeline, + addTimeline: timelineActions.addTimeline, deleteEventQuery: inputsActions.deleteOneQuery, updateItemsPerPage: timelineActions.updateItemsPerPage, removeColumn: timelineActions.removeColumn, diff --git a/x-pack/plugins/siem/public/components/matrix_histogram/__snapshots__/index.test.tsx.snap b/x-pack/plugins/siem/public/components/matrix_histogram/__snapshots__/index.test.tsx.snap index c4bdff7ea649a..e378afd9c7fec 100644 --- a/x-pack/plugins/siem/public/components/matrix_histogram/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/siem/public/components/matrix_histogram/__snapshots__/index.test.tsx.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Matrix Histogram Component not initial load it renders no MatrixLoader 1`] = `"
"`; +exports[`Matrix Histogram Component not initial load it renders no MatrixLoader 1`] = `"
"`; -exports[`Matrix Histogram Component on initial load it renders MatrixLoader 1`] = `"
"`; +exports[`Matrix Histogram Component on initial load it renders MatrixLoader 1`] = `"
"`; diff --git a/x-pack/plugins/siem/public/components/open_timeline/edit_timeline_batch_actions.tsx b/x-pack/plugins/siem/public/components/open_timeline/edit_timeline_batch_actions.tsx index 74b9a8cad98dc..7fb03b98432d0 100644 --- a/x-pack/plugins/siem/public/components/open_timeline/edit_timeline_batch_actions.tsx +++ b/x-pack/plugins/siem/public/components/open_timeline/edit_timeline_batch_actions.tsx @@ -20,7 +20,7 @@ const getExportedIds = (selectedTimelines: OpenTimelineResult[]) => { ); }; -export const useEditTimelinBatchActions = ({ +export const useEditTimelineBatchActions = ({ deleteTimelines, selectedItems, tableRef, diff --git a/x-pack/plugins/siem/public/components/open_timeline/helpers.test.ts b/x-pack/plugins/siem/public/components/open_timeline/helpers.test.ts index a7c0b08fc8a21..700fd15cdea05 100644 --- a/x-pack/plugins/siem/public/components/open_timeline/helpers.test.ts +++ b/x-pack/plugins/siem/public/components/open_timeline/helpers.test.ts @@ -300,7 +300,7 @@ describe('helpers', () => { sortDirection: 'desc', }, title: '', - timelineType: TimelineType.default, + timelineType: TimelineType.draft, templateTimelineId: null, templateTimelineVersion: null, version: '1', @@ -397,13 +397,14 @@ describe('helpers', () => { sortDirection: 'desc', }, title: '', - timelineType: TimelineType.default, + timelineType: TimelineType.draft, templateTimelineId: null, templateTimelineVersion: null, version: '1', width: 1100, }); }); + test('should merge columns when event.action is deleted without two extra column names of user.name', () => { const timeline = { savedObjectId: 'savedObject-1', @@ -416,38 +417,80 @@ describe('helpers', () => { savedObjectId: 'savedObject-1', columns: [ { + aggregatable: undefined, + category: undefined, columnHeaderType: 'not-filtered', + description: undefined, + example: undefined, id: '@timestamp', + placeholder: undefined, + type: undefined, width: 190, }, { + aggregatable: undefined, + category: undefined, columnHeaderType: 'not-filtered', + description: undefined, + example: undefined, id: 'message', + placeholder: undefined, + type: undefined, width: 180, }, { + aggregatable: undefined, + category: undefined, columnHeaderType: 'not-filtered', + description: undefined, + example: undefined, id: 'event.category', + placeholder: undefined, + type: undefined, width: 180, }, { + aggregatable: undefined, + category: undefined, columnHeaderType: 'not-filtered', + description: undefined, + example: undefined, id: 'host.name', + placeholder: undefined, + type: undefined, width: 180, }, { + aggregatable: undefined, + category: undefined, columnHeaderType: 'not-filtered', + description: undefined, + example: undefined, id: 'source.ip', + placeholder: undefined, + type: undefined, width: 180, }, { + aggregatable: undefined, + category: undefined, columnHeaderType: 'not-filtered', + description: undefined, + example: undefined, id: 'destination.ip', + placeholder: undefined, + type: undefined, width: 180, }, { + aggregatable: undefined, + category: undefined, columnHeaderType: 'not-filtered', + description: undefined, + example: undefined, id: 'user.name', + placeholder: undefined, + type: undefined, width: 180, }, ], @@ -474,7 +517,7 @@ describe('helpers', () => { }, loadingEventIds: [], title: '', - timelineType: TimelineType.default, + timelineType: TimelineType.draft, templateTimelineId: null, templateTimelineVersion: null, noteIds: [], @@ -642,7 +685,7 @@ describe('helpers', () => { }, loadingEventIds: [], title: '', - timelineType: TimelineType.default, + timelineType: TimelineType.draft, templateTimelineId: null, templateTimelineVersion: null, noteIds: [], diff --git a/x-pack/plugins/siem/public/components/open_timeline/helpers.ts b/x-pack/plugins/siem/public/components/open_timeline/helpers.ts index 681d39feb09f8..103040c3b0d9e 100644 --- a/x-pack/plugins/siem/public/components/open_timeline/helpers.ts +++ b/x-pack/plugins/siem/public/components/open_timeline/helpers.ts @@ -251,6 +251,10 @@ export const queryTimelineById = ({ } }; +export const epicUpdateTimeline = ({ id, timeline }: UpdateTimeline) => [ + dispatchAddTimeline({ id, timeline }), +]; + export const dispatchUpdateTimeline = (dispatch: Dispatch): DispatchUpdateTimeline => ({ duplicate, id, diff --git a/x-pack/plugins/siem/public/components/open_timeline/index.test.tsx b/x-pack/plugins/siem/public/components/open_timeline/index.test.tsx index 731c6d1ca9806..fee6e6614b863 100644 --- a/x-pack/plugins/siem/public/components/open_timeline/index.test.tsx +++ b/x-pack/plugins/siem/public/components/open_timeline/index.test.tsx @@ -4,14 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json'; import { mount } from 'enzyme'; import { MockedProvider } from 'react-apollo/test-utils'; import React from 'react'; -import { ThemeProvider } from 'styled-components'; import { wait } from '../../lib/helpers'; -import { TestProviderWithoutDragAndDrop, apolloClient } from '../../mock/test_providers'; +import { TestProviders, apolloClient } from '../../mock/test_providers'; import { mockOpenTimelineQueryResults } from '../../mock/timeline_results'; import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../pages/timelines/timelines_page'; @@ -41,7 +39,6 @@ jest.mock('./use_timeline_types', () => { }); describe('StatefulOpenTimeline', () => { - const theme = () => ({ eui: euiDarkVars, darkMode: true }); const title = 'All Timelines / Open Timelines'; beforeEach(() => { ((useGetAllTimeline as unknown) as jest.Mock).mockReturnValue({ @@ -58,19 +55,17 @@ describe('StatefulOpenTimeline', () => { test('it has the expected initial state', () => { const wrapper = mount( - - - - - - - + + + + + ); const componentProps = wrapper @@ -94,19 +89,17 @@ describe('StatefulOpenTimeline', () => { describe('#onQueryChange', () => { test('it updates the query state with the expected trimmed value when the user enters a query', () => { const wrapper = mount( - - - - - - - + + + + + ); wrapper .find('[data-test-subj="search-bar"] input') @@ -121,18 +114,16 @@ describe('StatefulOpenTimeline', () => { test('it appends the word "with" to the Showing in Timelines message when the user enters a query', async () => { const wrapper = mount( - - - - - - - + + + + + ); await wait(); @@ -151,18 +142,16 @@ describe('StatefulOpenTimeline', () => { test('echos (renders) the query when the user enters a query', async () => { const wrapper = mount( - - - - - - - + + + + + ); await wait(); @@ -183,18 +172,16 @@ describe('StatefulOpenTimeline', () => { describe('#focusInput', () => { test('focuses the input when the component mounts', async () => { const wrapper = mount( - - - - - - - + + + + + ); await wait(); @@ -214,18 +201,16 @@ describe('StatefulOpenTimeline', () => { const addTimelinesToFavorites = jest.fn(); const wrapper = mount( - - - - - - - + + + + + ); await wait(); @@ -260,18 +245,16 @@ describe('StatefulOpenTimeline', () => { const deleteTimelines = jest.fn(); const wrapper = mount( - - - - - - - + + + + + ); await wait(); @@ -303,19 +286,17 @@ describe('StatefulOpenTimeline', () => { describe('#onSelectionChange', () => { test('it updates the selection state when timelines are selected', async () => { const wrapper = mount( - - - - - - - + + + + + ); await wait(); @@ -337,19 +318,17 @@ describe('StatefulOpenTimeline', () => { describe('#onTableChange', () => { test('it updates the sort state when the user clicks on a column to sort it', () => { const wrapper = mount( - - - - - - - + + + + + ); expect( @@ -376,19 +355,17 @@ describe('StatefulOpenTimeline', () => { describe('#onToggleOnlyFavorites', () => { test('it updates the onlyFavorites state when the user clicks the Only Favorites button', () => { const wrapper = mount( - - - - - - - + + + + + ); expect( @@ -415,19 +392,17 @@ describe('StatefulOpenTimeline', () => { describe('#onToggleShowNotes', () => { test('it updates the itemIdToExpandedNotesRowMap state when the user clicks the expand notes button', async () => { const wrapper = mount( - - - - - - - + + + + + ); await wait(); @@ -467,19 +442,17 @@ describe('StatefulOpenTimeline', () => { test('it renders the expanded notes when the expand button is clicked', async () => { const wrapper = mount( - - - - - - - + + + + + ); await wait(); @@ -502,21 +475,19 @@ describe('StatefulOpenTimeline', () => { ).toEqual('elastic'); }); - test('it renders the title', async () => { + test('it renders the tabs', async () => { const wrapper = mount( - - - - - - - + + + + + ); await wait(); @@ -530,19 +501,17 @@ describe('StatefulOpenTimeline', () => { describe('#resetSelectionState', () => { test('when the user deletes selected timelines, resetSelectionState is invoked to clear the selection state', async () => { const wrapper = mount( - - - - - - - + + + + + ); const getSelectedItem = (): [] => wrapper @@ -561,19 +530,17 @@ describe('StatefulOpenTimeline', () => { test('it renders the expected count of matching timelines when no query has been entered', async () => { const wrapper = mount( - + - - - + - + ); await wait(); @@ -593,19 +560,17 @@ describe('StatefulOpenTimeline', () => { const onOpenTimeline = jest.fn(); const wrapper = mount( - - - - - - - + + + + + ); await wait(); @@ -631,19 +596,17 @@ describe('StatefulOpenTimeline', () => { const onOpenTimeline = jest.fn(); const wrapper = mount( - - - - - - - + + + + + ); await wait(); diff --git a/x-pack/plugins/siem/public/components/open_timeline/open_timeline.tsx b/x-pack/plugins/siem/public/components/open_timeline/open_timeline.tsx index e172a006abe4b..ce0eb52bc3839 100644 --- a/x-pack/plugins/siem/public/components/open_timeline/open_timeline.tsx +++ b/x-pack/plugins/siem/public/components/open_timeline/open_timeline.tsx @@ -8,7 +8,7 @@ import { EuiPanel, EuiBasicTable } from '@elastic/eui'; import React, { useCallback, useMemo, useRef } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { OPEN_TIMELINE_CLASS_NAME } from './helpers'; -import { OpenTimelineProps, OpenTimelineResult } from './types'; +import { OpenTimelineProps, OpenTimelineResult, ActionTimelineToShow } from './types'; import { SearchRow } from './search_row'; import { TimelinesTable } from './timelines_table'; import { ImportDataModal } from '../import_data_modal'; @@ -22,7 +22,7 @@ import { UtilityBarSection, UtilityBarAction, } from '../utility_bar'; -import { useEditTimelinBatchActions } from './edit_timeline_batch_actions'; +import { useEditTimelineBatchActions } from './edit_timeline_batch_actions'; import { useEditTimelineActions } from './edit_timeline_actions'; import { EditOneTimelineAction } from './export_timeline'; @@ -65,7 +65,7 @@ export const OpenTimeline = React.memo( onCompleteEditTimelineAction, } = useEditTimelineActions(); - const { getBatchItemsPopoverContent } = useEditTimelinBatchActions({ + const { getBatchItemsPopoverContent } = useEditTimelineBatchActions({ deleteTimelines, selectedItems, tableRef, @@ -106,6 +106,7 @@ export const OpenTimeline = React.memo( setImportDataModalToggle(false); } }, [setImportDataModalToggle]); + const handleComplete = useCallback(() => { if (setImportDataModalToggle != null) { setImportDataModalToggle(false); @@ -115,6 +116,14 @@ export const OpenTimeline = React.memo( } }, [setImportDataModalToggle, refetch, searchResults, totalSearchResultsCount]); + const actionTimelineToShow = useMemo( + () => + onDeleteSelected != null && deleteTimelines != null + ? ['delete', 'duplicate', 'export', 'selectable'] + : ['duplicate', 'export', 'selectable'], + [onDeleteSelected, deleteTimelines] + ); + return ( <> ( - onDeleteSelected != null && deleteTimelines != null - ? ['delete', 'duplicate', 'export', 'selectable'] - : ['duplicate', 'export', 'selectable'], - [onDeleteSelected, deleteTimelines] - )} + actionTimelineToShow={actionTimelineToShow} data-test-subj="timelines-table" deleteTimelines={deleteTimelines} defaultPageSize={defaultPageSize} diff --git a/x-pack/plugins/siem/public/components/open_timeline/types.ts b/x-pack/plugins/siem/public/components/open_timeline/types.ts index 4d953f6fa775e..bb7e508518047 100644 --- a/x-pack/plugins/siem/public/components/open_timeline/types.ts +++ b/x-pack/plugins/siem/public/components/open_timeline/types.ts @@ -8,7 +8,7 @@ import { SetStateAction, Dispatch } from 'react'; import { AllTimelinesVariables } from '../../containers/timeline/all'; import { TimelineModel } from '../../store/timeline/model'; import { NoteResult } from '../../graphql/types'; -import { TimelineType, TimelineTypeLiteral } from '../../../common/types/timeline'; +import { TimelineTypeLiteral } from '../../../common/types/timeline'; /** The users who added a timeline to favorites */ export interface FavoriteTimelineResult { @@ -48,7 +48,7 @@ export interface OpenTimelineResult { savedObjectId?: string | null; title?: string | null; templateTimelineId?: string | null; - type?: TimelineType.template | TimelineType.default; + type?: TimelineTypeLiteral; updated?: number | null; updatedBy?: string | null; } diff --git a/x-pack/plugins/siem/public/components/stat_items/__snapshots__/index.test.tsx.snap b/x-pack/plugins/siem/public/components/stat_items/__snapshots__/index.test.tsx.snap index e15ce0ae5f543..e209ca3b069d2 100644 --- a/x-pack/plugins/siem/public/components/stat_items/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/siem/public/components/stat_items/__snapshots__/index.test.tsx.snap @@ -38,18 +38,18 @@ exports[`Stat Items Component disable charts it renders the default widget 1`] = data-test-subj="stat-item" >

@@ -258,18 +258,18 @@ exports[`Stat Items Component disable charts it renders the default widget 2`] = data-test-subj="stat-item" >

@@ -548,18 +548,18 @@ exports[`Stat Items Component rendering kpis with charts it renders the default data-test-subj="stat-item" >

1,714 @@ -734,10 +734,10 @@ exports[`Stat Items Component rendering kpis with charts it renders the default key="stat-items-field-uniqueDestinationIps" >

2,359 @@ -815,10 +815,10 @@ exports[`Stat Items Component rendering kpis with charts it renders the default >

( ({ columns, - createTimeline, dataProviders, eventType, end, @@ -143,19 +141,13 @@ const StatefulTimelineComponent = React.memo( [columns, id] ); - useEffect(() => { - if (createTimeline != null) { - createTimeline({ id, columns: defaultHeaders, show: false }); - } - }, []); - return ( {({ indexPattern, browserFields }) => ( ( onDataProviderRemoved={onDataProviderRemoved} onToggleDataProviderEnabled={onToggleDataProviderEnabled} onToggleDataProviderExcluded={onToggleDataProviderExcluded} - show={show!} + show={show} showCallOutUnauthorizedMsg={showCallOutUnauthorizedMsg} - sort={sort!} + sort={sort} start={start} toggleColumn={toggleColumn} usersViewing={usersViewing} @@ -255,7 +247,6 @@ const makeMapStateToProps = () => { const mapDispatchToProps = { addProvider: timelineActions.addProvider, - createTimeline: timelineActions.createTimeline, onDataProviderEdited: timelineActions.dataProviderEdited, removeColumn: timelineActions.removeColumn, removeProvider: timelineActions.removeProvider, diff --git a/x-pack/plugins/siem/public/components/top_n/index.test.tsx b/x-pack/plugins/siem/public/components/top_n/index.test.tsx index 9325dcf499b2b..08d1b4d5ffd4c 100644 --- a/x-pack/plugins/siem/public/components/top_n/index.test.tsx +++ b/x-pack/plugins/siem/public/components/top_n/index.test.tsx @@ -18,6 +18,7 @@ import { Props } from './top_n'; import { ACTIVE_TIMELINE_REDUX_ID, StatefulTopN } from '.'; jest.mock('../../lib/kibana'); +jest.mock('../../store/timeline/actions'); const mockUiSettingsForFilterManager = createKibanaCoreStartMock().uiSettings; diff --git a/x-pack/plugins/siem/public/containers/timeline/api.ts b/x-pack/plugins/siem/public/containers/timeline/api.ts index 023e2e6af9f88..3a9cd2b0dc375 100644 --- a/x-pack/plugins/siem/public/containers/timeline/api.ts +++ b/x-pack/plugins/siem/public/containers/timeline/api.ts @@ -13,7 +13,13 @@ import { TimelineResponse, TimelineResponseType, } from '../../../common/types/timeline'; -import { TIMELINE_URL, TIMELINE_IMPORT_URL, TIMELINE_EXPORT_URL } from '../../../common/constants'; +import { + TIMELINE_URL, + TIMELINE_DRAFT_CLEAN_URL, + TIMELINE_DRAFT_URL, + TIMELINE_IMPORT_URL, + TIMELINE_EXPORT_URL, +} from '../../../common/constants'; import { KibanaServices } from '../../lib/kibana'; import { ExportSelectedData } from '../../components/generic_downloader'; @@ -113,3 +119,15 @@ export const exportSelectedTimeline: ExportSelectedData = async ({ return response.body!; }; + +export const getDraftTimeline = async (): Promise => { + const response = await KibanaServices.get().http.get(TIMELINE_DRAFT_URL); + + return decodeTimelineResponse(response); +}; + +export const cleanDraftTimeline = async (): Promise => { + const response = await KibanaServices.get().http.post(TIMELINE_DRAFT_CLEAN_URL); + + return decodeTimelineResponse(response); +}; diff --git a/x-pack/plugins/siem/public/graphql/introspection.json b/x-pack/plugins/siem/public/graphql/introspection.json index c2b21957a9056..d6f34255bcc1c 100644 --- a/x-pack/plugins/siem/public/graphql/introspection.json +++ b/x-pack/plugins/siem/public/graphql/introspection.json @@ -10377,6 +10377,7 @@ "isDeprecated": false, "deprecationReason": null }, + { "name": "draft", "description": "", "isDeprecated": false, "deprecationReason": null }, { "name": "template", "description": "", diff --git a/x-pack/plugins/siem/public/graphql/types.ts b/x-pack/plugins/siem/public/graphql/types.ts index dd4e967b185b9..3436ee84a2f30 100644 --- a/x-pack/plugins/siem/public/graphql/types.ts +++ b/x-pack/plugins/siem/public/graphql/types.ts @@ -342,6 +342,7 @@ export enum TlsFields { export enum TimelineType { default = 'default', + draft = 'draft', template = 'template', } diff --git a/x-pack/plugins/siem/public/mock/timeline_results.ts b/x-pack/plugins/siem/public/mock/timeline_results.ts index 1af0f533a7ca9..86acb2981be06 100644 --- a/x-pack/plugins/siem/public/mock/timeline_results.ts +++ b/x-pack/plugins/siem/public/mock/timeline_results.ts @@ -2243,7 +2243,7 @@ export const defaultTimelineProps: CreateTimelineProps = { showRowRenderers: true, sort: { columnId: '@timestamp', sortDirection: Direction.desc }, title: '', - timelineType: TimelineType.default, + timelineType: TimelineType.draft, templateTimelineVersion: null, templateTimelineId: null, version: null, diff --git a/x-pack/plugins/siem/public/pages/detection_engine/components/signals/index.test.tsx b/x-pack/plugins/siem/public/pages/detection_engine/components/signals/index.test.tsx index b66a9fc881045..ac31d12186d34 100644 --- a/x-pack/plugins/siem/public/pages/detection_engine/components/signals/index.test.tsx +++ b/x-pack/plugins/siem/public/pages/detection_engine/components/signals/index.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { SignalsTableComponent } from './index'; +import { SignalsTableComponent, PropsFromRedux } from './index'; describe('SignalsTableComponent', () => { it('renders correctly', () => { @@ -28,13 +28,15 @@ describe('SignalsTableComponent', () => { loadingEventIds={[]} selectedEventIds={{}} isSelectAllChecked={false} - clearSelected={jest.fn()} - setEventsLoading={jest.fn()} - clearEventsLoading={jest.fn()} - setEventsDeleted={jest.fn()} - clearEventsDeleted={jest.fn()} - updateTimelineIsLoading={jest.fn()} - updateTimeline={jest.fn()} + clearSelected={(jest.fn() as unknown) as PropsFromRedux['clearSelected']} + setEventsLoading={(jest.fn() as unknown) as PropsFromRedux['setEventsLoading']} + clearEventsLoading={(jest.fn() as unknown) as PropsFromRedux['clearEventsLoading']} + setEventsDeleted={(jest.fn() as unknown) as PropsFromRedux['setEventsDeleted']} + clearEventsDeleted={(jest.fn() as unknown) as PropsFromRedux['clearEventsDeleted']} + createTimeline={(jest.fn() as unknown) as PropsFromRedux['createTimeline']} + updateTimelineIsLoading={ + (jest.fn() as unknown) as PropsFromRedux['updateTimelineIsLoading'] + } /> ); diff --git a/x-pack/plugins/siem/public/pages/detection_engine/components/signals/index.tsx b/x-pack/plugins/siem/public/pages/detection_engine/components/signals/index.tsx index 5442c8c19b5a7..f1c7b50e49723 100644 --- a/x-pack/plugins/siem/public/pages/detection_engine/components/signals/index.tsx +++ b/x-pack/plugins/siem/public/pages/detection_engine/components/signals/index.tsx @@ -8,7 +8,6 @@ import { EuiPanel, EuiLoadingContent } from '@elastic/eui'; import { isEmpty } from 'lodash/fp'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { connect, ConnectedProps } from 'react-redux'; -import { Dispatch } from 'redux'; import { Filter, esQuery } from '../../../../../../../../src/plugins/data/public'; import { useFetchIndexPatterns } from '../../../../containers/detection_engine/rules/fetch_index_patterns'; @@ -45,7 +44,6 @@ import { UpdateSignalsStatusCallback, UpdateSignalsStatusProps, } from './types'; -import { dispatchUpdateTimeline } from '../../../../components/open_timeline/helpers'; export const SIGNALS_PAGE_TIMELINE_ID = 'signals-page'; @@ -66,6 +64,7 @@ export const SignalsTableComponent: React.FC = ({ clearEventsDeleted, clearEventsLoading, clearSelected, + createTimeline, defaultFilters, from, globalFilters, @@ -79,7 +78,6 @@ export const SignalsTableComponent: React.FC = ({ setEventsLoading, signalsIndex, to, - updateTimeline, updateTimelineIsLoading, }) => { const [selectAll, setSelectAll] = useState(false); @@ -114,22 +112,13 @@ export const SignalsTableComponent: React.FC = ({ // Callback for creating a new timeline -- utilized by row/batch actions const createTimelineCallback = useCallback( - ({ from: fromTimeline, timeline, to: toTimeline, ruleNote }: CreateTimelineProps) => { - updateTimelineIsLoading({ id: 'timeline-1', isLoading: false }); - updateTimeline({ - duplicate: true, - from: fromTimeline, + ({ timeline }: CreateTimelineProps) => + createTimeline({ id: 'timeline-1', - notes: [], - timeline: { - ...timeline, - show: true, - }, - to: toTimeline, - ruleNote, - })(); - }, - [updateTimeline, updateTimelineIsLoading] + ...timeline, + show: true, + }), + [createTimeline] ); const setEventsLoadingCallback = useCallback( @@ -333,37 +322,18 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -const mapDispatchToProps = (dispatch: Dispatch) => ({ - clearSelected: ({ id }: { id: string }) => dispatch(timelineActions.clearSelected({ id })), - setEventsLoading: ({ - id, - eventIds, - isLoading, - }: { - id: string; - eventIds: string[]; - isLoading: boolean; - }) => dispatch(timelineActions.setEventsLoading({ id, eventIds, isLoading })), - clearEventsLoading: ({ id }: { id: string }) => - dispatch(timelineActions.clearEventsLoading({ id })), - setEventsDeleted: ({ - id, - eventIds, - isDeleted, - }: { - id: string; - eventIds: string[]; - isDeleted: boolean; - }) => dispatch(timelineActions.setEventsDeleted({ id, eventIds, isDeleted })), - clearEventsDeleted: ({ id }: { id: string }) => - dispatch(timelineActions.clearEventsDeleted({ id })), - updateTimelineIsLoading: ({ id, isLoading }: { id: string; isLoading: boolean }) => - dispatch(timelineActions.updateIsLoading({ id, isLoading })), - updateTimeline: dispatchUpdateTimeline(dispatch), -}); +const mapDispatchToProps = { + clearSelected: timelineActions.clearSelected, + setEventsLoading: timelineActions.setEventsLoading, + clearEventsLoading: timelineActions.clearEventsLoading, + setEventsDeleted: timelineActions.setEventsDeleted, + clearEventsDeleted: timelineActions.clearEventsDeleted, + updateTimelineIsLoading: timelineActions.updateIsLoading, + createTimeline: timelineActions.createTimeline, +}; const connector = connect(makeMapStateToProps, mapDispatchToProps); -type PropsFromRedux = ConnectedProps; +export type PropsFromRedux = ConnectedProps; export const SignalsTable = connector(React.memo(SignalsTableComponent)); diff --git a/x-pack/plugins/siem/public/pages/timelines/index.tsx b/x-pack/plugins/siem/public/pages/timelines/index.tsx index 343be5cbe3839..992174f337f1e 100644 --- a/x-pack/plugins/siem/public/pages/timelines/index.tsx +++ b/x-pack/plugins/siem/public/pages/timelines/index.tsx @@ -23,7 +23,7 @@ import { appendSearch } from '../../components/link_to/helpers'; const timelinesPagePath = `/:pageName(${SiemPageName.timelines})/:tabName(${TimelineType.default}|${TimelineType.template})`; const timelinesDefaultPath = `/${SiemPageName.timelines}/${TimelineType.default}`; -const TabNameMappedToI18nKey: Record = { +const TabNameMappedToI18nKey: Record = { [TimelineType.default]: TAB_TIMELINES, [TimelineType.template]: TAB_TEMPLATES, }; diff --git a/x-pack/plugins/siem/public/store/epic.ts b/x-pack/plugins/siem/public/store/epic.ts index 336960588f48c..d7c15ac88e2a9 100644 --- a/x-pack/plugins/siem/public/store/epic.ts +++ b/x-pack/plugins/siem/public/store/epic.ts @@ -9,11 +9,13 @@ import { createTimelineEpic } from './timeline/epic'; import { createTimelineFavoriteEpic } from './timeline/epic_favorite'; import { createTimelineNoteEpic } from './timeline/epic_note'; import { createTimelinePinnedEventEpic } from './timeline/epic_pinned_event'; +import { createDraftTimelineEpic } from './timeline/epic_draft_timeline'; export const createRootEpic = () => combineEpics( createTimelineEpic(), createTimelineFavoriteEpic(), createTimelineNoteEpic(), - createTimelinePinnedEventEpic() + createTimelinePinnedEventEpic(), + createDraftTimelineEpic() ); diff --git a/x-pack/plugins/siem/public/store/timeline/actions.ts b/x-pack/plugins/siem/public/store/timeline/actions.ts index 12155decf40d4..205c96e57f883 100644 --- a/x-pack/plugins/siem/public/store/timeline/actions.ts +++ b/x-pack/plugins/siem/public/store/timeline/actions.ts @@ -69,6 +69,10 @@ export const createTimeline = actionCreator<{ showRowRenderers?: boolean; }>('CREATE_TIMELINE'); +export const getDraftTimeline = actionCreator<{ id: string }>('GET_DRAFT_TIMELINE'); + +export const cleanDraftTimeline = actionCreator<{ id: string }>('CLEAN_DRAFT_TIMELINE'); + export const pinEvent = actionCreator<{ id: string; eventId: string }>('PIN_EVENT'); export const removeColumn = actionCreator<{ diff --git a/x-pack/plugins/siem/public/store/timeline/defaults.ts b/x-pack/plugins/siem/public/store/timeline/defaults.ts index 9203720e2e28c..f40b0078c499f 100644 --- a/x-pack/plugins/siem/public/store/timeline/defaults.ts +++ b/x-pack/plugins/siem/public/store/timeline/defaults.ts @@ -35,7 +35,7 @@ export const timelineDefaults: SubsetTimelineModel & Pick { timelineByIdSelector: (state: State) => TimelineById; @@ -148,8 +150,13 @@ export const createTimelineEpic = (): Epic< return true; } if (action.type === createTimeline.type && isItAtimelineAction(timelineId)) { - myEpicTimelineId.setTimelineId(null); - myEpicTimelineId.setTimelineVersion(null); + if (timelineObj.timelineType !== 'draft') { + myEpicTimelineId.setTimelineVersion(null); + myEpicTimelineId.setTimelineId(null); + } + return true; + } else if (action.type === getDraftTimeline.type && isItAtimelineAction(timelineId)) { + return true; } else if (action.type === addTimeline.type && isItAtimelineAction(timelineId)) { const addNewTimeline: TimelineModel = get('payload.timeline', action); myEpicTimelineId.setTimelineId(addNewTimeline.savedObjectId); @@ -207,6 +214,10 @@ export const createTimelineEpic = (): Epic< timeline$, allTimelineQuery$ ); + } else if (action.type === getDraftTimeline.type) { + return epicDraftTimeline(action, action$, timeline$, false); + } else if (action.type === createTimeline.type) { + return epicDraftTimeline(action, action$, timeline$, true); } else if (timelineActionsType.includes(action.type)) { return from( persistTimeline({ diff --git a/x-pack/plugins/siem/public/store/timeline/epic_draft_timeline.ts b/x-pack/plugins/siem/public/store/timeline/epic_draft_timeline.ts new file mode 100644 index 0000000000000..9e8d861ea7584 --- /dev/null +++ b/x-pack/plugins/siem/public/store/timeline/epic_draft_timeline.ts @@ -0,0 +1,110 @@ +/* + * 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 { of, Observable, from } from 'rxjs'; +import { get } from 'lodash/fp'; +import { filter, withLatestFrom, mergeMap, takeUntil, startWith } from 'rxjs/operators'; +import { Epic } from 'redux-observable'; +import { Action } from 'redux'; +import { + addTimeline, + createTimeline, + showCallOutUnauthorizedMsg, + endTimelineSaving, +} from './actions'; +import { getDraftTimeline, cleanDraftTimeline } from '../../containers/timeline/api'; +import { ActionTimeline, TimelineById } from './types'; +import { myEpicTimelineId } from './my_epic_timeline_id'; +import { addError } from '../app/actions'; +import { + formatTimelineResultToModel, + epicUpdateTimeline, +} from '../../components/open_timeline/helpers'; +import { getTimeRangeSettings } from '../../utils/default_date_settings'; +import { ResponseTimeline } from '../../graphql/types'; +import { timelineDefaults } from './defaults'; + +export const epicDraftTimeline = ( + action: ActionTimeline, + action$: Observable, + timeline$: Observable, + clean: boolean +) => + from(clean ? cleanDraftTimeline() : getDraftTimeline()).pipe( + withLatestFrom(timeline$), + mergeMap(([result, recentTimelines]) => { + const savedTimeline = recentTimelines[action.payload.id]; + const response: ResponseTimeline = get('data.persistTimeline', result); + const callOutMsg = response.code === 403 ? [showCallOutUnauthorizedMsg()] : []; + + const { timeline: timelineModel, notes } = formatTimelineResultToModel( + { + savedObjectId: response.timeline.savedObjectId, + version: response.timeline.version, + timelineType: response.timeline.timelineType, + }, + false + ); + const { from: settingsFrom, to: settingsTo } = getTimeRangeSettings(); + + return [ + ...callOutMsg, + ...epicUpdateTimeline({ + duplicate: false, + from: savedTimeline?.dateRange.start ?? settingsFrom, + id: 'timeline-1', + notes, + timeline: { + ...savedTimeline, + ...timelineModel, + ...action.payload, + id: timelineModel.savedObjectId!, + savedObjectId: timelineModel.savedObjectId!, + version: timelineModel.version, + // @ts-ignore + show: action.payload.show ?? savedTimeline.show, + }, + to: savedTimeline?.dateRange.end ?? settingsTo, + }), + endTimelineSaving({ + id: action.payload.id, + }), + ]; + }), + takeUntil( + action$.pipe( + withLatestFrom(timeline$), + filter(([checkAction, updatedTimeline]) => { + if (checkAction.type === addError.type) { + return true; + } + if (checkAction.type === addTimeline.type) { + return true; + } + if ( + checkAction.type === endTimelineSaving.type && + updatedTimeline[get('payload.id', checkAction)].savedObjectId != null + ) { + myEpicTimelineId.setTimelineId( + updatedTimeline[get('payload.id', checkAction)].savedObjectId + ); + myEpicTimelineId.setTimelineVersion( + updatedTimeline[get('payload.id', checkAction)].version + ); + return true; + } + return false; + }) + ) + ) + ); + +export const createDraftTimelineEpic = (): Epic => () => + of(createTimeline({ id: 'timeline-1', columns: timelineDefaults.columns })).pipe( + startWith( + addTimeline({ id: 'timeline-1', timeline: { id: 'timeline-1', ...timelineDefaults } }) + ) + ); diff --git a/x-pack/plugins/siem/public/store/timeline/helpers.ts b/x-pack/plugins/siem/public/store/timeline/helpers.ts index adab029c11150..7b8d49119f323 100644 --- a/x-pack/plugins/siem/public/store/timeline/helpers.ts +++ b/x-pack/plugins/siem/public/store/timeline/helpers.ts @@ -125,7 +125,7 @@ export const addTimelineToStore = ({ ...timelineById, [id]: { ...timeline, - isLoading: timelineById[id].isLoading, + isLoading: timelineById[id]?.isLoading ?? timeline.isSaving, }, }); @@ -147,11 +147,10 @@ interface AddNewTimelineParams { sort?: Sort; showCheckboxes?: boolean; showRowRenderers?: boolean; - timelineById: TimelineById; } /** Adds a new `Timeline` to the provided collection of `TimelineById` */ -export const addNewTimeline = ({ +export const getNewTimeline = ({ columns, dataProviders = [], dateRange = { start: 0, end: 0 }, @@ -163,27 +162,19 @@ export const addNewTimeline = ({ show = false, showCheckboxes = false, showRowRenderers = true, - timelineById, -}: AddNewTimelineParams): TimelineById => ({ - ...timelineById, - [id]: { - id, - ...timelineDefaults, - columns, - dataProviders, - dateRange, - filters, - itemsPerPage, - kqlQuery, - sort, - show, - savedObjectId: null, - version: null, - isSaving: false, - isLoading: false, - showCheckboxes, - showRowRenderers, - }, +}: AddNewTimelineParams): TimelineModel => ({ + id, + ...timelineDefaults, + columns, + dataProviders, + dateRange, + filters, + itemsPerPage, + kqlQuery, + sort, + show, + showCheckboxes, + showRowRenderers, }); interface PinTimelineEventParams { diff --git a/x-pack/plugins/siem/public/store/timeline/model.ts b/x-pack/plugins/siem/public/store/timeline/model.ts index 54e19812634ac..b01c7cef1c6d2 100644 --- a/x-pack/plugins/siem/public/store/timeline/model.ts +++ b/x-pack/plugins/siem/public/store/timeline/model.ts @@ -152,6 +152,7 @@ export type SubsetTimelineModel = Readonly< | 'isLoading' | 'savedObjectId' | 'version' + | 'timelineType' > >; diff --git a/x-pack/plugins/siem/public/store/timeline/reducer.test.ts b/x-pack/plugins/siem/public/store/timeline/reducer.test.ts index 42c6d6ecb0e51..a2a74b2422370 100644 --- a/x-pack/plugins/siem/public/store/timeline/reducer.test.ts +++ b/x-pack/plugins/siem/public/store/timeline/reducer.test.ts @@ -23,10 +23,10 @@ import { Direction } from '../../graphql/types'; import { defaultHeaders } from '../../mock'; import { - addNewTimeline, addTimelineProvider, addTimelineToStore, applyDeltaToTimelineColumnWidth, + getNewTimeline, removeTimelineColumn, removeTimelineProvider, updateTimelineColumns, @@ -132,41 +132,32 @@ describe('Timeline', () => { }); }); - describe('#addNewTimeline', () => { + describe('#getNewTimeline', () => { test('should return a new reference and not the same reference', () => { - const update = addNewTimeline({ + const update = getNewTimeline({ id: 'bar', columns: defaultHeaders, - timelineById: timelineByIdMock, }); - expect(update).not.toBe(timelineByIdMock); + expect(update).not.toBe(timelineByIdMock.foo); }); - test('should add a new timeline', () => { - const update = addNewTimeline({ + test('should return a new timeline', () => { + const update = getNewTimeline({ id: 'bar', columns: timelineDefaults.columns, - timelineById: timelineByIdMock, - }); - expect(update).toEqual({ - foo: timelineByIdMock.foo, - bar: set('id', 'bar', timelineDefaults), }); + expect(update).toEqual(set('id', 'bar', timelineDefaults)); }); test('should add the specified columns to the timeline', () => { const barWithEmptyColumns = set('id', 'bar', timelineDefaults); const barWithPopulatedColumns = set('columns', defaultHeaders, barWithEmptyColumns); - const update = addNewTimeline({ + const update = getNewTimeline({ id: 'bar', columns: defaultHeaders, - timelineById: timelineByIdMock, - }); - expect(update).toEqual({ - foo: timelineByIdMock.foo, - bar: barWithPopulatedColumns, }); + expect(update).toEqual(barWithPopulatedColumns); }); }); diff --git a/x-pack/plugins/siem/public/store/timeline/reducer.ts b/x-pack/plugins/siem/public/store/timeline/reducer.ts index e99644daf50d8..b6b3a6deb1e5b 100644 --- a/x-pack/plugins/siem/public/store/timeline/reducer.ts +++ b/x-pack/plugins/siem/public/store/timeline/reducer.ts @@ -14,7 +14,6 @@ import { applyDeltaToColumnWidth, applyDeltaToWidth, applyKqlFilterQuery, - createTimeline, dataProviderEdited, endTimelineSaving, pinEvent, @@ -56,7 +55,6 @@ import { updateEventType, } from './actions'; import { - addNewTimeline, addTimelineHistory, addTimelineNote, addTimelineNoteToEvent, @@ -114,41 +112,6 @@ export const timelineReducer = reducerWithInitialState(initialTimelineState) ...state, timelineById: addTimelineToStore({ id, timeline, timelineById: state.timelineById }), })) - .case( - createTimeline, - ( - state, - { - id, - dataProviders, - dateRange, - show, - columns, - itemsPerPage, - kqlQuery, - sort, - showCheckboxes, - showRowRenderers, - filters, - } - ) => ({ - ...state, - timelineById: addNewTimeline({ - columns, - dataProviders, - dateRange, - filters, - id, - itemsPerPage, - kqlQuery, - sort, - show, - showCheckboxes, - showRowRenderers, - timelineById: state.timelineById, - }), - }) - ) .case(upsertColumn, (state, { column, id, index }) => ({ ...state, timelineById: upsertTimelineColumn({ column, id, index, timelineById: state.timelineById }), diff --git a/x-pack/plugins/siem/server/graphql/timeline/schema.gql.ts b/x-pack/plugins/siem/server/graphql/timeline/schema.gql.ts index a1c13fd21a88e..2432af9a379a1 100644 --- a/x-pack/plugins/siem/server/graphql/timeline/schema.gql.ts +++ b/x-pack/plugins/siem/server/graphql/timeline/schema.gql.ts @@ -127,6 +127,7 @@ export const timelineSchema = gql` enum TimelineType { default + draft template } diff --git a/x-pack/plugins/siem/server/graphql/types.ts b/x-pack/plugins/siem/server/graphql/types.ts index d74086357edbe..5313f4b9df268 100644 --- a/x-pack/plugins/siem/server/graphql/types.ts +++ b/x-pack/plugins/siem/server/graphql/types.ts @@ -344,6 +344,7 @@ export enum TlsFields { export enum TimelineType { default = 'default', + draft = 'draft', template = 'template', } diff --git a/x-pack/plugins/siem/server/lib/timeline/default_timeline.ts b/x-pack/plugins/siem/server/lib/timeline/default_timeline.ts new file mode 100644 index 0000000000000..710a43df1221d --- /dev/null +++ b/x-pack/plugins/siem/server/lib/timeline/default_timeline.ts @@ -0,0 +1,27 @@ +/* + * 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 { Direction } from '../../graphql/types'; +import { defaultHeaders } from './default_timeline_headers'; +import { SavedTimeline, TimelineType } from '../../../common/types/timeline'; + +export const draftTimelineDefaults: SavedTimeline = { + columns: defaultHeaders, + dataProviders: [], + description: '', + eventType: 'all', + filters: [], + kqlMode: 'filter', + timelineType: TimelineType.draft, + kqlQuery: { + filterQuery: null, + }, + title: '', + sort: { + columnId: '@timestamp', + sortDirection: Direction.desc, + }, +}; diff --git a/x-pack/plugins/siem/server/lib/timeline/default_timeline_headers.ts b/x-pack/plugins/siem/server/lib/timeline/default_timeline_headers.ts new file mode 100644 index 0000000000000..77b64bf2754c0 --- /dev/null +++ b/x-pack/plugins/siem/server/lib/timeline/default_timeline_headers.ts @@ -0,0 +1,44 @@ +/* + * 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 { SavedTimeline } from '../../../common/types/timeline'; + +export const defaultColumnHeaderType = 'not-filtered'; + +export const defaultHeaders: SavedTimeline['columns'] = [ + { + columnHeaderType: defaultColumnHeaderType, + id: '@timestamp', + }, + { + columnHeaderType: defaultColumnHeaderType, + id: 'message', + }, + { + columnHeaderType: defaultColumnHeaderType, + id: 'event.category', + }, + { + columnHeaderType: defaultColumnHeaderType, + id: 'event.action', + }, + { + columnHeaderType: defaultColumnHeaderType, + id: 'host.name', + }, + { + columnHeaderType: defaultColumnHeaderType, + id: 'source.ip', + }, + { + columnHeaderType: defaultColumnHeaderType, + id: 'destination.ip', + }, + { + columnHeaderType: defaultColumnHeaderType, + id: 'user.name', + }, +]; diff --git a/x-pack/plugins/siem/server/lib/timeline/pick_saved_timeline.ts b/x-pack/plugins/siem/server/lib/timeline/pick_saved_timeline.ts index 6de10bffb1325..3b06adf1b751e 100644 --- a/x-pack/plugins/siem/server/lib/timeline/pick_saved_timeline.ts +++ b/x-pack/plugins/siem/server/lib/timeline/pick_saved_timeline.ts @@ -5,6 +5,7 @@ */ import uuid from 'uuid'; +import { isEmpty } from 'lodash/fp'; import { AuthenticatedUser } from '../../../../security/common/model'; import { UNAUTHENTICATED_USER } from '../../../common/constants'; import { SavedTimeline, TimelineType } from '../../../common/types/timeline'; @@ -38,8 +39,14 @@ export const pickSavedTimeline = ( savedTimeline.templateTimelineVersion = savedTimeline.templateTimelineVersion + 1; } } + } else if (savedTimeline.timelineType === TimelineType.draft) { + savedTimeline.timelineType = !isEmpty(savedTimeline.title) + ? TimelineType.default + : TimelineType.draft; + savedTimeline.templateTimelineId = null; + savedTimeline.templateTimelineVersion = null; } else { - savedTimeline.timelineType = TimelineType.default; + savedTimeline.timelineType = savedTimeline.timelineType ?? TimelineType.default; savedTimeline.templateTimelineId = null; savedTimeline.templateTimelineVersion = null; } diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/__mocks__/import_timelines.ts b/x-pack/plugins/siem/server/lib/timeline/routes/__mocks__/import_timelines.ts index a832c818d48b0..e06e6c60ac65f 100644 --- a/x-pack/plugins/siem/server/lib/timeline/routes/__mocks__/import_timelines.ts +++ b/x-pack/plugins/siem/server/lib/timeline/routes/__mocks__/import_timelines.ts @@ -156,6 +156,29 @@ export const mockGetTemplateTimelineValue = { templateTimelineVersion: 1, }; +export const mockGetDraftTimelineValue = { + savedObjectId: '79deb4c0-6bc1-11ea-a90b-f5341fb7a189', + version: 'WzEyMjUsMV0=', + columns: [], + dataProviders: [], + description: 'description', + eventType: 'all', + filters: [], + kqlMode: 'filter', + kqlQuery: { filterQuery: [] }, + title: 'My duplicate timeline', + dateRange: { start: 1584523907294, end: 1584610307294 }, + savedQueryId: null, + sort: { columnId: '@timestamp', sortDirection: 'desc' }, + created: 1584828930463, + createdBy: 'angela', + updated: 1584868346013, + updatedBy: 'angela', + noteIds: [], + pinnedEventIds: ['k-gi8nABm-sIqJ_scOoS'], + timelineType: TimelineType.draft, +}; + export const mockParsedTimelineObject = omit( [ 'globalNotes', diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/__mocks__/request_responses.ts b/x-pack/plugins/siem/server/lib/timeline/routes/__mocks__/request_responses.ts index 2827c7a1c0ac6..6f03f5888f3b4 100644 --- a/x-pack/plugins/siem/server/lib/timeline/routes/__mocks__/request_responses.ts +++ b/x-pack/plugins/siem/server/lib/timeline/routes/__mocks__/request_responses.ts @@ -5,6 +5,8 @@ */ import * as rt from 'io-ts'; import { + TIMELINE_DRAFT_URL, + TIMELINE_DRAFT_CLEAN_URL, TIMELINE_EXPORT_URL, TIMELINE_IMPORT_URL, TIMELINE_URL, @@ -80,6 +82,14 @@ export const createTimelineWithoutTimelineId = { timelineType: TimelineType.default, }; +export const createDraftTimelineWithoutTimelineId = { + templateTimelineId: null, + timeline: inputTimeline, + timelineId: null, + version: null, + timelineType: TimelineType.draft, +}; + export const createTemplateTimelineWithoutTimelineId = { templateTimelineId: null, timeline: inputTemplateTimeline, @@ -93,6 +103,11 @@ export const createTimelineWithTimelineId = { timelineId: '79deb4c0-6bc1-11ea-a90b-f5341fb7a189', }; +export const createDraftTimelineWithTimelineId = { + ...createDraftTimelineWithoutTimelineId, + timelineId: '79deb4c0-6bc1-11ea-a90b-f5341fb7a189', +}; + export const createTemplateTimelineWithTimelineId = { ...createTemplateTimelineWithoutTimelineId, timelineId: '79deb4c0-6bc1-11ea-a90b-f5341fb7a189', @@ -139,6 +154,18 @@ export const getImportTimelinesRequestEnableOverwrite = (filename?: string) => }, }); +export const getDraftTimelinesRequest = () => + requestMock.create({ + method: 'get', + path: TIMELINE_DRAFT_URL, + }); + +export const cleanDraftTimelinesRequest = () => + requestMock.create({ + method: 'post', + path: TIMELINE_DRAFT_CLEAN_URL, + }); + export const mockTimelinesSavedObjects = () => ({ saved_objects: [ { diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/draft_clean_timelines_route.test.ts b/x-pack/plugins/siem/server/lib/timeline/routes/draft_clean_timelines_route.test.ts new file mode 100644 index 0000000000000..2902b0d119b7f --- /dev/null +++ b/x-pack/plugins/siem/server/lib/timeline/routes/draft_clean_timelines_route.test.ts @@ -0,0 +1,114 @@ +/* + * 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 { SecurityPluginSetup } from '../../../../../../plugins/security/server'; + +import { + serverMock, + requestContextMock, + createMockConfig, +} from '../../detection_engine/routes/__mocks__'; + +import { mockGetCurrentUser, mockGetDraftTimelineValue } from './__mocks__/import_timelines'; +import { + cleanDraftTimelinesRequest, + createTimelineWithTimelineId, +} from './__mocks__/request_responses'; + +describe('draft clean timelines', () => { + let server: ReturnType; + let securitySetup: SecurityPluginSetup; + let { context } = requestContextMock.createTools(); + let mockGetTimeline: jest.Mock; + let mockGetDraftTimeline: jest.Mock; + let mockPersistTimeline: jest.Mock; + let mockPersistPinnedEventOnTimeline: jest.Mock; + let mockPersistNote: jest.Mock; + let mockResetTimeline: jest.Mock; + + beforeEach(() => { + jest.resetModules(); + jest.resetAllMocks(); + jest.restoreAllMocks(); + jest.clearAllMocks(); + + server = serverMock.create(); + context = requestContextMock.createTools().context; + + securitySetup = ({ + authc: { + getCurrentUser: jest.fn().mockReturnValue(mockGetCurrentUser), + }, + authz: {}, + } as unknown) as SecurityPluginSetup; + + mockGetTimeline = jest.fn(); + mockGetDraftTimeline = jest.fn(); + mockPersistTimeline = jest.fn(); + mockPersistPinnedEventOnTimeline = jest.fn(); + mockPersistNote = jest.fn(); + mockResetTimeline = jest.fn(); + + jest.doMock('../saved_object', () => ({ + getTimeline: mockGetTimeline, + getDraftTimeline: mockGetDraftTimeline, + resetTimeline: mockResetTimeline, + persistTimeline: mockPersistTimeline.mockReturnValue({ + code: 200, + timeline: createTimelineWithTimelineId, + }), + })); + + jest.doMock('../../pinned_event/saved_object', () => ({ + persistPinnedEventOnTimeline: mockPersistPinnedEventOnTimeline, + })); + + jest.doMock('../../note/saved_object', () => ({ + persistNote: mockPersistNote, + })); + + const draftCleanTimelinesRoute = jest.requireActual('./draft_clean_timelines_route') + .draftCleanTimelinesRoute; + draftCleanTimelinesRoute(server.router, createMockConfig(), securitySetup); + }); + + test('should create new draft if none is available', async () => { + mockGetDraftTimeline.mockResolvedValue({ + timeline: [], + }); + + const response = await server.inject(cleanDraftTimelinesRequest(), context); + expect(mockPersistTimeline).toHaveBeenCalled(); + expect(response.status).toEqual(200); + expect(response.body).toEqual({ + data: { + persistTimeline: { + timeline: createTimelineWithTimelineId, + }, + }, + }); + }); + + test('should return clean existing draft if draft available ', async () => { + mockGetDraftTimeline.mockResolvedValue({ + timeline: [mockGetDraftTimelineValue], + }); + mockResetTimeline.mockResolvedValue({}); + mockGetTimeline.mockResolvedValue({ ...mockGetDraftTimelineValue }); + + const response = await server.inject(cleanDraftTimelinesRequest(), context); + expect(mockPersistTimeline).not.toHaveBeenCalled(); + expect(mockResetTimeline).toHaveBeenCalled(); + expect(mockGetTimeline).toHaveBeenCalled(); + expect(response.status).toEqual(200); + expect(response.body).toEqual({ + data: { + persistTimeline: { + timeline: mockGetDraftTimelineValue, + }, + }, + }); + }); +}); diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/draft_clean_timelines_route.ts b/x-pack/plugins/siem/server/lib/timeline/routes/draft_clean_timelines_route.ts new file mode 100644 index 0000000000000..eb876adab34d0 --- /dev/null +++ b/x-pack/plugins/siem/server/lib/timeline/routes/draft_clean_timelines_route.ts @@ -0,0 +1,86 @@ +/* + * 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 { IRouter } from '../../../../../../../src/core/server'; +import { ConfigType } from '../../..'; +import { transformError, buildSiemResponse } from '../../detection_engine/routes/utils'; +import { TIMELINE_DRAFT_CLEAN_URL } from '../../../../common/constants'; +import { buildFrameworkRequest } from './utils/common'; +import { SetupPlugins } from '../../../plugin'; +import { getDraftTimeline, resetTimeline, getTimeline, persistTimeline } from '../saved_object'; +import { draftTimelineDefaults } from '../default_timeline'; + +export const draftCleanTimelinesRoute = ( + router: IRouter, + config: ConfigType, + security: SetupPlugins['security'] +) => { + router.post( + { + path: TIMELINE_DRAFT_CLEAN_URL, + validate: {}, + options: { + tags: ['access:siem'], + }, + }, + async (context, request, response) => { + const frameworkRequest = await buildFrameworkRequest(context, security, request); + const siemResponse = buildSiemResponse(response); + + try { + const { + timeline: [draftTimeline], + } = await getDraftTimeline(frameworkRequest); + + if (draftTimeline?.savedObjectId) { + await resetTimeline(frameworkRequest, [draftTimeline.savedObjectId]); + const cleanedDraftTimeline = await getTimeline( + frameworkRequest, + draftTimeline.savedObjectId + ); + + return response.ok({ + body: { + data: { + persistTimeline: { + timeline: cleanedDraftTimeline, + }, + }, + }, + }); + } + + const newTimelineResponse = await persistTimeline( + frameworkRequest, + null, + null, + draftTimelineDefaults + ); + + if (newTimelineResponse.code === 200) { + return response.ok({ + body: { + data: { + persistTimeline: { + timeline: newTimelineResponse.timeline, + }, + }, + }, + }); + } + + return response.ok({}); + } catch (err) { + const error = transformError(err); + + return siemResponse.error({ + body: error.message, + statusCode: error.statusCode, + }); + } + } + ); +}; diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/draft_timelines_route.test.ts b/x-pack/plugins/siem/server/lib/timeline/routes/draft_timelines_route.test.ts new file mode 100644 index 0000000000000..1bea832790d8c --- /dev/null +++ b/x-pack/plugins/siem/server/lib/timeline/routes/draft_timelines_route.test.ts @@ -0,0 +1,113 @@ +/* + * 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 { SecurityPluginSetup } from '../../../../../../plugins/security/server'; + +import { + serverMock, + requestContextMock, + createMockConfig, +} from '../../detection_engine/routes/__mocks__'; + +import { mockGetCurrentUser, mockGetDraftTimelineValue } from './__mocks__/import_timelines'; +import { + getDraftTimelinesRequest, + createTimelineWithTimelineId, +} from './__mocks__/request_responses'; + +describe('draft timelines', () => { + let server: ReturnType; + let securitySetup: SecurityPluginSetup; + let { context } = requestContextMock.createTools(); + let mockGetTimeline: jest.Mock; + let mockGetDraftTimeline: jest.Mock; + let mockPersistTimeline: jest.Mock; + let mockPersistPinnedEventOnTimeline: jest.Mock; + let mockPersistNote: jest.Mock; + + beforeEach(() => { + jest.resetModules(); + jest.resetAllMocks(); + jest.restoreAllMocks(); + jest.clearAllMocks(); + + server = serverMock.create(); + context = requestContextMock.createTools().context; + + securitySetup = ({ + authc: { + getCurrentUser: jest.fn().mockReturnValue(mockGetCurrentUser), + }, + authz: {}, + } as unknown) as SecurityPluginSetup; + + mockGetTimeline = jest.fn(); + mockGetDraftTimeline = jest.fn(); + mockPersistTimeline = jest.fn(); + mockPersistPinnedEventOnTimeline = jest.fn(); + mockPersistNote = jest.fn(); + }); + + describe('Manipulate timeline', () => { + describe('Create a new timeline', () => { + beforeEach(async () => { + jest.doMock('../saved_object', () => ({ + getTimeline: mockGetTimeline, + getDraftTimeline: mockGetDraftTimeline, + persistTimeline: mockPersistTimeline.mockReturnValue({ + code: 200, + timeline: createTimelineWithTimelineId, + }), + })); + + jest.doMock('../../pinned_event/saved_object', () => ({ + persistPinnedEventOnTimeline: mockPersistPinnedEventOnTimeline, + })); + + jest.doMock('../../note/saved_object', () => ({ + persistNote: mockPersistNote, + })); + + const draftTimelinesRoute = jest.requireActual('./draft_timelines_route') + .draftTimelinesRoute; + draftTimelinesRoute(server.router, createMockConfig(), securitySetup); + }); + + test('should create new draft if none is available', async () => { + mockGetDraftTimeline.mockResolvedValue({ + timeline: [], + }); + + const response = await server.inject(getDraftTimelinesRequest(), context); + expect(mockPersistTimeline).toHaveBeenCalled(); + expect(response.status).toEqual(200); + expect(response.body).toEqual({ + data: { + persistTimeline: { + timeline: createTimelineWithTimelineId, + }, + }, + }); + }); + + test('should return an existing draft if available', async () => { + mockGetDraftTimeline.mockResolvedValue({ + timeline: [mockGetDraftTimelineValue], + }); + + const response = await server.inject(getDraftTimelinesRequest(), context); + expect(mockPersistTimeline).not.toHaveBeenCalled(); + expect(response.status).toEqual(200); + expect(response.body).toEqual({ + data: { + persistTimeline: { + timeline: mockGetDraftTimelineValue, + }, + }, + }); + }); + }); + }); +}); diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/draft_timelines_route.ts b/x-pack/plugins/siem/server/lib/timeline/routes/draft_timelines_route.ts new file mode 100644 index 0000000000000..14d7fb1801719 --- /dev/null +++ b/x-pack/plugins/siem/server/lib/timeline/routes/draft_timelines_route.ts @@ -0,0 +1,80 @@ +/* + * 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 { IRouter } from '../../../../../../../src/core/server'; +import { ConfigType } from '../../..'; +import { transformError, buildSiemResponse } from '../../detection_engine/routes/utils'; +import { TIMELINE_DRAFT_URL } from '../../../../common/constants'; +import { buildFrameworkRequest } from './utils/common'; +import { SetupPlugins } from '../../../plugin'; +import { getDraftTimeline, persistTimeline } from '../saved_object'; +import { draftTimelineDefaults } from '../default_timeline'; + +export const draftTimelinesRoute = ( + router: IRouter, + config: ConfigType, + security: SetupPlugins['security'] +) => { + router.get( + { + path: TIMELINE_DRAFT_URL, + validate: {}, + options: { + tags: ['access:siem'], + }, + }, + async (context, request, response) => { + const frameworkRequest = await buildFrameworkRequest(context, security, request); + const siemResponse = buildSiemResponse(response); + + try { + const { + timeline: [draftTimeline], + } = await getDraftTimeline(frameworkRequest); + + if (draftTimeline?.savedObjectId) { + return response.ok({ + body: { + data: { + persistTimeline: { + timeline: draftTimeline, + }, + }, + }, + }); + } + + const newTimelineResponse = await persistTimeline( + frameworkRequest, + null, + null, + draftTimelineDefaults + ); + + if (newTimelineResponse.code === 200) { + return response.ok({ + body: { + data: { + persistTimeline: { + timeline: newTimelineResponse.timeline, + }, + }, + }, + }); + } + + return response.ok({}); + } catch (err) { + const error = transformError(err); + + return siemResponse.error({ + body: error.message, + statusCode: error.statusCode, + }); + } + } + ); +}; diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/export_timelines_route.ts b/x-pack/plugins/siem/server/lib/timeline/routes/export_timelines_route.ts index e0eefbf811a56..e74069fb748a5 100644 --- a/x-pack/plugins/siem/server/lib/timeline/routes/export_timelines_route.ts +++ b/x-pack/plugins/siem/server/lib/timeline/routes/export_timelines_route.ts @@ -4,8 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { set as _set } from 'lodash/fp'; - import { TIMELINE_EXPORT_URL } from '../../../../common/constants'; import { IRouter } from '../../../../../../../src/core/server'; import { ConfigType } from '../../../config'; diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.test.ts b/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.test.ts index 11f93a9c48bf6..2f5200c87137d 100644 --- a/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.test.ts +++ b/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.test.ts @@ -12,6 +12,7 @@ import { createMockConfig, } from '../../detection_engine/routes/__mocks__'; import { TIMELINE_EXPORT_URL } from '../../../../common/constants'; +import { TimelineType } from '../../../../common/types/timeline'; import { SecurityPluginSetup } from '../../../../../../plugins/security/server'; import { @@ -33,6 +34,7 @@ describe('import timelines', () => { let mockPersistTimeline: jest.Mock; let mockPersistPinnedEventOnTimeline: jest.Mock; let mockPersistNote: jest.Mock; + let mockGetTupleDuplicateErrorsAndUniqueTimeline: jest.Mock; const newTimelineSavedObjectId = '79deb4c0-6bc1-11ea-9999-f5341fb7a189'; const newTimelineVersion = '9999'; beforeEach(() => { @@ -56,6 +58,7 @@ describe('import timelines', () => { mockPersistTimeline = jest.fn(); mockPersistPinnedEventOnTimeline = jest.fn(); mockPersistNote = jest.fn(); + mockGetTupleDuplicateErrorsAndUniqueTimeline = jest.fn(); jest.doMock('../create_timelines_stream_from_ndjson', () => { return { @@ -73,9 +76,9 @@ describe('import timelines', () => { const originalModule = jest.requireActual('./utils/import_timelines'); return { ...originalModule, - getTupleDuplicateErrorsAndUniqueTimeline: jest - .fn() - .mockReturnValue([mockDuplicateIdErrors, mockUniqueParsedObjects]), + getTupleDuplicateErrorsAndUniqueTimeline: mockGetTupleDuplicateErrorsAndUniqueTimeline.mockReturnValue( + [mockDuplicateIdErrors, mockUniqueParsedObjects] + ), }; }); }); @@ -133,12 +136,25 @@ describe('import timelines', () => { expect(mockPersistTimeline.mock.calls[0][2]).toBeNull(); }); - test('should Create a new timeline savedObject witn given timeline', async () => { + test('should Create a new timeline savedObject with given timeline', async () => { const mockRequest = getImportTimelinesRequest(); await server.inject(mockRequest, context); expect(mockPersistTimeline.mock.calls[0][3]).toEqual(mockParsedTimelineObject); }); + test('should Create a new timeline savedObject with given draft timeline', async () => { + mockGetTupleDuplicateErrorsAndUniqueTimeline.mockReturnValue([ + mockDuplicateIdErrors, + [{ ...mockUniqueParsedObjects[0], timelineType: TimelineType.draft }], + ]); + const mockRequest = getImportTimelinesRequest(); + await server.inject(mockRequest, context); + expect(mockPersistTimeline.mock.calls[0][3]).toEqual({ + ...mockParsedTimelineObject, + timelineType: TimelineType.default, + }); + }); + test('should Create new pinned events', async () => { const mockRequest = getImportTimelinesRequest(); await server.inject(mockRequest, context); diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.ts b/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.ts index 4a79dada07171..bb63d1dce5554 100644 --- a/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.ts +++ b/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.ts @@ -152,7 +152,13 @@ export const importTimelinesRoute = ( // create timeline / template timeline newTimeline = await createTimelines( frameworkRequest, - parsedTimelineObject, + { + ...parsedTimelineObject, + timelineType: + parsedTimelineObject.timelineType === TimelineType.draft + ? TimelineType.default + : parsedTimelineObject.timelineType, + }, null, // timelineSavedObjectId null, // timelineVersion pinnedEventIds, diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/utils/export_timelines.ts b/x-pack/plugins/siem/server/lib/timeline/routes/utils/export_timelines.ts index ea9a5fab66805..1e64e38ea5b0a 100644 --- a/x-pack/plugins/siem/server/lib/timeline/routes/utils/export_timelines.ts +++ b/x-pack/plugins/siem/server/lib/timeline/routes/utils/export_timelines.ts @@ -16,6 +16,7 @@ import { ExportedNotes, TimelineSavedObject, ExportTimelineNotFoundError, + TimelineType, } from '../../../../../common/types/timeline'; import { NoteSavedObject } from '../../../../../common/types/timeline/note'; import { PinnedEventSavedObject } from '../../../../../common/types/timeline/pinned_event'; @@ -179,6 +180,10 @@ const getTimelinesFromObjects = async ( ...acc, { ...myTimeline, + timelineType: + myTimeline.timelineType === TimelineType.draft + ? TimelineType.default + : myTimeline.timelineType, ...getGlobalEventNotesByTimelineId(timelineNotes), pinnedEventIds: getPinnedEventsIdsByTimelineId(timelinePinnedEventIds), }, diff --git a/x-pack/plugins/siem/server/lib/timeline/saved_object.ts b/x-pack/plugins/siem/server/lib/timeline/saved_object.ts index 6d022ab42fa7b..f95cd01b2b788 100644 --- a/x-pack/plugins/siem/server/lib/timeline/saved_object.ts +++ b/x-pack/plugins/siem/server/lib/timeline/saved_object.ts @@ -25,6 +25,7 @@ import * as pinnedEvent from '../pinned_event/saved_object'; import { convertSavedObjectToSavedTimeline } from './convert_saved_object_to_savedtimeline'; import { pickSavedTimeline } from './pick_saved_timeline'; import { timelineSavedObjectType } from './saved_object_mappings'; +import { draftTimelineDefaults } from './default_timeline'; interface ResponseTimelines { timeline: TimelineSavedObject[]; @@ -103,7 +104,7 @@ const getTimelineTypeFilter = (timelineType: string | null) => { : /** Show me every timeline whose timelineType is not "template". * which includes timelineType === 'default' and * those timelineType doesn't exists */ - `not siem-ui-timeline.attributes.timelineType: ${TimelineType.template}`; + `not siem-ui-timeline.attributes.timelineType: ${TimelineType.template} and not siem-ui-timeline.attributes.timelineType: ${TimelineType.draft}`; }; export const getAllTimeline = async ( @@ -129,6 +130,17 @@ export const getAllTimeline = async ( return getAllSavedTimeline(request, options); }; +export const getDraftTimeline = async (request: FrameworkRequest): Promise => { + const options: SavedObjectsFindOptions = { + type: timelineSavedObjectType, + perPage: 1, + filter: `siem-ui-timeline.attributes.timelineType: ${TimelineType.draft}`, + sortField: 'created', + sortOrder: 'desc', + }; + return getAllSavedTimeline(request, options); +}; + export const persistFavorite = async ( request: FrameworkRequest, timelineId: string | null @@ -257,6 +269,54 @@ export const persistTimeline = async ( } }; +const updatePartialSavedTimeline = async ( + request: FrameworkRequest, + timelineId: string, + timeline: SavedTimeline +) => { + const savedObjectsClient = request.context.core.savedObjects.client; + const currentSavedTimeline = await savedObjectsClient.get( + timelineSavedObjectType, + timelineId + ); + + return savedObjectsClient.update( + timelineSavedObjectType, + timelineId, + pickSavedTimeline( + null, + { + ...timeline, + dateRange: currentSavedTimeline.attributes.dateRange, + }, + request.user + ) + ); +}; + +export const resetTimeline = async (request: FrameworkRequest, timelineIds: string[]) => { + if (!timelineIds.length) { + return Promise.reject(new Error('timelineIds is empty')); + } + + await Promise.all( + timelineIds.map(timelineId => + Promise.all([ + note.deleteNoteByTimelineId(request, timelineId), + pinnedEvent.deleteAllPinnedEventsOnTimeline(request, timelineId), + ]) + ) + ); + + const response = await Promise.all( + timelineIds.map(timelineId => + updatePartialSavedTimeline(request, timelineId, draftTimelineDefaults) + ) + ); + + return response; +}; + export const deleteTimeline = async (request: FrameworkRequest, timelineIds: string[]) => { const savedObjectsClient = request.context.core.savedObjects.client; diff --git a/x-pack/plugins/siem/server/routes/index.ts b/x-pack/plugins/siem/server/routes/index.ts index ffad86a09cee7..4a7bc4a4aa02f 100644 --- a/x-pack/plugins/siem/server/routes/index.ts +++ b/x-pack/plugins/siem/server/routes/index.ts @@ -32,6 +32,8 @@ import { importTimelinesRoute } from '../lib/timeline/routes/import_timelines_ro import { exportTimelinesRoute } from '../lib/timeline/routes/export_timelines_route'; import { createTimelinesRoute } from '../lib/timeline/routes/create_timelines_route'; import { updateTimelinesRoute } from '../lib/timeline/routes/update_timelines_route'; +import { draftTimelinesRoute } from '../lib/timeline/routes/draft_timelines_route'; +import { draftCleanTimelinesRoute } from '../lib/timeline/routes/draft_clean_timelines_route'; import { SetupPlugins } from '../plugin'; import { ConfigType } from '../config'; @@ -64,6 +66,8 @@ export const initRoutes = ( importTimelinesRoute(router, config, security); exportTimelinesRoute(router, config); + draftTimelinesRoute(router, config, security); + draftCleanTimelinesRoute(router, config, security); findRulesStatusesRoute(router); diff --git a/x-pack/test/siem_cypress/es_archives/timeline/data.json.gz b/x-pack/test/siem_cypress/es_archives/timeline/data.json.gz index c7acb36992af3d928d5b8aaf904c3d79eb9a2c20..cde2775bddb2402d97cdc4a051852393414cbadd 100644 GIT binary patch literal 1827 zcmV+;2i*7{iwFP!000026YUz?Zre8WdHxDbPwfz^y4%uTwxw$uv{}0)Ylk+4KufgE zMiMoW%Hjn6_mPsE=w@3{?X&?BB#3o*bnZMC($@n?lG!4GvMb2}_T>WsxBy`)AlLkX zKcYaa`Z%7VnQJSmq7Ffr%z>6+3xqg;mjXvQM-vbO?`DPKl=!!#q!pPGgu^B&3WGn= zh(pJwJvz8u2>^pHFo^(j*_Gh%_vxWrEH77hGJ#V_VC+N6Q9c#W&o|2}{R-9@csUS% z%faBfy9H_xq7`sF@V%3C}BA( z`E-t`#DCcwN`)3u_STPb+2n|VNeF`%5U`X~n3dRZ#27@GxX%lNGz4B*HJ7Zn*^9s% zi@@7M#5t-u(i}&(%#o=&j`o$&bpuZm5xjv1m{`?ST^*|CP#v9Ws%tu~YALpuRf--Ax#3=|VY?X_l z2p)n&B!Qqcgf&%hM)t?v`M5P?x9^+^+dex7BuR+;%nDvg!3=tgfS3YbKtSl)Fqk@) zsSZcuNiftj2!_r`8}mf~V z(0VW)R~2o{eZI-fYBw)ix@*~rG19-Wm+Nx$^Kw)wh?S>)&WqNT!x@ZOHO-bYrw>Sg zxax>4>Z!P7nr3w=I;tvEunR-4h2_n<7Ssw&qpIcp%=(?q?+?~JRqJI+A<3m{DufA| zp?aWyr%JVZQdHSSJ($b3i>1FT9emv(~fP2)DSQ;82r=i5|Eut?&}DCZYJNj(KZNp?tJ}?L;WL zf*y*!$%18)>gu>>-lTIL#B{x8T8F`b!Qw!nVYDc0%}CxCJfU8jCE8i6yp`?#wj|H( z&0@&vfg#Uu1M~%4fF_U*CxF5RJjMb1LL1;@!RA?LR>35lELwokFelMI-T->uFS9d@ z&)Y&T66DN|?q5^-HWSyoQeWSJY-6E09a&^$p=H|K%E0c(phyQE?_BR}D62D%wOeSb z9%@G(3Bg33WSSxKiDBInpZ#g8YO`2o_^D zoT89Haq?5E_qhRnxg9Cj#mi3ka3*4++%J=CTPl2lg)_{f=pJ|#9oAks%`s(4Hc{@C zO&+rf+H)WTJlc3c6K2~xFEPV6F=16PrhiaEa<;N0M z7QZV~iq5>WmRohb66gPh$Goi*Z|10Sb@9&>lE#5aj@h;(UTOskF)tIsQ%9l8%~o)K zk{iwbIm%2}&>C!*3`B)R;s6~6D|zJWGkJn>cqY626P@EU4EX0y`~hAf%4ohY703Df z4+0?eOtOl`T8w|D2@q7WrJIE>RUEU#kH=+^TMaa7OY zwW*e{=ZHYR918N9D*_f~{yaJQ{aE4?5i7g2sKVv=baZFj#HenL_4kPNYS-;#(QqwC zF;x9N>%C<>*89hL|5)!I>-~eN_XJGYW2Jwr^jj+Z4hsCi;D^%1q^M)7Fw2ARJ8S?r z)BFy@6*9Oufw5PU;!bsb#r1}6NtGK=t+?lBw$1M+ZPeX#O+&Ga@g6VFxn-S+q3`_c zqu=HE97k~5<+*A)8^0oL-5Q}RO!hv@KMY#o&PKy#SDfL2S{&Eq<P)#>q@11Uu3P#})`l2yXXtb+RoB(NFuLyGSt^1z^Z^s6x~i)q)f}ngD^2xG*HbOUHnsP|%@Tu@ zju?z!3>jH@^~XWcS*K957hsH_NyZ?31IYzQYp2CM1(!KRdWN%vHO>WvrEr0IT8GBq zrVENhys8!8x{4vgn7)Mp!{ilM@tf4evHn6N@UFO7`{Eu+i<1tPg^%8F3qz97cZkiO zL;MWEDBQ?UA)Gtu3NsLO9a6{`N@ld_9XiMVa;LpTGy@U3%~Mcr4URYk5rv&{F%-iy zkcuP_c80K~D(={RKR6$EhV1^EQ)4^i=72PfP>@@}&nTEdpAnEy5C{l}JR62n*D}@7 z*qMYQO@ma)7Jb?$`w8kPEhlZ{x3LCg5R9w&nTM6Qhp&^%fIuihOjj(^ za*X>wW;IJ^@dT3B(=*O`A^f514Ifhm;e&o7H|^wsg<36=SS_V=p)580O`;QV?rT!<-jyEr&ChuzH%UX3hYR5OLKJ zTQyU0#Wd~eQg&2zs9+aGeh16Db1iHXnpRaS{F(PVz286C_EfKz8HJ>fuB{LzXoi}B z{y$Z!+moWow(4mvwqG=SS<%sVvG zOBBFuEOrvBgy}&@@+*Xb11XD>3C=Ir>_7xdt>}Z*Dso2LYKI34l7i$wq__izXtXmu z^%bP^Cd~o$L9+5I#?D*MdL!K7hLS@=7AAV&uC&5S#Fm5-Y&zz>Ife4k0(KLj=ob1Y z@h2;mORB5Rz`RN4Jc#Lb&9oka1B2y4p=Go<>dZ*~Cp@8kmnFJcY`m4<{;nj??adO% znt>tDa0~PaEI}JcM-xC{3!dN*exfaKx?=M@H0xlJO;#PicvO(+9&Z3$49n~c<3(5K z#e$sK)BRgY-)`c1U+UXCkbNvPwjJI!aycu7dZY+-mk0 zC^unA>tx4dASx^p3v?K6&1mQZ|3mER7==X zL|{-21$oOS0v6@|ygdKyLgEtO?}*K6*Kf0Ec$TXe>X&R5 zIn!c=;RzW$oWjI!Nb#VuzTtXDx1!1&s8P#{k*)oCa;NU5XBvuSI7i%_bIZCDLqB-y zGi-N0$1&WuJ6BD2=NA&K=jyy++;6rzKY)`P0ltZCUu3HA>qfZ#)g$~~`9iPJ{Yu-r zz_%!hz!OVRrAHSa-~%J3^Pi-1J~&1a2S~3krN8+w=xe5LKbC&s9)<7Vr%Qr&5F#Pli@;`3%_GxJ)003)gW7q%y diff --git a/x-pack/test/siem_cypress/es_archives/timeline/mappings.json b/x-pack/test/siem_cypress/es_archives/timeline/mappings.json index d3412f9d43b57..ae36c130ee168 100644 --- a/x-pack/test/siem_cypress/es_archives/timeline/mappings.json +++ b/x-pack/test/siem_cypress/es_archives/timeline/mappings.json @@ -2413,6 +2413,9 @@ }, "siem-ui-timeline": { "properties": { + "timelineType": { + "type": "keyword" + }, "columns": { "properties": { "aggregatable": { diff --git a/yarn.lock b/yarn.lock index 1ce919e210e66..d7d1aa3b89185 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15675,7 +15675,7 @@ handle-thing@^2.0.0: resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754" integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ== -handlebars@4.7.6, handlebars@^4.0.1, handlebars@^4.1.2: +handlebars@4.7.6, handlebars@^4.0.1: version "4.7.6" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.6.tgz#d4c05c1baf90e9945f77aa68a7a219aa4a7df74e" integrity sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA== @@ -17881,11 +17881,11 @@ istanbul-lib-source-maps@^4.0.0: source-map "^0.6.1" istanbul-reports@^2.2.6: - version "2.2.6" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-2.2.6.tgz#7b4f2660d82b29303a8fe6091f8ca4bf058da1af" - integrity sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA== + version "2.2.7" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-2.2.7.tgz#5d939f6237d7b48393cc0959eab40cd4fd056931" + integrity sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg== dependencies: - handlebars "^4.1.2" + html-escaper "^2.0.0" istanbul-reports@^3.0.2: version "3.0.2" From ce0d39bfdf334589d3c4b851a8ac3085e8bd1bdd Mon Sep 17 00:00:00 2001 From: Candace Park <56409205+parkiino@users.noreply.github.com> Date: Wed, 6 May 2020 09:02:48 -0400 Subject: [PATCH 13/23] Task/policy response (#64838) host details policy response --- .../plugins/endpoint/common/generate_data.ts | 4 +- x-pack/plugins/endpoint/common/types.ts | 4 +- .../endpoint/store/hosts/middleware.ts | 28 ++- .../endpoint/store/hosts/selectors.ts | 62 ++++++- .../details/components/flyout_sub_header.tsx | 8 +- .../view/hosts/details/host_constants.ts | 15 ++ .../view/hosts/details/host_details.tsx | 11 +- .../endpoint/view/hosts/details/index.tsx | 35 +++- .../view/hosts/details/policy_response.tsx | 145 ++++++++++++++- .../details/policy_response_friendly_names.ts | 170 ++++++++++++++++++ .../endpoint/view/hosts/index.test.tsx | 50 +++++- 11 files changed, 501 insertions(+), 31 deletions(-) create mode 100644 x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details/host_constants.ts create mode 100644 x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details/policy_response_friendly_names.ts diff --git a/x-pack/plugins/endpoint/common/generate_data.ts b/x-pack/plugins/endpoint/common/generate_data.ts index 58393b88e37a3..9e7aedcc90bb5 100644 --- a/x-pack/plugins/endpoint/common/generate_data.ts +++ b/x-pack/plugins/endpoint/common/generate_data.ts @@ -560,7 +560,7 @@ export class EndpointDocGenerator { applied: { actions: { configure_elasticsearch_connection: { - message: 'elasticsearch comms configured successfully', + message: 'elasticsearch comes configured successfully', status: HostPolicyResponseActionStatus.success, }, configure_kernel: { @@ -648,7 +648,7 @@ export class EndpointDocGenerator { response: { configurations: { events: { - concerned_actions: this.randomHostPolicyResponseActions(), + concerned_actions: ['download_model'], status: this.randomHostPolicyResponseActionStatus(), }, logging: { diff --git a/x-pack/plugins/endpoint/common/types.ts b/x-pack/plugins/endpoint/common/types.ts index a1ddc97a90d29..181b0e7ab3884 100644 --- a/x-pack/plugins/endpoint/common/types.ts +++ b/x-pack/plugins/endpoint/common/types.ts @@ -25,7 +25,7 @@ export type Immutable = T extends undefined | null | boolean | string | numbe ? ImmutableSet : ImmutableObject; -type ImmutableArray = ReadonlyArray>; +export type ImmutableArray = ReadonlyArray>; type ImmutableMap = ReadonlyMap, Immutable>; type ImmutableSet = ReadonlySet>; type ImmutableObject = { readonly [K in keyof T]: Immutable }; @@ -644,6 +644,8 @@ export interface HostPolicyResponseActions { read_malware_config: HostPolicyResponseActionDetails; } +export type HostPolicyResponseConfiguration = HostPolicyResponse['endpoint']['policy']['applied']['response']['configurations']; + interface HostPolicyResponseConfigurationStatus { status: HostPolicyResponseActionStatus; concerned_actions: Array; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/middleware.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/middleware.ts index bcfd6b96c9eb8..a5378a02ed6fb 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/middleware.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/middleware.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { HostResultList } from '../../../../../common/types'; +import { HostResultList, HostPolicyResponseActionStatus } from '../../../../../common/types'; import { isOnHostPage, hasSelectedHost, uiQueryParams, listData } from './selectors'; import { HostState } from '../../types'; import { ImmutableMiddlewareFactory } from '../../types'; @@ -77,7 +77,31 @@ export const hostMiddlewareFactory: ImmutableMiddlewareFactory = core endpoint: { policy: { applied: { - status: 'success', + version: '1.0.0', + status: HostPolicyResponseActionStatus.success, + id: '17d4b81d-9940-4b64-9de5-3e03ef1fb5cf', + actions: { + download_model: { + status: 'success', + message: 'Model downloaded', + }, + ingest_events_config: { + status: 'failure', + message: 'No action taken', + }, + }, + response: { + configurations: { + malware: { + status: 'success', + concerned_actions: ['download_model'], + }, + events: { + status: 'failure', + concerned_actions: ['ingest_events_config'], + }, + }, + }, }, }, }, diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/selectors.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/selectors.ts index b0711baf9cdff..e16d4ff5d18c2 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/selectors.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/selectors.ts @@ -5,7 +5,12 @@ */ import querystring from 'querystring'; import { createSelector } from 'reselect'; -import { Immutable } from '../../../../../common/types'; +import { + Immutable, + HostPolicyResponseActions, + HostPolicyResponseConfiguration, + HostPolicyResponseActionStatus, +} from '../../../../../common/types'; import { HostState, HostIndexUIQueryParams } from '../../types'; const PAGE_SIZES = Object.freeze([10, 20, 50]); @@ -28,6 +33,61 @@ export const detailsLoading = (state: Immutable): boolean => state.de export const detailsError = (state: Immutable) => state.detailsError; +/** + * Returns the full policy response from the endpoint after a user modifies a policy. + */ +const detailsPolicyAppliedResponse = (state: Immutable) => + state.policyResponse && state.policyResponse.endpoint.policy.applied; + +/** + * Returns the response configurations from the endpoint after a user modifies a policy. + */ +export const policyResponseConfigurations: ( + state: Immutable +) => undefined | Immutable = createSelector( + detailsPolicyAppliedResponse, + applied => { + return applied?.response?.configurations; + } +); + +/** + * Returns a map of the number of failed and warning policy response actions per configuration. + */ +export const policyResponseFailedOrWarningActionCount: ( + state: Immutable +) => Map = createSelector(detailsPolicyAppliedResponse, applied => { + const failureOrWarningByConfigType = new Map(); + if (applied?.response?.configurations !== undefined && applied?.actions !== undefined) { + Object.entries(applied.response.configurations).map(([key, val]) => { + let count = 0; + for (const action of val.concerned_actions) { + const actionStatus = applied.actions[action]?.status; + if ( + actionStatus === HostPolicyResponseActionStatus.failure || + actionStatus === HostPolicyResponseActionStatus.warning + ) { + count += 1; + } + } + return failureOrWarningByConfigType.set(key, count); + }); + } + return failureOrWarningByConfigType; +}); + +/** + * Returns the actions taken by the endpoint for each response configuration after a user modifies a policy. + */ +export const policyResponseActions: ( + state: Immutable +) => undefined | Partial = createSelector( + detailsPolicyAppliedResponse, + applied => { + return applied?.actions; + } +); + export const isOnHostPage = (state: Immutable) => state.location ? state.location.pathname === '/hosts' : false; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details/components/flyout_sub_header.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details/components/flyout_sub_header.tsx index 02f91307c988e..9abb54e8b1807 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details/components/flyout_sub_header.tsx +++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details/components/flyout_sub_header.tsx @@ -9,7 +9,7 @@ import { EuiFlyoutHeader, CommonProps, EuiButtonEmpty } from '@elastic/eui'; import styled from 'styled-components'; export type FlyoutSubHeaderProps = CommonProps & { - children: React.ReactNode; + children?: React.ReactNode; backButton?: { title: string; onClick: MouseEventHandler; @@ -25,6 +25,9 @@ const StyledEuiFlyoutHeader = styled(EuiFlyoutHeader)` padding-bottom: ${props => props.theme.eui.paddingSizes.s}; } + .flyoutSubHeaderBackButton { + font-size: ${props => props.theme.eui.euiFontSizeXS}; + } .back-button-content { padding-left: 0; &-text { @@ -48,7 +51,7 @@ const BUTTON_TEXT_PROPS = Object.freeze({ className: 'back-button-content-text' export const FlyoutSubHeader = memo( ({ children, backButton, ...otherProps }) => { return ( - + {backButton && (
{/* eslint-disable-next-line @elastic/eui/href-or-on-click */} @@ -60,6 +63,7 @@ export const FlyoutSubHeader = memo( size="xs" href={backButton?.href ?? ''} onClick={backButton?.onClick} + className="flyoutSubHeaderBackButton" > {backButton?.title} diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details/host_constants.ts b/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details/host_constants.ts new file mode 100644 index 0000000000000..5250eeaf028d5 --- /dev/null +++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details/host_constants.ts @@ -0,0 +1,15 @@ +/* + * 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 { HostPolicyResponseActionStatus } from '../../../../../../common/types'; + +export const POLICY_STATUS_TO_HEALTH_COLOR = Object.freeze< + { [key in keyof typeof HostPolicyResponseActionStatus]: string } +>({ + success: 'success', + warning: 'warning', + failure: 'danger', +}); diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details/host_details.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details/host_details.tsx index 7d948f54bd0bc..ee1c7543d7e0a 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details/host_details.tsx +++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details/host_details.tsx @@ -16,13 +16,14 @@ import { import React, { memo, useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; -import { HostMetadata, HostPolicyResponseActionStatus } from '../../../../../../common/types'; +import { HostMetadata } from '../../../../../../common/types'; import { FormattedDateAndTime } from '../../formatted_date_time'; import { LinkToApp } from '../../components/link_to_app'; import { useHostSelector, useHostLogsUrl } from '../hooks'; import { urlFromQueryParams } from '../url_from_query_params'; import { policyResponseStatus, uiQueryParams } from '../../../store/hosts/selectors'; import { useNavigateByRouterEventHandler } from '../../hooks/use_navigate_by_router_event_handler'; +import { POLICY_STATUS_TO_HEALTH_COLOR } from './host_constants'; const HostIds = styled(EuiListGroupItem)` margin-top: 0; @@ -31,14 +32,6 @@ const HostIds = styled(EuiListGroupItem)` } `; -const POLICY_STATUS_TO_HEALTH_COLOR = Object.freeze< - { [key in keyof typeof HostPolicyResponseActionStatus]: string } ->({ - success: 'success', - warning: 'warning', - failure: 'danger', -}); - export const HostDetails = memo(({ details }: { details: HostMetadata }) => { const { appId, appPath, url } = useHostLogsUrl(details.host.id); const queryParams = useHostSelector(uiQueryParams); diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details/index.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details/index.tsx index e44a45f300daa..017ce9a66f8c5 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details/index.tsx +++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details/index.tsx @@ -9,8 +9,9 @@ import { EuiFlyout, EuiFlyoutBody, EuiFlyoutHeader, - EuiTitle, EuiLoadingContent, + EuiTitle, + EuiText, EuiSpacer, } from '@elastic/eui'; import { useHistory } from 'react-router-dom'; @@ -25,6 +26,9 @@ import { detailsError, showView, detailsLoading, + policyResponseConfigurations, + policyResponseActions, + policyResponseFailedOrWarningActionCount, } from '../../../store/hosts/selectors'; import { HostDetails } from './host_details'; import { PolicyResponse } from './policy_response'; @@ -101,6 +105,9 @@ const PolicyResponseFlyoutPanel = memo<{ hostMeta: HostMetadata; }>(({ hostMeta }) => { const { show, ...queryParams } = useHostSelector(uiQueryParams); + const responseConfig = useHostSelector(policyResponseConfigurations); + const responseActionStatus = useHostSelector(policyResponseActions); + const responseAttentionCount = useHostSelector(policyResponseFailedOrWarningActionCount); const detailsUri = useMemo( () => urlFromQueryParams({ @@ -125,18 +132,28 @@ const PolicyResponseFlyoutPanel = memo<{ - -

+ /> + + +

-

- - - - +

+ + {responseConfig !== undefined && responseActionStatus !== undefined ? ( + + ) : ( + + )} ); diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details/policy_response.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details/policy_response.tsx index eacb6a52d3184..aa04f2fdff57f 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details/policy_response.tsx +++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details/policy_response.tsx @@ -3,8 +3,145 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React, { memo } from 'react'; +import React, { memo, useMemo } from 'react'; +import styled from 'styled-components'; +import { EuiAccordion, EuiNotificationBadge, EuiHealth } from '@elastic/eui'; +import { EuiText } from '@elastic/eui'; +import { htmlIdGenerator } from '@elastic/eui'; +import { + HostPolicyResponseActions, + HostPolicyResponseConfiguration, + Immutable, + ImmutableArray, +} from '../../../../../../common/types'; +import { formatResponse } from './policy_response_friendly_names'; +import { POLICY_STATUS_TO_HEALTH_COLOR } from './host_constants'; -export const PolicyResponse = memo(() => { - return
Policy Status to be displayed here soon.
; -}); +/** + * Nested accordion in the policy response detailing any concerned + * actions the endpoint took to apply the policy configuration. + */ +const PolicyResponseConfigAccordion = styled(EuiAccordion)` + > .euiAccordion__triggerWrapper { + padding: ${props => props.theme.eui.paddingSizes.s}; + } + &.euiAccordion-isOpen { + background-color: ${props => props.theme.eui.euiFocusBackgroundColor}; + } + .euiAccordion__childWrapper { + background-color: ${props => props.theme.eui.euiColorLightestShade}; + } + .policyResponseAttentionBadge { + background-color: ${props => props.theme.eui.euiColorDanger}; + color: ${props => props.theme.eui.euiColorEmptyShade}; + } + .euiAccordion__button { + :hover, + :focus { + text-decoration: none; + } + } + :hover:not(.euiAccordion-isOpen) { + background-color: ${props => props.theme.eui.euiColorLightestShade}; + } +`; + +const ResponseActions = memo( + ({ + actions, + actionStatus, + }: { + actions: ImmutableArray; + actionStatus: Partial; + }) => { + return ( + <> + {actions.map((action, index) => { + const statuses = actionStatus[action]; + if (statuses === undefined) { + return undefined; + } + return ( + +

{formatResponse(action)}

+ + } + paddingSize="s" + extraAction={ + + +

{formatResponse(statuses.status)}

+
+
+ } + > + +

{statuses.message}

+
+
+ ); + })} + + ); + } +); + +/** + * A policy response is returned by the endpoint and shown in the host details after a user modifies a policy + */ +export const PolicyResponse = memo( + ({ + responseConfig, + responseActionStatus, + responseAttentionCount, + }: { + responseConfig: Immutable; + responseActionStatus: Partial; + responseAttentionCount: Map; + }) => { + return ( + <> + {Object.entries(responseConfig).map(([key, val]) => { + const attentionCount = responseAttentionCount.get(key); + return ( + htmlIdGenerator()(), [])} + key={useMemo(() => htmlIdGenerator()(), [])} + data-test-subj="hostDetailsPolicyResponseConfigAccordion" + buttonContent={ + +

{formatResponse(key)}

+
+ } + paddingSize="m" + extraAction={ + attentionCount && + attentionCount > 0 && ( + + {attentionCount} + + ) + } + > + +
+ ); + })} + + ); + } +); diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details/policy_response_friendly_names.ts b/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details/policy_response_friendly_names.ts new file mode 100644 index 0000000000000..251b3e86bc3f9 --- /dev/null +++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details/policy_response_friendly_names.ts @@ -0,0 +1,170 @@ +/* + * 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 { i18n } from '@kbn/i18n'; + +const responseMap = new Map(); +responseMap.set( + 'success', + i18n.translate('xpack.endpoint.hostDetails.policyResponse.success', { + defaultMessage: 'Success', + }) +); +responseMap.set( + 'warning', + i18n.translate('xpack.endpoint.hostDetails.policyResponse.warning', { + defaultMessage: 'Warning', + }) +); +responseMap.set( + 'failure', + i18n.translate('xpack.endpoint.hostDetails.policyResponse.failed', { + defaultMessage: 'Failed', + }) +); +responseMap.set( + 'malware', + i18n.translate('xpack.endpoint.hostDetails.policyResponse.malware', { + defaultMessage: 'Malware', + }) +); +responseMap.set( + 'events', + i18n.translate('xpack.endpoint.hostDetails.policyResponse.events', { + defaultMessage: 'Events', + }) +); +responseMap.set( + 'configure_elasticsearch_connection', + i18n.translate('xpack.endpoint.hostDetails.policyResponse.configureElasticSearchConnection', { + defaultMessage: 'Configure Elastic Search Connection', + }) +); +responseMap.set( + 'configure_logging', + i18n.translate('xpack.endpoint.hostDetails.policyResponse.configureLogging', { + defaultMessage: 'Configure Logging', + }) +); +responseMap.set( + 'configure_kernel', + i18n.translate('xpack.endpoint.hostDetails.policyResponse.configureKernel', { + defaultMessage: 'Configure Kernel', + }) +); +responseMap.set( + 'configure_malware', + i18n.translate('xpack.endpoint.hostDetails.policyResponse.configureMalware', { + defaultMessage: 'Configure Malware', + }) +); +responseMap.set( + 'connect_kernel', + i18n.translate('xpack.endpoint.hostDetails.policyResponse.connectKernel', { + defaultMessage: 'Connect Kernel', + }) +); +responseMap.set( + 'detect_file_open_events', + i18n.translate('xpack.endpoint.hostDetails.policyResponse.detectFileOpenEvents', { + defaultMessage: 'Detect File Open Events', + }) +); +responseMap.set( + 'detect_file_write_events', + i18n.translate('xpack.endpoint.hostDetails.policyResponse.detectFileWriteEvents', { + defaultMessage: 'Detect File Write Events', + }) +); +responseMap.set( + 'detect_image_load_events', + i18n.translate('xpack.endpoint.hostDetails.policyResponse.detectImageLoadEvents', { + defaultMessage: 'Detect Image Load Events', + }) +); +responseMap.set( + 'detect_process_events', + i18n.translate('xpack.endpoint.hostDetails.policyResponse.detectProcessEvents', { + defaultMessage: 'Detect Process Events', + }) +); +responseMap.set( + 'download_global_artifacts', + i18n.translate('xpack.endpoint.hostDetails.policyResponse.downloadGlobalArtifacts', { + defaultMessage: 'Download Global Artifacts', + }) +); +responseMap.set( + 'load_config', + i18n.translate('xpack.endpoint.hostDetails.policyResponse.loadConfig', { + defaultMessage: 'Load Config', + }) +); +responseMap.set( + 'load_malware_model', + i18n.translate('xpack.endpoint.hostDetails.policyResponse.loadMalwareModel', { + defaultMessage: 'Load Malware Model', + }) +); +responseMap.set( + 'read_elasticsearch_config', + i18n.translate('xpack.endpoint.hostDetails.policyResponse.readElasticSearchConfig', { + defaultMessage: 'Read ElasticSearch Config', + }) +); +responseMap.set( + 'read_events_config', + i18n.translate('xpack.endpoint.hostDetails.policyResponse.readEventsConfig', { + defaultMessage: 'Read Events Config', + }) +); +responseMap.set( + 'read_kernel_config', + i18n.translate('xpack.endpoint.hostDetails.policyResponse.readKernelConfig', { + defaultMessage: 'Read Kernel Config', + }) +); +responseMap.set( + 'read_logging_config', + i18n.translate('xpack.endpoint.hostDetails.policyResponse.readLoggingConfig', { + defaultMessage: 'Read Logging Config', + }) +); +responseMap.set( + 'read_malware_config', + i18n.translate('xpack.endpoint.hostDetails.policyResponse.readMalwareConfig', { + defaultMessage: 'Read Malware Config', + }) +); +responseMap.set( + 'workflow', + i18n.translate('xpack.endpoint.hostDetails.policyResponse.workflow', { + defaultMessage: 'Workflow', + }) +); +responseMap.set( + 'download_model', + i18n.translate('xpack.endpoint.hostDetails.policyResponse.downloadModel', { + defaultMessage: 'Download Model', + }) +); +responseMap.set( + 'ingest_events_config', + i18n.translate('xpack.endpoint.hostDetails.policyResponse.injestEventsConfig', { + defaultMessage: 'Injest Events Config', + }) +); + +/** + * Takes in the snake-cased response from the API and + * removes the underscores and capitalizes the string. + */ +export function formatResponse(responseString: string) { + if (responseMap.has(responseString)) { + return responseMap.get(responseString); + } + return responseString; +} diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/index.test.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/index.test.tsx index 5a8765110c909..aaeff935b32b4 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/index.test.tsx +++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/index.test.tsx @@ -25,7 +25,7 @@ describe('when on the hosts page', () => { let coreStart: AppContextTestRender['coreStart']; let middlewareSpy: AppContextTestRender['middlewareSpy']; - beforeEach(async () => { + beforeEach(() => { const mockedContext = createAppRootMockRenderer(); ({ history, store, coreStart, middlewareSpy } = mockedContext); render = () => mockedContext.render(); @@ -127,6 +127,14 @@ describe('when on the hosts page', () => { ) => { const policyResponse = docGenerator.generatePolicyResponse(); policyResponse.endpoint.policy.applied.status = overallStatus; + policyResponse.endpoint.policy.applied.response.configurations.malware.status = overallStatus; + policyResponse.endpoint.policy.applied.actions.download_model!.status = overallStatus; + if ( + overallStatus === HostPolicyResponseActionStatus.failure || + overallStatus === HostPolicyResponseActionStatus.warning + ) { + policyResponse.endpoint.policy.applied.actions.download_model!.message = 'no action taken'; + } store.dispatch({ type: 'serverReturnedHostPolicyResponse', payload: { @@ -281,6 +289,9 @@ describe('when on the hosts page', () => { fireEvent.click(policyStatusLink); }); await userChangedUrlChecker; + reactTestingLibrary.act(() => { + dispatchServerReturnedHostPolicyResponse(); + }); }); it('should hide the host details panel', async () => { const hostDetailsFlyout = await renderResult.queryByTestId('hostDetailsFlyoutBody'); @@ -299,6 +310,43 @@ describe('when on the hosts page', () => { (await renderResult.findByTestId('hostDetailsPolicyResponseFlyoutTitle')).textContent ).toBe('Policy Response'); }); + it('should show a configuration section for each protection', async () => { + const configAccordions = await renderResult.findAllByTestId( + 'hostDetailsPolicyResponseConfigAccordion' + ); + expect(configAccordions).not.toBeNull(); + }); + it('should show an actions section for each configuration', async () => { + const actionAccordions = await renderResult.findAllByTestId( + 'hostDetailsPolicyResponseActionsAccordion' + ); + const action = await renderResult.findAllByTestId('policyResponseAction'); + const statusHealth = await renderResult.findAllByTestId('policyResponseStatusHealth'); + const message = await renderResult.findAllByTestId('policyResponseMessage'); + expect(actionAccordions).not.toBeNull(); + expect(action).not.toBeNull(); + expect(statusHealth).not.toBeNull(); + expect(message).not.toBeNull(); + }); + it('should not show any numbered badges if all actions are succesful', () => { + return renderResult.findByTestId('hostDetailsPolicyResponseAttentionBadge').catch(e => { + expect(e).not.toBeNull(); + }); + }); + it('should show a numbered badge if at least one action failed', () => { + reactTestingLibrary.act(() => { + dispatchServerReturnedHostPolicyResponse(HostPolicyResponseActionStatus.failure); + }); + const attentionBadge = renderResult.findByTestId('hostDetailsPolicyResponseAttentionBadge'); + expect(attentionBadge).not.toBeNull(); + }); + it('should show a numbered badge if at least one action has a warning', () => { + reactTestingLibrary.act(() => { + dispatchServerReturnedHostPolicyResponse(HostPolicyResponseActionStatus.warning); + }); + const attentionBadge = renderResult.findByTestId('hostDetailsPolicyResponseAttentionBadge'); + expect(attentionBadge).not.toBeNull(); + }); it('should include the back to details link', async () => { const subHeaderBackLink = await renderResult.findByTestId('flyoutSubHeaderBackButton'); expect(subHeaderBackLink.textContent).toBe('Endpoint Details'); From 313d80228acbcfd779eae18c551b770dd5c02a31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Wed, 6 May 2020 15:11:29 +0200 Subject: [PATCH 14/23] Add version 7.8 to backport config (#65445) --- .backportrc.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.backportrc.json b/.backportrc.json index 731f49183dba5..0894909d2aac4 100644 --- a/.backportrc.json +++ b/.backportrc.json @@ -3,6 +3,7 @@ "targetBranchChoices": [ { "name": "master", "checked": true }, { "name": "7.x", "checked": true }, + "7.8", "7.7", "7.6", "7.5", From e86383037a5bf80164ff3bee6cc91077d9e9b80b Mon Sep 17 00:00:00 2001 From: Aleh Zasypkin Date: Wed, 6 May 2020 15:30:50 +0200 Subject: [PATCH 15/23] Add tests for the concurrent refresh token requests. (#62027) --- .../apis/security/saml_login.ts | 46 +++++++++++++++---- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/x-pack/test/saml_api_integration/apis/security/saml_login.ts b/x-pack/test/saml_api_integration/apis/security/saml_login.ts index 0b127288e7958..0684a5e572f55 100644 --- a/x-pack/test/saml_api_integration/apis/security/saml_login.ts +++ b/x-pack/test/saml_api_integration/apis/security/saml_login.ts @@ -515,7 +515,9 @@ export default function({ getService }: FtrProviderContext) { describe('API access with expired access token.', () => { let sessionCookie: Cookie; - beforeEach(async () => { + beforeEach(async function() { + this.timeout(40000); + const captureURLResponse = await supertest .get('/abc/xyz/handshake?one=two three') .expect(302); @@ -539,6 +541,10 @@ export default function({ getService }: FtrProviderContext) { .expect(302); sessionCookie = request.cookie(samlAuthenticationResponse.headers['set-cookie'][0])!; + + // Access token expiration is set to 15s for API integration tests. + // Let's wait for 20s to make sure token expires. + await delay(20000); }); const expectNewSessionCookie = (cookie: Cookie) => { @@ -549,13 +555,7 @@ export default function({ getService }: FtrProviderContext) { expect(cookie.value).to.not.be(sessionCookie.value); }; - it('expired access token should be automatically refreshed', async function() { - this.timeout(40000); - - // Access token expiration is set to 15s for API integration tests. - // Let's wait for 20s to make sure token expires. - await delay(20000); - + it('expired access token should be automatically refreshed', async () => { // This api call should succeed and automatically refresh token. Returned cookie will contain // the new access and refresh token pair. const firstResponse = await supertest @@ -600,6 +600,19 @@ export default function({ getService }: FtrProviderContext) { .set('Cookie', secondNewCookie.cookieString()) .expect(200); }); + + it('should refresh access token even if multiple concurrent requests try to refresh it', async () => { + // Send 5 concurrent requests with a cookie that contains an expired access token. + await Promise.all( + Array.from({ length: 5 }).map((value, index) => + supertest + .get(`/internal/security/me?a=${index}`) + .set('kbn-xsrf', 'xxx') + .set('Cookie', sessionCookie.cookieString()) + .expect(200) + ) + ); + }); }); describe('API access with missing access token document.', () => { @@ -629,9 +642,7 @@ export default function({ getService }: FtrProviderContext) { .expect(302); sessionCookie = request.cookie(samlAuthenticationResponse.headers['set-cookie'][0])!; - }); - it('should properly set cookie and start new SAML handshake', async function() { // Let's delete tokens from `.security` index directly to simulate the case when // Elasticsearch automatically removes access/refresh token document from the index // after some period of time. @@ -643,7 +654,9 @@ export default function({ getService }: FtrProviderContext) { expect(esResponse) .to.have.property('deleted') .greaterThan(0); + }); + it('should properly set cookie and start new SAML handshake', async () => { const handshakeResponse = await supertest .get('/abc/xyz/handshake?one=two three') .set('Cookie', sessionCookie.cookieString()) @@ -662,6 +675,19 @@ export default function({ getService }: FtrProviderContext) { '/internal/security/saml/capture-url-fragment' ); }); + + it('should start new SAML handshake even if multiple concurrent requests try to refresh access token', async () => { + // Issue 5 concurrent requests with a cookie that contains access/refresh token pair without + // a corresponding document in Elasticsearch. + await Promise.all( + Array.from({ length: 5 }).map((value, index) => + supertest + .get(`/abc/xyz/handshake?one=two three&a=${index}`) + .set('Cookie', sessionCookie.cookieString()) + .expect(302) + ) + ); + }); }); describe('IdP initiated login with active session', () => { From 4571536ba099e5fa196f22170c73d5d2e969e551 Mon Sep 17 00:00:00 2001 From: Robert Austin Date: Wed, 6 May 2020 09:41:40 -0400 Subject: [PATCH 16/23] [Resolver] use just left and top, and remove transform, from process nodes. (#65108) --- .../resolver/view/process_event_dot.tsx | 71 +++++++++---------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/x-pack/plugins/endpoint/public/embeddables/resolver/view/process_event_dot.tsx b/x-pack/plugins/endpoint/public/embeddables/resolver/view/process_event_dot.tsx index 0840b990ea315..27844f09e2272 100644 --- a/x-pack/plugins/endpoint/public/embeddables/resolver/view/process_event_dot.tsx +++ b/x-pack/plugins/endpoint/public/embeddables/resolver/view/process_event_dot.tsx @@ -142,20 +142,27 @@ export const ProcessEventDot = styled( const activeDescendantId = useSelector(selectors.uiActiveDescendantId); const selectedDescendantId = useSelector(selectors.uiSelectedDescendantId); + const logicalProcessNodeViewWidth = 360; + const logicalProcessNodeViewHeight = 120; + /** + * The `left` and `top` values represent the 'center' point of the process node. + * Since the view has content to the left and above the 'center' point, offset the + * position to accomodate for that. This aligns the logical center of the process node + * with the correct position on the map. + */ + const processNodeViewXOffset = -0.172413 * logicalProcessNodeViewWidth * magFactorX; + const processNodeViewYOffset = -0.73684 * logicalProcessNodeViewHeight * magFactorX; + const nodeViewportStyle = useMemo( () => ({ - left: `${left}px`, - top: `${top}px`, + left: `${left + processNodeViewXOffset}px`, + top: `${top + processNodeViewYOffset}px`, // Width of symbol viewport scaled to fit - width: `${360 * magFactorX}px`, + width: `${logicalProcessNodeViewWidth * magFactorX}px`, // Height according to symbol viewbox AR - height: `${120 * magFactorX}px`, - // Adjusted to position/scale with camera - transform: `translateX(-${0.172413 * 360 * magFactorX + 10}px) translateY(-${0.73684 * - 120 * - magFactorX}px)`, + height: `${logicalProcessNodeViewHeight * magFactorX}px`, }), - [left, magFactorX, top] + [left, magFactorX, processNodeViewXOffset, processNodeViewYOffset, top] ); /** @@ -202,32 +209,26 @@ export const ProcessEventDot = styled( const dispatch = useResolverDispatch(); - const handleFocus = useCallback( - (focusEvent: React.FocusEvent) => { - dispatch({ - type: 'userFocusedOnResolverNode', - payload: { - nodeId, - }, - }); - }, - [dispatch, nodeId] - ); + const handleFocus = useCallback(() => { + dispatch({ + type: 'userFocusedOnResolverNode', + payload: { + nodeId, + }, + }); + }, [dispatch, nodeId]); - const handleClick = useCallback( - (clickEvent: React.MouseEvent) => { - if (animationTarget.current !== null) { - (animationTarget.current as any).beginElement(); - } - dispatch({ - type: 'userSelectedResolverNode', - payload: { - nodeId, - }, - }); - }, - [animationTarget, dispatch, nodeId] - ); + const handleClick = useCallback(() => { + if (animationTarget.current !== null) { + (animationTarget.current as any).beginElement(); + } + dispatch({ + type: 'userSelectedResolverNode', + payload: { + nodeId, + }, + }); + }, [animationTarget, dispatch, nodeId]); /* eslint-disable jsx-a11y/click-events-have-key-events */ /** @@ -375,13 +376,11 @@ export const ProcessEventDot = styled( ) )` position: absolute; - display: block; text-align: left; font-size: 10px; user-select: none; box-sizing: border-box; border-radius: 10%; - padding: 4px; white-space: nowrap; will-change: left, top, width, height; contain: strict; From eccdbdbf4067fd2fc3eb472c87fa3e4c34565af6 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Wed, 6 May 2020 15:48:06 +0200 Subject: [PATCH 17/23] [ML] Data Frame Analytics: Skip job cloning functional tests. (#65465) --- .../apps/machine_learning/data_frame_analytics/cloning.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/functional/apps/machine_learning/data_frame_analytics/cloning.ts b/x-pack/test/functional/apps/machine_learning/data_frame_analytics/cloning.ts index 93f225989592e..d87d7d654f5c4 100644 --- a/x-pack/test/functional/apps/machine_learning/data_frame_analytics/cloning.ts +++ b/x-pack/test/functional/apps/machine_learning/data_frame_analytics/cloning.ts @@ -13,7 +13,8 @@ export default function({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const ml = getService('ml'); - describe('jobs cloning supported by UI form', function() { + // TODO add fix for https://github.com/elastic/elasticsearch/pull/56118 + describe.skip('jobs cloning supported by UI form', function() { const testDataList: Array<{ suiteTitle: string; archive: string; From 3e9a12cf330d4cc19237ffb070bc99074b2a9714 Mon Sep 17 00:00:00 2001 From: spalger Date: Wed, 6 May 2020 08:11:04 -0700 Subject: [PATCH 18/23] Revert "[SIEM] Eliminate Superfluous Untitled Timelines (#64341)" This reverts commit a06c02f606637e82d6964dd3be77b8c496f10156. --- x-pack/plugins/siem/common/constants.ts | 2 - .../siem/common/types/timeline/index.ts | 2 - .../timeline_toggle_column.spec.ts | 2 +- .../cypress/integration/url_state.spec.ts | 62 ++- .../siem/cypress/tasks/create_new_case.ts | 1 - .../public/components/events_viewer/index.tsx | 19 +- .../__snapshots__/index.test.tsx.snap | 4 +- .../edit_timeline_batch_actions.tsx | 2 +- .../components/open_timeline/helpers.test.ts | 51 +-- .../components/open_timeline/helpers.ts | 4 - .../components/open_timeline/index.test.tsx | 401 ++++++++++-------- .../open_timeline/open_timeline.tsx | 23 +- .../public/components/open_timeline/types.ts | 4 +- .../__snapshots__/index.test.tsx.snap | 82 ++-- .../siem/public/components/timeline/index.tsx | 17 +- .../public/components/top_n/index.test.tsx | 1 - .../siem/public/containers/timeline/api.ts | 20 +- .../siem/public/graphql/introspection.json | 1 - x-pack/plugins/siem/public/graphql/types.ts | 1 - .../siem/public/mock/timeline_results.ts | 2 +- .../components/signals/index.test.tsx | 18 +- .../components/signals/index.tsx | 64 ++- .../siem/public/pages/timelines/index.tsx | 2 +- x-pack/plugins/siem/public/store/epic.ts | 4 +- .../siem/public/store/timeline/actions.ts | 4 - .../siem/public/store/timeline/defaults.ts | 2 +- .../siem/public/store/timeline/epic.ts | 15 +- .../store/timeline/epic_draft_timeline.ts | 110 ----- .../siem/public/store/timeline/helpers.ts | 39 +- .../siem/public/store/timeline/model.ts | 1 - .../public/store/timeline/reducer.test.ts | 27 +- .../siem/public/store/timeline/reducer.ts | 37 ++ .../server/graphql/timeline/schema.gql.ts | 1 - x-pack/plugins/siem/server/graphql/types.ts | 1 - .../server/lib/timeline/default_timeline.ts | 27 -- .../lib/timeline/default_timeline_headers.ts | 44 -- .../lib/timeline/pick_saved_timeline.ts | 9 +- .../routes/__mocks__/import_timelines.ts | 23 - .../routes/__mocks__/request_responses.ts | 27 -- .../draft_clean_timelines_route.test.ts | 114 ----- .../routes/draft_clean_timelines_route.ts | 86 ---- .../routes/draft_timelines_route.test.ts | 113 ----- .../timeline/routes/draft_timelines_route.ts | 80 ---- .../timeline/routes/export_timelines_route.ts | 2 + .../routes/import_timelines_route.test.ts | 24 +- .../timeline/routes/import_timelines_route.ts | 8 +- .../timeline/routes/utils/export_timelines.ts | 5 - .../siem/server/lib/timeline/saved_object.ts | 62 +-- x-pack/plugins/siem/server/routes/index.ts | 4 - .../es_archives/timeline/data.json.gz | Bin 1827 -> 1775 bytes .../es_archives/timeline/mappings.json | 3 - yarn.lock | 10 +- 52 files changed, 478 insertions(+), 1189 deletions(-) delete mode 100644 x-pack/plugins/siem/public/store/timeline/epic_draft_timeline.ts delete mode 100644 x-pack/plugins/siem/server/lib/timeline/default_timeline.ts delete mode 100644 x-pack/plugins/siem/server/lib/timeline/default_timeline_headers.ts delete mode 100644 x-pack/plugins/siem/server/lib/timeline/routes/draft_clean_timelines_route.test.ts delete mode 100644 x-pack/plugins/siem/server/lib/timeline/routes/draft_clean_timelines_route.ts delete mode 100644 x-pack/plugins/siem/server/lib/timeline/routes/draft_timelines_route.test.ts delete mode 100644 x-pack/plugins/siem/server/lib/timeline/routes/draft_timelines_route.ts diff --git a/x-pack/plugins/siem/common/constants.ts b/x-pack/plugins/siem/common/constants.ts index 9bfd89e8bb576..bcf5c78be3644 100644 --- a/x-pack/plugins/siem/common/constants.ts +++ b/x-pack/plugins/siem/common/constants.ts @@ -91,8 +91,6 @@ export const DETECTION_ENGINE_RULES_STATUS_URL = `${DETECTION_ENGINE_RULES_URL}/ export const DETECTION_ENGINE_PREPACKAGED_RULES_STATUS_URL = `${DETECTION_ENGINE_RULES_URL}/prepackaged/_status`; export const TIMELINE_URL = '/api/timeline'; -export const TIMELINE_DRAFT_CLEAN_URL = `${TIMELINE_URL}/_draft/clean`; -export const TIMELINE_DRAFT_URL = `${TIMELINE_URL}/_draft`; export const TIMELINE_EXPORT_URL = `${TIMELINE_URL}/_export`; export const TIMELINE_IMPORT_URL = `${TIMELINE_URL}/_import`; diff --git a/x-pack/plugins/siem/common/types/timeline/index.ts b/x-pack/plugins/siem/common/types/timeline/index.ts index e87986fd1bdf2..43f66da6109df 100644 --- a/x-pack/plugins/siem/common/types/timeline/index.ts +++ b/x-pack/plugins/siem/common/types/timeline/index.ts @@ -136,13 +136,11 @@ const SavedSortRuntimeType = runtimeTypes.partial({ export enum TimelineType { default = 'default', - draft = 'draft', template = 'template', } export const TimelineTypeLiteralRt = runtimeTypes.union([ runtimeTypes.literal(TimelineType.template), - runtimeTypes.literal(TimelineType.draft), runtimeTypes.literal(TimelineType.default), ]); diff --git a/x-pack/plugins/siem/cypress/integration/timeline_toggle_column.spec.ts b/x-pack/plugins/siem/cypress/integration/timeline_toggle_column.spec.ts index 26006ec5030b6..7b2c6f3b55b2e 100644 --- a/x-pack/plugins/siem/cypress/integration/timeline_toggle_column.spec.ts +++ b/x-pack/plugins/siem/cypress/integration/timeline_toggle_column.spec.ts @@ -27,10 +27,10 @@ import { HOSTS_PAGE } from '../urls/navigation'; describe('toggle column in timeline', () => { before(() => { loginAndWaitForPage(HOSTS_PAGE); - openTimeline(); }); beforeEach(() => { + openTimeline(); populateTimeline(); }); diff --git a/x-pack/plugins/siem/cypress/integration/url_state.spec.ts b/x-pack/plugins/siem/cypress/integration/url_state.spec.ts index 489315a819647..cd60745b19040 100644 --- a/x-pack/plugins/siem/cypress/integration/url_state.spec.ts +++ b/x-pack/plugins/siem/cypress/integration/url_state.spec.ts @@ -30,7 +30,7 @@ import { openAllHosts } from '../tasks/hosts/main'; import { waitForIpsTableToBeLoaded } from '../tasks/network/flows'; import { clearSearchBar, kqlSearch, navigateFromHeaderTo } from '../tasks/siem_header'; -import { openTimeline, openTimelineIfClosed } from '../tasks/siem_main'; +import { openTimeline } from '../tasks/siem_main'; import { addDescriptionToTimeline, addNameToTimeline, @@ -174,11 +174,10 @@ describe('url state', () => { kqlSearch('source.ip: "10.142.0.9" {enter}'); navigateFromHeaderTo(HOSTS); - cy.get(NETWORK).should($div => - // @ts-ignore - expect($div[0].attributes.href.value).to.include( - "#/link-to/network?query=(language:kuery,query:'source.ip:%20%2210.142.0.9%22%20')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1564691609186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1564691609186)))" - ) + cy.get(NETWORK).should( + 'have.attr', + 'href', + "#/link-to/network?query=(language:kuery,query:'source.ip:%20%2210.142.0.9%22%20')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1564691609186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1564691609186)))" ); }); @@ -188,20 +187,16 @@ describe('url state', () => { openAllHosts(); waitForAllHostsToBeLoaded(); - cy.get(HOSTS).should($div => - // @ts-ignore - expect($div[0].attributes.href.value).to.include( - "#/link-to/hosts?query=(language:kuery,query:'host.name:%20%22siem-kibana%22%20')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1577914409186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1577914409186)))" - ) + cy.get(HOSTS).should( + 'have.attr', + 'href', + "#/link-to/hosts?query=(language:kuery,query:'host.name:%20%22siem-kibana%22%20')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1577914409186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1577914409186)))" ); - - cy.get(NETWORK).should($div => - // @ts-ignore - expect($div[0].attributes.href.value).to.include( - "#/link-to/network?query=(language:kuery,query:'host.name:%20%22siem-kibana%22%20')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1577914409186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1577914409186)))" - ) + cy.get(NETWORK).should( + 'have.attr', + 'href', + "#/link-to/network?query=(language:kuery,query:'host.name:%20%22siem-kibana%22%20')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1577914409186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1577914409186)))" ); - cy.get(HOSTS_NAMES) .first() .invoke('text') @@ -211,29 +206,24 @@ describe('url state', () => { clearSearchBar(); kqlSearch('agent.type: "auditbeat" {enter}'); - cy.get(ANOMALIES_TAB).should($div => - // @ts-ignore - expect($div[0].attributes.href.value).to.include( - "#/hosts/siem-kibana/anomalies?query=(language:kuery,query:'agent.type:%20%22auditbeat%22%20')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1577914409186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1577914409186)))" - ) + cy.get(ANOMALIES_TAB).should( + 'have.attr', + 'href', + "#/hosts/siem-kibana/anomalies?query=(language:kuery,query:'agent.type:%20%22auditbeat%22%20')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1577914409186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1577914409186)))" ); - cy.get(BREADCRUMBS) .eq(1) - .should($div => - // @ts-ignore - expect($div[0].attributes.href.value).to.include( - "#/link-to/hosts?query=(language:kuery,query:'agent.type:%20%22auditbeat%22%20')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1577914409186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1577914409186)))" - ) + .should( + 'have.attr', + 'href', + "#/link-to/hosts?query=(language:kuery,query:'agent.type:%20%22auditbeat%22%20')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1577914409186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1577914409186)))" ); - cy.get(BREADCRUMBS) .eq(2) - .should($div => - // @ts-ignore - expect($div[0].attributes.href.value).to.include( - "#/link-to/hosts/siem-kibana?query=(language:kuery,query:'agent.type:%20%22auditbeat%22%20')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1577914409186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1577914409186)))" - ) + .should( + 'have.attr', + 'href', + "#/link-to/hosts/siem-kibana?query=(language:kuery,query:'agent.type:%20%22auditbeat%22%20')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1577914409186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1577914409186)))" ); }); @@ -246,7 +236,7 @@ describe('url state', () => { it('sets and reads the url state for timeline by id', () => { loginAndWaitForPage(HOSTS_PAGE); - openTimelineIfClosed(); + openTimeline(); executeTimelineKQL('host.name: *'); cy.get(SERVER_SIDE_EVENT_COUNT) diff --git a/x-pack/plugins/siem/cypress/tasks/create_new_case.ts b/x-pack/plugins/siem/cypress/tasks/create_new_case.ts index 491fdd84e9b38..b7078a1033de8 100644 --- a/x-pack/plugins/siem/cypress/tasks/create_new_case.ts +++ b/x-pack/plugins/siem/cypress/tasks/create_new_case.ts @@ -32,7 +32,6 @@ export const createNewCase = (newCase: TestCase) => { cy.get(INSERT_TIMELINE_BTN).click({ force: true }); cy.get(TIMELINE_SEARCHBOX).type(`${newCase.timeline.title}{enter}`); cy.get(TIMELINE).should('be.visible'); - cy.wait(300); cy.get(TIMELINE) .eq(1) .click({ force: true }); diff --git a/x-pack/plugins/siem/public/components/events_viewer/index.tsx b/x-pack/plugins/siem/public/components/events_viewer/index.tsx index 5131033d994a1..bc6a1b3b77bfa 100644 --- a/x-pack/plugins/siem/public/components/events_viewer/index.tsx +++ b/x-pack/plugins/siem/public/components/events_viewer/index.tsx @@ -16,7 +16,6 @@ import { SubsetTimelineModel, TimelineModel, } from '../../store/timeline/model'; -import { getNewTimeline } from '../../store/timeline/helpers'; import { OnChangeItemsPerPage } from '../timeline/events'; import { Filter } from '../../../../../../src/plugins/data/public'; import { useUiSetting } from '../../lib/kibana'; @@ -45,7 +44,7 @@ const defaultTimelineTypeContext = { }; const StatefulEventsViewerComponent: React.FC = ({ - addTimeline, + createTimeline, columns, dataProviders, deletedEventIds, @@ -76,18 +75,8 @@ const StatefulEventsViewerComponent: React.FC = ({ ); useEffect(() => { - if (addTimeline != null) { - addTimeline({ - id, - timeline: getNewTimeline({ - id, - columns, - sort, - itemsPerPage, - showCheckboxes, - showRowRenderers, - }), - }); + if (createTimeline != null) { + createTimeline({ id, columns, sort, itemsPerPage, showCheckboxes, showRowRenderers }); } return () => { deleteEventQuery({ id, inputId: 'global' }); @@ -191,7 +180,7 @@ const makeMapStateToProps = () => { }; const mapDispatchToProps = { - addTimeline: timelineActions.addTimeline, + createTimeline: timelineActions.createTimeline, deleteEventQuery: inputsActions.deleteOneQuery, updateItemsPerPage: timelineActions.updateItemsPerPage, removeColumn: timelineActions.removeColumn, diff --git a/x-pack/plugins/siem/public/components/matrix_histogram/__snapshots__/index.test.tsx.snap b/x-pack/plugins/siem/public/components/matrix_histogram/__snapshots__/index.test.tsx.snap index e378afd9c7fec..c4bdff7ea649a 100644 --- a/x-pack/plugins/siem/public/components/matrix_histogram/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/siem/public/components/matrix_histogram/__snapshots__/index.test.tsx.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Matrix Histogram Component not initial load it renders no MatrixLoader 1`] = `"
"`; +exports[`Matrix Histogram Component not initial load it renders no MatrixLoader 1`] = `"
"`; -exports[`Matrix Histogram Component on initial load it renders MatrixLoader 1`] = `"
"`; +exports[`Matrix Histogram Component on initial load it renders MatrixLoader 1`] = `"
"`; diff --git a/x-pack/plugins/siem/public/components/open_timeline/edit_timeline_batch_actions.tsx b/x-pack/plugins/siem/public/components/open_timeline/edit_timeline_batch_actions.tsx index 7fb03b98432d0..74b9a8cad98dc 100644 --- a/x-pack/plugins/siem/public/components/open_timeline/edit_timeline_batch_actions.tsx +++ b/x-pack/plugins/siem/public/components/open_timeline/edit_timeline_batch_actions.tsx @@ -20,7 +20,7 @@ const getExportedIds = (selectedTimelines: OpenTimelineResult[]) => { ); }; -export const useEditTimelineBatchActions = ({ +export const useEditTimelinBatchActions = ({ deleteTimelines, selectedItems, tableRef, diff --git a/x-pack/plugins/siem/public/components/open_timeline/helpers.test.ts b/x-pack/plugins/siem/public/components/open_timeline/helpers.test.ts index 700fd15cdea05..a7c0b08fc8a21 100644 --- a/x-pack/plugins/siem/public/components/open_timeline/helpers.test.ts +++ b/x-pack/plugins/siem/public/components/open_timeline/helpers.test.ts @@ -300,7 +300,7 @@ describe('helpers', () => { sortDirection: 'desc', }, title: '', - timelineType: TimelineType.draft, + timelineType: TimelineType.default, templateTimelineId: null, templateTimelineVersion: null, version: '1', @@ -397,14 +397,13 @@ describe('helpers', () => { sortDirection: 'desc', }, title: '', - timelineType: TimelineType.draft, + timelineType: TimelineType.default, templateTimelineId: null, templateTimelineVersion: null, version: '1', width: 1100, }); }); - test('should merge columns when event.action is deleted without two extra column names of user.name', () => { const timeline = { savedObjectId: 'savedObject-1', @@ -417,80 +416,38 @@ describe('helpers', () => { savedObjectId: 'savedObject-1', columns: [ { - aggregatable: undefined, - category: undefined, columnHeaderType: 'not-filtered', - description: undefined, - example: undefined, id: '@timestamp', - placeholder: undefined, - type: undefined, width: 190, }, { - aggregatable: undefined, - category: undefined, columnHeaderType: 'not-filtered', - description: undefined, - example: undefined, id: 'message', - placeholder: undefined, - type: undefined, width: 180, }, { - aggregatable: undefined, - category: undefined, columnHeaderType: 'not-filtered', - description: undefined, - example: undefined, id: 'event.category', - placeholder: undefined, - type: undefined, width: 180, }, { - aggregatable: undefined, - category: undefined, columnHeaderType: 'not-filtered', - description: undefined, - example: undefined, id: 'host.name', - placeholder: undefined, - type: undefined, width: 180, }, { - aggregatable: undefined, - category: undefined, columnHeaderType: 'not-filtered', - description: undefined, - example: undefined, id: 'source.ip', - placeholder: undefined, - type: undefined, width: 180, }, { - aggregatable: undefined, - category: undefined, columnHeaderType: 'not-filtered', - description: undefined, - example: undefined, id: 'destination.ip', - placeholder: undefined, - type: undefined, width: 180, }, { - aggregatable: undefined, - category: undefined, columnHeaderType: 'not-filtered', - description: undefined, - example: undefined, id: 'user.name', - placeholder: undefined, - type: undefined, width: 180, }, ], @@ -517,7 +474,7 @@ describe('helpers', () => { }, loadingEventIds: [], title: '', - timelineType: TimelineType.draft, + timelineType: TimelineType.default, templateTimelineId: null, templateTimelineVersion: null, noteIds: [], @@ -685,7 +642,7 @@ describe('helpers', () => { }, loadingEventIds: [], title: '', - timelineType: TimelineType.draft, + timelineType: TimelineType.default, templateTimelineId: null, templateTimelineVersion: null, noteIds: [], diff --git a/x-pack/plugins/siem/public/components/open_timeline/helpers.ts b/x-pack/plugins/siem/public/components/open_timeline/helpers.ts index 103040c3b0d9e..681d39feb09f8 100644 --- a/x-pack/plugins/siem/public/components/open_timeline/helpers.ts +++ b/x-pack/plugins/siem/public/components/open_timeline/helpers.ts @@ -251,10 +251,6 @@ export const queryTimelineById = ({ } }; -export const epicUpdateTimeline = ({ id, timeline }: UpdateTimeline) => [ - dispatchAddTimeline({ id, timeline }), -]; - export const dispatchUpdateTimeline = (dispatch: Dispatch): DispatchUpdateTimeline => ({ duplicate, id, diff --git a/x-pack/plugins/siem/public/components/open_timeline/index.test.tsx b/x-pack/plugins/siem/public/components/open_timeline/index.test.tsx index fee6e6614b863..731c6d1ca9806 100644 --- a/x-pack/plugins/siem/public/components/open_timeline/index.test.tsx +++ b/x-pack/plugins/siem/public/components/open_timeline/index.test.tsx @@ -4,12 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ +import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json'; import { mount } from 'enzyme'; import { MockedProvider } from 'react-apollo/test-utils'; import React from 'react'; +import { ThemeProvider } from 'styled-components'; import { wait } from '../../lib/helpers'; -import { TestProviders, apolloClient } from '../../mock/test_providers'; +import { TestProviderWithoutDragAndDrop, apolloClient } from '../../mock/test_providers'; import { mockOpenTimelineQueryResults } from '../../mock/timeline_results'; import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../pages/timelines/timelines_page'; @@ -39,6 +41,7 @@ jest.mock('./use_timeline_types', () => { }); describe('StatefulOpenTimeline', () => { + const theme = () => ({ eui: euiDarkVars, darkMode: true }); const title = 'All Timelines / Open Timelines'; beforeEach(() => { ((useGetAllTimeline as unknown) as jest.Mock).mockReturnValue({ @@ -55,17 +58,19 @@ describe('StatefulOpenTimeline', () => { test('it has the expected initial state', () => { const wrapper = mount( - - - - - + + + + + + + ); const componentProps = wrapper @@ -89,17 +94,19 @@ describe('StatefulOpenTimeline', () => { describe('#onQueryChange', () => { test('it updates the query state with the expected trimmed value when the user enters a query', () => { const wrapper = mount( - - - - - + + + + + + + ); wrapper .find('[data-test-subj="search-bar"] input') @@ -114,16 +121,18 @@ describe('StatefulOpenTimeline', () => { test('it appends the word "with" to the Showing in Timelines message when the user enters a query', async () => { const wrapper = mount( - - - - - + + + + + + + ); await wait(); @@ -142,16 +151,18 @@ describe('StatefulOpenTimeline', () => { test('echos (renders) the query when the user enters a query', async () => { const wrapper = mount( - - - - - + + + + + + + ); await wait(); @@ -172,16 +183,18 @@ describe('StatefulOpenTimeline', () => { describe('#focusInput', () => { test('focuses the input when the component mounts', async () => { const wrapper = mount( - - - - - + + + + + + + ); await wait(); @@ -201,16 +214,18 @@ describe('StatefulOpenTimeline', () => { const addTimelinesToFavorites = jest.fn(); const wrapper = mount( - - - - - + + + + + + + ); await wait(); @@ -245,16 +260,18 @@ describe('StatefulOpenTimeline', () => { const deleteTimelines = jest.fn(); const wrapper = mount( - - - - - + + + + + + + ); await wait(); @@ -286,17 +303,19 @@ describe('StatefulOpenTimeline', () => { describe('#onSelectionChange', () => { test('it updates the selection state when timelines are selected', async () => { const wrapper = mount( - - - - - + + + + + + + ); await wait(); @@ -318,17 +337,19 @@ describe('StatefulOpenTimeline', () => { describe('#onTableChange', () => { test('it updates the sort state when the user clicks on a column to sort it', () => { const wrapper = mount( - - - - - + + + + + + + ); expect( @@ -355,17 +376,19 @@ describe('StatefulOpenTimeline', () => { describe('#onToggleOnlyFavorites', () => { test('it updates the onlyFavorites state when the user clicks the Only Favorites button', () => { const wrapper = mount( - - - - - + + + + + + + ); expect( @@ -392,17 +415,19 @@ describe('StatefulOpenTimeline', () => { describe('#onToggleShowNotes', () => { test('it updates the itemIdToExpandedNotesRowMap state when the user clicks the expand notes button', async () => { const wrapper = mount( - - - - - + + + + + + + ); await wait(); @@ -442,17 +467,19 @@ describe('StatefulOpenTimeline', () => { test('it renders the expanded notes when the expand button is clicked', async () => { const wrapper = mount( - - - - - + + + + + + + ); await wait(); @@ -475,19 +502,21 @@ describe('StatefulOpenTimeline', () => { ).toEqual('elastic'); }); - test('it renders the tabs', async () => { + test('it renders the title', async () => { const wrapper = mount( - - - - - + + + + + + + ); await wait(); @@ -501,17 +530,19 @@ describe('StatefulOpenTimeline', () => { describe('#resetSelectionState', () => { test('when the user deletes selected timelines, resetSelectionState is invoked to clear the selection state', async () => { const wrapper = mount( - - - - - + + + + + + + ); const getSelectedItem = (): [] => wrapper @@ -530,17 +561,19 @@ describe('StatefulOpenTimeline', () => { test('it renders the expected count of matching timelines when no query has been entered', async () => { const wrapper = mount( - + - + + + - + ); await wait(); @@ -560,17 +593,19 @@ describe('StatefulOpenTimeline', () => { const onOpenTimeline = jest.fn(); const wrapper = mount( - - - - - + + + + + + + ); await wait(); @@ -596,17 +631,19 @@ describe('StatefulOpenTimeline', () => { const onOpenTimeline = jest.fn(); const wrapper = mount( - - - - - + + + + + + + ); await wait(); diff --git a/x-pack/plugins/siem/public/components/open_timeline/open_timeline.tsx b/x-pack/plugins/siem/public/components/open_timeline/open_timeline.tsx index ce0eb52bc3839..e172a006abe4b 100644 --- a/x-pack/plugins/siem/public/components/open_timeline/open_timeline.tsx +++ b/x-pack/plugins/siem/public/components/open_timeline/open_timeline.tsx @@ -8,7 +8,7 @@ import { EuiPanel, EuiBasicTable } from '@elastic/eui'; import React, { useCallback, useMemo, useRef } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { OPEN_TIMELINE_CLASS_NAME } from './helpers'; -import { OpenTimelineProps, OpenTimelineResult, ActionTimelineToShow } from './types'; +import { OpenTimelineProps, OpenTimelineResult } from './types'; import { SearchRow } from './search_row'; import { TimelinesTable } from './timelines_table'; import { ImportDataModal } from '../import_data_modal'; @@ -22,7 +22,7 @@ import { UtilityBarSection, UtilityBarAction, } from '../utility_bar'; -import { useEditTimelineBatchActions } from './edit_timeline_batch_actions'; +import { useEditTimelinBatchActions } from './edit_timeline_batch_actions'; import { useEditTimelineActions } from './edit_timeline_actions'; import { EditOneTimelineAction } from './export_timeline'; @@ -65,7 +65,7 @@ export const OpenTimeline = React.memo( onCompleteEditTimelineAction, } = useEditTimelineActions(); - const { getBatchItemsPopoverContent } = useEditTimelineBatchActions({ + const { getBatchItemsPopoverContent } = useEditTimelinBatchActions({ deleteTimelines, selectedItems, tableRef, @@ -106,7 +106,6 @@ export const OpenTimeline = React.memo( setImportDataModalToggle(false); } }, [setImportDataModalToggle]); - const handleComplete = useCallback(() => { if (setImportDataModalToggle != null) { setImportDataModalToggle(false); @@ -116,14 +115,6 @@ export const OpenTimeline = React.memo( } }, [setImportDataModalToggle, refetch, searchResults, totalSearchResultsCount]); - const actionTimelineToShow = useMemo( - () => - onDeleteSelected != null && deleteTimelines != null - ? ['delete', 'duplicate', 'export', 'selectable'] - : ['duplicate', 'export', 'selectable'], - [onDeleteSelected, deleteTimelines] - ); - return ( <> ( + onDeleteSelected != null && deleteTimelines != null + ? ['delete', 'duplicate', 'export', 'selectable'] + : ['duplicate', 'export', 'selectable'], + [onDeleteSelected, deleteTimelines] + )} data-test-subj="timelines-table" deleteTimelines={deleteTimelines} defaultPageSize={defaultPageSize} diff --git a/x-pack/plugins/siem/public/components/open_timeline/types.ts b/x-pack/plugins/siem/public/components/open_timeline/types.ts index bb7e508518047..4d953f6fa775e 100644 --- a/x-pack/plugins/siem/public/components/open_timeline/types.ts +++ b/x-pack/plugins/siem/public/components/open_timeline/types.ts @@ -8,7 +8,7 @@ import { SetStateAction, Dispatch } from 'react'; import { AllTimelinesVariables } from '../../containers/timeline/all'; import { TimelineModel } from '../../store/timeline/model'; import { NoteResult } from '../../graphql/types'; -import { TimelineTypeLiteral } from '../../../common/types/timeline'; +import { TimelineType, TimelineTypeLiteral } from '../../../common/types/timeline'; /** The users who added a timeline to favorites */ export interface FavoriteTimelineResult { @@ -48,7 +48,7 @@ export interface OpenTimelineResult { savedObjectId?: string | null; title?: string | null; templateTimelineId?: string | null; - type?: TimelineTypeLiteral; + type?: TimelineType.template | TimelineType.default; updated?: number | null; updatedBy?: string | null; } diff --git a/x-pack/plugins/siem/public/components/stat_items/__snapshots__/index.test.tsx.snap b/x-pack/plugins/siem/public/components/stat_items/__snapshots__/index.test.tsx.snap index e209ca3b069d2..e15ce0ae5f543 100644 --- a/x-pack/plugins/siem/public/components/stat_items/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/siem/public/components/stat_items/__snapshots__/index.test.tsx.snap @@ -38,18 +38,18 @@ exports[`Stat Items Component disable charts it renders the default widget 1`] = data-test-subj="stat-item" >

@@ -258,18 +258,18 @@ exports[`Stat Items Component disable charts it renders the default widget 2`] = data-test-subj="stat-item" >

@@ -548,18 +548,18 @@ exports[`Stat Items Component rendering kpis with charts it renders the default data-test-subj="stat-item" >

1,714 @@ -734,10 +734,10 @@ exports[`Stat Items Component rendering kpis with charts it renders the default key="stat-items-field-uniqueDestinationIps" >

2,359 @@ -815,10 +815,10 @@ exports[`Stat Items Component rendering kpis with charts it renders the default >

( ({ columns, + createTimeline, dataProviders, eventType, end, @@ -141,13 +143,19 @@ const StatefulTimelineComponent = React.memo( [columns, id] ); + useEffect(() => { + if (createTimeline != null) { + createTimeline({ id, columns: defaultHeaders, show: false }); + } + }, []); + return ( {({ indexPattern, browserFields }) => ( ( onDataProviderRemoved={onDataProviderRemoved} onToggleDataProviderEnabled={onToggleDataProviderEnabled} onToggleDataProviderExcluded={onToggleDataProviderExcluded} - show={show} + show={show!} showCallOutUnauthorizedMsg={showCallOutUnauthorizedMsg} - sort={sort} + sort={sort!} start={start} toggleColumn={toggleColumn} usersViewing={usersViewing} @@ -247,6 +255,7 @@ const makeMapStateToProps = () => { const mapDispatchToProps = { addProvider: timelineActions.addProvider, + createTimeline: timelineActions.createTimeline, onDataProviderEdited: timelineActions.dataProviderEdited, removeColumn: timelineActions.removeColumn, removeProvider: timelineActions.removeProvider, diff --git a/x-pack/plugins/siem/public/components/top_n/index.test.tsx b/x-pack/plugins/siem/public/components/top_n/index.test.tsx index 08d1b4d5ffd4c..9325dcf499b2b 100644 --- a/x-pack/plugins/siem/public/components/top_n/index.test.tsx +++ b/x-pack/plugins/siem/public/components/top_n/index.test.tsx @@ -18,7 +18,6 @@ import { Props } from './top_n'; import { ACTIVE_TIMELINE_REDUX_ID, StatefulTopN } from '.'; jest.mock('../../lib/kibana'); -jest.mock('../../store/timeline/actions'); const mockUiSettingsForFilterManager = createKibanaCoreStartMock().uiSettings; diff --git a/x-pack/plugins/siem/public/containers/timeline/api.ts b/x-pack/plugins/siem/public/containers/timeline/api.ts index 3a9cd2b0dc375..023e2e6af9f88 100644 --- a/x-pack/plugins/siem/public/containers/timeline/api.ts +++ b/x-pack/plugins/siem/public/containers/timeline/api.ts @@ -13,13 +13,7 @@ import { TimelineResponse, TimelineResponseType, } from '../../../common/types/timeline'; -import { - TIMELINE_URL, - TIMELINE_DRAFT_CLEAN_URL, - TIMELINE_DRAFT_URL, - TIMELINE_IMPORT_URL, - TIMELINE_EXPORT_URL, -} from '../../../common/constants'; +import { TIMELINE_URL, TIMELINE_IMPORT_URL, TIMELINE_EXPORT_URL } from '../../../common/constants'; import { KibanaServices } from '../../lib/kibana'; import { ExportSelectedData } from '../../components/generic_downloader'; @@ -119,15 +113,3 @@ export const exportSelectedTimeline: ExportSelectedData = async ({ return response.body!; }; - -export const getDraftTimeline = async (): Promise => { - const response = await KibanaServices.get().http.get(TIMELINE_DRAFT_URL); - - return decodeTimelineResponse(response); -}; - -export const cleanDraftTimeline = async (): Promise => { - const response = await KibanaServices.get().http.post(TIMELINE_DRAFT_CLEAN_URL); - - return decodeTimelineResponse(response); -}; diff --git a/x-pack/plugins/siem/public/graphql/introspection.json b/x-pack/plugins/siem/public/graphql/introspection.json index d6f34255bcc1c..c2b21957a9056 100644 --- a/x-pack/plugins/siem/public/graphql/introspection.json +++ b/x-pack/plugins/siem/public/graphql/introspection.json @@ -10377,7 +10377,6 @@ "isDeprecated": false, "deprecationReason": null }, - { "name": "draft", "description": "", "isDeprecated": false, "deprecationReason": null }, { "name": "template", "description": "", diff --git a/x-pack/plugins/siem/public/graphql/types.ts b/x-pack/plugins/siem/public/graphql/types.ts index 3436ee84a2f30..dd4e967b185b9 100644 --- a/x-pack/plugins/siem/public/graphql/types.ts +++ b/x-pack/plugins/siem/public/graphql/types.ts @@ -342,7 +342,6 @@ export enum TlsFields { export enum TimelineType { default = 'default', - draft = 'draft', template = 'template', } diff --git a/x-pack/plugins/siem/public/mock/timeline_results.ts b/x-pack/plugins/siem/public/mock/timeline_results.ts index 86acb2981be06..1af0f533a7ca9 100644 --- a/x-pack/plugins/siem/public/mock/timeline_results.ts +++ b/x-pack/plugins/siem/public/mock/timeline_results.ts @@ -2243,7 +2243,7 @@ export const defaultTimelineProps: CreateTimelineProps = { showRowRenderers: true, sort: { columnId: '@timestamp', sortDirection: Direction.desc }, title: '', - timelineType: TimelineType.draft, + timelineType: TimelineType.default, templateTimelineVersion: null, templateTimelineId: null, version: null, diff --git a/x-pack/plugins/siem/public/pages/detection_engine/components/signals/index.test.tsx b/x-pack/plugins/siem/public/pages/detection_engine/components/signals/index.test.tsx index ac31d12186d34..b66a9fc881045 100644 --- a/x-pack/plugins/siem/public/pages/detection_engine/components/signals/index.test.tsx +++ b/x-pack/plugins/siem/public/pages/detection_engine/components/signals/index.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { SignalsTableComponent, PropsFromRedux } from './index'; +import { SignalsTableComponent } from './index'; describe('SignalsTableComponent', () => { it('renders correctly', () => { @@ -28,15 +28,13 @@ describe('SignalsTableComponent', () => { loadingEventIds={[]} selectedEventIds={{}} isSelectAllChecked={false} - clearSelected={(jest.fn() as unknown) as PropsFromRedux['clearSelected']} - setEventsLoading={(jest.fn() as unknown) as PropsFromRedux['setEventsLoading']} - clearEventsLoading={(jest.fn() as unknown) as PropsFromRedux['clearEventsLoading']} - setEventsDeleted={(jest.fn() as unknown) as PropsFromRedux['setEventsDeleted']} - clearEventsDeleted={(jest.fn() as unknown) as PropsFromRedux['clearEventsDeleted']} - createTimeline={(jest.fn() as unknown) as PropsFromRedux['createTimeline']} - updateTimelineIsLoading={ - (jest.fn() as unknown) as PropsFromRedux['updateTimelineIsLoading'] - } + clearSelected={jest.fn()} + setEventsLoading={jest.fn()} + clearEventsLoading={jest.fn()} + setEventsDeleted={jest.fn()} + clearEventsDeleted={jest.fn()} + updateTimelineIsLoading={jest.fn()} + updateTimeline={jest.fn()} /> ); diff --git a/x-pack/plugins/siem/public/pages/detection_engine/components/signals/index.tsx b/x-pack/plugins/siem/public/pages/detection_engine/components/signals/index.tsx index f1c7b50e49723..5442c8c19b5a7 100644 --- a/x-pack/plugins/siem/public/pages/detection_engine/components/signals/index.tsx +++ b/x-pack/plugins/siem/public/pages/detection_engine/components/signals/index.tsx @@ -8,6 +8,7 @@ import { EuiPanel, EuiLoadingContent } from '@elastic/eui'; import { isEmpty } from 'lodash/fp'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { connect, ConnectedProps } from 'react-redux'; +import { Dispatch } from 'redux'; import { Filter, esQuery } from '../../../../../../../../src/plugins/data/public'; import { useFetchIndexPatterns } from '../../../../containers/detection_engine/rules/fetch_index_patterns'; @@ -44,6 +45,7 @@ import { UpdateSignalsStatusCallback, UpdateSignalsStatusProps, } from './types'; +import { dispatchUpdateTimeline } from '../../../../components/open_timeline/helpers'; export const SIGNALS_PAGE_TIMELINE_ID = 'signals-page'; @@ -64,7 +66,6 @@ export const SignalsTableComponent: React.FC = ({ clearEventsDeleted, clearEventsLoading, clearSelected, - createTimeline, defaultFilters, from, globalFilters, @@ -78,6 +79,7 @@ export const SignalsTableComponent: React.FC = ({ setEventsLoading, signalsIndex, to, + updateTimeline, updateTimelineIsLoading, }) => { const [selectAll, setSelectAll] = useState(false); @@ -112,13 +114,22 @@ export const SignalsTableComponent: React.FC = ({ // Callback for creating a new timeline -- utilized by row/batch actions const createTimelineCallback = useCallback( - ({ timeline }: CreateTimelineProps) => - createTimeline({ + ({ from: fromTimeline, timeline, to: toTimeline, ruleNote }: CreateTimelineProps) => { + updateTimelineIsLoading({ id: 'timeline-1', isLoading: false }); + updateTimeline({ + duplicate: true, + from: fromTimeline, id: 'timeline-1', - ...timeline, - show: true, - }), - [createTimeline] + notes: [], + timeline: { + ...timeline, + show: true, + }, + to: toTimeline, + ruleNote, + })(); + }, + [updateTimeline, updateTimelineIsLoading] ); const setEventsLoadingCallback = useCallback( @@ -322,18 +333,37 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -const mapDispatchToProps = { - clearSelected: timelineActions.clearSelected, - setEventsLoading: timelineActions.setEventsLoading, - clearEventsLoading: timelineActions.clearEventsLoading, - setEventsDeleted: timelineActions.setEventsDeleted, - clearEventsDeleted: timelineActions.clearEventsDeleted, - updateTimelineIsLoading: timelineActions.updateIsLoading, - createTimeline: timelineActions.createTimeline, -}; +const mapDispatchToProps = (dispatch: Dispatch) => ({ + clearSelected: ({ id }: { id: string }) => dispatch(timelineActions.clearSelected({ id })), + setEventsLoading: ({ + id, + eventIds, + isLoading, + }: { + id: string; + eventIds: string[]; + isLoading: boolean; + }) => dispatch(timelineActions.setEventsLoading({ id, eventIds, isLoading })), + clearEventsLoading: ({ id }: { id: string }) => + dispatch(timelineActions.clearEventsLoading({ id })), + setEventsDeleted: ({ + id, + eventIds, + isDeleted, + }: { + id: string; + eventIds: string[]; + isDeleted: boolean; + }) => dispatch(timelineActions.setEventsDeleted({ id, eventIds, isDeleted })), + clearEventsDeleted: ({ id }: { id: string }) => + dispatch(timelineActions.clearEventsDeleted({ id })), + updateTimelineIsLoading: ({ id, isLoading }: { id: string; isLoading: boolean }) => + dispatch(timelineActions.updateIsLoading({ id, isLoading })), + updateTimeline: dispatchUpdateTimeline(dispatch), +}); const connector = connect(makeMapStateToProps, mapDispatchToProps); -export type PropsFromRedux = ConnectedProps; +type PropsFromRedux = ConnectedProps; export const SignalsTable = connector(React.memo(SignalsTableComponent)); diff --git a/x-pack/plugins/siem/public/pages/timelines/index.tsx b/x-pack/plugins/siem/public/pages/timelines/index.tsx index 992174f337f1e..343be5cbe3839 100644 --- a/x-pack/plugins/siem/public/pages/timelines/index.tsx +++ b/x-pack/plugins/siem/public/pages/timelines/index.tsx @@ -23,7 +23,7 @@ import { appendSearch } from '../../components/link_to/helpers'; const timelinesPagePath = `/:pageName(${SiemPageName.timelines})/:tabName(${TimelineType.default}|${TimelineType.template})`; const timelinesDefaultPath = `/${SiemPageName.timelines}/${TimelineType.default}`; -const TabNameMappedToI18nKey: Record = { +const TabNameMappedToI18nKey: Record = { [TimelineType.default]: TAB_TIMELINES, [TimelineType.template]: TAB_TEMPLATES, }; diff --git a/x-pack/plugins/siem/public/store/epic.ts b/x-pack/plugins/siem/public/store/epic.ts index d7c15ac88e2a9..336960588f48c 100644 --- a/x-pack/plugins/siem/public/store/epic.ts +++ b/x-pack/plugins/siem/public/store/epic.ts @@ -9,13 +9,11 @@ import { createTimelineEpic } from './timeline/epic'; import { createTimelineFavoriteEpic } from './timeline/epic_favorite'; import { createTimelineNoteEpic } from './timeline/epic_note'; import { createTimelinePinnedEventEpic } from './timeline/epic_pinned_event'; -import { createDraftTimelineEpic } from './timeline/epic_draft_timeline'; export const createRootEpic = () => combineEpics( createTimelineEpic(), createTimelineFavoriteEpic(), createTimelineNoteEpic(), - createTimelinePinnedEventEpic(), - createDraftTimelineEpic() + createTimelinePinnedEventEpic() ); diff --git a/x-pack/plugins/siem/public/store/timeline/actions.ts b/x-pack/plugins/siem/public/store/timeline/actions.ts index 205c96e57f883..12155decf40d4 100644 --- a/x-pack/plugins/siem/public/store/timeline/actions.ts +++ b/x-pack/plugins/siem/public/store/timeline/actions.ts @@ -69,10 +69,6 @@ export const createTimeline = actionCreator<{ showRowRenderers?: boolean; }>('CREATE_TIMELINE'); -export const getDraftTimeline = actionCreator<{ id: string }>('GET_DRAFT_TIMELINE'); - -export const cleanDraftTimeline = actionCreator<{ id: string }>('CLEAN_DRAFT_TIMELINE'); - export const pinEvent = actionCreator<{ id: string; eventId: string }>('PIN_EVENT'); export const removeColumn = actionCreator<{ diff --git a/x-pack/plugins/siem/public/store/timeline/defaults.ts b/x-pack/plugins/siem/public/store/timeline/defaults.ts index f40b0078c499f..9203720e2e28c 100644 --- a/x-pack/plugins/siem/public/store/timeline/defaults.ts +++ b/x-pack/plugins/siem/public/store/timeline/defaults.ts @@ -35,7 +35,7 @@ export const timelineDefaults: SubsetTimelineModel & Pick { timelineByIdSelector: (state: State) => TimelineById; @@ -150,13 +148,8 @@ export const createTimelineEpic = (): Epic< return true; } if (action.type === createTimeline.type && isItAtimelineAction(timelineId)) { - if (timelineObj.timelineType !== 'draft') { - myEpicTimelineId.setTimelineVersion(null); - myEpicTimelineId.setTimelineId(null); - } - return true; - } else if (action.type === getDraftTimeline.type && isItAtimelineAction(timelineId)) { - return true; + myEpicTimelineId.setTimelineId(null); + myEpicTimelineId.setTimelineVersion(null); } else if (action.type === addTimeline.type && isItAtimelineAction(timelineId)) { const addNewTimeline: TimelineModel = get('payload.timeline', action); myEpicTimelineId.setTimelineId(addNewTimeline.savedObjectId); @@ -214,10 +207,6 @@ export const createTimelineEpic = (): Epic< timeline$, allTimelineQuery$ ); - } else if (action.type === getDraftTimeline.type) { - return epicDraftTimeline(action, action$, timeline$, false); - } else if (action.type === createTimeline.type) { - return epicDraftTimeline(action, action$, timeline$, true); } else if (timelineActionsType.includes(action.type)) { return from( persistTimeline({ diff --git a/x-pack/plugins/siem/public/store/timeline/epic_draft_timeline.ts b/x-pack/plugins/siem/public/store/timeline/epic_draft_timeline.ts deleted file mode 100644 index 9e8d861ea7584..0000000000000 --- a/x-pack/plugins/siem/public/store/timeline/epic_draft_timeline.ts +++ /dev/null @@ -1,110 +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 { of, Observable, from } from 'rxjs'; -import { get } from 'lodash/fp'; -import { filter, withLatestFrom, mergeMap, takeUntil, startWith } from 'rxjs/operators'; -import { Epic } from 'redux-observable'; -import { Action } from 'redux'; -import { - addTimeline, - createTimeline, - showCallOutUnauthorizedMsg, - endTimelineSaving, -} from './actions'; -import { getDraftTimeline, cleanDraftTimeline } from '../../containers/timeline/api'; -import { ActionTimeline, TimelineById } from './types'; -import { myEpicTimelineId } from './my_epic_timeline_id'; -import { addError } from '../app/actions'; -import { - formatTimelineResultToModel, - epicUpdateTimeline, -} from '../../components/open_timeline/helpers'; -import { getTimeRangeSettings } from '../../utils/default_date_settings'; -import { ResponseTimeline } from '../../graphql/types'; -import { timelineDefaults } from './defaults'; - -export const epicDraftTimeline = ( - action: ActionTimeline, - action$: Observable, - timeline$: Observable, - clean: boolean -) => - from(clean ? cleanDraftTimeline() : getDraftTimeline()).pipe( - withLatestFrom(timeline$), - mergeMap(([result, recentTimelines]) => { - const savedTimeline = recentTimelines[action.payload.id]; - const response: ResponseTimeline = get('data.persistTimeline', result); - const callOutMsg = response.code === 403 ? [showCallOutUnauthorizedMsg()] : []; - - const { timeline: timelineModel, notes } = formatTimelineResultToModel( - { - savedObjectId: response.timeline.savedObjectId, - version: response.timeline.version, - timelineType: response.timeline.timelineType, - }, - false - ); - const { from: settingsFrom, to: settingsTo } = getTimeRangeSettings(); - - return [ - ...callOutMsg, - ...epicUpdateTimeline({ - duplicate: false, - from: savedTimeline?.dateRange.start ?? settingsFrom, - id: 'timeline-1', - notes, - timeline: { - ...savedTimeline, - ...timelineModel, - ...action.payload, - id: timelineModel.savedObjectId!, - savedObjectId: timelineModel.savedObjectId!, - version: timelineModel.version, - // @ts-ignore - show: action.payload.show ?? savedTimeline.show, - }, - to: savedTimeline?.dateRange.end ?? settingsTo, - }), - endTimelineSaving({ - id: action.payload.id, - }), - ]; - }), - takeUntil( - action$.pipe( - withLatestFrom(timeline$), - filter(([checkAction, updatedTimeline]) => { - if (checkAction.type === addError.type) { - return true; - } - if (checkAction.type === addTimeline.type) { - return true; - } - if ( - checkAction.type === endTimelineSaving.type && - updatedTimeline[get('payload.id', checkAction)].savedObjectId != null - ) { - myEpicTimelineId.setTimelineId( - updatedTimeline[get('payload.id', checkAction)].savedObjectId - ); - myEpicTimelineId.setTimelineVersion( - updatedTimeline[get('payload.id', checkAction)].version - ); - return true; - } - return false; - }) - ) - ) - ); - -export const createDraftTimelineEpic = (): Epic => () => - of(createTimeline({ id: 'timeline-1', columns: timelineDefaults.columns })).pipe( - startWith( - addTimeline({ id: 'timeline-1', timeline: { id: 'timeline-1', ...timelineDefaults } }) - ) - ); diff --git a/x-pack/plugins/siem/public/store/timeline/helpers.ts b/x-pack/plugins/siem/public/store/timeline/helpers.ts index 7b8d49119f323..adab029c11150 100644 --- a/x-pack/plugins/siem/public/store/timeline/helpers.ts +++ b/x-pack/plugins/siem/public/store/timeline/helpers.ts @@ -125,7 +125,7 @@ export const addTimelineToStore = ({ ...timelineById, [id]: { ...timeline, - isLoading: timelineById[id]?.isLoading ?? timeline.isSaving, + isLoading: timelineById[id].isLoading, }, }); @@ -147,10 +147,11 @@ interface AddNewTimelineParams { sort?: Sort; showCheckboxes?: boolean; showRowRenderers?: boolean; + timelineById: TimelineById; } /** Adds a new `Timeline` to the provided collection of `TimelineById` */ -export const getNewTimeline = ({ +export const addNewTimeline = ({ columns, dataProviders = [], dateRange = { start: 0, end: 0 }, @@ -162,19 +163,27 @@ export const getNewTimeline = ({ show = false, showCheckboxes = false, showRowRenderers = true, -}: AddNewTimelineParams): TimelineModel => ({ - id, - ...timelineDefaults, - columns, - dataProviders, - dateRange, - filters, - itemsPerPage, - kqlQuery, - sort, - show, - showCheckboxes, - showRowRenderers, + timelineById, +}: AddNewTimelineParams): TimelineById => ({ + ...timelineById, + [id]: { + id, + ...timelineDefaults, + columns, + dataProviders, + dateRange, + filters, + itemsPerPage, + kqlQuery, + sort, + show, + savedObjectId: null, + version: null, + isSaving: false, + isLoading: false, + showCheckboxes, + showRowRenderers, + }, }); interface PinTimelineEventParams { diff --git a/x-pack/plugins/siem/public/store/timeline/model.ts b/x-pack/plugins/siem/public/store/timeline/model.ts index b01c7cef1c6d2..54e19812634ac 100644 --- a/x-pack/plugins/siem/public/store/timeline/model.ts +++ b/x-pack/plugins/siem/public/store/timeline/model.ts @@ -152,7 +152,6 @@ export type SubsetTimelineModel = Readonly< | 'isLoading' | 'savedObjectId' | 'version' - | 'timelineType' > >; diff --git a/x-pack/plugins/siem/public/store/timeline/reducer.test.ts b/x-pack/plugins/siem/public/store/timeline/reducer.test.ts index a2a74b2422370..42c6d6ecb0e51 100644 --- a/x-pack/plugins/siem/public/store/timeline/reducer.test.ts +++ b/x-pack/plugins/siem/public/store/timeline/reducer.test.ts @@ -23,10 +23,10 @@ import { Direction } from '../../graphql/types'; import { defaultHeaders } from '../../mock'; import { + addNewTimeline, addTimelineProvider, addTimelineToStore, applyDeltaToTimelineColumnWidth, - getNewTimeline, removeTimelineColumn, removeTimelineProvider, updateTimelineColumns, @@ -132,32 +132,41 @@ describe('Timeline', () => { }); }); - describe('#getNewTimeline', () => { + describe('#addNewTimeline', () => { test('should return a new reference and not the same reference', () => { - const update = getNewTimeline({ + const update = addNewTimeline({ id: 'bar', columns: defaultHeaders, + timelineById: timelineByIdMock, }); - expect(update).not.toBe(timelineByIdMock.foo); + expect(update).not.toBe(timelineByIdMock); }); - test('should return a new timeline', () => { - const update = getNewTimeline({ + test('should add a new timeline', () => { + const update = addNewTimeline({ id: 'bar', columns: timelineDefaults.columns, + timelineById: timelineByIdMock, + }); + expect(update).toEqual({ + foo: timelineByIdMock.foo, + bar: set('id', 'bar', timelineDefaults), }); - expect(update).toEqual(set('id', 'bar', timelineDefaults)); }); test('should add the specified columns to the timeline', () => { const barWithEmptyColumns = set('id', 'bar', timelineDefaults); const barWithPopulatedColumns = set('columns', defaultHeaders, barWithEmptyColumns); - const update = getNewTimeline({ + const update = addNewTimeline({ id: 'bar', columns: defaultHeaders, + timelineById: timelineByIdMock, + }); + expect(update).toEqual({ + foo: timelineByIdMock.foo, + bar: barWithPopulatedColumns, }); - expect(update).toEqual(barWithPopulatedColumns); }); }); diff --git a/x-pack/plugins/siem/public/store/timeline/reducer.ts b/x-pack/plugins/siem/public/store/timeline/reducer.ts index b6b3a6deb1e5b..e99644daf50d8 100644 --- a/x-pack/plugins/siem/public/store/timeline/reducer.ts +++ b/x-pack/plugins/siem/public/store/timeline/reducer.ts @@ -14,6 +14,7 @@ import { applyDeltaToColumnWidth, applyDeltaToWidth, applyKqlFilterQuery, + createTimeline, dataProviderEdited, endTimelineSaving, pinEvent, @@ -55,6 +56,7 @@ import { updateEventType, } from './actions'; import { + addNewTimeline, addTimelineHistory, addTimelineNote, addTimelineNoteToEvent, @@ -112,6 +114,41 @@ export const timelineReducer = reducerWithInitialState(initialTimelineState) ...state, timelineById: addTimelineToStore({ id, timeline, timelineById: state.timelineById }), })) + .case( + createTimeline, + ( + state, + { + id, + dataProviders, + dateRange, + show, + columns, + itemsPerPage, + kqlQuery, + sort, + showCheckboxes, + showRowRenderers, + filters, + } + ) => ({ + ...state, + timelineById: addNewTimeline({ + columns, + dataProviders, + dateRange, + filters, + id, + itemsPerPage, + kqlQuery, + sort, + show, + showCheckboxes, + showRowRenderers, + timelineById: state.timelineById, + }), + }) + ) .case(upsertColumn, (state, { column, id, index }) => ({ ...state, timelineById: upsertTimelineColumn({ column, id, index, timelineById: state.timelineById }), diff --git a/x-pack/plugins/siem/server/graphql/timeline/schema.gql.ts b/x-pack/plugins/siem/server/graphql/timeline/schema.gql.ts index 2432af9a379a1..a1c13fd21a88e 100644 --- a/x-pack/plugins/siem/server/graphql/timeline/schema.gql.ts +++ b/x-pack/plugins/siem/server/graphql/timeline/schema.gql.ts @@ -127,7 +127,6 @@ export const timelineSchema = gql` enum TimelineType { default - draft template } diff --git a/x-pack/plugins/siem/server/graphql/types.ts b/x-pack/plugins/siem/server/graphql/types.ts index 5313f4b9df268..d74086357edbe 100644 --- a/x-pack/plugins/siem/server/graphql/types.ts +++ b/x-pack/plugins/siem/server/graphql/types.ts @@ -344,7 +344,6 @@ export enum TlsFields { export enum TimelineType { default = 'default', - draft = 'draft', template = 'template', } diff --git a/x-pack/plugins/siem/server/lib/timeline/default_timeline.ts b/x-pack/plugins/siem/server/lib/timeline/default_timeline.ts deleted file mode 100644 index 710a43df1221d..0000000000000 --- a/x-pack/plugins/siem/server/lib/timeline/default_timeline.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { Direction } from '../../graphql/types'; -import { defaultHeaders } from './default_timeline_headers'; -import { SavedTimeline, TimelineType } from '../../../common/types/timeline'; - -export const draftTimelineDefaults: SavedTimeline = { - columns: defaultHeaders, - dataProviders: [], - description: '', - eventType: 'all', - filters: [], - kqlMode: 'filter', - timelineType: TimelineType.draft, - kqlQuery: { - filterQuery: null, - }, - title: '', - sort: { - columnId: '@timestamp', - sortDirection: Direction.desc, - }, -}; diff --git a/x-pack/plugins/siem/server/lib/timeline/default_timeline_headers.ts b/x-pack/plugins/siem/server/lib/timeline/default_timeline_headers.ts deleted file mode 100644 index 77b64bf2754c0..0000000000000 --- a/x-pack/plugins/siem/server/lib/timeline/default_timeline_headers.ts +++ /dev/null @@ -1,44 +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 { SavedTimeline } from '../../../common/types/timeline'; - -export const defaultColumnHeaderType = 'not-filtered'; - -export const defaultHeaders: SavedTimeline['columns'] = [ - { - columnHeaderType: defaultColumnHeaderType, - id: '@timestamp', - }, - { - columnHeaderType: defaultColumnHeaderType, - id: 'message', - }, - { - columnHeaderType: defaultColumnHeaderType, - id: 'event.category', - }, - { - columnHeaderType: defaultColumnHeaderType, - id: 'event.action', - }, - { - columnHeaderType: defaultColumnHeaderType, - id: 'host.name', - }, - { - columnHeaderType: defaultColumnHeaderType, - id: 'source.ip', - }, - { - columnHeaderType: defaultColumnHeaderType, - id: 'destination.ip', - }, - { - columnHeaderType: defaultColumnHeaderType, - id: 'user.name', - }, -]; diff --git a/x-pack/plugins/siem/server/lib/timeline/pick_saved_timeline.ts b/x-pack/plugins/siem/server/lib/timeline/pick_saved_timeline.ts index 3b06adf1b751e..6de10bffb1325 100644 --- a/x-pack/plugins/siem/server/lib/timeline/pick_saved_timeline.ts +++ b/x-pack/plugins/siem/server/lib/timeline/pick_saved_timeline.ts @@ -5,7 +5,6 @@ */ import uuid from 'uuid'; -import { isEmpty } from 'lodash/fp'; import { AuthenticatedUser } from '../../../../security/common/model'; import { UNAUTHENTICATED_USER } from '../../../common/constants'; import { SavedTimeline, TimelineType } from '../../../common/types/timeline'; @@ -39,14 +38,8 @@ export const pickSavedTimeline = ( savedTimeline.templateTimelineVersion = savedTimeline.templateTimelineVersion + 1; } } - } else if (savedTimeline.timelineType === TimelineType.draft) { - savedTimeline.timelineType = !isEmpty(savedTimeline.title) - ? TimelineType.default - : TimelineType.draft; - savedTimeline.templateTimelineId = null; - savedTimeline.templateTimelineVersion = null; } else { - savedTimeline.timelineType = savedTimeline.timelineType ?? TimelineType.default; + savedTimeline.timelineType = TimelineType.default; savedTimeline.templateTimelineId = null; savedTimeline.templateTimelineVersion = null; } diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/__mocks__/import_timelines.ts b/x-pack/plugins/siem/server/lib/timeline/routes/__mocks__/import_timelines.ts index e06e6c60ac65f..a832c818d48b0 100644 --- a/x-pack/plugins/siem/server/lib/timeline/routes/__mocks__/import_timelines.ts +++ b/x-pack/plugins/siem/server/lib/timeline/routes/__mocks__/import_timelines.ts @@ -156,29 +156,6 @@ export const mockGetTemplateTimelineValue = { templateTimelineVersion: 1, }; -export const mockGetDraftTimelineValue = { - savedObjectId: '79deb4c0-6bc1-11ea-a90b-f5341fb7a189', - version: 'WzEyMjUsMV0=', - columns: [], - dataProviders: [], - description: 'description', - eventType: 'all', - filters: [], - kqlMode: 'filter', - kqlQuery: { filterQuery: [] }, - title: 'My duplicate timeline', - dateRange: { start: 1584523907294, end: 1584610307294 }, - savedQueryId: null, - sort: { columnId: '@timestamp', sortDirection: 'desc' }, - created: 1584828930463, - createdBy: 'angela', - updated: 1584868346013, - updatedBy: 'angela', - noteIds: [], - pinnedEventIds: ['k-gi8nABm-sIqJ_scOoS'], - timelineType: TimelineType.draft, -}; - export const mockParsedTimelineObject = omit( [ 'globalNotes', diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/__mocks__/request_responses.ts b/x-pack/plugins/siem/server/lib/timeline/routes/__mocks__/request_responses.ts index 6f03f5888f3b4..2827c7a1c0ac6 100644 --- a/x-pack/plugins/siem/server/lib/timeline/routes/__mocks__/request_responses.ts +++ b/x-pack/plugins/siem/server/lib/timeline/routes/__mocks__/request_responses.ts @@ -5,8 +5,6 @@ */ import * as rt from 'io-ts'; import { - TIMELINE_DRAFT_URL, - TIMELINE_DRAFT_CLEAN_URL, TIMELINE_EXPORT_URL, TIMELINE_IMPORT_URL, TIMELINE_URL, @@ -82,14 +80,6 @@ export const createTimelineWithoutTimelineId = { timelineType: TimelineType.default, }; -export const createDraftTimelineWithoutTimelineId = { - templateTimelineId: null, - timeline: inputTimeline, - timelineId: null, - version: null, - timelineType: TimelineType.draft, -}; - export const createTemplateTimelineWithoutTimelineId = { templateTimelineId: null, timeline: inputTemplateTimeline, @@ -103,11 +93,6 @@ export const createTimelineWithTimelineId = { timelineId: '79deb4c0-6bc1-11ea-a90b-f5341fb7a189', }; -export const createDraftTimelineWithTimelineId = { - ...createDraftTimelineWithoutTimelineId, - timelineId: '79deb4c0-6bc1-11ea-a90b-f5341fb7a189', -}; - export const createTemplateTimelineWithTimelineId = { ...createTemplateTimelineWithoutTimelineId, timelineId: '79deb4c0-6bc1-11ea-a90b-f5341fb7a189', @@ -154,18 +139,6 @@ export const getImportTimelinesRequestEnableOverwrite = (filename?: string) => }, }); -export const getDraftTimelinesRequest = () => - requestMock.create({ - method: 'get', - path: TIMELINE_DRAFT_URL, - }); - -export const cleanDraftTimelinesRequest = () => - requestMock.create({ - method: 'post', - path: TIMELINE_DRAFT_CLEAN_URL, - }); - export const mockTimelinesSavedObjects = () => ({ saved_objects: [ { diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/draft_clean_timelines_route.test.ts b/x-pack/plugins/siem/server/lib/timeline/routes/draft_clean_timelines_route.test.ts deleted file mode 100644 index 2902b0d119b7f..0000000000000 --- a/x-pack/plugins/siem/server/lib/timeline/routes/draft_clean_timelines_route.test.ts +++ /dev/null @@ -1,114 +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 { SecurityPluginSetup } from '../../../../../../plugins/security/server'; - -import { - serverMock, - requestContextMock, - createMockConfig, -} from '../../detection_engine/routes/__mocks__'; - -import { mockGetCurrentUser, mockGetDraftTimelineValue } from './__mocks__/import_timelines'; -import { - cleanDraftTimelinesRequest, - createTimelineWithTimelineId, -} from './__mocks__/request_responses'; - -describe('draft clean timelines', () => { - let server: ReturnType; - let securitySetup: SecurityPluginSetup; - let { context } = requestContextMock.createTools(); - let mockGetTimeline: jest.Mock; - let mockGetDraftTimeline: jest.Mock; - let mockPersistTimeline: jest.Mock; - let mockPersistPinnedEventOnTimeline: jest.Mock; - let mockPersistNote: jest.Mock; - let mockResetTimeline: jest.Mock; - - beforeEach(() => { - jest.resetModules(); - jest.resetAllMocks(); - jest.restoreAllMocks(); - jest.clearAllMocks(); - - server = serverMock.create(); - context = requestContextMock.createTools().context; - - securitySetup = ({ - authc: { - getCurrentUser: jest.fn().mockReturnValue(mockGetCurrentUser), - }, - authz: {}, - } as unknown) as SecurityPluginSetup; - - mockGetTimeline = jest.fn(); - mockGetDraftTimeline = jest.fn(); - mockPersistTimeline = jest.fn(); - mockPersistPinnedEventOnTimeline = jest.fn(); - mockPersistNote = jest.fn(); - mockResetTimeline = jest.fn(); - - jest.doMock('../saved_object', () => ({ - getTimeline: mockGetTimeline, - getDraftTimeline: mockGetDraftTimeline, - resetTimeline: mockResetTimeline, - persistTimeline: mockPersistTimeline.mockReturnValue({ - code: 200, - timeline: createTimelineWithTimelineId, - }), - })); - - jest.doMock('../../pinned_event/saved_object', () => ({ - persistPinnedEventOnTimeline: mockPersistPinnedEventOnTimeline, - })); - - jest.doMock('../../note/saved_object', () => ({ - persistNote: mockPersistNote, - })); - - const draftCleanTimelinesRoute = jest.requireActual('./draft_clean_timelines_route') - .draftCleanTimelinesRoute; - draftCleanTimelinesRoute(server.router, createMockConfig(), securitySetup); - }); - - test('should create new draft if none is available', async () => { - mockGetDraftTimeline.mockResolvedValue({ - timeline: [], - }); - - const response = await server.inject(cleanDraftTimelinesRequest(), context); - expect(mockPersistTimeline).toHaveBeenCalled(); - expect(response.status).toEqual(200); - expect(response.body).toEqual({ - data: { - persistTimeline: { - timeline: createTimelineWithTimelineId, - }, - }, - }); - }); - - test('should return clean existing draft if draft available ', async () => { - mockGetDraftTimeline.mockResolvedValue({ - timeline: [mockGetDraftTimelineValue], - }); - mockResetTimeline.mockResolvedValue({}); - mockGetTimeline.mockResolvedValue({ ...mockGetDraftTimelineValue }); - - const response = await server.inject(cleanDraftTimelinesRequest(), context); - expect(mockPersistTimeline).not.toHaveBeenCalled(); - expect(mockResetTimeline).toHaveBeenCalled(); - expect(mockGetTimeline).toHaveBeenCalled(); - expect(response.status).toEqual(200); - expect(response.body).toEqual({ - data: { - persistTimeline: { - timeline: mockGetDraftTimelineValue, - }, - }, - }); - }); -}); diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/draft_clean_timelines_route.ts b/x-pack/plugins/siem/server/lib/timeline/routes/draft_clean_timelines_route.ts deleted file mode 100644 index eb876adab34d0..0000000000000 --- a/x-pack/plugins/siem/server/lib/timeline/routes/draft_clean_timelines_route.ts +++ /dev/null @@ -1,86 +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 { IRouter } from '../../../../../../../src/core/server'; -import { ConfigType } from '../../..'; -import { transformError, buildSiemResponse } from '../../detection_engine/routes/utils'; -import { TIMELINE_DRAFT_CLEAN_URL } from '../../../../common/constants'; -import { buildFrameworkRequest } from './utils/common'; -import { SetupPlugins } from '../../../plugin'; -import { getDraftTimeline, resetTimeline, getTimeline, persistTimeline } from '../saved_object'; -import { draftTimelineDefaults } from '../default_timeline'; - -export const draftCleanTimelinesRoute = ( - router: IRouter, - config: ConfigType, - security: SetupPlugins['security'] -) => { - router.post( - { - path: TIMELINE_DRAFT_CLEAN_URL, - validate: {}, - options: { - tags: ['access:siem'], - }, - }, - async (context, request, response) => { - const frameworkRequest = await buildFrameworkRequest(context, security, request); - const siemResponse = buildSiemResponse(response); - - try { - const { - timeline: [draftTimeline], - } = await getDraftTimeline(frameworkRequest); - - if (draftTimeline?.savedObjectId) { - await resetTimeline(frameworkRequest, [draftTimeline.savedObjectId]); - const cleanedDraftTimeline = await getTimeline( - frameworkRequest, - draftTimeline.savedObjectId - ); - - return response.ok({ - body: { - data: { - persistTimeline: { - timeline: cleanedDraftTimeline, - }, - }, - }, - }); - } - - const newTimelineResponse = await persistTimeline( - frameworkRequest, - null, - null, - draftTimelineDefaults - ); - - if (newTimelineResponse.code === 200) { - return response.ok({ - body: { - data: { - persistTimeline: { - timeline: newTimelineResponse.timeline, - }, - }, - }, - }); - } - - return response.ok({}); - } catch (err) { - const error = transformError(err); - - return siemResponse.error({ - body: error.message, - statusCode: error.statusCode, - }); - } - } - ); -}; diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/draft_timelines_route.test.ts b/x-pack/plugins/siem/server/lib/timeline/routes/draft_timelines_route.test.ts deleted file mode 100644 index 1bea832790d8c..0000000000000 --- a/x-pack/plugins/siem/server/lib/timeline/routes/draft_timelines_route.test.ts +++ /dev/null @@ -1,113 +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 { SecurityPluginSetup } from '../../../../../../plugins/security/server'; - -import { - serverMock, - requestContextMock, - createMockConfig, -} from '../../detection_engine/routes/__mocks__'; - -import { mockGetCurrentUser, mockGetDraftTimelineValue } from './__mocks__/import_timelines'; -import { - getDraftTimelinesRequest, - createTimelineWithTimelineId, -} from './__mocks__/request_responses'; - -describe('draft timelines', () => { - let server: ReturnType; - let securitySetup: SecurityPluginSetup; - let { context } = requestContextMock.createTools(); - let mockGetTimeline: jest.Mock; - let mockGetDraftTimeline: jest.Mock; - let mockPersistTimeline: jest.Mock; - let mockPersistPinnedEventOnTimeline: jest.Mock; - let mockPersistNote: jest.Mock; - - beforeEach(() => { - jest.resetModules(); - jest.resetAllMocks(); - jest.restoreAllMocks(); - jest.clearAllMocks(); - - server = serverMock.create(); - context = requestContextMock.createTools().context; - - securitySetup = ({ - authc: { - getCurrentUser: jest.fn().mockReturnValue(mockGetCurrentUser), - }, - authz: {}, - } as unknown) as SecurityPluginSetup; - - mockGetTimeline = jest.fn(); - mockGetDraftTimeline = jest.fn(); - mockPersistTimeline = jest.fn(); - mockPersistPinnedEventOnTimeline = jest.fn(); - mockPersistNote = jest.fn(); - }); - - describe('Manipulate timeline', () => { - describe('Create a new timeline', () => { - beforeEach(async () => { - jest.doMock('../saved_object', () => ({ - getTimeline: mockGetTimeline, - getDraftTimeline: mockGetDraftTimeline, - persistTimeline: mockPersistTimeline.mockReturnValue({ - code: 200, - timeline: createTimelineWithTimelineId, - }), - })); - - jest.doMock('../../pinned_event/saved_object', () => ({ - persistPinnedEventOnTimeline: mockPersistPinnedEventOnTimeline, - })); - - jest.doMock('../../note/saved_object', () => ({ - persistNote: mockPersistNote, - })); - - const draftTimelinesRoute = jest.requireActual('./draft_timelines_route') - .draftTimelinesRoute; - draftTimelinesRoute(server.router, createMockConfig(), securitySetup); - }); - - test('should create new draft if none is available', async () => { - mockGetDraftTimeline.mockResolvedValue({ - timeline: [], - }); - - const response = await server.inject(getDraftTimelinesRequest(), context); - expect(mockPersistTimeline).toHaveBeenCalled(); - expect(response.status).toEqual(200); - expect(response.body).toEqual({ - data: { - persistTimeline: { - timeline: createTimelineWithTimelineId, - }, - }, - }); - }); - - test('should return an existing draft if available', async () => { - mockGetDraftTimeline.mockResolvedValue({ - timeline: [mockGetDraftTimelineValue], - }); - - const response = await server.inject(getDraftTimelinesRequest(), context); - expect(mockPersistTimeline).not.toHaveBeenCalled(); - expect(response.status).toEqual(200); - expect(response.body).toEqual({ - data: { - persistTimeline: { - timeline: mockGetDraftTimelineValue, - }, - }, - }); - }); - }); - }); -}); diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/draft_timelines_route.ts b/x-pack/plugins/siem/server/lib/timeline/routes/draft_timelines_route.ts deleted file mode 100644 index 14d7fb1801719..0000000000000 --- a/x-pack/plugins/siem/server/lib/timeline/routes/draft_timelines_route.ts +++ /dev/null @@ -1,80 +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 { IRouter } from '../../../../../../../src/core/server'; -import { ConfigType } from '../../..'; -import { transformError, buildSiemResponse } from '../../detection_engine/routes/utils'; -import { TIMELINE_DRAFT_URL } from '../../../../common/constants'; -import { buildFrameworkRequest } from './utils/common'; -import { SetupPlugins } from '../../../plugin'; -import { getDraftTimeline, persistTimeline } from '../saved_object'; -import { draftTimelineDefaults } from '../default_timeline'; - -export const draftTimelinesRoute = ( - router: IRouter, - config: ConfigType, - security: SetupPlugins['security'] -) => { - router.get( - { - path: TIMELINE_DRAFT_URL, - validate: {}, - options: { - tags: ['access:siem'], - }, - }, - async (context, request, response) => { - const frameworkRequest = await buildFrameworkRequest(context, security, request); - const siemResponse = buildSiemResponse(response); - - try { - const { - timeline: [draftTimeline], - } = await getDraftTimeline(frameworkRequest); - - if (draftTimeline?.savedObjectId) { - return response.ok({ - body: { - data: { - persistTimeline: { - timeline: draftTimeline, - }, - }, - }, - }); - } - - const newTimelineResponse = await persistTimeline( - frameworkRequest, - null, - null, - draftTimelineDefaults - ); - - if (newTimelineResponse.code === 200) { - return response.ok({ - body: { - data: { - persistTimeline: { - timeline: newTimelineResponse.timeline, - }, - }, - }, - }); - } - - return response.ok({}); - } catch (err) { - const error = transformError(err); - - return siemResponse.error({ - body: error.message, - statusCode: error.statusCode, - }); - } - } - ); -}; diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/export_timelines_route.ts b/x-pack/plugins/siem/server/lib/timeline/routes/export_timelines_route.ts index e74069fb748a5..e0eefbf811a56 100644 --- a/x-pack/plugins/siem/server/lib/timeline/routes/export_timelines_route.ts +++ b/x-pack/plugins/siem/server/lib/timeline/routes/export_timelines_route.ts @@ -4,6 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ +import { set as _set } from 'lodash/fp'; + import { TIMELINE_EXPORT_URL } from '../../../../common/constants'; import { IRouter } from '../../../../../../../src/core/server'; import { ConfigType } from '../../../config'; diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.test.ts b/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.test.ts index 2f5200c87137d..11f93a9c48bf6 100644 --- a/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.test.ts +++ b/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.test.ts @@ -12,7 +12,6 @@ import { createMockConfig, } from '../../detection_engine/routes/__mocks__'; import { TIMELINE_EXPORT_URL } from '../../../../common/constants'; -import { TimelineType } from '../../../../common/types/timeline'; import { SecurityPluginSetup } from '../../../../../../plugins/security/server'; import { @@ -34,7 +33,6 @@ describe('import timelines', () => { let mockPersistTimeline: jest.Mock; let mockPersistPinnedEventOnTimeline: jest.Mock; let mockPersistNote: jest.Mock; - let mockGetTupleDuplicateErrorsAndUniqueTimeline: jest.Mock; const newTimelineSavedObjectId = '79deb4c0-6bc1-11ea-9999-f5341fb7a189'; const newTimelineVersion = '9999'; beforeEach(() => { @@ -58,7 +56,6 @@ describe('import timelines', () => { mockPersistTimeline = jest.fn(); mockPersistPinnedEventOnTimeline = jest.fn(); mockPersistNote = jest.fn(); - mockGetTupleDuplicateErrorsAndUniqueTimeline = jest.fn(); jest.doMock('../create_timelines_stream_from_ndjson', () => { return { @@ -76,9 +73,9 @@ describe('import timelines', () => { const originalModule = jest.requireActual('./utils/import_timelines'); return { ...originalModule, - getTupleDuplicateErrorsAndUniqueTimeline: mockGetTupleDuplicateErrorsAndUniqueTimeline.mockReturnValue( - [mockDuplicateIdErrors, mockUniqueParsedObjects] - ), + getTupleDuplicateErrorsAndUniqueTimeline: jest + .fn() + .mockReturnValue([mockDuplicateIdErrors, mockUniqueParsedObjects]), }; }); }); @@ -136,25 +133,12 @@ describe('import timelines', () => { expect(mockPersistTimeline.mock.calls[0][2]).toBeNull(); }); - test('should Create a new timeline savedObject with given timeline', async () => { + test('should Create a new timeline savedObject witn given timeline', async () => { const mockRequest = getImportTimelinesRequest(); await server.inject(mockRequest, context); expect(mockPersistTimeline.mock.calls[0][3]).toEqual(mockParsedTimelineObject); }); - test('should Create a new timeline savedObject with given draft timeline', async () => { - mockGetTupleDuplicateErrorsAndUniqueTimeline.mockReturnValue([ - mockDuplicateIdErrors, - [{ ...mockUniqueParsedObjects[0], timelineType: TimelineType.draft }], - ]); - const mockRequest = getImportTimelinesRequest(); - await server.inject(mockRequest, context); - expect(mockPersistTimeline.mock.calls[0][3]).toEqual({ - ...mockParsedTimelineObject, - timelineType: TimelineType.default, - }); - }); - test('should Create new pinned events', async () => { const mockRequest = getImportTimelinesRequest(); await server.inject(mockRequest, context); diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.ts b/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.ts index bb63d1dce5554..4a79dada07171 100644 --- a/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.ts +++ b/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.ts @@ -152,13 +152,7 @@ export const importTimelinesRoute = ( // create timeline / template timeline newTimeline = await createTimelines( frameworkRequest, - { - ...parsedTimelineObject, - timelineType: - parsedTimelineObject.timelineType === TimelineType.draft - ? TimelineType.default - : parsedTimelineObject.timelineType, - }, + parsedTimelineObject, null, // timelineSavedObjectId null, // timelineVersion pinnedEventIds, diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/utils/export_timelines.ts b/x-pack/plugins/siem/server/lib/timeline/routes/utils/export_timelines.ts index 1e64e38ea5b0a..ea9a5fab66805 100644 --- a/x-pack/plugins/siem/server/lib/timeline/routes/utils/export_timelines.ts +++ b/x-pack/plugins/siem/server/lib/timeline/routes/utils/export_timelines.ts @@ -16,7 +16,6 @@ import { ExportedNotes, TimelineSavedObject, ExportTimelineNotFoundError, - TimelineType, } from '../../../../../common/types/timeline'; import { NoteSavedObject } from '../../../../../common/types/timeline/note'; import { PinnedEventSavedObject } from '../../../../../common/types/timeline/pinned_event'; @@ -180,10 +179,6 @@ const getTimelinesFromObjects = async ( ...acc, { ...myTimeline, - timelineType: - myTimeline.timelineType === TimelineType.draft - ? TimelineType.default - : myTimeline.timelineType, ...getGlobalEventNotesByTimelineId(timelineNotes), pinnedEventIds: getPinnedEventsIdsByTimelineId(timelinePinnedEventIds), }, diff --git a/x-pack/plugins/siem/server/lib/timeline/saved_object.ts b/x-pack/plugins/siem/server/lib/timeline/saved_object.ts index f95cd01b2b788..6d022ab42fa7b 100644 --- a/x-pack/plugins/siem/server/lib/timeline/saved_object.ts +++ b/x-pack/plugins/siem/server/lib/timeline/saved_object.ts @@ -25,7 +25,6 @@ import * as pinnedEvent from '../pinned_event/saved_object'; import { convertSavedObjectToSavedTimeline } from './convert_saved_object_to_savedtimeline'; import { pickSavedTimeline } from './pick_saved_timeline'; import { timelineSavedObjectType } from './saved_object_mappings'; -import { draftTimelineDefaults } from './default_timeline'; interface ResponseTimelines { timeline: TimelineSavedObject[]; @@ -104,7 +103,7 @@ const getTimelineTypeFilter = (timelineType: string | null) => { : /** Show me every timeline whose timelineType is not "template". * which includes timelineType === 'default' and * those timelineType doesn't exists */ - `not siem-ui-timeline.attributes.timelineType: ${TimelineType.template} and not siem-ui-timeline.attributes.timelineType: ${TimelineType.draft}`; + `not siem-ui-timeline.attributes.timelineType: ${TimelineType.template}`; }; export const getAllTimeline = async ( @@ -130,17 +129,6 @@ export const getAllTimeline = async ( return getAllSavedTimeline(request, options); }; -export const getDraftTimeline = async (request: FrameworkRequest): Promise => { - const options: SavedObjectsFindOptions = { - type: timelineSavedObjectType, - perPage: 1, - filter: `siem-ui-timeline.attributes.timelineType: ${TimelineType.draft}`, - sortField: 'created', - sortOrder: 'desc', - }; - return getAllSavedTimeline(request, options); -}; - export const persistFavorite = async ( request: FrameworkRequest, timelineId: string | null @@ -269,54 +257,6 @@ export const persistTimeline = async ( } }; -const updatePartialSavedTimeline = async ( - request: FrameworkRequest, - timelineId: string, - timeline: SavedTimeline -) => { - const savedObjectsClient = request.context.core.savedObjects.client; - const currentSavedTimeline = await savedObjectsClient.get( - timelineSavedObjectType, - timelineId - ); - - return savedObjectsClient.update( - timelineSavedObjectType, - timelineId, - pickSavedTimeline( - null, - { - ...timeline, - dateRange: currentSavedTimeline.attributes.dateRange, - }, - request.user - ) - ); -}; - -export const resetTimeline = async (request: FrameworkRequest, timelineIds: string[]) => { - if (!timelineIds.length) { - return Promise.reject(new Error('timelineIds is empty')); - } - - await Promise.all( - timelineIds.map(timelineId => - Promise.all([ - note.deleteNoteByTimelineId(request, timelineId), - pinnedEvent.deleteAllPinnedEventsOnTimeline(request, timelineId), - ]) - ) - ); - - const response = await Promise.all( - timelineIds.map(timelineId => - updatePartialSavedTimeline(request, timelineId, draftTimelineDefaults) - ) - ); - - return response; -}; - export const deleteTimeline = async (request: FrameworkRequest, timelineIds: string[]) => { const savedObjectsClient = request.context.core.savedObjects.client; diff --git a/x-pack/plugins/siem/server/routes/index.ts b/x-pack/plugins/siem/server/routes/index.ts index 4a7bc4a4aa02f..ffad86a09cee7 100644 --- a/x-pack/plugins/siem/server/routes/index.ts +++ b/x-pack/plugins/siem/server/routes/index.ts @@ -32,8 +32,6 @@ import { importTimelinesRoute } from '../lib/timeline/routes/import_timelines_ro import { exportTimelinesRoute } from '../lib/timeline/routes/export_timelines_route'; import { createTimelinesRoute } from '../lib/timeline/routes/create_timelines_route'; import { updateTimelinesRoute } from '../lib/timeline/routes/update_timelines_route'; -import { draftTimelinesRoute } from '../lib/timeline/routes/draft_timelines_route'; -import { draftCleanTimelinesRoute } from '../lib/timeline/routes/draft_clean_timelines_route'; import { SetupPlugins } from '../plugin'; import { ConfigType } from '../config'; @@ -66,8 +64,6 @@ export const initRoutes = ( importTimelinesRoute(router, config, security); exportTimelinesRoute(router, config); - draftTimelinesRoute(router, config, security); - draftCleanTimelinesRoute(router, config, security); findRulesStatusesRoute(router); diff --git a/x-pack/test/siem_cypress/es_archives/timeline/data.json.gz b/x-pack/test/siem_cypress/es_archives/timeline/data.json.gz index cde2775bddb2402d97cdc4a051852393414cbadd..c7acb36992af3d928d5b8aaf904c3d79eb9a2c20 100644 GIT binary patch literal 1775 zcmV#})`l2yXXtb+RoB(NFuLyGSt^1z^Z^s6x~i)q)f}ngD^2xG*HbOUHnsP|%@Tu@ zju?z!3>jH@^~XWcS*K957hsH_NyZ?31IYzQYp2CM1(!KRdWN%vHO>WvrEr0IT8GBq zrVENhys8!8x{4vgn7)Mp!{ilM@tf4evHn6N@UFO7`{Eu+i<1tPg^%8F3qz97cZkiO zL;MWEDBQ?UA)Gtu3NsLO9a6{`N@ld_9XiMVa;LpTGy@U3%~Mcr4URYk5rv&{F%-iy zkcuP_c80K~D(={RKR6$EhV1^EQ)4^i=72PfP>@@}&nTEdpAnEy5C{l}JR62n*D}@7 z*qMYQO@ma)7Jb?$`w8kPEhlZ{x3LCg5R9w&nTM6Qhp&^%fIuihOjj(^ za*X>wW;IJ^@dT3B(=*O`A^f514Ifhm;e&o7H|^wsg<36=SS_V=p)580O`;QV?rT!<-jyEr&ChuzH%UX3hYR5OLKJ zTQyU0#Wd~eQg&2zs9+aGeh16Db1iHXnpRaS{F(PVz286C_EfKz8HJ>fuB{LzXoi}B z{y$Z!+moWow(4mvwqG=SS<%sVvG zOBBFuEOrvBgy}&@@+*Xb11XD>3C=Ir>_7xdt>}Z*Dso2LYKI34l7i$wq__izXtXmu z^%bP^Cd~o$L9+5I#?D*MdL!K7hLS@=7AAV&uC&5S#Fm5-Y&zz>Ife4k0(KLj=ob1Y z@h2;mORB5Rz`RN4Jc#Lb&9oka1B2y4p=Go<>dZ*~Cp@8kmnFJcY`m4<{;nj??adO% znt>tDa0~PaEI}JcM-xC{3!dN*exfaKx?=M@H0xlJO;#PicvO(+9&Z3$49n~c<3(5K z#e$sK)BRgY-)`c1U+UXCkbNvPwjJI!aycu7dZY+-mk0 zC^unA>tx4dASx^p3v?K6&1mQZ|3mER7==X zL|{-21$oOS0v6@|ygdKyLgEtO?}*K6*Kf0Ec$TXe>X&R5 zIn!c=;RzW$oWjI!Nb#VuzTtXDx1!1&s8P#{k*)oCa;NU5XBvuSI7i%_bIZCDLqB-y zGi-N0$1&WuJ6BD2=NA&K=jyy++;6rzKY)`P0ltZCUu3HA>qfZ#)g$~~`9iPJ{Yu-r zz_%!hz!OVRrAHSa-~%J3^Pi-1J~&1a2S~3krN8+w=xe5LKbC&s9)<7Vr%Qr&5F#Pli@;`3%_GxJ)003)gW7q%y literal 1827 zcmV+;2i*7{iwFP!000026YUz?Zre8WdHxDbPwfz^y4%uTwxw$uv{}0)Ylk+4KufgE zMiMoW%Hjn6_mPsE=w@3{?X&?BB#3o*bnZMC($@n?lG!4GvMb2}_T>WsxBy`)AlLkX zKcYaa`Z%7VnQJSmq7Ffr%z>6+3xqg;mjXvQM-vbO?`DPKl=!!#q!pPGgu^B&3WGn= zh(pJwJvz8u2>^pHFo^(j*_Gh%_vxWrEH77hGJ#V_VC+N6Q9c#W&o|2}{R-9@csUS% z%faBfy9H_xq7`sF@V%3C}BA( z`E-t`#DCcwN`)3u_STPb+2n|VNeF`%5U`X~n3dRZ#27@GxX%lNGz4B*HJ7Zn*^9s% zi@@7M#5t-u(i}&(%#o=&j`o$&bpuZm5xjv1m{`?ST^*|CP#v9Ws%tu~YALpuRf--Ax#3=|VY?X_l z2p)n&B!Qqcgf&%hM)t?v`M5P?x9^+^+dex7BuR+;%nDvg!3=tgfS3YbKtSl)Fqk@) zsSZcuNiftj2!_r`8}mf~V z(0VW)R~2o{eZI-fYBw)ix@*~rG19-Wm+Nx$^Kw)wh?S>)&WqNT!x@ZOHO-bYrw>Sg zxax>4>Z!P7nr3w=I;tvEunR-4h2_n<7Ssw&qpIcp%=(?q?+?~JRqJI+A<3m{DufA| zp?aWyr%JVZQdHSSJ($b3i>1FT9emv(~fP2)DSQ;82r=i5|Eut?&}DCZYJNj(KZNp?tJ}?L;WL zf*y*!$%18)>gu>>-lTIL#B{x8T8F`b!Qw!nVYDc0%}CxCJfU8jCE8i6yp`?#wj|H( z&0@&vfg#Uu1M~%4fF_U*CxF5RJjMb1LL1;@!RA?LR>35lELwokFelMI-T->uFS9d@ z&)Y&T66DN|?q5^-HWSyoQeWSJY-6E09a&^$p=H|K%E0c(phyQE?_BR}D62D%wOeSb z9%@G(3Bg33WSSxKiDBInpZ#g8YO`2o_^D zoT89Haq?5E_qhRnxg9Cj#mi3ka3*4++%J=CTPl2lg)_{f=pJ|#9oAks%`s(4Hc{@C zO&+rf+H)WTJlc3c6K2~xFEPV6F=16PrhiaEa<;N0M z7QZV~iq5>WmRohb66gPh$Goi*Z|10Sb@9&>lE#5aj@h;(UTOskF)tIsQ%9l8%~o)K zk{iwbIm%2}&>C!*3`B)R;s6~6D|zJWGkJn>cqY626P@EU4EX0y`~hAf%4ohY703Df z4+0?eOtOl`T8w|D2@q7WrJIE>RUEU#kH=+^TMaa7OY zwW*e{=ZHYR918N9D*_f~{yaJQ{aE4?5i7g2sKVv=baZFj#HenL_4kPNYS-;#(QqwC zF;x9N>%C<>*89hL|5)!I>-~eN_XJGYW2Jwr^jj+Z4hsCi;D^%1q^M)7Fw2ARJ8S?r z)BFy@6*9Oufw5PU;!bsb#r1}6NtGK=t+?lBw$1M+ZPeX#O+&Ga@g6VFxn-S+q3`_c zqu=HE97k~5<+*A)8^0oL-5Q}RO!hv@KMY#o&PKy#SDfL2S{&Eq<P)#>q@11Uu3P Date: Wed, 6 May 2020 11:25:46 -0400 Subject: [PATCH 19/23] [Doc-Table] Import styles into JS where possible (#65329) Fixes styles and overflow table vis --- src/plugins/discover/public/application/angular/_index.scss | 1 - .../public/application/angular/doc_table/_doc_table.scss | 1 + .../discover/public/application/angular/doc_table/doc_table.ts | 1 + .../application/angular/doc_table/{_index.scss => index.scss} | 2 ++ src/plugins/discover/public/application/components/_index.scss | 3 --- .../public/application/components/doc_viewer/_index.scss | 1 - .../doc_viewer/{_doc_viewer.scss => doc_viewer.scss} | 0 .../public/application/components/doc_viewer/doc_viewer.tsx | 1 + .../public/application/components/fetch_error/_index.scss | 1 - .../fetch_error/{_fetch_error.scss => fetch_error.scss} | 0 .../public/application/components/fetch_error/fetch_error.tsx | 1 + .../discover/public/application/components/sidebar/_index.scss | 1 - .../sidebar/{_sidebar.scss => discover_sidebar.scss} | 0 .../public/application/components/sidebar/discover_sidebar.tsx | 1 + src/plugins/discover/public/application/embeddable/_index.scss | 2 -- .../embeddable/{_embeddables.scss => search_embeddable.scss} | 0 .../public/application/embeddable/search_embeddable.ts | 1 + src/plugins/discover/public/application/index.scss | 2 -- 18 files changed, 8 insertions(+), 11 deletions(-) rename src/plugins/discover/public/application/angular/doc_table/{_index.scss => index.scss} (66%) delete mode 100644 src/plugins/discover/public/application/components/_index.scss delete mode 100644 src/plugins/discover/public/application/components/doc_viewer/_index.scss rename src/plugins/discover/public/application/components/doc_viewer/{_doc_viewer.scss => doc_viewer.scss} (100%) delete mode 100644 src/plugins/discover/public/application/components/fetch_error/_index.scss rename src/plugins/discover/public/application/components/fetch_error/{_fetch_error.scss => fetch_error.scss} (100%) delete mode 100644 src/plugins/discover/public/application/components/sidebar/_index.scss rename src/plugins/discover/public/application/components/sidebar/{_sidebar.scss => discover_sidebar.scss} (100%) delete mode 100644 src/plugins/discover/public/application/embeddable/_index.scss rename src/plugins/discover/public/application/embeddable/{_embeddables.scss => search_embeddable.scss} (100%) diff --git a/src/plugins/discover/public/application/angular/_index.scss b/src/plugins/discover/public/application/angular/_index.scss index 9e00ade3d41f6..b0e5b6e3edf7b 100644 --- a/src/plugins/discover/public/application/angular/_index.scss +++ b/src/plugins/discover/public/application/angular/_index.scss @@ -1,3 +1,2 @@ @import 'directives/index'; -@import 'doc_table/index'; @import 'context/index'; diff --git a/src/plugins/discover/public/application/angular/doc_table/_doc_table.scss b/src/plugins/discover/public/application/angular/doc_table/_doc_table.scss index 8b754d23f9604..3e30214acd2a9 100644 --- a/src/plugins/discover/public/application/angular/doc_table/_doc_table.scss +++ b/src/plugins/discover/public/application/angular/doc_table/_doc_table.scss @@ -2,6 +2,7 @@ * 1. Stack content vertically so the table can scroll when its constrained by a fixed container height. */ doc-table { + @include euiScrollBar; overflow: auto; flex: 1 1 100%; flex-direction: column; /* 1 */ diff --git a/src/plugins/discover/public/application/angular/doc_table/doc_table.ts b/src/plugins/discover/public/application/angular/doc_table/doc_table.ts index 66b162a4584a7..8af7380afcdc9 100644 --- a/src/plugins/discover/public/application/angular/doc_table/doc_table.ts +++ b/src/plugins/discover/public/application/angular/doc_table/doc_table.ts @@ -22,6 +22,7 @@ import { dispatchRenderComplete } from '../../../../../kibana_utils/public'; // @ts-ignore import { getLimitedSearchResultsMessage } from './doc_table_strings'; import { getServices } from '../../../kibana_services'; +import './index.scss'; export interface LazyScope extends ng.IScope { [key: string]: any; diff --git a/src/plugins/discover/public/application/angular/doc_table/_index.scss b/src/plugins/discover/public/application/angular/doc_table/index.scss similarity index 66% rename from src/plugins/discover/public/application/angular/doc_table/_index.scss rename to src/plugins/discover/public/application/angular/doc_table/index.scss index 3663d807851c4..4e6cb83c5fe5a 100644 --- a/src/plugins/discover/public/application/angular/doc_table/_index.scss +++ b/src/plugins/discover/public/application/angular/doc_table/index.scss @@ -1,2 +1,4 @@ +@import '../../mixins'; + @import 'doc_table'; @import 'components/index'; diff --git a/src/plugins/discover/public/application/components/_index.scss b/src/plugins/discover/public/application/components/_index.scss deleted file mode 100644 index 91fb3df79b177..0000000000000 --- a/src/plugins/discover/public/application/components/_index.scss +++ /dev/null @@ -1,3 +0,0 @@ -@import 'doc_viewer/index'; -@import 'fetch_error/index'; -@import 'sidebar/index'; diff --git a/src/plugins/discover/public/application/components/doc_viewer/_index.scss b/src/plugins/discover/public/application/components/doc_viewer/_index.scss deleted file mode 100644 index aaf925f435d81..0000000000000 --- a/src/plugins/discover/public/application/components/doc_viewer/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import 'doc_viewer'; diff --git a/src/plugins/discover/public/application/components/doc_viewer/_doc_viewer.scss b/src/plugins/discover/public/application/components/doc_viewer/doc_viewer.scss similarity index 100% rename from src/plugins/discover/public/application/components/doc_viewer/_doc_viewer.scss rename to src/plugins/discover/public/application/components/doc_viewer/doc_viewer.scss diff --git a/src/plugins/discover/public/application/components/doc_viewer/doc_viewer.tsx b/src/plugins/discover/public/application/components/doc_viewer/doc_viewer.tsx index dce6de150155c..80c43db016698 100644 --- a/src/plugins/discover/public/application/components/doc_viewer/doc_viewer.tsx +++ b/src/plugins/discover/public/application/components/doc_viewer/doc_viewer.tsx @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +import './doc_viewer.scss'; import React from 'react'; import { EuiTabbedContent } from '@elastic/eui'; import { getDocViewsRegistry } from '../../../kibana_services'; diff --git a/src/plugins/discover/public/application/components/fetch_error/_index.scss b/src/plugins/discover/public/application/components/fetch_error/_index.scss deleted file mode 100644 index 596f7b66866e3..0000000000000 --- a/src/plugins/discover/public/application/components/fetch_error/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import 'fetch_error'; diff --git a/src/plugins/discover/public/application/components/fetch_error/_fetch_error.scss b/src/plugins/discover/public/application/components/fetch_error/fetch_error.scss similarity index 100% rename from src/plugins/discover/public/application/components/fetch_error/_fetch_error.scss rename to src/plugins/discover/public/application/components/fetch_error/fetch_error.scss diff --git a/src/plugins/discover/public/application/components/fetch_error/fetch_error.tsx b/src/plugins/discover/public/application/components/fetch_error/fetch_error.tsx index e16089500d3e5..0bae2456f743c 100644 --- a/src/plugins/discover/public/application/components/fetch_error/fetch_error.tsx +++ b/src/plugins/discover/public/application/components/fetch_error/fetch_error.tsx @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +import './fetch_error.scss'; import React, { Fragment } from 'react'; import { FormattedMessage, I18nProvider } from '@kbn/i18n/react'; import { EuiFlexGroup, EuiFlexItem, EuiCallOut, EuiCodeBlock, EuiSpacer } from '@elastic/eui'; diff --git a/src/plugins/discover/public/application/components/sidebar/_index.scss b/src/plugins/discover/public/application/components/sidebar/_index.scss deleted file mode 100644 index 17b0a6c9cfe4e..0000000000000 --- a/src/plugins/discover/public/application/components/sidebar/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import './_sidebar'; diff --git a/src/plugins/discover/public/application/components/sidebar/_sidebar.scss b/src/plugins/discover/public/application/components/sidebar/discover_sidebar.scss similarity index 100% rename from src/plugins/discover/public/application/components/sidebar/_sidebar.scss rename to src/plugins/discover/public/application/components/sidebar/discover_sidebar.scss diff --git a/src/plugins/discover/public/application/components/sidebar/discover_sidebar.tsx b/src/plugins/discover/public/application/components/sidebar/discover_sidebar.tsx index 74d1347b1694c..56597dd31e572 100644 --- a/src/plugins/discover/public/application/components/sidebar/discover_sidebar.tsx +++ b/src/plugins/discover/public/application/components/sidebar/discover_sidebar.tsx @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +import './discover_sidebar.scss'; import React, { useCallback, useEffect, useState, useMemo } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiButtonIcon, EuiTitle } from '@elastic/eui'; diff --git a/src/plugins/discover/public/application/embeddable/_index.scss b/src/plugins/discover/public/application/embeddable/_index.scss deleted file mode 100644 index 6d64040e9e7a3..0000000000000 --- a/src/plugins/discover/public/application/embeddable/_index.scss +++ /dev/null @@ -1,2 +0,0 @@ - -@import 'embeddables'; diff --git a/src/plugins/discover/public/application/embeddable/_embeddables.scss b/src/plugins/discover/public/application/embeddable/search_embeddable.scss similarity index 100% rename from src/plugins/discover/public/application/embeddable/_embeddables.scss rename to src/plugins/discover/public/application/embeddable/search_embeddable.scss diff --git a/src/plugins/discover/public/application/embeddable/search_embeddable.ts b/src/plugins/discover/public/application/embeddable/search_embeddable.ts index b650672ccaea7..2f8ac40bdf52c 100644 --- a/src/plugins/discover/public/application/embeddable/search_embeddable.ts +++ b/src/plugins/discover/public/application/embeddable/search_embeddable.ts @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +import './search_embeddable.scss'; import angular from 'angular'; import _ from 'lodash'; import * as Rx from 'rxjs'; diff --git a/src/plugins/discover/public/application/index.scss b/src/plugins/discover/public/application/index.scss index 0de036b1e1707..aaec7ab387e96 100644 --- a/src/plugins/discover/public/application/index.scss +++ b/src/plugins/discover/public/application/index.scss @@ -10,6 +10,4 @@ // monChart__legend--small // monChart__legend-isLoading -@import 'components/index'; @import 'angular/index'; -@import 'embeddable/index'; From 8581ba8c381458f43edcff54ff244aa88b64cbe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez?= Date: Wed, 6 May 2020 17:37:30 +0200 Subject: [PATCH 20/23] [Logs UI] Add tests to the log alert executor (#64881) --- .../log_threshold_executor.test.ts | 311 ++++++++++++++++++ .../lib/alerting/log_threshold/mocks/index.ts | 20 ++ 2 files changed, 331 insertions(+) create mode 100644 x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.test.ts create mode 100644 x-pack/plugins/infra/server/lib/alerting/log_threshold/mocks/index.ts diff --git a/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.test.ts b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.test.ts new file mode 100644 index 0000000000000..995d415ef3c8f --- /dev/null +++ b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.test.ts @@ -0,0 +1,311 @@ +/* + * 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 { createLogThresholdExecutor } from './log_threshold_executor'; +import { + Comparator, + AlertStates, + LogDocumentCountAlertParams, + Criterion, +} from '../../../../common/alerting/logs/types'; +import { AlertExecutorOptions } from '../../../../../alerting/server'; +import { + alertsMock, + AlertInstanceMock, + AlertServicesMock, +} from '../../../../../alerting/server/mocks'; +import { libsMock } from './mocks'; + +interface AlertTestInstance { + instance: AlertInstanceMock; + actionQueue: any[]; + state: any; +} + +/* + * Mocks + */ +const alertInstances = new Map(); + +const services: AlertServicesMock = alertsMock.createAlertServices(); +services.alertInstanceFactory.mockImplementation((instanceId: string) => { + const alertInstance: AlertTestInstance = { + instance: alertsMock.createAlertInstanceFactory(), + actionQueue: [], + state: {}, + }; + alertInstance.instance.replaceState.mockImplementation((newState: any) => { + alertInstance.state = newState; + return alertInstance.instance; + }); + alertInstance.instance.scheduleActions.mockImplementation((id: string, action: any) => { + alertInstance.actionQueue.push({ id, action }); + return alertInstance.instance; + }); + + alertInstances.set(instanceId, alertInstance); + + return alertInstance.instance; +}); + +/* + * Helper functions + */ +function getAlertState(instanceId: string): AlertStates { + const alert = alertInstances.get(instanceId); + if (alert) { + return alert.state.alertState; + } else { + throw new Error('Could not find alert instance `' + instanceId + '`'); + } +} + +/* + * Executor instance (our test subject) + */ +const executor = (createLogThresholdExecutor('test', libsMock) as unknown) as (opts: { + params: LogDocumentCountAlertParams; + services: { callCluster: AlertExecutorOptions['params']['callCluster'] }; +}) => Promise; + +// Wrapper to test +type Comparison = [number, Comparator, number]; +async function callExecutor( + [value, comparator, threshold]: Comparison, + criteria: Criterion[] = [] +) { + services.callCluster.mockImplementationOnce(async (..._) => ({ count: value })); + + return await executor({ + services, + params: { + count: { value: threshold, comparator }, + timeSize: 1, + timeUnit: 'm', + criteria, + }, + }); +} + +describe('Comparators trigger alerts correctly', () => { + it('does not alert when counts do not reach the threshold', async () => { + await callExecutor([0, Comparator.GT, 1]); + expect(getAlertState('test')).toBe(AlertStates.OK); + + await callExecutor([0, Comparator.GT_OR_EQ, 1]); + expect(getAlertState('test')).toBe(AlertStates.OK); + + await callExecutor([1, Comparator.LT, 0]); + expect(getAlertState('test')).toBe(AlertStates.OK); + + await callExecutor([1, Comparator.LT_OR_EQ, 0]); + expect(getAlertState('test')).toBe(AlertStates.OK); + }); + + it('alerts when counts reach the threshold', async () => { + await callExecutor([2, Comparator.GT, 1]); + expect(getAlertState('test')).toBe(AlertStates.ALERT); + + await callExecutor([1, Comparator.GT_OR_EQ, 1]); + expect(getAlertState('test')).toBe(AlertStates.ALERT); + + await callExecutor([1, Comparator.LT, 2]); + expect(getAlertState('test')).toBe(AlertStates.ALERT); + + await callExecutor([2, Comparator.LT_OR_EQ, 2]); + expect(getAlertState('test')).toBe(AlertStates.ALERT); + }); +}); + +describe('Comparators create the correct ES queries', () => { + beforeEach(() => { + services.callCluster.mockReset(); + }); + + it('Works with `Comparator.EQ`', async () => { + await callExecutor( + [2, Comparator.GT, 1], // Not relevant + [{ field: 'foo', comparator: Comparator.EQ, value: 'bar' }] + ); + + const query = services.callCluster.mock.calls[0][1]!; + expect(query.body).toMatchObject({ + query: { + bool: { + must: [{ term: { foo: { value: 'bar' } } }], + }, + }, + }); + }); + + it('works with `Comparator.NOT_EQ`', async () => { + await callExecutor( + [2, Comparator.GT, 1], // Not relevant + [{ field: 'foo', comparator: Comparator.NOT_EQ, value: 'bar' }] + ); + + const query = services.callCluster.mock.calls[0][1]!; + expect(query.body).toMatchObject({ + query: { + bool: { + must_not: [{ term: { foo: { value: 'bar' } } }], + }, + }, + }); + }); + + it('works with `Comparator.MATCH`', async () => { + await callExecutor( + [2, Comparator.GT, 1], // Not relevant + [{ field: 'foo', comparator: Comparator.MATCH, value: 'bar' }] + ); + + const query = services.callCluster.mock.calls[0][1]!; + expect(query.body).toMatchObject({ + query: { + bool: { + must: [{ match: { foo: 'bar' } }], + }, + }, + }); + }); + + it('works with `Comparator.NOT_MATCH`', async () => { + await callExecutor( + [2, Comparator.GT, 1], // Not relevant + [{ field: 'foo', comparator: Comparator.NOT_MATCH, value: 'bar' }] + ); + + const query = services.callCluster.mock.calls[0][1]!; + expect(query.body).toMatchObject({ + query: { + bool: { + must_not: [{ match: { foo: 'bar' } }], + }, + }, + }); + }); + + it('works with `Comparator.MATCH_PHRASE`', async () => { + await callExecutor( + [2, Comparator.GT, 1], // Not relevant + [{ field: 'foo', comparator: Comparator.MATCH_PHRASE, value: 'bar' }] + ); + + const query = services.callCluster.mock.calls[0][1]!; + expect(query.body).toMatchObject({ + query: { + bool: { + must: [{ match_phrase: { foo: 'bar' } }], + }, + }, + }); + }); + + it('works with `Comparator.NOT_MATCH_PHRASE`', async () => { + await callExecutor( + [2, Comparator.GT, 1], // Not relevant + [{ field: 'foo', comparator: Comparator.NOT_MATCH_PHRASE, value: 'bar' }] + ); + + const query = services.callCluster.mock.calls[0][1]!; + expect(query.body).toMatchObject({ + query: { + bool: { + must_not: [{ match_phrase: { foo: 'bar' } }], + }, + }, + }); + }); + + it('works with `Comparator.GT`', async () => { + await callExecutor( + [2, Comparator.GT, 1], // Not relevant + [{ field: 'foo', comparator: Comparator.GT, value: 1 }] + ); + + const query = services.callCluster.mock.calls[0][1]!; + expect(query.body).toMatchObject({ + query: { + bool: { + must: [{ range: { foo: { gt: 1 } } }], + }, + }, + }); + }); + + it('works with `Comparator.GT_OR_EQ`', async () => { + await callExecutor( + [2, Comparator.GT, 1], // Not relevant + [{ field: 'foo', comparator: Comparator.GT_OR_EQ, value: 1 }] + ); + + const query = services.callCluster.mock.calls[0][1]!; + expect(query.body).toMatchObject({ + query: { + bool: { + must: [{ range: { foo: { gte: 1 } } }], + }, + }, + }); + }); + + it('works with `Comparator.LT`', async () => { + await callExecutor( + [2, Comparator.GT, 1], // Not relevant + [{ field: 'foo', comparator: Comparator.LT, value: 1 }] + ); + + const query = services.callCluster.mock.calls[0][1]!; + expect(query.body).toMatchObject({ + query: { + bool: { + must: [{ range: { foo: { lt: 1 } } }], + }, + }, + }); + }); + + it('works with `Comparator.LT_OR_EQ`', async () => { + await callExecutor( + [2, Comparator.GT, 1], // Not relevant + [{ field: 'foo', comparator: Comparator.LT_OR_EQ, value: 1 }] + ); + + const query = services.callCluster.mock.calls[0][1]!; + expect(query.body).toMatchObject({ + query: { + bool: { + must: [{ range: { foo: { lte: 1 } } }], + }, + }, + }); + }); +}); + +describe('Multiple criteria create the right ES query', () => { + beforeEach(() => { + services.callCluster.mockReset(); + }); + it('works', async () => { + await callExecutor( + [2, Comparator.GT, 1], // Not relevant + [ + { field: 'foo', comparator: Comparator.EQ, value: 'bar' }, + { field: 'http.status', comparator: Comparator.LT, value: 400 }, + ] + ); + + const query = services.callCluster.mock.calls[0][1]!; + expect(query.body).toMatchObject({ + query: { + bool: { + must: [{ term: { foo: { value: 'bar' } } }, { range: { 'http.status': { lt: 400 } } }], + }, + }, + }); + }); +}); diff --git a/x-pack/plugins/infra/server/lib/alerting/log_threshold/mocks/index.ts b/x-pack/plugins/infra/server/lib/alerting/log_threshold/mocks/index.ts new file mode 100644 index 0000000000000..449bc03a922cf --- /dev/null +++ b/x-pack/plugins/infra/server/lib/alerting/log_threshold/mocks/index.ts @@ -0,0 +1,20 @@ +/* + * 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 { InfraBackendLibs } from '../../../infra_types'; + +export const libsMock = { + sources: { + getSourceConfiguration: (savedObjectsClient: any, sourceId: string) => { + return Promise.resolve({ + id: sourceId, + configuration: { + logAlias: 'filebeat-*', + fields: { timestamp: '@timestamp' }, + }, + }); + }, + }, +} as InfraBackendLibs; From 46b91cc9fdbe7794005631bbb47e22c6b73db9d0 Mon Sep 17 00:00:00 2001 From: Pete Harverson Date: Wed, 6 May 2020 17:03:01 +0100 Subject: [PATCH 21/23] [ML] Add check for loss_function when cloning a regression job (#65481) --- .../components/analytics_list/action_clone.test.ts | 2 ++ .../components/analytics_list/action_clone.tsx | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/action_clone.test.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/action_clone.test.ts index 2463da054d140..9221f8c500326 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/action_clone.test.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/action_clone.test.ts @@ -92,6 +92,7 @@ describe('Analytics job clone action', () => { training_percent: 20, randomize_seed: -2228827740028660200, num_top_feature_importance_values: 4, + loss_function: 'mse', }, }, analyzed_fields: { @@ -192,6 +193,7 @@ describe('Analytics job clone action', () => { training_percent: 20, randomize_seed: -2228827740028660200, num_top_feature_importance_values: 4, + loss_function: 'mse', }, }, analyzed_fields: { diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/action_clone.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/action_clone.tsx index cc75ddbe08cfb..cfb11856670c4 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/action_clone.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/action_clone.tsx @@ -179,6 +179,10 @@ const getAnalyticsJobMeta = (config: CloneDataFrameAnalyticsConfig): AnalyticsJo // By default it is randomly generated ignore: true, }, + loss_function: { + optional: true, + defaultValue: 'mse', + }, }, } : {}), From 5f314227d9a9329048dbc731e22d5de241a2ced5 Mon Sep 17 00:00:00 2001 From: Josh Dover Date: Wed, 6 May 2020 10:42:07 -0600 Subject: [PATCH 22/23] Fix logstash integration with monitoring (#65165) --- x-pack/plugins/logstash/kibana.json | 1 + x-pack/plugins/logstash/public/application/index.tsx | 8 ++------ x-pack/plugins/logstash/public/plugin.ts | 3 ++- .../public/services/monitoring/monitoring_service.js | 8 +++++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/logstash/kibana.json b/x-pack/plugins/logstash/kibana.json index 97dbf58865a88..1eb325dcc1610 100644 --- a/x-pack/plugins/logstash/kibana.json +++ b/x-pack/plugins/logstash/kibana.json @@ -9,6 +9,7 @@ ], "optionalPlugins": [ "home", + "monitoring", "security" ], "server": true, diff --git a/x-pack/plugins/logstash/public/application/index.tsx b/x-pack/plugins/logstash/public/application/index.tsx index 438038d6c885e..3588e1f6b2417 100644 --- a/x-pack/plugins/logstash/public/application/index.tsx +++ b/x-pack/plugins/logstash/public/application/index.tsx @@ -31,16 +31,12 @@ import * as Breadcrumbs from './breadcrumbs'; export const renderApp = async ( core: CoreStart, { basePath, element, setBreadcrumbs }: ManagementAppMountParams, + isMonitoringEnabled: boolean, licenseService$: Observable ) => { const logstashLicenseService = await licenseService$.pipe(first()).toPromise(); const clusterService = new ClusterService(core.http); - const monitoringService = new MonitoringService( - core.http, - // When monitoring is migrated this should be fetched from monitoring's plugin contract - core.injectedMetadata.getInjectedVar('monitoringUiEnabled'), - clusterService - ); + const monitoringService = new MonitoringService(core.http, isMonitoringEnabled, clusterService); const pipelinesService = new PipelinesService(core.http, monitoringService); const pipelineService = new PipelineService(core.http, pipelinesService); const upgradeService = new UpgradeService(core.http); diff --git a/x-pack/plugins/logstash/public/plugin.ts b/x-pack/plugins/logstash/public/plugin.ts index 91d1a39d3970c..7fbed5b3b8602 100644 --- a/x-pack/plugins/logstash/public/plugin.ts +++ b/x-pack/plugins/logstash/public/plugin.ts @@ -49,8 +49,9 @@ export class LogstashPlugin implements Plugin { mount: async params => { const [coreStart] = await core.getStartServices(); const { renderApp } = await import('./application'); + const isMonitoringEnabled = 'monitoring' in plugins; - return renderApp(coreStart, params, logstashLicense$); + return renderApp(coreStart, params, isMonitoringEnabled, logstashLicense$); }, }); diff --git a/x-pack/plugins/logstash/public/services/monitoring/monitoring_service.js b/x-pack/plugins/logstash/public/services/monitoring/monitoring_service.js index d551f4fba61d2..4db2838cb5354 100755 --- a/x-pack/plugins/logstash/public/services/monitoring/monitoring_service.js +++ b/x-pack/plugins/logstash/public/services/monitoring/monitoring_service.js @@ -9,14 +9,14 @@ import { ROUTES, MONITORING } from '../../../common/constants'; import { PipelineListItem } from '../../models/pipeline_list_item'; export class MonitoringService { - constructor(http, monitoringUiEnabled, clusterService) { + constructor(http, isMonitoringEnabled, clusterService) { this.http = http; - this.monitoringUiEnabled = monitoringUiEnabled; + this._isMonitoringEnabled = isMonitoringEnabled; this.clusterService = clusterService; } isMonitoringEnabled() { - return this.monitoringUiEnabled; + return this._isMonitoringEnabled; } getPipelineList() { @@ -27,6 +27,8 @@ export class MonitoringService { return this.clusterService .loadCluster() .then(cluster => { + // This API call should live within the Monitoring plugin + // https://github.com/elastic/kibana/issues/63931 const url = `${ROUTES.MONITORING_API_ROOT}/v1/clusters/${cluster.uuid}/logstash/pipeline_ids`; const now = moment.utc(); const body = JSON.stringify({ From b71b13947e451c48822d2f7a33db4c16c532b462 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20C=C3=B4t=C3=A9?= Date: Wed, 6 May 2020 13:39:09 -0400 Subject: [PATCH 23/23] Shallow clone properties when adding to registry (#65309) --- .../server/action_type_registry.test.ts | 13 +++++++++++++ .../actions/server/action_type_registry.ts | 2 +- .../server/alert_type_registry.test.ts | 19 +++++++++++++++++++ .../alerting/server/alert_type_registry.ts | 2 +- 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/actions/server/action_type_registry.test.ts b/x-pack/plugins/actions/server/action_type_registry.test.ts index 3be2f26557079..a8f50ec3535e2 100644 --- a/x-pack/plugins/actions/server/action_type_registry.test.ts +++ b/x-pack/plugins/actions/server/action_type_registry.test.ts @@ -71,6 +71,19 @@ describe('register()', () => { `); }); + test('shallow clones the given action type', () => { + const myType: ActionType = { + id: 'my-action-type', + name: 'My action type', + minimumLicenseRequired: 'basic', + executor, + }; + const actionTypeRegistry = new ActionTypeRegistry(actionTypeRegistryParams); + actionTypeRegistry.register(myType); + myType.name = 'Changed'; + expect(actionTypeRegistry.get('my-action-type').name).toEqual('My action type'); + }); + test('throws error if action type already registered', () => { const actionTypeRegistry = new ActionTypeRegistry(actionTypeRegistryParams); actionTypeRegistry.register({ diff --git a/x-pack/plugins/actions/server/action_type_registry.ts b/x-pack/plugins/actions/server/action_type_registry.ts index 723982b11e1cc..73ae49a7e69c2 100644 --- a/x-pack/plugins/actions/server/action_type_registry.ts +++ b/x-pack/plugins/actions/server/action_type_registry.ts @@ -91,7 +91,7 @@ export class ActionTypeRegistry { ) ); } - this.actionTypes.set(actionType.id, actionType); + this.actionTypes.set(actionType.id, { ...actionType }); this.taskManager.registerTaskDefinitions({ [`actions:${actionType.id}`]: { title: actionType.name, diff --git a/x-pack/plugins/alerting/server/alert_type_registry.test.ts b/x-pack/plugins/alerting/server/alert_type_registry.test.ts index f9df390242cd4..f556287703347 100644 --- a/x-pack/plugins/alerting/server/alert_type_registry.test.ts +++ b/x-pack/plugins/alerting/server/alert_type_registry.test.ts @@ -72,6 +72,25 @@ describe('register()', () => { `); }); + test('shallow clones the given alert type', () => { + const alertType: AlertType = { + id: 'test', + name: 'Test', + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', + executor: jest.fn(), + }; + const registry = new AlertTypeRegistry(alertTypeRegistryParams); + registry.register(alertType); + alertType.name = 'Changed'; + expect(registry.get('test').name).toEqual('Test'); + }); + test('should throw an error if type is already registered', () => { const registry = new AlertTypeRegistry(alertTypeRegistryParams); registry.register({ diff --git a/x-pack/plugins/alerting/server/alert_type_registry.ts b/x-pack/plugins/alerting/server/alert_type_registry.ts index 55e39b6a817db..8bcb4d838ca1b 100644 --- a/x-pack/plugins/alerting/server/alert_type_registry.ts +++ b/x-pack/plugins/alerting/server/alert_type_registry.ts @@ -41,7 +41,7 @@ export class AlertTypeRegistry { ); } alertType.actionVariables = normalizedActionVariables(alertType.actionVariables); - this.alertTypes.set(alertType.id, alertType); + this.alertTypes.set(alertType.id, { ...alertType }); this.taskManager.registerTaskDefinitions({ [`alerting:${alertType.id}`]: { title: alertType.name,