diff --git a/.ci/packer_cache.sh b/.ci/packer_cache.sh
index b697f22c009d..ab68a60dcfc2 100755
--- a/.ci/packer_cache.sh
+++ b/.ci/packer_cache.sh
@@ -44,6 +44,7 @@ tar -cf "$HOME/.kibana/bootstrap_cache/$branch.tar" \
x-pack/legacy/plugins/*/node_modules \
x-pack/legacy/plugins/reporting/.chromium \
test/plugin_functional/plugins/*/node_modules \
+ examples/*/node_modules \
.es \
.chromedriver \
.geckodriver;
diff --git a/.eslintrc.js b/.eslintrc.js
index 106724c323d3..367ac892107a 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -170,13 +170,6 @@ module.exports = {
'react-hooks/rules-of-hooks': 'off',
},
},
- {
- files: ['x-pack/legacy/plugins/infra/**/*.{js,ts,tsx}'],
- rules: {
- 'react-hooks/exhaustive-deps': 'off',
- 'react-hooks/rules-of-hooks': 'off',
- },
- },
{
files: ['x-pack/legacy/plugins/lens/**/*.{js,ts,tsx}'],
rules: {
@@ -209,13 +202,6 @@ module.exports = {
'react-hooks/rules-of-hooks': 'off',
},
},
- {
- files: ['x-pack/legacy/plugins/watcher/**/*.{js,ts,tsx}'],
- rules: {
- 'react-hooks/rules-of-hooks': 'off',
- 'react-hooks/exhaustive-deps': 'off',
- },
- },
/**
* Prettier
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index c5e6768c17d4..338fbf2e359b 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -5,6 +5,8 @@
# App
/x-pack/legacy/plugins/lens/ @elastic/kibana-app
/x-pack/legacy/plugins/graph/ @elastic/kibana-app
+/src/plugins/share/ @elastic/kibana-app
+/src/legacy/server/url_shortening/ @elastic/kibana-app
/src/legacy/server/sample_data/ @elastic/kibana-app
# App Architecture
@@ -14,7 +16,6 @@
/src/plugins/kibana_react/ @elastic/kibana-app-arch
/src/plugins/kibana_utils/ @elastic/kibana-app-arch
/src/plugins/navigation/ @elastic/kibana-app-arch
-/src/plugins/share/ @elastic/kibana-app-arch
/src/plugins/ui_actions/ @elastic/kibana-app-arch
/src/plugins/visualizations/ @elastic/kibana-app-arch
/x-pack/plugins/advanced_ui_actions/ @elastic/kibana-app-arch
@@ -28,7 +29,6 @@
/src/legacy/core_plugins/kibana/server/routes/api/suggestions/ @elastic/kibana-app-arch
/src/legacy/core_plugins/visualizations/ @elastic/kibana-app-arch
/src/legacy/server/index_patterns/ @elastic/kibana-app-arch
-/src/legacy/server/url_shortening/ @elastic/kibana-app-arch
# APM
/x-pack/legacy/plugins/apm/ @elastic/apm-ui
diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc
index 39c87d97af4b..5cda7b2b214f 100644
--- a/docs/setup/settings.asciidoc
+++ b/docs/setup/settings.asciidoc
@@ -65,6 +65,8 @@ connects to this Kibana instance.
`elasticsearch.requestHeadersWhitelist:`:: *Default: `[ 'authorization' ]`* List
of Kibana client-side headers to send to Elasticsearch. To send *no* client-side
headers, set this value to [] (an empty list).
+Removing the `authorization` header from being whitelisted means that you cannot
+use <> in Kibana.
`elasticsearch.requestTimeout:`:: *Default: 30000* Time in milliseconds to wait
for responses from the back end or Elasticsearch. This value must be a positive
diff --git a/examples/README.md b/examples/README.md
new file mode 100644
index 000000000000..7cade0b35f82
--- /dev/null
+++ b/examples/README.md
@@ -0,0 +1,8 @@
+## Example plugins
+
+This folder contains example plugins. To run the plugins in this folder, use the `--run-examples` flag, via
+
+```
+yarn start --run-examples
+```
+
diff --git a/examples/demo_search/README.md b/examples/demo_search/README.md
new file mode 100644
index 000000000000..f0b461e3287b
--- /dev/null
+++ b/examples/demo_search/README.md
@@ -0,0 +1,8 @@
+## Demo search strategy
+
+This example registers a custom search strategy that simply takes a name string in the request and returns the
+string `Hello {name}`
+
+To see the demo search strategy in action, navigate to the `Search explorer` app.
+
+To run these examples, use the command `yarn start --run-examples`.
\ No newline at end of file
diff --git a/test/plugin_functional/plugins/demo_search/common/index.ts b/examples/demo_search/common/index.ts
similarity index 90%
rename from test/plugin_functional/plugins/demo_search/common/index.ts
rename to examples/demo_search/common/index.ts
index 9254412ece29..6587ee96ef61 100644
--- a/test/plugin_functional/plugins/demo_search/common/index.ts
+++ b/examples/demo_search/common/index.ts
@@ -17,10 +17,7 @@
* under the License.
*/
-import {
- IKibanaSearchRequest,
- IKibanaSearchResponse,
-} from '../../../../../src/plugins/data/public';
+import { IKibanaSearchRequest, IKibanaSearchResponse } from '../../../src/plugins/data/public';
export const DEMO_SEARCH_STRATEGY = 'DEMO_SEARCH_STRATEGY';
diff --git a/test/plugin_functional/plugins/demo_search/kibana.json b/examples/demo_search/kibana.json
similarity index 100%
rename from test/plugin_functional/plugins/demo_search/kibana.json
rename to examples/demo_search/kibana.json
diff --git a/test/plugin_functional/plugins/demo_search/package.json b/examples/demo_search/package.json
similarity index 88%
rename from test/plugin_functional/plugins/demo_search/package.json
rename to examples/demo_search/package.json
index 1f4fa1421906..404002a50e71 100644
--- a/test/plugin_functional/plugins/demo_search/package.json
+++ b/examples/demo_search/package.json
@@ -8,7 +8,7 @@
},
"license": "Apache-2.0",
"scripts": {
- "kbn": "node ../../../../scripts/kbn.js",
+ "kbn": "node ../../scripts/kbn.js",
"build": "rm -rf './target' && tsc"
},
"devDependencies": {
diff --git a/test/plugin_functional/plugins/demo_search/public/demo_search_strategy.ts b/examples/demo_search/public/demo_search_strategy.ts
similarity index 96%
rename from test/plugin_functional/plugins/demo_search/public/demo_search_strategy.ts
rename to examples/demo_search/public/demo_search_strategy.ts
index 298eaaaf420e..d2854151e14c 100644
--- a/test/plugin_functional/plugins/demo_search/public/demo_search_strategy.ts
+++ b/examples/demo_search/public/demo_search_strategy.ts
@@ -22,8 +22,8 @@ import {
ISearchContext,
SYNC_SEARCH_STRATEGY,
ISearchGeneric,
-} from '../../../../../src/plugins/data/public';
-import { TSearchStrategyProvider, ISearchStrategy } from '../../../../../src/plugins/data/public';
+} from '../../../src/plugins/data/public';
+import { TSearchStrategyProvider, ISearchStrategy } from '../../../src/plugins/data/public';
import { DEMO_SEARCH_STRATEGY, IDemoResponse } from '../common';
diff --git a/test/plugin_functional/plugins/demo_search/public/index.ts b/examples/demo_search/public/index.ts
similarity index 100%
rename from test/plugin_functional/plugins/demo_search/public/index.ts
rename to examples/demo_search/public/index.ts
diff --git a/test/plugin_functional/plugins/demo_search/public/plugin.ts b/examples/demo_search/public/plugin.ts
similarity index 92%
rename from test/plugin_functional/plugins/demo_search/public/plugin.ts
rename to examples/demo_search/public/plugin.ts
index 37f8d3955708..81ba585b9919 100644
--- a/test/plugin_functional/plugins/demo_search/public/plugin.ts
+++ b/examples/demo_search/public/plugin.ts
@@ -17,8 +17,8 @@
* under the License.
*/
-import { DataPublicPluginSetup } from '../../../../../src/plugins/data/public';
-import { Plugin, CoreSetup, PluginInitializerContext } from '../../../../../src/core/public';
+import { DataPublicPluginSetup } from '../../../src/plugins/data/public';
+import { Plugin, CoreSetup, PluginInitializerContext } from '../../../src/core/public';
import { DEMO_SEARCH_STRATEGY } from '../common';
import { demoClientSearchStrategyProvider } from './demo_search_strategy';
import { IDemoRequest, IDemoResponse } from '../common';
@@ -36,7 +36,7 @@ interface DemoDataSearchSetupDependencies {
* If the caller does not pass in the right `request` shape, typescript will
* complain. The caller will also get a typed response.
*/
-declare module '../../../../../src/plugins/data/public' {
+declare module '../../../src/plugins/data/public' {
export interface IRequestTypesMap {
[DEMO_SEARCH_STRATEGY]: IDemoRequest;
}
diff --git a/test/plugin_functional/plugins/demo_search/server/demo_search_strategy.ts b/examples/demo_search/server/demo_search_strategy.ts
similarity index 94%
rename from test/plugin_functional/plugins/demo_search/server/demo_search_strategy.ts
rename to examples/demo_search/server/demo_search_strategy.ts
index d3f2360add6c..5b0883be1fc5 100644
--- a/test/plugin_functional/plugins/demo_search/server/demo_search_strategy.ts
+++ b/examples/demo_search/server/demo_search_strategy.ts
@@ -17,7 +17,7 @@
* under the License.
*/
-import { TSearchStrategyProvider } from 'src/plugins/data/server';
+import { TSearchStrategyProvider } from '../../../src/plugins/data/server';
import { DEMO_SEARCH_STRATEGY } from '../common';
export const demoSearchStrategyProvider: TSearchStrategyProvider = () => {
diff --git a/test/plugin_functional/plugins/demo_search/server/index.ts b/examples/demo_search/server/index.ts
similarity index 100%
rename from test/plugin_functional/plugins/demo_search/server/index.ts
rename to examples/demo_search/server/index.ts
diff --git a/test/plugin_functional/plugins/demo_search/server/plugin.ts b/examples/demo_search/server/plugin.ts
similarity index 97%
rename from test/plugin_functional/plugins/demo_search/server/plugin.ts
rename to examples/demo_search/server/plugin.ts
index c6628e7c7682..23c82225563c 100644
--- a/test/plugin_functional/plugins/demo_search/server/plugin.ts
+++ b/examples/demo_search/server/plugin.ts
@@ -35,7 +35,7 @@ interface IDemoSearchExplorerDeps {
* If the caller does not pass in the right `request` shape, typescript will
* complain. The caller will also get a typed response.
*/
-declare module '../../../../../src/plugins/data/server' {
+declare module '../../../src/plugins/data/server' {
export interface IRequestTypesMap {
[DEMO_SEARCH_STRATEGY]: IDemoRequest;
}
diff --git a/test/plugin_functional/plugins/demo_search/tsconfig.json b/examples/demo_search/tsconfig.json
similarity index 75%
rename from test/plugin_functional/plugins/demo_search/tsconfig.json
rename to examples/demo_search/tsconfig.json
index 304ffdc0a299..7fa03739119b 100644
--- a/test/plugin_functional/plugins/demo_search/tsconfig.json
+++ b/examples/demo_search/tsconfig.json
@@ -1,5 +1,5 @@
{
- "extends": "../../../../tsconfig.json",
+ "extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./target",
"skipLibCheck": true
@@ -10,7 +10,7 @@
"public/**/*.ts",
"public/**/*.tsx",
"server/**/*.ts",
- "../../../../typings/**/*"
+ "../../typings/**/*"
],
"exclude": []
}
diff --git a/examples/search_explorer/README.md b/examples/search_explorer/README.md
new file mode 100644
index 000000000000..0e5a48cf22dc
--- /dev/null
+++ b/examples/search_explorer/README.md
@@ -0,0 +1,8 @@
+## Search explorer
+
+This example search explorer app shows how to use different search strategies in order to retrieve data.
+
+One demo uses the built in elasticsearch search strategy, and runs a search against data in elasticsearch. The
+other demo uses the custom demo search strategy, a custom search strategy registerd inside the [demo_search plugin](../demo_search).
+
+To run this example, use the command `yarn start --run-examples`.
\ No newline at end of file
diff --git a/test/plugin_functional/plugins/search_explorer/kibana.json b/examples/search_explorer/kibana.json
similarity index 100%
rename from test/plugin_functional/plugins/search_explorer/kibana.json
rename to examples/search_explorer/kibana.json
diff --git a/test/plugin_functional/plugins/search_explorer/package.json b/examples/search_explorer/package.json
similarity index 87%
rename from test/plugin_functional/plugins/search_explorer/package.json
rename to examples/search_explorer/package.json
index 9a5e0e83a220..62d0127c30cc 100644
--- a/test/plugin_functional/plugins/search_explorer/package.json
+++ b/examples/search_explorer/package.json
@@ -8,7 +8,7 @@
},
"license": "Apache-2.0",
"scripts": {
- "kbn": "node ../../../../scripts/kbn.js",
+ "kbn": "node ../../scripts/kbn.js",
"build": "rm -rf './target' && tsc"
},
"devDependencies": {
diff --git a/test/plugin_functional/plugins/search_explorer/public/application.tsx b/examples/search_explorer/public/application.tsx
similarity index 97%
rename from test/plugin_functional/plugins/search_explorer/public/application.tsx
rename to examples/search_explorer/public/application.tsx
index 4762209a548c..801a3c615ac6 100644
--- a/test/plugin_functional/plugins/search_explorer/public/application.tsx
+++ b/examples/search_explorer/public/application.tsx
@@ -28,7 +28,7 @@ import {
EuiSideNav,
} from '@elastic/eui';
-import { AppMountContext, AppMountParameters } from '../../../../../src/core/public';
+import { AppMountContext, AppMountParameters } from '../../../src/core/public';
import { EsSearchTest } from './es_strategy';
import { Page } from './page';
import { DemoStrategy } from './demo_strategy';
diff --git a/test/plugin_functional/plugins/search_explorer/public/demo_strategy.tsx b/examples/search_explorer/public/demo_strategy.tsx
similarity index 98%
rename from test/plugin_functional/plugins/search_explorer/public/demo_strategy.tsx
rename to examples/search_explorer/public/demo_strategy.tsx
index 8a0dd31e3595..7c6c21d2b7ae 100644
--- a/test/plugin_functional/plugins/search_explorer/public/demo_strategy.tsx
+++ b/examples/search_explorer/public/demo_strategy.tsx
@@ -25,7 +25,7 @@ import {
EuiFlexGroup,
EuiFieldText,
} from '@elastic/eui';
-import { ISearchGeneric } from '../../../../../src/plugins/data/public';
+import { ISearchGeneric } from '../../../src/plugins/data/public';
import { DoSearch } from './do_search';
import { GuideSection } from './guide_section';
diff --git a/test/plugin_functional/plugins/search_explorer/public/do_search.tsx b/examples/search_explorer/public/do_search.tsx
similarity index 97%
rename from test/plugin_functional/plugins/search_explorer/public/do_search.tsx
rename to examples/search_explorer/public/do_search.tsx
index e039e4ff3f63..f279b9fcd6e2 100644
--- a/test/plugin_functional/plugins/search_explorer/public/do_search.tsx
+++ b/examples/search_explorer/public/do_search.tsx
@@ -21,10 +21,7 @@ import React from 'react';
import { EuiButton, EuiCodeBlock, EuiFlexItem, EuiFlexGroup, EuiText } from '@elastic/eui';
import { EuiProgress } from '@elastic/eui';
import { Observable } from 'rxjs';
-import {
- IKibanaSearchResponse,
- IKibanaSearchRequest,
-} from '../../../../../src/plugins/data/public';
+import { IKibanaSearchResponse, IKibanaSearchRequest } from '../../../src/plugins/data/public';
interface Props {
request: IKibanaSearchRequest;
diff --git a/test/plugin_functional/plugins/search_explorer/public/documentation.tsx b/examples/search_explorer/public/documentation.tsx
similarity index 100%
rename from test/plugin_functional/plugins/search_explorer/public/documentation.tsx
rename to examples/search_explorer/public/documentation.tsx
diff --git a/test/plugin_functional/plugins/search_explorer/public/es_strategy.tsx b/examples/search_explorer/public/es_strategy.tsx
similarity index 87%
rename from test/plugin_functional/plugins/search_explorer/public/es_strategy.tsx
rename to examples/search_explorer/public/es_strategy.tsx
index d35c67191a1f..e26c11a64666 100644
--- a/test/plugin_functional/plugins/search_explorer/public/es_strategy.tsx
+++ b/examples/search_explorer/public/es_strategy.tsx
@@ -29,19 +29,19 @@ import {
ISearchGeneric,
IEsSearchResponse,
IEsSearchRequest,
-} from '../../../../../src/plugins/data/public';
+} from '../../../src/plugins/data/public';
import { DoSearch } from './do_search';
import { GuideSection } from './guide_section';
// @ts-ignore
-import serverPlugin from '!!raw-loader!./../../../../../src/plugins/data/server/search/es_search/es_search_service';
+import serverPlugin from '!!raw-loader!./../../../src/plugins/data/server/search/es_search/es_search_service';
// @ts-ignore
-import serverStrategy from '!!raw-loader!./../../../../../src/plugins/data/server/search/es_search/es_search_strategy';
+import serverStrategy from '!!raw-loader!./../../../src/plugins/data/server/search/es_search/es_search_strategy';
// @ts-ignore
-import publicPlugin from '!!raw-loader!./../../../../../src/plugins/data/public/search/es_search/es_search_service';
+import publicPlugin from '!!raw-loader!./../../../src/plugins/data/public/search/es_search/es_search_service';
// @ts-ignore
-import publicStrategy from '!!raw-loader!./../../../../../src/plugins/data/public/search/es_search/es_search_strategy';
+import publicStrategy from '!!raw-loader!./../../../src/plugins/data/public/search/es_search/es_search_strategy';
interface Props {
search: ISearchGeneric;
diff --git a/test/plugin_functional/plugins/search_explorer/public/guide_section.tsx b/examples/search_explorer/public/guide_section.tsx
similarity index 100%
rename from test/plugin_functional/plugins/search_explorer/public/guide_section.tsx
rename to examples/search_explorer/public/guide_section.tsx
diff --git a/test/plugin_functional/plugins/search_explorer/public/index.ts b/examples/search_explorer/public/index.ts
similarity index 100%
rename from test/plugin_functional/plugins/search_explorer/public/index.ts
rename to examples/search_explorer/public/index.ts
diff --git a/test/plugin_functional/plugins/search_explorer/public/page.tsx b/examples/search_explorer/public/page.tsx
similarity index 100%
rename from test/plugin_functional/plugins/search_explorer/public/page.tsx
rename to examples/search_explorer/public/page.tsx
diff --git a/test/plugin_functional/plugins/search_explorer/public/plugin.tsx b/examples/search_explorer/public/plugin.tsx
similarity index 94%
rename from test/plugin_functional/plugins/search_explorer/public/plugin.tsx
rename to examples/search_explorer/public/plugin.tsx
index cbe1073aa186..a7a6fd11341a 100644
--- a/test/plugin_functional/plugins/search_explorer/public/plugin.tsx
+++ b/examples/search_explorer/public/plugin.tsx
@@ -18,7 +18,7 @@
*/
import { Plugin, CoreSetup } from 'kibana/public';
-import { ISearchAppMountContext } from '../../../../../src/plugins/data/public';
+import { ISearchAppMountContext } from '../../../src/plugins/data/public';
declare module 'kibana/public' {
interface AppMountContext {
diff --git a/test/plugin_functional/plugins/search_explorer/public/search_api.tsx b/examples/search_explorer/public/search_api.tsx
similarity index 70%
rename from test/plugin_functional/plugins/search_explorer/public/search_api.tsx
rename to examples/search_explorer/public/search_api.tsx
index 8ec6225d1f17..fc68571e4ef6 100644
--- a/test/plugin_functional/plugins/search_explorer/public/search_api.tsx
+++ b/examples/search_explorer/public/search_api.tsx
@@ -20,22 +20,22 @@ import React from 'react';
import { GuideSection } from './guide_section';
// @ts-ignore
-import publicSetupContract from '!!raw-loader!./../../../../../src/plugins/data/public/search/i_search_setup';
+import publicSetupContract from '!!raw-loader!./../../../src/plugins/data/public/search/i_search_setup';
// @ts-ignore
-import publicSearchStrategy from '!!raw-loader!./../../../../../src/plugins/data/public/search/i_search_strategy';
+import publicSearchStrategy from '!!raw-loader!./../../../src/plugins/data/public/search/i_search_strategy';
// @ts-ignore
-import publicSearch from '!!raw-loader!./../../../../../src/plugins/data/public/search/i_search';
+import publicSearch from '!!raw-loader!./../../../src/plugins/data/public/search/i_search';
// @ts-ignore
-import publicPlugin from '!!raw-loader!./../../../../../src/plugins/data/public/search/search_service';
+import publicPlugin from '!!raw-loader!./../../../src/plugins/data/public/search/search_service';
// @ts-ignore
-import serverSetupContract from '!!raw-loader!./../../../../../src/plugins/data/server/search/i_search_setup';
+import serverSetupContract from '!!raw-loader!./../../../src/plugins/data/server/search/i_search_setup';
// @ts-ignore
-import serverSearchStrategy from '!!raw-loader!./../../../../../src/plugins/data/server/search/i_search_strategy';
+import serverSearchStrategy from '!!raw-loader!./../../../src/plugins/data/server/search/i_search_strategy';
// @ts-ignore
-import serverSearch from '!!raw-loader!./../../../../../src/plugins/data/server/search/i_search';
+import serverSearch from '!!raw-loader!./../../../src/plugins/data/server/search/i_search';
// @ts-ignore
-import serverPlugin from '!!raw-loader!./../../../../../src/plugins/data/server/search/search_service';
+import serverPlugin from '!!raw-loader!./../../../src/plugins/data/server/search/search_service';
export const SearchApiPage = () => (
- str.length >= width ? str : `${str}${' '.repeat(width - str.length)}`;
-
-run(
- async ({ log, flags }) => {
- await withProcRunner(log, async proc => {
- log.info('Deleting old output');
- await del(BUILD_DIR);
-
- const cwd = ROOT_DIR;
- const env = { ...process.env };
- if (supportsColor.stdout) {
- env.FORCE_COLOR = 'true';
- }
-
- log.info(`Starting babel and typescript${flags.watch ? ' in watch mode' : ''}`);
- await Promise.all([
- ...['web', 'node'].map(subTask =>
- proc.run(padRight(10, `babel:${subTask}`), {
- cmd: 'babel',
- args: [
- 'src',
- '--config-file',
- require.resolve('../babel.config.js'),
- '--out-dir',
- resolve(BUILD_DIR, subTask),
- '--extensions',
- '.ts,.js,.tsx',
- ...(flags.watch ? ['--watch'] : ['--quiet']),
- ...(flags['source-maps'] ? ['--source-map', 'inline'] : []),
- ],
- wait: true,
- env: {
- ...env,
- BABEL_ENV: subTask,
- },
- cwd,
- })
- ),
-
- proc.run(padRight(10, 'tsc'), {
- cmd: 'tsc',
- args: [
- '--emitDeclarationOnly',
- ...(flags.watch ? ['--watch', '--preserveWatchOutput', 'true'] : []),
- ...(flags['source-maps'] ? ['--declarationMap', 'true'] : []),
- ],
- wait: true,
- env,
- cwd,
- }),
- ]);
-
- log.success('Complete');
- });
- },
- {
- description: 'Simple build tool for @kbn/analytics package',
- flags: {
- boolean: ['watch', 'source-maps'],
- help: `
- --watch Run in watch mode
- --source-maps Include sourcemaps
- `,
- },
- }
-);
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+const { resolve } = require('path');
+
+const del = require('del');
+const supportsColor = require('supports-color');
+const { run, withProcRunner } = require('@kbn/dev-utils');
+
+const ROOT_DIR = resolve(__dirname, '..');
+const BUILD_DIR = resolve(ROOT_DIR, 'target');
+
+const padRight = (width, str) =>
+ str.length >= width ? str : `${str}${' '.repeat(width - str.length)}`;
+
+run(
+ async ({ log, flags }) => {
+ await withProcRunner(log, async proc => {
+ log.info('Deleting old output');
+ await del(BUILD_DIR);
+
+ const cwd = ROOT_DIR;
+ const env = { ...process.env };
+ if (supportsColor.stdout) {
+ env.FORCE_COLOR = 'true';
+ }
+
+ log.info(`Starting babel and typescript${flags.watch ? ' in watch mode' : ''}`);
+ await Promise.all([
+ ...['web', 'node'].map(subTask =>
+ proc.run(padRight(10, `babel:${subTask}`), {
+ cmd: 'babel',
+ args: [
+ 'src',
+ '--config-file',
+ require.resolve('../babel.config.js'),
+ '--out-dir',
+ resolve(BUILD_DIR, subTask),
+ '--extensions',
+ '.ts,.js,.tsx',
+ ...(flags.watch ? ['--watch'] : ['--quiet']),
+ ...(flags['source-maps'] ? ['--source-maps', 'inline'] : []),
+ ],
+ wait: true,
+ env: {
+ ...env,
+ BABEL_ENV: subTask,
+ },
+ cwd,
+ })
+ ),
+
+ proc.run(padRight(10, 'tsc'), {
+ cmd: 'tsc',
+ args: [
+ '--emitDeclarationOnly',
+ ...(flags.watch ? ['--watch', '--preserveWatchOutput', 'true'] : []),
+ ...(flags['source-maps'] ? ['--declarationMap', 'true'] : []),
+ ],
+ wait: true,
+ env,
+ cwd,
+ }),
+ ]);
+
+ log.success('Complete');
+ });
+ },
+ {
+ description: 'Simple build tool for @kbn/analytics package',
+ flags: {
+ boolean: ['watch', 'source-maps'],
+ help: `
+ --watch Run in watch mode
+ --source-maps Include sourcemaps
+ `,
+ },
+ }
+);
diff --git a/packages/kbn-i18n/scripts/build.js b/packages/kbn-i18n/scripts/build.js
index f4260d31d80f..ccdddc87dbc1 100644
--- a/packages/kbn-i18n/scripts/build.js
+++ b/packages/kbn-i18n/scripts/build.js
@@ -55,7 +55,7 @@ run(
'--extensions',
'.ts,.js,.tsx',
...(flags.watch ? ['--watch'] : ['--quiet']),
- ...(flags['source-maps'] ? ['--source-map', 'inline'] : []),
+ ...(flags['source-maps'] ? ['--source-maps', 'inline'] : []),
],
wait: true,
env: {
diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js
index bbe12a93c241..aea85c13d7f3 100644
--- a/packages/kbn-pm/dist/index.js
+++ b/packages/kbn-pm/dist/index.js
@@ -23185,6 +23185,7 @@ function getProjectPaths(rootPath, options = {}) {
projectPaths.push(Object(path__WEBPACK_IMPORTED_MODULE_0__["resolve"])(rootPath, 'test/plugin_functional/plugins/*'));
projectPaths.push(Object(path__WEBPACK_IMPORTED_MODULE_0__["resolve"])(rootPath, 'test/interpreter_functional/plugins/*'));
+ projectPaths.push(Object(path__WEBPACK_IMPORTED_MODULE_0__["resolve"])(rootPath, 'examples/*'));
if (!ossOnly) {
projectPaths.push(Object(path__WEBPACK_IMPORTED_MODULE_0__["resolve"])(rootPath, 'x-pack'));
diff --git a/packages/kbn-pm/src/config.ts b/packages/kbn-pm/src/config.ts
index 4886b0c266a8..2e42a182e7ec 100644
--- a/packages/kbn-pm/src/config.ts
+++ b/packages/kbn-pm/src/config.ts
@@ -44,6 +44,7 @@ export function getProjectPaths(rootPath: string, options: IProjectPathOptions =
// correct and the expect behavior.
projectPaths.push(resolve(rootPath, 'test/plugin_functional/plugins/*'));
projectPaths.push(resolve(rootPath, 'test/interpreter_functional/plugins/*'));
+ projectPaths.push(resolve(rootPath, 'examples/*'));
if (!ossOnly) {
projectPaths.push(resolve(rootPath, 'x-pack'));
diff --git a/renovate.json5 b/renovate.json5
index 3886715618e9..e4cb02604f50 100644
--- a/renovate.json5
+++ b/renovate.json5
@@ -13,6 +13,7 @@
'x-pack/package.json',
'x-pack/legacy/plugins/*/package.json',
'packages/*/package.json',
+ 'examples/*/package.json',
'test/plugin_functional/plugins/*/package.json',
'test/interpreter_functional/plugins/*/package.json',
],
diff --git a/scripts/functional_tests.js b/scripts/functional_tests.js
index b65cd3835cc0..2526e2b14e9a 100644
--- a/scripts/functional_tests.js
+++ b/scripts/functional_tests.js
@@ -24,4 +24,5 @@ require('@kbn/test').runTestsCli([
require.resolve('../test/plugin_functional/config.js'),
require.resolve('../test/interpreter_functional/config.ts'),
require.resolve('../test/ui_capabilities/newsfeed_err/config.ts'),
+ require.resolve('../test/examples/config.js')
]);
diff --git a/src/cli/serve/serve.js b/src/cli/serve/serve.js
index 48b5db318d1c..fd0502e07e42 100644
--- a/src/cli/serve/serve.js
+++ b/src/cli/serve/serve.js
@@ -144,6 +144,11 @@ function applyConfigOverrides(rawConfig, opts, extraCliOptions) {
set('plugins.paths', _.compact([].concat(
get('plugins.paths'),
opts.pluginPath,
+ opts.runExamples ? [
+ // Ideally this would automatically include all plugins in the examples dir
+ fromRoot('examples/demo_search'),
+ fromRoot('examples/search_explorer'),
+ ] : [],
XPACK_INSTALLED && !opts.oss
? [XPACK_DIR]
@@ -201,7 +206,8 @@ export default function (program) {
if (!IS_KIBANA_DISTRIBUTABLE) {
command
- .option('--oss', 'Start Kibana without X-Pack');
+ .option('--oss', 'Start Kibana without X-Pack')
+ .option('--run-examples', 'Adds plugin paths for all the Kibana example plugins and runs with no base path');
}
if (CAN_CLUSTER) {
@@ -238,7 +244,12 @@ export default function (program) {
silent: !!opts.silent,
watch: !!opts.watch,
repl: !!opts.repl,
- basePath: !!opts.basePath,
+ // We want to run without base path when the `--run-examples` flag is given so that we can use local
+ // links in other documentation sources, like "View this tutorial [here](http://localhost:5601/app/tutorial/xyz)".
+ // We can tell users they only have to run with `yarn start --run-examples` to get those
+ // local links to work. Similar to what we do for "View in Console" links in our
+ // elastic.co links.
+ basePath: opts.runExamples ? false : !!opts.basePath,
optimize: !!opts.optimize,
oss: !!opts.oss
},
diff --git a/src/dev/register_git_hook/register_git_hook.js b/src/dev/register_git_hook/register_git_hook.js
index a61922078e68..31136cab0ada 100644
--- a/src/dev/register_git_hook/register_git_hook.js
+++ b/src/dev/register_git_hook/register_git_hook.js
@@ -58,6 +58,15 @@ function getKbnPrecommitGitHookScript(rootPath, nodeHome, platform) {
set -euo pipefail
+ # Make it possible to terminate pre commit hook
+ # using ctrl-c so nothing else would happen or be
+ # sent to the output.
+ #
+ # The correct exit code on that situation
+ # according the linux documentation project is 130
+ # https://www.tldp.org/LDP/abs/html/exitcodes.html
+ trap "exit 130" SIGINT
+
has_node() {
command -v node >/dev/null 2>&1
}
diff --git a/src/dev/renovate/package_globs.ts b/src/dev/renovate/package_globs.ts
index dd98f929be8e..825e6ffed0ec 100644
--- a/src/dev/renovate/package_globs.ts
+++ b/src/dev/renovate/package_globs.ts
@@ -28,6 +28,7 @@ export const PACKAGE_GLOBS = [
'x-pack/package.json',
'x-pack/legacy/plugins/*/package.json',
'packages/*/package.json',
+ 'examples/*/package.json',
'test/plugin_functional/plugins/*/package.json',
'test/interpreter_functional/plugins/*/package.json',
];
diff --git a/src/dev/typescript/projects.ts b/src/dev/typescript/projects.ts
index 2f8894f77ebc..602657ad7383 100644
--- a/src/dev/typescript/projects.ts
+++ b/src/dev/typescript/projects.ts
@@ -40,6 +40,9 @@ export const PROJECTS = [
...glob
.sync('packages/*/tsconfig.json', { cwd: REPO_ROOT })
.map(path => new Project(resolve(REPO_ROOT, path))),
+ ...glob
+ .sync('examples/*/tsconfig.json', { cwd: REPO_ROOT })
+ .map(path => new Project(resolve(REPO_ROOT, path))),
...glob
.sync('test/plugin_functional/plugins/*/tsconfig.json', { cwd: REPO_ROOT })
.map(path => new Project(resolve(REPO_ROOT, path))),
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/__tests__/__snapshots__/dashboard_empty_screen.test.tsx.snap b/src/legacy/core_plugins/kibana/public/dashboard/__tests__/__snapshots__/dashboard_empty_screen.test.tsx.snap
index 07e4173d5323..8410040a0100 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/__tests__/__snapshots__/dashboard_empty_screen.test.tsx.snap
+++ b/src/legacy/core_plugins/kibana/public/dashboard/__tests__/__snapshots__/dashboard_empty_screen.test.tsx.snap
@@ -193,78 +193,160 @@ exports[`DashboardEmptyScreen renders correctly with visualize paragraph 1`] = `
textComponent={Symbol(react.fragment)}
>
-
-
-
-
-
-
- This dashboard is empty. Let’s fill it up!
-
-
-
- Click the
-
-
- Add
-
-
- button in the menu bar above to add a visualization to the dashboard.
-
-
-
-
- visit the Visualize app
- ,
+ "maxWidth": "36em",
}
}
>
- If you haven't set up any visualizations yet,
-
- visit the Visualize app
-
- to create your first visualization
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This dashboard is empty. Let’s fill it up!
+
+
+
+
+
+
+
+
+
+ Click the
+
+
+ Add
+
+
+ button in the menu bar above to add a visualization to the dashboard.
+
+
+
+
+
+
+
+
+
+
+ visit the Visualize app
+ ,
+ }
+ }
+ >
+ If you haven't set up any visualizations yet,
+
+ visit the Visualize app
+
+ to create your first visualization
+
+
+
+
+
+
+
+
+
+
+
@@ -464,51 +546,119 @@ exports[`DashboardEmptyScreen renders correctly without visualize paragraph 1`]
textComponent={Symbol(react.fragment)}
>
-
-
-
-
-
-
- This dashboard is empty. Let’s fill it up!
-
-
-
- Click the
-
-
- Edit
-
-
- button in the menu bar above to start working on your new dashboard.
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This dashboard is empty. Let’s fill it up!
+
+
+
+
+
+
+
+
+
+ Click the
+
+
+ Edit
+
+
+ button in the menu bar above to start working on your new dashboard.
+
+
+
+
+
+
+
+
+
+
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/__tests__/dashboard_empty_screen.test.tsx b/src/legacy/core_plugins/kibana/public/dashboard/__tests__/dashboard_empty_screen.test.tsx
index a4604d17ddec..69bdcf59bb22 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/__tests__/dashboard_empty_screen.test.tsx
+++ b/src/legacy/core_plugins/kibana/public/dashboard/__tests__/dashboard_empty_screen.test.tsx
@@ -18,7 +18,9 @@
*/
import React from 'react';
import { mountWithIntl } from 'test_utils/enzyme_helpers';
-import { DashboardEmptyScreen, Props } from '../dashboard_empty_screen';
+import { DashboardEmptyScreen, DashboardEmptyScreenProps } from '../dashboard_empty_screen';
+// @ts-ignore
+import { findTestSubject } from '@elastic/eui/lib/test';
describe('DashboardEmptyScreen', () => {
const defaultProps = {
@@ -26,7 +28,7 @@ describe('DashboardEmptyScreen', () => {
onLinkClick: jest.fn(),
};
- function mountComponent(props?: Props) {
+ function mountComponent(props?: DashboardEmptyScreenProps) {
const compProps = props || defaultProps;
const comp = mountWithIntl( );
return comp;
@@ -35,14 +37,14 @@ describe('DashboardEmptyScreen', () => {
test('renders correctly with visualize paragraph', () => {
const component = mountComponent();
expect(component).toMatchSnapshot();
- const paragraph = component.find('.linkToVisualizeParagraph');
+ const paragraph = findTestSubject(component, 'linkToVisualizeParagraph');
expect(paragraph.length).toBe(1);
});
test('renders correctly without visualize paragraph', () => {
const component = mountComponent({ ...defaultProps, ...{ showLinkToVisualize: false } });
expect(component).toMatchSnapshot();
- const paragraph = component.find('.linkToVisualizeParagraph');
+ const paragraph = findTestSubject(component, 'linkToVisualizeParagraph');
expect(paragraph.length).toBe(0);
});
});
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/_dashboard_app.scss b/src/legacy/core_plugins/kibana/public/dashboard/_dashboard_app.scss
index 14c35759d70a..d9eadf6c0e37 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/_dashboard_app.scss
+++ b/src/legacy/core_plugins/kibana/public/dashboard/_dashboard_app.scss
@@ -6,9 +6,5 @@
.dshStartScreen {
text-align: center;
- padding: $euiSize;
-
- > * {
- max-width: 36em !important;
- }
+ padding: $euiSizeS;
}
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/application.ts b/src/legacy/core_plugins/kibana/public/dashboard/application.ts
index b58325a77e61..ef1bcab589c4 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/application.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/application.ts
@@ -131,7 +131,6 @@ function createLocalAngularModule(core: AppMountContext['core'], navigation: Nav
'app/dashboard/State',
'app/dashboard/ConfirmModal',
'app/dashboard/icon',
- 'app/dashboard/emptyScreen',
]);
return dashboardAngularModule;
}
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.html b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.html
index c7fd8600b73b..3cf8932958b6 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.html
+++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.html
@@ -48,24 +48,6 @@
>
-
-
{{screenTitle}}
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx
index 7eac251a532c..fd49b26e0d94 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx
+++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx
@@ -21,9 +21,10 @@ import _ from 'lodash';
import { i18n } from '@kbn/i18n';
import React from 'react';
import angular from 'angular';
-import { uniq } from 'lodash';
+import { uniq, noop } from 'lodash';
import { Subscription } from 'rxjs';
+import { DashboardEmptyScreen, DashboardEmptyScreenProps } from './dashboard_empty_screen';
import {
subscribeWithScope,
@@ -35,14 +36,11 @@ import {
AppStateClass as TAppStateClass,
KbnUrl,
SaveOptions,
- SavedObjectFinder,
unhashUrl,
} from './legacy_imports';
import { FilterStateManager, IndexPattern } from '../../../data/public';
import { Query, SavedQuery, IndexPatternsContract } from '../../../../../plugins/data/public';
-import './dashboard_empty_screen_directive';
-
import {
DashboardContainer,
DASHBOARD_CONTAINER_TYPE,
@@ -71,6 +69,10 @@ import { DashboardAppScope } from './dashboard_app';
import { VISUALIZE_EMBEDDABLE_TYPE } from '../visualize/embeddable';
import { convertSavedDashboardPanelToPanelState } from './lib/embeddable_saved_object_converters';
import { RenderDeps } from './application';
+import {
+ SavedObjectFinderProps,
+ SavedObjectFinderUi,
+} from '../../../../../plugins/kibana_react/public';
export interface DashboardAppControllerDependencies extends RenderDeps {
$scope: DashboardAppScope;
@@ -115,7 +117,7 @@ export class DashboardAppController {
timefilter: { timefilter },
},
},
- core: { notifications, overlays, chrome, injectedMetadata },
+ core: { notifications, overlays, chrome, injectedMetadata, uiSettings, savedObjects },
}: DashboardAppControllerDependencies) {
new FilterStateManager(globalState, getAppState, filterManager);
const queryFilter = filterManager;
@@ -143,6 +145,16 @@ export class DashboardAppController {
}
$scope.showSaveQuery = dashboardCapabilities.saveQuery as boolean;
+ $scope.getShouldShowEditHelp = () =>
+ !dashboardStateManager.getPanels().length &&
+ dashboardStateManager.getIsEditMode() &&
+ !dashboardConfig.getHideWriteControls();
+
+ $scope.getShouldShowViewHelp = () =>
+ !dashboardStateManager.getPanels().length &&
+ dashboardStateManager.getIsViewMode() &&
+ !dashboardConfig.getHideWriteControls();
+
const updateIndexPatterns = (container?: DashboardContainer) => {
if (!container || isErrorEmbeddable(container)) {
return;
@@ -171,6 +183,17 @@ export class DashboardAppController {
}
};
+ const getEmptyScreenProps = (shouldShowEditHelp: boolean): DashboardEmptyScreenProps => {
+ const emptyScreenProps: DashboardEmptyScreenProps = {
+ onLinkClick: shouldShowEditHelp ? $scope.showAddPanel : $scope.enterEditMode,
+ showLinkToVisualize: shouldShowEditHelp,
+ };
+ if (shouldShowEditHelp) {
+ emptyScreenProps.onVisualizeClick = noop;
+ }
+ return emptyScreenProps;
+ };
+
const getDashboardInput = (): DashboardContainerInput => {
const embeddablesMap: {
[key: string]: DashboardPanelState;
@@ -182,6 +205,8 @@ export class DashboardAppController {
if (dashboardContainer && !isErrorEmbeddable(dashboardContainer)) {
expandedPanelId = dashboardContainer.getInput().expandedPanelId;
}
+ const shouldShowEditHelp = $scope.getShouldShowEditHelp();
+ const shouldShowViewHelp = $scope.getShouldShowViewHelp();
return {
id: dashboardStateManager.savedDashboard.id || '',
filters: queryFilter.getFilters(),
@@ -194,6 +219,7 @@ export class DashboardAppController {
viewMode: dashboardStateManager.getViewMode(),
panels: embeddablesMap,
isFullScreenMode: dashboardStateManager.getFullScreenMode(),
+ isEmptyState: shouldShowEditHelp || shouldShowViewHelp,
useMargins: dashboardStateManager.getUseMargins(),
lastReloadRequestTime,
title: dashboardStateManager.getTitle(),
@@ -234,6 +260,15 @@ export class DashboardAppController {
if (!isErrorEmbeddable(container)) {
dashboardContainer = container;
+ dashboardContainer.renderEmpty = () => {
+ const shouldShowEditHelp = $scope.getShouldShowEditHelp();
+ const shouldShowViewHelp = $scope.getShouldShowViewHelp();
+ const isEmptyState = shouldShowEditHelp || shouldShowViewHelp;
+ return isEmptyState ? (
+
+ ) : null;
+ };
+
updateIndexPatterns(dashboardContainer);
outputSubscription = dashboardContainer.getOutput$().subscribe(() => {
@@ -334,15 +369,6 @@ export class DashboardAppController {
updateBreadcrumbs();
dashboardStateManager.registerChangeListener(updateBreadcrumbs);
- $scope.getShouldShowEditHelp = () =>
- !dashboardStateManager.getPanels().length &&
- dashboardStateManager.getIsEditMode() &&
- !dashboardConfig.getHideWriteControls();
- $scope.getShouldShowViewHelp = () =>
- !dashboardStateManager.getPanels().length &&
- dashboardStateManager.getIsViewMode() &&
- !dashboardConfig.getHideWriteControls();
-
const getChangesFromAppStateForContainerState = () => {
const appStateDashboardInput = getDashboardInput();
if (!dashboardContainer || isErrorEmbeddable(dashboardContainer)) {
@@ -718,6 +744,10 @@ export class DashboardAppController {
};
navActions[TopNavIds.ADD] = () => {
if (dashboardContainer && !isErrorEmbeddable(dashboardContainer)) {
+ const SavedObjectFinder = (props: SavedObjectFinderProps) => (
+
+ );
+
openAddPanelFlyout({
embeddable: dashboardContainer,
getAllFactories: embeddables.getEmbeddableFactories,
@@ -729,6 +759,8 @@ export class DashboardAppController {
}
};
+ navActions[TopNavIds.VISUALIZE] = async () => {};
+
navActions[TopNavIds.OPTIONS] = anchorElement => {
showOptionsPopover({
anchorElement,
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen.tsx b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen.tsx
index d5a4e6e6a325..234228ba4166 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen.tsx
+++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen.tsx
@@ -18,29 +18,43 @@
*/
import React from 'react';
import { I18nProvider, FormattedMessage } from '@kbn/i18n/react';
-import { EuiIcon, EuiLink } from '@elastic/eui';
+import {
+ EuiIcon,
+ EuiLink,
+ EuiSpacer,
+ EuiPageContent,
+ EuiPageBody,
+ EuiPage,
+ EuiText,
+} from '@elastic/eui';
import * as constants from './dashboard_empty_screen_constants';
-export interface Props {
+export interface DashboardEmptyScreenProps {
showLinkToVisualize: boolean;
onLinkClick: () => void;
+ onVisualizeClick?: () => void;
}
-export function DashboardEmptyScreen({ showLinkToVisualize, onLinkClick }: Props) {
+export function DashboardEmptyScreen({
+ showLinkToVisualize,
+ onLinkClick,
+}: DashboardEmptyScreenProps) {
const linkToVisualizeParagraph = (
-
-
- {constants.visualizeAppLinkTest}
-
- ),
- }}
- />
-
+
+
+
+ {constants.visualizeAppLinkTest}
+
+ ),
+ }}
+ />
+
+
);
const paragraph = (
description1: string,
@@ -50,15 +64,15 @@ export function DashboardEmptyScreen({ showLinkToVisualize, onLinkClick }: Props
dataTestSubj?: string
) => {
return (
-
-
+
+
{description1}
{linkText}
{description2}
-
-
+
+
);
};
const addVisualizationParagraph = (
@@ -70,6 +84,7 @@ export function DashboardEmptyScreen({ showLinkToVisualize, onLinkClick }: Props
constants.addVisualizationLinkAriaLabel,
'emptyDashboardAddPanelButton'
)}
+
{linkToVisualizeParagraph}
);
@@ -81,11 +96,19 @@ export function DashboardEmptyScreen({ showLinkToVisualize, onLinkClick }: Props
);
return (
-
-
- {constants.fillDashboardTitle}
- {showLinkToVisualize ? addVisualizationParagraph : enterEditModeParagraph}
-
+
+
+
+
+
+
+ {constants.fillDashboardTitle}
+
+
+ {showLinkToVisualize ? addVisualizationParagraph : enterEditModeParagraph}
+
+
+
);
}
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts b/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts
index b0f09f0cf974..af0a833399a5 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts
@@ -65,4 +65,3 @@ export { stateMonitorFactory, StateMonitor } from 'ui/state_management/state_mon
export { ensureDefaultIndexPattern } from 'ui/legacy_compat';
export { unhashUrl } from '../../../../../plugins/kibana_utils/public';
export { IInjector } from 'ui/chrome';
-export { SavedObjectFinder } from 'ui/saved_objects/components/saved_object_finder';
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/top_nav/top_nav_ids.ts b/src/legacy/core_plugins/kibana/public/dashboard/top_nav/top_nav_ids.ts
index 9df86f2ca3cc..c67d6891c18e 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/top_nav/top_nav_ids.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/top_nav/top_nav_ids.ts
@@ -26,4 +26,5 @@ export const TopNavIds = {
ENTER_EDIT_MODE: 'enterEditMode',
CLONE: 'clone',
FULL_SCREEN: 'fullScreenMode',
+ VISUALIZE: 'visualize',
};
diff --git a/src/legacy/core_plugins/kibana/public/discover/components/top_nav/__snapshots__/open_search_panel.test.js.snap b/src/legacy/core_plugins/kibana/public/discover/components/top_nav/__snapshots__/open_search_panel.test.js.snap
index cc53e4bdcdcf..2878b11040cf 100644
--- a/src/legacy/core_plugins/kibana/public/discover/components/top_nav/__snapshots__/open_search_panel.test.js.snap
+++ b/src/legacy/core_plugins/kibana/public/discover/components/top_nav/__snapshots__/open_search_panel.test.js.snap
@@ -26,7 +26,7 @@ exports[`render 1`] = `
-
diff --git a/src/legacy/core_plugins/kibana/public/discover/components/top_nav/open_search_panel.js b/src/legacy/core_plugins/kibana/public/discover/components/top_nav/open_search_panel.js
index 0c3b52fbf064..ec1763f44f25 100644
--- a/src/legacy/core_plugins/kibana/public/discover/components/top_nav/open_search_panel.js
+++ b/src/legacy/core_plugins/kibana/public/discover/components/top_nav/open_search_panel.js
@@ -32,11 +32,16 @@ import {
EuiFlyoutBody,
EuiTitle,
} from '@elastic/eui';
-import { SavedObjectFinder } from 'ui/saved_objects/components/saved_object_finder';
+import { SavedObjectFinderUi } from '../../../../../../../plugins/kibana_react/public';
+import { getServices } from '../../kibana_services';
const SEARCH_OBJECT_TYPE = 'search';
export function OpenSearchPanel(props) {
+ const {
+ core: { uiSettings, savedObjects },
+ } = getServices();
+
return (
@@ -50,7 +55,7 @@ export function OpenSearchPanel(props) {
-
diff --git a/src/legacy/core_plugins/kibana/public/discover/components/top_nav/open_search_panel.test.js b/src/legacy/core_plugins/kibana/public/discover/components/top_nav/open_search_panel.test.js
index ea5c0ef39604..0c82aeea9529 100644
--- a/src/legacy/core_plugins/kibana/public/discover/components/top_nav/open_search_panel.test.js
+++ b/src/legacy/core_plugins/kibana/public/discover/components/top_nav/open_search_panel.test.js
@@ -23,7 +23,7 @@ import { shallow } from 'enzyme';
jest.mock('../../kibana_services', () => {
return {
getServices: () => ({
- SavedObjectFinder: jest.fn()
+ core: { uiSettings: {}, savedObjects: {} },
}),
};
});
diff --git a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx
index 7c9efa280c9f..a377dafe9e51 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx
+++ b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx
@@ -199,7 +199,8 @@ export class VisualizeEmbeddableFactory extends EmbeddableFactory<
editorParams: ['addToDashboard'],
},
npStart.core.http.basePath.prepend,
- npStart.core.uiSettings
+ npStart.core.uiSettings,
+ npStart.core.savedObjects
);
}
return undefined;
diff --git a/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts b/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts
index 6adcfd2cc718..b9909e522b57 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts
+++ b/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts
@@ -45,7 +45,6 @@ export { PrivateProvider } from 'ui/private/private';
export { SavedObjectRegistryProvider } from 'ui/saved_objects';
export { SavedObjectSaveModal } from 'ui/saved_objects/components/saved_object_save_modal';
-export { SavedObjectFinder } from 'ui/saved_objects/components/saved_object_finder';
export { showSaveModal } from 'ui/saved_objects/show_saved_object_save_modal';
export { subscribeWithScope } from 'ui/utils/subscribe_with_scope';
diff --git a/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.html b/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.html
index 4511ac61f739..4ee8809fab22 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.html
+++ b/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.html
@@ -16,6 +16,7 @@
vis-types-registry="listingController.visTypeRegistry"
add-base-path="listingController.addBasePath"
ui-settings="listingController.uiSettings"
+ saved-objects="listingController.savedObjects"
>
diff --git a/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.js b/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.js
index 9b02be0581b8..b1ed5ce81d6e 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.js
@@ -34,6 +34,7 @@ export function initListingDirective(app) {
['onClose', { watchDepth: 'reference' }],
['addBasePath', { watchDepth: 'reference' }],
['uiSettings', { watchDepth: 'reference' }],
+ ['savedObjects', { watchDepth: 'reference' }],
'isOpen',
])
);
@@ -54,7 +55,7 @@ export function VisualizeListingController($injector, createNewVis) {
toastNotifications,
uiSettings,
visualizations,
- core: { docLinks },
+ core: { docLinks, savedObjects },
} = getServices();
const kbnUrl = $injector.get('kbnUrl');
@@ -64,6 +65,7 @@ export function VisualizeListingController($injector, createNewVis) {
this.showNewVisModal = false;
this.addBasePath = addBasePath;
this.uiSettings = uiSettings;
+ this.savedObjects = savedObjects;
this.createNewVis = () => {
this.showNewVisModal = true;
diff --git a/src/legacy/core_plugins/kibana/public/visualize/wizard/__snapshots__/new_vis_modal.test.tsx.snap b/src/legacy/core_plugins/kibana/public/visualize/wizard/__snapshots__/new_vis_modal.test.tsx.snap
index 5be5f5899488..04b7cddc7528 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/wizard/__snapshots__/new_vis_modal.test.tsx.snap
+++ b/src/legacy/core_plugins/kibana/public/visualize/wizard/__snapshots__/new_vis_modal.test.tsx.snap
@@ -108,6 +108,7 @@ exports[`NewVisModal filter for visualization types should render as expected 1`
}
isOpen={true}
onClose={[Function]}
+ savedObjects={Object {}}
uiSettings={
Object {
"get": [MockFunction] {
@@ -1413,6 +1414,7 @@ exports[`NewVisModal should render as expected 1`] = `
}
isOpen={true}
onClose={[Function]}
+ savedObjects={Object {}}
uiSettings={
Object {
"get": [MockFunction] {
diff --git a/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.test.tsx b/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.test.tsx
index 0dd2091bbfee..4eafd06c7bb2 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.test.tsx
+++ b/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.test.tsx
@@ -29,6 +29,7 @@ jest.mock('../legacy_imports', () => ({
}));
import { NewVisModal } from './new_vis_modal';
+import { SavedObjectsStart } from 'kibana/public';
describe('NewVisModal', () => {
const defaultVisTypeParams = {
@@ -76,6 +77,7 @@ describe('NewVisModal', () => {
visTypesRegistry={visTypes}
addBasePath={addBasePath}
uiSettings={uiSettings}
+ savedObjects={{} as SavedObjectsStart}
/>
);
expect(wrapper).toMatchSnapshot();
@@ -89,6 +91,7 @@ describe('NewVisModal', () => {
visTypesRegistry={visTypes}
addBasePath={addBasePath}
uiSettings={uiSettings}
+ savedObjects={{} as SavedObjectsStart}
/>
);
expect(wrapper.find('[data-test-subj="visType-vis"]').exists()).toBe(true);
@@ -104,6 +107,7 @@ describe('NewVisModal', () => {
visTypesRegistry={visTypes}
addBasePath={addBasePath}
uiSettings={uiSettings}
+ savedObjects={{} as SavedObjectsStart}
/>
);
const visButton = wrapper.find('button[data-test-subj="visType-vis"]');
@@ -121,6 +125,7 @@ describe('NewVisModal', () => {
editorParams={['foo=true', 'bar=42']}
addBasePath={addBasePath}
uiSettings={uiSettings}
+ savedObjects={{} as SavedObjectsStart}
/>
);
const visButton = wrapper.find('button[data-test-subj="visType-vis"]');
@@ -138,6 +143,7 @@ describe('NewVisModal', () => {
visTypesRegistry={visTypes}
addBasePath={addBasePath}
uiSettings={uiSettings}
+ savedObjects={{} as SavedObjectsStart}
/>
);
const searchBox = wrapper.find('input[data-test-subj="filterVisType"]');
@@ -156,6 +162,7 @@ describe('NewVisModal', () => {
visTypesRegistry={visTypes}
addBasePath={addBasePath}
uiSettings={uiSettings}
+ savedObjects={{} as SavedObjectsStart}
/>
);
expect(wrapper.find('[data-test-subj="visType-visExp"]').exists()).toBe(false);
@@ -170,6 +177,7 @@ describe('NewVisModal', () => {
visTypesRegistry={visTypes}
addBasePath={addBasePath}
uiSettings={uiSettings}
+ savedObjects={{} as SavedObjectsStart}
/>
);
expect(wrapper.find('[data-test-subj="visType-visExp"]').exists()).toBe(true);
diff --git a/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.tsx b/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.tsx
index 0b46b562f214..0402265610fb 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.tsx
+++ b/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.tsx
@@ -22,7 +22,7 @@ import React from 'react';
import { EuiModal, EuiOverlayMask } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
-import { IUiSettingsClient } from 'kibana/public';
+import { IUiSettingsClient, SavedObjectsStart } from 'kibana/public';
import { VisType } from '../legacy_imports';
import { VisualizeConstants } from '../visualize_constants';
import { createUiStatsReporter, METRIC_TYPE } from '../../../../ui_metric/public';
@@ -37,6 +37,7 @@ interface TypeSelectionProps {
editorParams?: string[];
addBasePath: (path: string) => string;
uiSettings: IUiSettingsClient;
+ savedObjects: SavedObjectsStart;
}
interface TypeSelectionState {
@@ -81,7 +82,12 @@ class NewVisModal extends React.Component
-
+
) : (
void;
visType: VisType;
+ uiSettings: IUiSettingsClient;
+ savedObjects: SavedObjectsStart;
}
export class SearchSelection extends React.Component {
@@ -50,7 +54,7 @@ export class SearchSelection extends React.Component {
- {
},
]}
fixedPageSize={this.fixedPageSize}
+ uiSettings={this.props.uiSettings}
+ savedObjects={this.props.savedObjects}
/>
diff --git a/src/legacy/core_plugins/kibana/public/visualize/wizard/show_new_vis.tsx b/src/legacy/core_plugins/kibana/public/visualize/wizard/show_new_vis.tsx
index 92320f7bb443..88838e16c40e 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/wizard/show_new_vis.tsx
+++ b/src/legacy/core_plugins/kibana/public/visualize/wizard/show_new_vis.tsx
@@ -21,7 +21,7 @@ import React from 'react';
import ReactDOM from 'react-dom';
import { I18nProvider } from '@kbn/i18n/react';
-import { IUiSettingsClient } from 'kibana/public';
+import { IUiSettingsClient, SavedObjectsStart } from 'kibana/public';
import { NewVisModal } from './new_vis_modal';
import { TypesStart } from '../../../../visualizations/public/np_ready/public/types';
@@ -33,7 +33,8 @@ export function showNewVisModal(
visTypeRegistry: TypesStart,
{ editorParams = [] }: ShowNewVisModalParams = {},
addBasePath: (path: string) => string,
- uiSettings: IUiSettingsClient
+ uiSettings: IUiSettingsClient,
+ savedObjects: SavedObjectsStart
) {
const container = document.createElement('div');
const onClose = () => {
@@ -51,6 +52,7 @@ export function showNewVisModal(
editorParams={editorParams}
addBasePath={addBasePath}
uiSettings={uiSettings}
+ savedObjects={savedObjects}
/>
);
diff --git a/src/legacy/core_plugins/kibana/server/tutorials/apm/index_pattern.json b/src/legacy/core_plugins/kibana/server/tutorials/apm/index_pattern.json
index 69a165c09c2f..9001613623cc 100644
--- a/src/legacy/core_plugins/kibana/server/tutorials/apm/index_pattern.json
+++ b/src/legacy/core_plugins/kibana/server/tutorials/apm/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.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\":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\":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\":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\":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\":\"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\":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\":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\":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\":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.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.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\":\"file.accessed\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"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.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.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\":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\":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.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\":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\":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\":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\":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\":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\":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\":\"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.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\":\"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.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\":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\":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\":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\":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\":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.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.size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"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\":\"process.args\",\"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\":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\":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\":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\":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\":\"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\":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\":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\":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\":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\":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\":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\":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\":\"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\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.original\",\"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\":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\":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\":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\":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\":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\":\"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\":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\":\"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\":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\":\"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\":\"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\":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\":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\":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\":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\":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\":\"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\":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\":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\":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\":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.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.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\":\"file.accessed\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"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.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.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\":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\":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.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\":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\":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\":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\":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\":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\":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\":\"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.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\":\"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.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\":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\":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\":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\":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\":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.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.size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"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\":\"process.args\",\"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\":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\":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\":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\":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\":\"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\":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\":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\":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\":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\":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\":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\":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\":\"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\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.original\",\"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\":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\":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\":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\":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\":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\":\"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\":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\":\"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\":\"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\":\"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\":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"
},
diff --git a/src/legacy/core_plugins/telemetry/public/components/__snapshots__/telemetry_form.test.js.snap b/src/legacy/core_plugins/telemetry/public/components/__snapshots__/telemetry_form.test.js.snap
index a7f8d72e016f..079a43e77616 100644
--- a/src/legacy/core_plugins/telemetry/public/components/__snapshots__/telemetry_form.test.js.snap
+++ b/src/legacy/core_plugins/telemetry/public/components/__snapshots__/telemetry_form.test.js.snap
@@ -38,7 +38,24 @@ exports[`TelemetryForm renders as expected when allows to change optIn status 1`
"defVal": true,
"description":
- Help us improve the Elastic Stack by providing usage statistics for basic features. We will not share this data outside of Elastic.
+
+
+ ,
+ }
+ }
+ />
-
-
-
-
-
,
"type": "boolean",
"value": false,
diff --git a/src/legacy/core_plugins/telemetry/public/components/telemetry_form.js b/src/legacy/core_plugins/telemetry/public/components/telemetry_form.js
index d4bbe1029b40..f6012a271cde 100644
--- a/src/legacy/core_plugins/telemetry/public/components/telemetry_form.js
+++ b/src/legacy/core_plugins/telemetry/public/components/telemetry_form.js
@@ -29,7 +29,7 @@ import {
EuiSpacer,
EuiText,
} from '@elastic/eui';
-import { getConfigTelemetryDesc, PRIVACY_STATEMENT_URL } from '../../common/constants';
+import { PRIVACY_STATEMENT_URL } from '../../common/constants';
import { OptInExampleFlyout } from './opt_in_details_component';
import { Field } from 'ui/management';
import { FormattedMessage } from '@kbn/i18n/react';
@@ -162,7 +162,23 @@ export class TelemetryForm extends Component {
renderDescription = () => (
- {getConfigTelemetryDesc()}
+
+
+
+
+ )
+ }}
+ />
+
-
-
-
-
-
)
diff --git a/src/legacy/server/url_shortening/routes/create_routes.js b/src/legacy/server/url_shortening/routes/create_routes.js
index 091eabcf47c1..c6347ace873f 100644
--- a/src/legacy/server/url_shortening/routes/create_routes.js
+++ b/src/legacy/server/url_shortening/routes/create_routes.js
@@ -19,12 +19,10 @@
import { shortUrlLookupProvider } from './lib/short_url_lookup';
import { createGotoRoute } from './goto';
-import { createShortenUrlRoute } from './shorten_url';
export function createRoutes(server) {
const shortUrlLookup = shortUrlLookupProvider(server);
server.route(createGotoRoute({ server, shortUrlLookup }));
- server.route(createShortenUrlRoute({ shortUrlLookup }));
}
diff --git a/src/legacy/server/url_shortening/routes/goto.js b/src/legacy/server/url_shortening/routes/goto.js
index 675bc5df5067..60a34499dd2d 100644
--- a/src/legacy/server/url_shortening/routes/goto.js
+++ b/src/legacy/server/url_shortening/routes/goto.js
@@ -22,18 +22,12 @@ import { shortUrlAssertValid } from './lib/short_url_assert_valid';
export const createGotoRoute = ({ server, shortUrlLookup }) => ({
method: 'GET',
- path: '/goto/{urlId}',
+ path: '/goto_LP/{urlId}',
handler: async function (request, h) {
try {
const url = await shortUrlLookup.getUrl(request.params.urlId, request);
shortUrlAssertValid(url);
- const uiSettings = request.getUiSettingsService();
- const stateStoreInSessionStorage = await uiSettings.get('state:storeInSessionStorage');
- if (!stateStoreInSessionStorage) {
- return h.redirect(request.getBasePath() + url);
- }
-
const app = server.getHiddenUiAppById('stateSessionStorageRedirect');
return h.renderApp(app, {
redirectUrl: url,
diff --git a/src/legacy/server/url_shortening/routes/lib/short_url_lookup.js b/src/legacy/server/url_shortening/routes/lib/short_url_lookup.js
index c4f6af03d7d9..3a4b96c802c5 100644
--- a/src/legacy/server/url_shortening/routes/lib/short_url_lookup.js
+++ b/src/legacy/server/url_shortening/routes/lib/short_url_lookup.js
@@ -17,7 +17,6 @@
* under the License.
*/
-import crypto from 'crypto';
import { get } from 'lodash';
export function shortUrlLookupProvider(server) {
@@ -34,29 +33,6 @@ export function shortUrlLookupProvider(server) {
}
return {
- async generateUrlId(url, req) {
- const id = crypto.createHash('md5').update(url).digest('hex');
- const savedObjectsClient = req.getSavedObjectsClient();
- const { isConflictError } = savedObjectsClient.errors;
-
- try {
- const doc = await savedObjectsClient.create('url', {
- url,
- accessCount: 0,
- createDate: new Date(),
- accessDate: new Date()
- }, { id });
-
- return doc.id;
- } catch (error) {
- if (isConflictError(error)) {
- return id;
- }
-
- throw error;
- }
- },
-
async getUrl(id, req) {
const doc = await req.getSavedObjectsClient().get('url', id);
updateMetadata(doc, req);
diff --git a/src/legacy/server/url_shortening/routes/lib/short_url_lookup.test.js b/src/legacy/server/url_shortening/routes/lib/short_url_lookup.test.js
index 033aeb92926a..7303682c63e0 100644
--- a/src/legacy/server/url_shortening/routes/lib/short_url_lookup.test.js
+++ b/src/legacy/server/url_shortening/routes/lib/short_url_lookup.test.js
@@ -48,43 +48,6 @@ describe('shortUrlLookupProvider', () => {
sandbox.restore();
});
- describe('generateUrlId', () => {
- it('returns the document id', async () => {
- const id = await shortUrl.generateUrlId(URL, req);
- expect(id).toEqual(ID);
- });
-
- it('provides correct arguments to savedObjectsClient', async () => {
- await shortUrl.generateUrlId(URL, req);
-
- sinon.assert.calledOnce(savedObjectsClient.create);
- const [type, attributes, options] = savedObjectsClient.create.getCall(0).args;
-
- expect(type).toEqual(TYPE);
- expect(Object.keys(attributes).sort()).toEqual(['accessCount', 'accessDate', 'createDate', 'url']);
- expect(attributes.url).toEqual(URL);
- expect(options.id).toEqual(ID);
- });
-
- it('passes persists attributes', async () => {
- await shortUrl.generateUrlId(URL, req);
-
- sinon.assert.calledOnce(savedObjectsClient.create);
- const [type, attributes] = savedObjectsClient.create.getCall(0).args;
-
- expect(type).toEqual(TYPE);
- expect(Object.keys(attributes).sort()).toEqual(['accessCount', 'accessDate', 'createDate', 'url']);
- expect(attributes.url).toEqual(URL);
- });
-
- it('gracefully handles version conflict', async () => {
- const error = savedObjectsClient.errors.decorateConflictError(new Error());
- savedObjectsClient.create.throws(error);
- const id = await shortUrl.generateUrlId(URL, req);
- expect(id).toEqual(ID);
- });
- });
-
describe('getUrl', () => {
beforeEach(() => {
const attributes = { accessCount: 2, url: URL };
diff --git a/src/legacy/ui/public/agg_types/buckets/geo_hash.ts b/src/legacy/ui/public/agg_types/buckets/geo_hash.ts
index 700f5a048fce..0acbaf4aa02a 100644
--- a/src/legacy/ui/public/agg_types/buckets/geo_hash.ts
+++ b/src/legacy/ui/public/agg_types/buckets/geo_hash.ts
@@ -18,13 +18,13 @@
*/
import { i18n } from '@kbn/i18n';
+import { geohashColumns } from 'ui/vis/map/decode_geo_hash';
import chrome from '../../chrome';
import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type';
import { AutoPrecisionParamEditor } from '../../vis/editors/default/controls/auto_precision';
import { UseGeocentroidParamEditor } from '../../vis/editors/default/controls/use_geocentroid';
import { IsFilteredByCollarParamEditor } from '../../vis/editors/default/controls/is_filtered_by_collar';
import { PrecisionParamEditor } from '../../vis/editors/default/controls/precision';
-import { geohashColumns } from '../../utils/decode_geo_hash';
import { AggGroupNames } from '../../vis/editors/default/agg_groups';
import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public';
diff --git a/src/legacy/ui/public/saved_objects/components/saved_object_finder.tsx b/src/legacy/ui/public/saved_objects/components/saved_object_finder.tsx
deleted file mode 100644
index 5b787eb26550..000000000000
--- a/src/legacy/ui/public/saved_objects/components/saved_object_finder.tsx
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import React from 'react';
-import { npStart } from 'ui/new_platform';
-import { IconType } from '@elastic/eui';
-import { SavedObjectAttributes } from 'src/core/server';
-import { SimpleSavedObject } from 'src/core/public';
-import { SavedObjectFinder as SavedObjectFinderNP } from '../../../../../plugins/kibana_react/public';
-
-/**
- * DO NOT USE THIS COMPONENT, IT IS DEPRECATED.
- * Use the one in `src/plugins/kibana_react` instead.
- */
-
-export interface SavedObjectMetaData {
- type: string;
- name: string;
- getIconForSavedObject(savedObject: SimpleSavedObject): IconType;
- getTooltipForSavedObject?(savedObject: SimpleSavedObject): string;
- showSavedObject?(savedObject: SimpleSavedObject): boolean;
-}
-
-interface BaseSavedObjectFinder {
- /**
- * @deprecated
- *
- * Use component in `src/plugins/kibana_react` instead.
- */
- onChoose?: (
- id: SimpleSavedObject['id'],
- type: SimpleSavedObject['type'],
- name: string
- ) => void;
- /**
- * @deprecated
- *
- * Use component in `src/plugins/kibana_react` instead.
- */
- noItemsMessage?: React.ReactNode;
- /**
- * @deprecated
- *
- * Use component in `src/plugins/kibana_react` instead.
- */
- savedObjectMetaData: Array>;
- /**
- * @deprecated
- *
- * Use component in `src/plugins/kibana_react` instead.
- */
- showFilter?: boolean;
-}
-
-interface SavedObjectFinderFixedPage extends BaseSavedObjectFinder {
- /**
- * @deprecated
- *
- * Use component in `src/plugins/kibana_react` instead.
- */
- initialPageSize?: undefined;
- /**
- * @deprecated
- *
- * Use component in `src/plugins/kibana_react` instead.
- */
- fixedPageSize: number;
-}
-
-interface SavedObjectFinderInitialPageSize extends BaseSavedObjectFinder {
- /**
- * @deprecated
- *
- * Use component in `src/plugins/kibana_react` instead.
- */
- initialPageSize?: 5 | 10 | 15 | 25;
- /**
- * @deprecated
- *
- * Use component in `src/plugins/kibana_react` instead.
- */
- fixedPageSize?: undefined;
-}
-type SavedObjectFinderProps = SavedObjectFinderFixedPage | SavedObjectFinderInitialPageSize;
-
-export const SavedObjectFinder: React.FC = props => (
-
-);
diff --git a/src/legacy/ui/public/state_management/state.js b/src/legacy/ui/public/state_management/state.js
index 27186b424997..e868abb98c85 100644
--- a/src/legacy/ui/public/state_management/state.js
+++ b/src/legacy/ui/public/state_management/state.js
@@ -316,6 +316,27 @@ export function StateProvider(Private, $rootScope, $location, stateManagementCon
return this._urlParam;
};
+ /**
+ * Returns an object with each property name and value corresponding to the entries in this collection
+ * excluding fields started from '$', '_' and all methods
+ *
+ * @return {object}
+ */
+ State.prototype.toObject = function () {
+ return _.omit(this, (value, key) => {
+ return key.charAt(0) === '$' || key.charAt(0) === '_' || _.isFunction(value);
+ });
+ };
+
+ /** Alias for method 'toObject'
+ *
+ * @obsolete Please use 'toObject' method instead
+ * @return {object}
+ */
+ State.prototype.toJSON = function () {
+ return this.toObject();
+ };
+
return State;
}
diff --git a/src/legacy/ui/public/utils/range.d.ts b/src/legacy/ui/public/time_buckets/index.d.ts
similarity index 81%
rename from src/legacy/ui/public/utils/range.d.ts
rename to src/legacy/ui/public/time_buckets/index.d.ts
index c484c6f43eeb..70b9495b81f0 100644
--- a/src/legacy/ui/public/utils/range.d.ts
+++ b/src/legacy/ui/public/time_buckets/index.d.ts
@@ -17,12 +17,6 @@
* under the License.
*/
-export function parseRange(input: string): Range;
-
-export interface Range {
- min: number;
- max: number;
- minInclusive: boolean;
- maxInclusive: boolean;
- within(n: number): boolean;
+declare module 'ui/time_buckets' {
+ export const TimeBuckets: any;
}
diff --git a/src/legacy/ui/public/utils/__tests__/base_object.js b/src/legacy/ui/public/utils/__tests__/base_object.js
deleted file mode 100644
index dfc5688c7b2f..000000000000
--- a/src/legacy/ui/public/utils/__tests__/base_object.js
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import expect from '@kbn/expect';
-import ngMock from 'ng_mock';
-import '../../private';
-
-import { BaseObject } from '../base_object';
-
-describe('Base Object', function () {
- beforeEach(ngMock.module('kibana'));
-
- it('should take an inital set of values', function () {
- const baseObject = new BaseObject({ message: 'test' });
- expect(baseObject).to.have.property('message', 'test');
- });
-
- it('should serialize attributes to RISON', function () {
- const baseObject = new BaseObject();
- baseObject.message = 'Testing... 1234';
- const rison = baseObject.toRISON();
- expect(rison).to.equal('(message:\'Testing... 1234\')');
- });
-
- it('should not serialize $$attributes to RISON', function () {
- const baseObject = new BaseObject();
- baseObject.$$attributes = { foo: 'bar' };
- baseObject.message = 'Testing... 1234';
- const rison = baseObject.toRISON();
- expect(rison).to.equal('(message:\'Testing... 1234\')');
- });
-
- it('should serialize attributes for JSON', function () {
- const baseObject = new BaseObject();
- baseObject.message = 'Testing... 1234';
- baseObject._private = 'foo';
- baseObject.$private = 'stuff';
- const json = JSON.stringify(baseObject);
- expect(json).to.equal('{"message":"Testing... 1234"}');
- });
-});
diff --git a/src/legacy/ui/public/utils/__tests__/simple_emitter.js b/src/legacy/ui/public/utils/__tests__/simple_emitter.js
deleted file mode 100644
index 25224a409f8f..000000000000
--- a/src/legacy/ui/public/utils/__tests__/simple_emitter.js
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import { SimpleEmitter } from '../simple_emitter';
-import expect from '@kbn/expect';
-import sinon from 'sinon';
-
-describe('SimpleEmitter class', function () {
- let emitter;
-
- beforeEach(function () {
- emitter = new SimpleEmitter();
- });
-
- it('constructs an event emitter', function () {
- expect(emitter).to.have.property('on');
- expect(emitter).to.have.property('off');
- expect(emitter).to.have.property('emit');
- expect(emitter).to.have.property('listenerCount');
- expect(emitter).to.have.property('removeAllListeners');
- });
-
- describe('#listenerCount', function () {
- it('counts all event listeners without any arg', function () {
- expect(emitter.listenerCount()).to.be(0);
- emitter.on('a', function () {});
- expect(emitter.listenerCount()).to.be(1);
- emitter.on('b', function () {});
- expect(emitter.listenerCount()).to.be(2);
- });
-
- it('limits to the event that is passed in', function () {
- expect(emitter.listenerCount()).to.be(0);
- emitter.on('a', function () {});
- expect(emitter.listenerCount('a')).to.be(1);
- emitter.on('a', function () {});
- expect(emitter.listenerCount('a')).to.be(2);
- emitter.on('b', function () {});
- expect(emitter.listenerCount('a')).to.be(2);
- expect(emitter.listenerCount('b')).to.be(1);
- expect(emitter.listenerCount()).to.be(3);
- });
- });
-
- describe('#on', function () {
- it('registers a handler', function () {
- const handler = sinon.stub();
- emitter.on('a', handler);
- expect(emitter.listenerCount('a')).to.be(1);
-
- expect(handler.callCount).to.be(0);
- emitter.emit('a');
- expect(handler.callCount).to.be(1);
- });
-
- it('allows multiple event handlers for the same event', function () {
- emitter.on('a', function () {});
- emitter.on('a', function () {});
- expect(emitter.listenerCount('a')).to.be(2);
- });
-
- it('allows the same function to be registered multiple times', function () {
- const handler = function () {};
- emitter.on('a', handler);
- expect(emitter.listenerCount()).to.be(1);
- emitter.on('a', handler);
- expect(emitter.listenerCount()).to.be(2);
- });
- });
-
- describe('#off', function () {
- it('removes a listener if it was registered', function () {
- const handler = sinon.stub();
- expect(emitter.listenerCount()).to.be(0);
- emitter.on('a', handler);
- expect(emitter.listenerCount('a')).to.be(1);
- emitter.off('a', handler);
- expect(emitter.listenerCount('a')).to.be(0);
- });
-
- it('clears all listeners if no handler is passed', function () {
- emitter.on('a', function () {});
- emitter.on('a', function () {});
- expect(emitter.listenerCount()).to.be(2);
- emitter.off('a');
- expect(emitter.listenerCount()).to.be(0);
- });
-
- it('does not mind if the listener is not registered', function () {
- emitter.off('a', function () {});
- });
-
- it('does not mind if the event has no listeners', function () {
- emitter.off('a');
- });
- });
-
- describe('#emit', function () {
- it('calls the handlers in the order they were defined', function () {
- let i = 0;
- const incr = function () { return ++i; };
- const one = sinon.spy(incr);
- const two = sinon.spy(incr);
- const three = sinon.spy(incr);
- const four = sinon.spy(incr);
-
- emitter
- .on('a', one)
- .on('a', two)
- .on('a', three)
- .on('a', four)
- .emit('a');
-
- expect(one).to.have.property('callCount', 1);
- expect(one.returned(1)).to.be.ok();
-
- expect(two).to.have.property('callCount', 1);
- expect(two.returned(2)).to.be.ok();
-
- expect(three).to.have.property('callCount', 1);
- expect(three.returned(3)).to.be.ok();
-
- expect(four).to.have.property('callCount', 1);
- expect(four.returned(4)).to.be.ok();
- });
-
- it('always emits the handlers that were initially registered', function () {
-
- const destructive = sinon.spy(function () {
- emitter.removeAllListeners();
- expect(emitter.listenerCount()).to.be(0);
- });
- const stub = sinon.stub();
-
- emitter.on('run', destructive).on('run', stub).emit('run');
-
- expect(destructive).to.have.property('callCount', 1);
- expect(stub).to.have.property('callCount', 1);
- });
-
- it('applies all arguments except the first', function () {
- emitter
- .on('a', function (a, b, c) {
- expect(a).to.be('foo');
- expect(b).to.be('bar');
- expect(c).to.be('baz');
- })
- .emit('a', 'foo', 'bar', 'baz');
- });
-
- it('uses the SimpleEmitter as the this context', function () {
- emitter
- .on('a', function () {
- expect(this).to.be(emitter);
- })
- .emit('a');
- });
- });
-});
diff --git a/src/legacy/ui/public/utils/base_object.ts b/src/legacy/ui/public/utils/base_object.ts
deleted file mode 100644
index 63c7ebf6de5b..000000000000
--- a/src/legacy/ui/public/utils/base_object.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import angular from 'angular';
-import _ from 'lodash';
-// @ts-ignore -- awaiting https://github.com/w33ble/rison-node/issues/1
-import rison from 'rison-node';
-
-export class BaseObject {
- // Set the attributes or default to an empty object
- constructor(attributes: Record = {}) {
- // Set the attributes or default to an empty object
- _.assign(this, attributes);
- }
-
- public toObject() {
- // return just the data.
- return _.omit(this, (value: any, key: string) => {
- return key.charAt(0) === '$' || key.charAt(0) === '_' || _.isFunction(value);
- });
- }
-
- public toRISON() {
- // Use Angular to remove the private vars, and JSON.stringify to serialize
- return rison.encode(JSON.parse(angular.toJson(this)));
- }
-
- public toJSON() {
- return this.toObject();
- }
-}
diff --git a/src/legacy/ui/public/utils/simple_emitter.js b/src/legacy/ui/public/utils/simple_emitter.js
index 84397962c286..503798ba160d 100644
--- a/src/legacy/ui/public/utils/simple_emitter.js
+++ b/src/legacy/ui/public/utils/simple_emitter.js
@@ -18,8 +18,6 @@
*/
import _ from 'lodash';
-import { BaseObject } from './base_object';
-import { createLegacyClass } from './legacy_class';
/**
* Simple event emitter class used in the vislib. Calls
@@ -27,7 +25,6 @@ import { createLegacyClass } from './legacy_class';
*
* @class
*/
-createLegacyClass(SimpleEmitter).inherits(BaseObject);
export function SimpleEmitter() {
this._listeners = {};
}
@@ -134,4 +131,3 @@ SimpleEmitter.prototype.listenerCount = function (name) {
return count + _.size(handlers);
}, 0);
};
-
diff --git a/src/legacy/ui/public/utils/simple_emitter.test.js b/src/legacy/ui/public/utils/simple_emitter.test.js
new file mode 100644
index 000000000000..ff884a12be7e
--- /dev/null
+++ b/src/legacy/ui/public/utils/simple_emitter.test.js
@@ -0,0 +1,173 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { SimpleEmitter } from './simple_emitter';
+import sinon from 'sinon';
+
+describe('SimpleEmitter class', () => {
+ let emitter;
+
+ beforeEach(() => {
+ emitter = new SimpleEmitter();
+ });
+
+ it('constructs an event emitter', () => {
+ expect(emitter).toHaveProperty('on');
+ expect(emitter).toHaveProperty('off');
+ expect(emitter).toHaveProperty('emit');
+ expect(emitter).toHaveProperty('listenerCount');
+ expect(emitter).toHaveProperty('removeAllListeners');
+ });
+
+ describe('#listenerCount', () => {
+ it('counts all event listeners without any arg', () => {
+ expect(emitter.listenerCount()).toBe(0);
+ emitter.on('a', () => {});
+ expect(emitter.listenerCount()).toBe(1);
+ emitter.on('b', () => {});
+ expect(emitter.listenerCount()).toBe(2);
+ });
+
+ it('limits to the event that is passed in', () => {
+ expect(emitter.listenerCount()).toBe(0);
+ emitter.on('a', () => {});
+ expect(emitter.listenerCount('a')).toBe(1);
+ emitter.on('a', () => {});
+ expect(emitter.listenerCount('a')).toBe(2);
+ emitter.on('b', () => {});
+ expect(emitter.listenerCount('a')).toBe(2);
+ expect(emitter.listenerCount('b')).toBe(1);
+ expect(emitter.listenerCount()).toBe(3);
+ });
+ });
+
+ describe('#on', () => {
+ it('registers a handler', () => {
+ const handler = sinon.stub();
+ emitter.on('a', handler);
+ expect(emitter.listenerCount('a')).toBe(1);
+
+ expect(handler.callCount).toBe(0);
+ emitter.emit('a');
+ expect(handler.callCount).toBe(1);
+ });
+
+ it('allows multiple event handlers for the same event', () => {
+ emitter.on('a', () => {});
+ emitter.on('a', () => {});
+ expect(emitter.listenerCount('a')).toBe(2);
+ });
+
+ it('allows the same function to be registered multiple times', () => {
+ const handler = () => {};
+ emitter.on('a', handler);
+ expect(emitter.listenerCount()).toBe(1);
+ emitter.on('a', handler);
+ expect(emitter.listenerCount()).toBe(2);
+ });
+ });
+
+ describe('#off', () => {
+ it('removes a listener if it was registered', () => {
+ const handler = sinon.stub();
+ expect(emitter.listenerCount()).toBe(0);
+ emitter.on('a', handler);
+ expect(emitter.listenerCount('a')).toBe(1);
+ emitter.off('a', handler);
+ expect(emitter.listenerCount('a')).toBe(0);
+ });
+
+ it('clears all listeners if no handler is passed', () => {
+ emitter.on('a', () => {});
+ emitter.on('a', () => {});
+ expect(emitter.listenerCount()).toBe(2);
+ emitter.off('a');
+ expect(emitter.listenerCount()).toBe(0);
+ });
+
+ it('does not mind if the listener is not registered', () => {
+ emitter.off('a', () => {});
+ });
+
+ it('does not mind if the event has no listeners', () => {
+ emitter.off('a');
+ });
+ });
+
+ describe('#emit', () => {
+ it('calls the handlers in the order they were defined', () => {
+ let i = 0;
+ const incr = () => ++i;
+ const one = sinon.spy(incr);
+ const two = sinon.spy(incr);
+ const three = sinon.spy(incr);
+ const four = sinon.spy(incr);
+
+ emitter
+ .on('a', one)
+ .on('a', two)
+ .on('a', three)
+ .on('a', four)
+ .emit('a');
+
+ expect(one).toHaveProperty('callCount', 1);
+ expect(one.returned(1)).toBeDefined();
+
+ expect(two).toHaveProperty('callCount', 1);
+ expect(two.returned(2)).toBeDefined();
+
+ expect(three).toHaveProperty('callCount', 1);
+ expect(three.returned(3)).toBeDefined();
+
+ expect(four).toHaveProperty('callCount', 1);
+ expect(four.returned(4)).toBeDefined();
+ });
+
+ it('always emits the handlers that were initially registered', () => {
+ const destructive = sinon.spy(() => {
+ emitter.removeAllListeners();
+ expect(emitter.listenerCount()).toBe(0);
+ });
+ const stub = sinon.stub();
+
+ emitter.on('run', destructive).on('run', stub).emit('run');
+
+ expect(destructive).toHaveProperty('callCount', 1);
+ expect(stub).toHaveProperty('callCount', 1);
+ });
+
+ it('applies all arguments except the first', () => {
+ emitter
+ .on('a', (a, b, c) => {
+ expect(a).toBe('foo');
+ expect(b).toBe('bar');
+ expect(c).toBe('baz');
+ })
+ .emit('a', 'foo', 'bar', 'baz');
+ });
+
+ it('uses the SimpleEmitter as the this context', () => {
+ emitter
+ .on('a', function () {
+ expect(this).toBe(emitter);
+ })
+ .emit('a');
+ });
+ });
+});
diff --git a/src/legacy/ui/public/vis/editors/default/controls/components/number_list/__snapshots__/number_list.test.tsx.snap b/src/legacy/ui/public/vis/editors/default/controls/components/number_list/__snapshots__/number_list.test.tsx.snap
index ab192e6fd3cb..4004f8627a89 100644
--- a/src/legacy/ui/public/vis/editors/default/controls/components/number_list/__snapshots__/number_list.test.tsx.snap
+++ b/src/legacy/ui/public/vis/editors/default/controls/components/number_list/__snapshots__/number_list.test.tsx.snap
@@ -18,7 +18,7 @@ exports[`NumberList should be rendered with default set of props 1`] = `
onChange={[Function]}
onDelete={[Function]}
range={
- Range {
+ NumberListRange {
"max": 10,
"maxInclusive": true,
"min": 1,
@@ -45,7 +45,7 @@ exports[`NumberList should be rendered with default set of props 1`] = `
onChange={[Function]}
onDelete={[Function]}
range={
- Range {
+ NumberListRange {
"max": 10,
"maxInclusive": true,
"min": 1,
diff --git a/src/legacy/ui/public/vis/editors/default/controls/components/number_list/number_row.tsx b/src/legacy/ui/public/vis/editors/default/controls/components/number_list/number_row.tsx
index 23e671180e98..777b0a94f0f3 100644
--- a/src/legacy/ui/public/vis/editors/default/controls/components/number_list/number_row.tsx
+++ b/src/legacy/ui/public/vis/editors/default/controls/components/number_list/number_row.tsx
@@ -21,7 +21,7 @@ import React, { useCallback } from 'react';
import { EuiFieldNumber, EuiFlexGroup, EuiFlexItem, EuiButtonIcon } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
-import { Range } from '../../../../../../utils/range';
+import { NumberListRange } from './range';
export interface NumberRowProps {
autoFocus: boolean;
@@ -29,7 +29,7 @@ export interface NumberRowProps {
isInvalid: boolean;
labelledbyId: string;
model: NumberRowModel;
- range: Range;
+ range: NumberListRange;
onBlur(): void;
onChange({ id, value }: { id: string; value: string }): void;
onDelete(index: string): void;
diff --git a/src/legacy/ui/public/utils/__tests__/range.js b/src/legacy/ui/public/vis/editors/default/controls/components/number_list/range.test.ts
similarity index 66%
rename from src/legacy/ui/public/utils/__tests__/range.js
rename to src/legacy/ui/public/vis/editors/default/controls/components/number_list/range.test.ts
index e7947894d3e2..e9090e5b38ef 100644
--- a/src/legacy/ui/public/utils/__tests__/range.js
+++ b/src/legacy/ui/public/vis/editors/default/controls/components/number_list/range.test.ts
@@ -17,32 +17,30 @@
* under the License.
*/
-import _ from 'lodash';
-import expect from '@kbn/expect';
-import { parseRange } from '../range';
+import { forOwn } from 'lodash';
+import { parseRange } from './range';
-describe('Range parsing utility', function () {
-
- it('throws an error for inputs that are not formatted properly', function () {
- expect(function () {
+describe('Range parsing utility', () => {
+ test('throws an error for inputs that are not formatted properly', () => {
+ expect(() => {
parseRange('');
- }).to.throwException(TypeError);
+ }).toThrowError(TypeError);
- expect(function () {
+ expect(function() {
parseRange('p10202');
- }).to.throwException(TypeError);
+ }).toThrowError(TypeError);
- expect(function () {
+ expect(function() {
parseRange('{0,100}');
- }).to.throwException(TypeError);
+ }).toThrowError(TypeError);
- expect(function () {
+ expect(function() {
parseRange('[0,100');
- }).to.throwException(TypeError);
+ }).toThrowError(TypeError);
- expect(function () {
+ expect(function() {
parseRange(')0,100(');
- }).to.throwException(TypeError);
+ }).toThrowError(TypeError);
});
const tests = {
@@ -51,52 +49,52 @@ describe('Range parsing utility', function () {
min: 0,
max: 100,
minInclusive: true,
- maxInclusive: true
+ maxInclusive: true,
},
within: [
[0, true],
[0.0000001, true],
[1, true],
[99.99999, true],
- [100, true]
- ]
+ [100, true],
+ ],
},
'(26.3 , 42]': {
props: {
min: 26.3,
max: 42,
minInclusive: false,
- maxInclusive: true
+ maxInclusive: true,
},
within: [
[26.2999999, false],
[26.3000001, true],
[30, true],
[41, true],
- [42, true]
- ]
+ [42, true],
+ ],
},
'(-50,50)': {
props: {
min: -50,
max: 50,
minInclusive: false,
- maxInclusive: false
+ maxInclusive: false,
},
within: [
[-50, false],
[-49.99999, true],
[0, true],
[49.99999, true],
- [50, false]
- ]
+ [50, false],
+ ],
},
'(Infinity, -Infinity)': {
props: {
min: -Infinity,
max: Infinity,
minInclusive: false,
- maxInclusive: false
+ maxInclusive: false,
},
within: [
[0, true],
@@ -105,25 +103,24 @@ describe('Range parsing utility', function () {
[-10000000000, true],
[-Infinity, false],
[Infinity, false],
- ]
- }
+ ],
+ },
};
- _.forOwn(tests, function (spec, str) {
-
- describe(str, function () {
+ forOwn(tests, (spec, str: any) => {
+ // eslint-disable-next-line jest/valid-describe
+ describe(str, () => {
const range = parseRange(str);
- it('creation', function () {
- expect(range).to.eql(spec.props);
+ it('creation', () => {
+ expect(range).toEqual(spec.props);
});
- spec.within.forEach(function (tup) {
- it('#within(' + tup[0] + ')', function () {
- expect(range.within(tup[0])).to.be(tup[1]);
+ spec.within.forEach((tup: any[]) => {
+ it('#within(' + tup[0] + ')', () => {
+ expect(range.within(tup[0])).toBe(tup[1]);
});
});
});
-
});
});
diff --git a/src/legacy/ui/public/utils/range.js b/src/legacy/ui/public/vis/editors/default/controls/components/number_list/range.ts
similarity index 59%
rename from src/legacy/ui/public/utils/range.js
rename to src/legacy/ui/public/vis/editors/default/controls/components/number_list/range.ts
index 54bd1b190334..da3b7a61aea9 100644
--- a/src/legacy/ui/public/utils/range.js
+++ b/src/legacy/ui/public/vis/editors/default/controls/components/number_list/range.ts
@@ -17,8 +17,6 @@
* under the License.
*/
-import _ from 'lodash';
-
/**
* Regexp portion that matches our number
*
@@ -44,41 +42,44 @@ const _RE_NUMBER = '(\\-?(?:\\d+(?:\\.\\d+)?|Infinity))';
*
* @type {RegExp}
*/
-const RANGE_RE = new RegExp('^\\s*([\\[|\\(])\\s*' + _RE_NUMBER + '\\s*,\\s*' + _RE_NUMBER + '\\s*([\\]|\\)])\\s*$');
+const RANGE_RE = new RegExp(
+ '^\\s*([\\[|\\(])\\s*' + _RE_NUMBER + '\\s*,\\s*' + _RE_NUMBER + '\\s*([\\]|\\)])\\s*$'
+);
+
+export class NumberListRange {
+ constructor(
+ public minInclusive: boolean,
+ public min: number,
+ public max: number,
+ public maxInclusive: boolean
+ ) {}
-export function parseRange(input) {
+ within(n: number): boolean {
+ if ((this.min === n && !this.minInclusive) || this.min > n) return false;
+ if ((this.max === n && !this.maxInclusive) || this.max < n) return false;
+
+ return true;
+ }
+}
+export function parseRange(input: string): NumberListRange {
const match = String(input).match(RANGE_RE);
if (!match) {
throw new TypeError('expected input to be in interval notation e.g., (100, 200]');
}
- return new Range(
- match[1] === '[',
- parseFloat(match[2]),
- parseFloat(match[3]),
- match[4] === ']'
- );
-}
-
-function Range(/* minIncl, min, max, maxIncl */) {
- const args = _.toArray(arguments);
- if (args[1] > args[2]) args.reverse();
+ const args = [match[1] === '[', parseFloat(match[2]), parseFloat(match[3]), match[4] === ']'];
- this.minInclusive = args[0];
- this.min = args[1];
- this.max = args[2];
- this.maxInclusive = args[3];
-}
-
-Range.prototype.within = function (n) {
- if (this.min === n && !this.minInclusive) return false;
- if (this.min > n) return false;
-
- if (this.max === n && !this.maxInclusive) return false;
- if (this.max < n) return false;
-
- return true;
-};
+ if (args[1] > args[2]) {
+ args.reverse();
+ }
+ const [minInclusive, min, max, maxInclusive] = args;
+ return new NumberListRange(
+ minInclusive as boolean,
+ min as number,
+ max as number,
+ maxInclusive as boolean
+ );
+}
diff --git a/src/legacy/ui/public/vis/editors/default/controls/components/number_list/utils.test.ts b/src/legacy/ui/public/vis/editors/default/controls/components/number_list/utils.test.ts
index c6772cc10876..89fb5738db37 100644
--- a/src/legacy/ui/public/vis/editors/default/controls/components/number_list/utils.test.ts
+++ b/src/legacy/ui/public/vis/editors/default/controls/components/number_list/utils.test.ts
@@ -27,12 +27,12 @@ import {
getNextModel,
getRange,
} from './utils';
-import { Range } from '../../../../../../utils/range';
+import { NumberListRange } from './range';
import { NumberRowModel } from './number_row';
describe('NumberList utils', () => {
let modelList: NumberRowModel[];
- let range: Range;
+ let range: NumberListRange;
beforeEach(() => {
modelList = [
diff --git a/src/legacy/ui/public/vis/editors/default/controls/components/number_list/utils.ts b/src/legacy/ui/public/vis/editors/default/controls/components/number_list/utils.ts
index 563e8f0a6a9b..399253f27445 100644
--- a/src/legacy/ui/public/vis/editors/default/controls/components/number_list/utils.ts
+++ b/src/legacy/ui/public/vis/editors/default/controls/components/number_list/utils.ts
@@ -21,7 +21,7 @@ import { last } from 'lodash';
import { i18n } from '@kbn/i18n';
import { htmlIdGenerator } from '@elastic/eui';
-import { parseRange, Range } from '../../../../../../utils/range';
+import { parseRange, NumberListRange } from './range';
import { NumberRowModel } from './number_row';
const EMPTY_STRING = '';
@@ -34,7 +34,7 @@ function parse(value: string) {
return isNaN(parsedValue) ? EMPTY_STRING : parsedValue;
}
-function getRange(range?: string): Range {
+function getRange(range?: string): NumberListRange {
try {
return range ? parseRange(range) : defaultRange;
} catch (e) {
@@ -42,7 +42,7 @@ function getRange(range?: string): Range {
}
}
-function validateValue(value: number | '', numberRange: Range) {
+function validateValue(value: number | '', numberRange: NumberListRange) {
const result: { isInvalid: boolean; error?: string } = {
isInvalid: false,
};
@@ -76,7 +76,7 @@ function validateOrder(list: Array) {
return result;
}
-function getNextModel(list: NumberRowModel[], range: Range): NumberRowModel {
+function getNextModel(list: NumberRowModel[], range: NumberListRange): NumberRowModel {
const lastValue = last(list).value;
let next = Number(lastValue) ? Number(lastValue) + 1 : 1;
@@ -104,7 +104,7 @@ function getInitModelList(list: Array): NumberRowModel[] {
function getUpdatedModels(
numberList: Array,
modelList: NumberRowModel[],
- numberRange: Range,
+ numberRange: NumberListRange,
invalidOrderModelIndex?: number
): NumberRowModel[] {
if (!numberList.length) {
diff --git a/src/legacy/ui/public/vis/map/convert_to_geojson.js b/src/legacy/ui/public/vis/map/convert_to_geojson.js
index 77896490678f..14c282b58bed 100644
--- a/src/legacy/ui/public/vis/map/convert_to_geojson.js
+++ b/src/legacy/ui/public/vis/map/convert_to_geojson.js
@@ -17,10 +17,9 @@
* under the License.
*/
-import { decodeGeoHash } from 'ui/utils/decode_geo_hash';
+import { decodeGeoHash } from './decode_geo_hash';
import { gridDimensions } from './grid_dimensions';
-
export function convertToGeoJson(tabifiedResponse, { geohash, geocentroid, metric }) {
let features;
diff --git a/src/legacy/ui/public/utils/__tests__/decode_geo_hash.test.js b/src/legacy/ui/public/vis/map/decode_geo_hash.test.ts
similarity index 75%
rename from src/legacy/ui/public/utils/__tests__/decode_geo_hash.test.js
rename to src/legacy/ui/public/vis/map/decode_geo_hash.test.ts
index 1ffe9ca7b4df..c1ca7e4c8038 100644
--- a/src/legacy/ui/public/utils/__tests__/decode_geo_hash.test.js
+++ b/src/legacy/ui/public/vis/map/decode_geo_hash.test.ts
@@ -17,27 +17,18 @@
* under the License.
*/
-import { geohashColumns, decodeGeoHash } from '../decode_geo_hash';
+import { geohashColumns, decodeGeoHash } from './decode_geo_hash';
-test('geohashColumns', function () {
+test('geohashColumns', () => {
expect(geohashColumns(1)).toBe(8);
expect(geohashColumns(2)).toBe(8 * 4);
expect(geohashColumns(3)).toBe(8 * 4 * 8);
expect(geohashColumns(4)).toBe(8 * 4 * 8 * 4);
});
-test('decodeGeoHash', function () {
+test('decodeGeoHash', () => {
expect(decodeGeoHash('drm3btev3e86')).toEqual({
- latitude: [
- 41.119999922811985,
- 41.12000009045005,
- 41.12000000663102,
- ],
- longitude: [
- -71.34000029414892,
- -71.3399999588728,
- -71.34000012651086,
- ],
+ latitude: [41.119999922811985, 41.12000009045005, 41.12000000663102],
+ longitude: [-71.34000029414892, -71.3399999588728, -71.34000012651086],
});
});
-
diff --git a/src/legacy/ui/public/utils/decode_geo_hash.ts b/src/legacy/ui/public/vis/map/decode_geo_hash.ts
similarity index 100%
rename from src/legacy/ui/public/utils/decode_geo_hash.ts
rename to src/legacy/ui/public/vis/map/decode_geo_hash.ts
diff --git a/src/legacy/ui/public/vis/map/kibana_map.js b/src/legacy/ui/public/vis/map/kibana_map.js
index dc57809b6570..cb618444af7c 100644
--- a/src/legacy/ui/public/vis/map/kibana_map.js
+++ b/src/legacy/ui/public/vis/map/kibana_map.js
@@ -22,7 +22,7 @@ import { createZoomWarningMsg } from './map_messages';
import L from 'leaflet';
import $ from 'jquery';
import _ from 'lodash';
-import { zoomToPrecision } from '../../utils/zoom_to_precision';
+import { zoomToPrecision } from './zoom_to_precision';
import { i18n } from '@kbn/i18n';
import { ORIGIN } from '../../../../core_plugins/tile_map/common/origin';
diff --git a/src/legacy/ui/public/utils/zoom_to_precision.js b/src/legacy/ui/public/vis/map/zoom_to_precision.ts
similarity index 52%
rename from src/legacy/ui/public/utils/zoom_to_precision.js
rename to src/legacy/ui/public/vis/map/zoom_to_precision.ts
index f5c16b640d12..552c50959028 100644
--- a/src/legacy/ui/public/utils/zoom_to_precision.js
+++ b/src/legacy/ui/public/vis/map/zoom_to_precision.ts
@@ -19,39 +19,42 @@
import { geohashColumns } from './decode_geo_hash';
-const maxPrecision = 12;
-/**
- * Map Leaflet zoom levels to geohash precision levels.
- * The size of a geohash column-width on the map should be at least `minGeohashPixels` pixels wide.
- */
-
-
+const defaultMaxPrecision = 12;
+const minGeoHashPixels = 16;
-
-const zoomPrecisionMap = {};
-const minGeohashPixels = 16;
-
-function calculateZoomToPrecisionMap(maxZoom) {
+const calculateZoomToPrecisionMap = (maxZoom: number): Map => {
+ /**
+ * Map Leaflet zoom levels to geohash precision levels.
+ * The size of a geohash column-width on the map should be at least `minGeohashPixels` pixels wide.
+ */
+ const zoomPrecisionMap = new Map();
for (let zoom = 0; zoom <= maxZoom; zoom += 1) {
- if (typeof zoomPrecisionMap[zoom] === 'number') {
+ if (typeof zoomPrecisionMap.get(zoom) === 'number') {
continue;
}
+
const worldPixels = 256 * Math.pow(2, zoom);
- zoomPrecisionMap[zoom] = 1;
- for (let precision = 2; precision <= maxPrecision; precision += 1) {
+
+ zoomPrecisionMap.set(zoom, 1);
+
+ for (let precision = 2; precision <= defaultMaxPrecision; precision += 1) {
const columns = geohashColumns(precision);
- if ((worldPixels / columns) >= minGeohashPixels) {
- zoomPrecisionMap[zoom] = precision;
+
+ if (worldPixels / columns >= minGeoHashPixels) {
+ zoomPrecisionMap.set(zoom, precision);
} else {
break;
}
}
}
-}
+ return zoomPrecisionMap;
+};
+
+export function zoomToPrecision(mapZoom: number, maxPrecision: number, maxZoom: number) {
+ const zoomPrecisionMap = calculateZoomToPrecisionMap(typeof maxZoom === 'number' ? maxZoom : 21);
+ const precision = zoomPrecisionMap.get(mapZoom);
-export function zoomToPrecision(mapZoom, maxPrecision, maxZoom) {
- calculateZoomToPrecisionMap(typeof maxZoom === 'number' ? maxZoom : 21);
- return Math.min(zoomPrecisionMap[mapZoom], maxPrecision);
+ return precision ? Math.min(precision, maxPrecision) : maxPrecision;
}
diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/dashboard_container.tsx b/src/plugins/dashboard_embeddable_container/public/embeddable/dashboard_container.tsx
index 684aa93779bc..021a1a9d1e64 100644
--- a/src/plugins/dashboard_embeddable_container/public/embeddable/dashboard_container.tsx
+++ b/src/plugins/dashboard_embeddable_container/public/embeddable/dashboard_container.tsx
@@ -90,6 +90,8 @@ export type DashboardReactContext = KibanaReactContext {
public readonly type = DASHBOARD_CONTAINER_TYPE;
+ public renderEmpty?: undefined | (() => React.ReactNode);
+
constructor(
initialInput: DashboardContainerInput,
private readonly options: DashboardContainerOptions,
@@ -124,7 +126,7 @@ export class DashboardContainer extends Container
-
+
,
dom
diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/grid/_dashboard_grid.scss b/src/plugins/dashboard_embeddable_container/public/embeddable/grid/_dashboard_grid.scss
index 24b813ec5896..0bd356522c7f 100644
--- a/src/plugins/dashboard_embeddable_container/public/embeddable/grid/_dashboard_grid.scss
+++ b/src/plugins/dashboard_embeddable_container/public/embeddable/grid/_dashboard_grid.scss
@@ -34,7 +34,7 @@
.dshLayout-isMaximizedPanel {
height: 100% !important; /* 1. */
width: 100%;
- position: absolute;
+ position: absolute !important;
}
/**
diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/viewport/dashboard_viewport.test.tsx b/src/plugins/dashboard_embeddable_container/public/embeddable/viewport/dashboard_viewport.test.tsx
index a2f7b8dc28fb..e3d9b8552f06 100644
--- a/src/plugins/dashboard_embeddable_container/public/embeddable/viewport/dashboard_viewport.test.tsx
+++ b/src/plugins/dashboard_embeddable_container/public/embeddable/viewport/dashboard_viewport.test.tsx
@@ -121,6 +121,24 @@ test('renders DashboardViewport with no visualizations', () => {
component.unmount();
});
+test('renders DashboardEmptyScreen', () => {
+ const renderEmptyScreen = jest.fn();
+ const { props, options } = getProps({ renderEmpty: renderEmptyScreen });
+ props.container.updateInput({ isEmptyState: true });
+ const component = mount(
+
+
+
+
+
+ );
+ const dashboardEmptyScreenDiv = component.find('.dshDashboardEmptyScreen');
+ expect(dashboardEmptyScreenDiv.length).toBe(1);
+ expect(renderEmptyScreen).toHaveBeenCalled();
+
+ component.unmount();
+});
+
test('renders exit full screen button when in full screen mode', async () => {
const { props, options } = getProps();
props.container.updateInput({ isFullScreenMode: true });
@@ -153,6 +171,39 @@ test('renders exit full screen button when in full screen mode', async () => {
component.unmount();
});
+test('renders exit full screen button when in full screen mode and empty screen', async () => {
+ const renderEmptyScreen = jest.fn();
+ renderEmptyScreen.mockReturnValue(React.createElement('div'));
+ const { props, options } = getProps({ renderEmpty: renderEmptyScreen });
+ props.container.updateInput({ isEmptyState: true, isFullScreenMode: true });
+ const component = mount(
+
+
+
+
+
+ );
+ expect(
+ (component
+ .find('.dshDashboardEmptyScreen')
+ .childAt(0)
+ .type() as any).name
+ ).toBe('ExitFullScreenButton');
+
+ props.container.updateInput({ isFullScreenMode: false });
+ component.update();
+ await nextTick();
+
+ expect(
+ (component
+ .find('.dshDashboardEmptyScreen')
+ .childAt(0)
+ .type() as any).name
+ ).not.toBe('ExitFullScreenButton');
+
+ component.unmount();
+});
+
test('DashboardViewport unmount unsubscribes', async done => {
const { props, options } = getProps();
const component = mount(
diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/viewport/dashboard_viewport.tsx b/src/plugins/dashboard_embeddable_container/public/embeddable/viewport/dashboard_viewport.tsx
index 13407e5e3372..e7fd379898dd 100644
--- a/src/plugins/dashboard_embeddable_container/public/embeddable/viewport/dashboard_viewport.tsx
+++ b/src/plugins/dashboard_embeddable_container/public/embeddable/viewport/dashboard_viewport.tsx
@@ -26,6 +26,7 @@ import { context } from '../../../../kibana_react/public';
export interface DashboardViewportProps {
container: DashboardContainer;
+ renderEmpty?: () => React.ReactNode;
}
interface State {
@@ -34,6 +35,7 @@ interface State {
title: string;
description?: string;
panels: { [key: string]: PanelState };
+ isEmptyState?: boolean;
}
export class DashboardViewport extends React.Component {
@@ -44,26 +46,40 @@ export class DashboardViewport extends React.Component {
- const { isFullScreenMode, useMargins, title, description } = this.props.container.getInput();
+ const {
+ isFullScreenMode,
+ useMargins,
+ title,
+ description,
+ isEmptyState,
+ } = this.props.container.getInput();
if (this.mounted) {
this.setState({
isFullScreenMode,
description,
useMargins,
title,
+ isEmptyState,
});
}
});
@@ -82,19 +98,33 @@ export class DashboardViewport extends React.Component
+ {isFullScreenMode && (
+
+ )}
+ {renderEmpty && renderEmpty()}
+
+ );
+ }
+
+ private renderContainerScreen() {
const { container } = this.props;
+ const { isFullScreenMode, panels, title, description, useMargins } = this.state;
return (
- {this.state.isFullScreenMode && (
+ {isFullScreenMode && (
@@ -103,4 +133,13 @@ export class DashboardViewport extends React.Component
);
}
+
+ public render() {
+ return (
+
+ {this.state.isEmptyState ? this.renderEmptyScreen() : null}
+ {this.renderContainerScreen()}
+
+ );
+ }
}
diff --git a/src/plugins/dashboard_embeddable_container/public/plugin.tsx b/src/plugins/dashboard_embeddable_container/public/plugin.tsx
index 79cc9b698054..d18fbba239ec 100644
--- a/src/plugins/dashboard_embeddable_container/public/plugin.tsx
+++ b/src/plugins/dashboard_embeddable_container/public/plugin.tsx
@@ -27,7 +27,7 @@ import { ExpandPanelAction, ReplacePanelAction } from '.';
import { DashboardContainerFactory } from './embeddable/dashboard_container_factory';
import { Start as InspectorStartContract } from '../../../plugins/inspector/public';
import {
- SavedObjectFinder as SavedObjectFinderUi,
+ SavedObjectFinderUi,
SavedObjectFinderProps,
ExitFullScreenButton as ExitFullScreenButtonUi,
ExitFullScreenButtonProps,
diff --git a/src/plugins/embeddable/public/lib/containers/container.ts b/src/plugins/embeddable/public/lib/containers/container.ts
index bce16747ed48..71e7cca3552b 100644
--- a/src/plugins/embeddable/public/lib/containers/container.ts
+++ b/src/plugins/embeddable/public/lib/containers/container.ts
@@ -240,6 +240,7 @@ export abstract class Container<
...this.input.panels,
[panelState.explicitInput.id]: panelState,
},
+ isEmptyState: false,
} as Partial);
return await this.untilEmbeddableLoaded(panelState.explicitInput.id);
diff --git a/src/plugins/embeddable/public/lib/embeddables/i_embeddable.ts b/src/plugins/embeddable/public/lib/embeddables/i_embeddable.ts
index 33cb146a056c..019758277894 100644
--- a/src/plugins/embeddable/public/lib/embeddables/i_embeddable.ts
+++ b/src/plugins/embeddable/public/lib/embeddables/i_embeddable.ts
@@ -28,7 +28,7 @@ export interface EmbeddableInput {
id: string;
lastReloadRequestTime?: number;
hidePanelTitles?: boolean;
-
+ isEmptyState?: boolean;
/**
* List of action IDs that this embeddable should not render.
*/
diff --git a/src/plugins/es_ui_shared/public/request/np_ready_request.ts b/src/plugins/es_ui_shared/public/request/np_ready_request.ts
index 48c7904661e5..5a3f28ed7648 100644
--- a/src/plugins/es_ui_shared/public/request/np_ready_request.ts
+++ b/src/plugins/es_ui_shared/public/request/np_ready_request.ts
@@ -19,11 +19,12 @@
import { useEffect, useState, useRef } from 'react';
-import { HttpServiceBase } from '../../../../../src/core/public';
+import { HttpServiceBase, HttpFetchQuery } from '../../../../../src/core/public';
export interface SendRequestConfig {
path: string;
method: 'get' | 'post' | 'put' | 'delete' | 'patch' | 'head';
+ query?: HttpFetchQuery;
body?: any;
}
@@ -48,10 +49,10 @@ export interface UseRequestResponse {
export const sendRequest = async (
httpClient: HttpServiceBase,
- { path, method, body }: SendRequestConfig
+ { path, method, body, query }: SendRequestConfig
): Promise => {
try {
- const response = await httpClient[method](path, { body });
+ const response = await httpClient[method](path, { body, query });
return {
data: response.data ? response.data : response,
@@ -70,6 +71,7 @@ export const useRequest = (
{
path,
method,
+ query,
body,
pollIntervalMs,
initialData,
@@ -112,6 +114,7 @@ export const useRequest = (
const requestBody = {
path,
method,
+ query,
body,
};
diff --git a/src/plugins/kibana_react/public/saved_objects/saved_object_finder.test.tsx b/src/plugins/kibana_react/public/saved_objects/saved_object_finder.test.tsx
index b35ba427378a..58b396d57639 100644
--- a/src/plugins/kibana_react/public/saved_objects/saved_object_finder.test.tsx
+++ b/src/plugins/kibana_react/public/saved_objects/saved_object_finder.test.tsx
@@ -35,7 +35,7 @@ import { IconType } from '@elastic/eui';
import { shallow } from 'enzyme';
import React from 'react';
import * as sinon from 'sinon';
-import { SavedObjectFinder } from './saved_object_finder';
+import { SavedObjectFinderUi as SavedObjectFinder } from './saved_object_finder';
// eslint-disable-next-line
import { coreMock } from '../../../../core/public/mocks';
diff --git a/src/plugins/kibana_react/public/saved_objects/saved_object_finder.tsx b/src/plugins/kibana_react/public/saved_objects/saved_object_finder.tsx
index c65d42895876..51fbbd2ba304 100644
--- a/src/plugins/kibana_react/public/saved_objects/saved_object_finder.tsx
+++ b/src/plugins/kibana_react/public/saved_objects/saved_object_finder.tsx
@@ -46,6 +46,7 @@ import { i18n } from '@kbn/i18n';
import { SavedObjectAttributes } from '../../../../core/server';
import { SimpleSavedObject, CoreStart } from '../../../../core/public';
+import { useKibana } from '../context';
// TODO the typings for EuiListGroup are incorrect - maxWidth is missing. This can be removed when the types are adjusted
const FixedEuiListGroup = (EuiListGroup as any) as React.FunctionComponent<
@@ -104,12 +105,18 @@ interface SavedObjectFinderInitialPageSize extends BaseSavedObjectFinder {
initialPageSize?: 5 | 10 | 15 | 25;
fixedPageSize?: undefined;
}
-export type SavedObjectFinderProps = {
+
+export type SavedObjectFinderProps = SavedObjectFinderFixedPage | SavedObjectFinderInitialPageSize;
+
+export type SavedObjectFinderUiProps = {
savedObjects: CoreStart['savedObjects'];
uiSettings: CoreStart['uiSettings'];
-} & (SavedObjectFinderFixedPage | SavedObjectFinderInitialPageSize);
+} & SavedObjectFinderProps;
-class SavedObjectFinder extends React.Component {
+class SavedObjectFinderUi extends React.Component<
+ SavedObjectFinderUiProps,
+ SavedObjectFinderState
+> {
public static propTypes = {
onChoose: PropTypes.func,
noItemsMessage: PropTypes.node,
@@ -174,7 +181,7 @@ class SavedObjectFinder extends React.Component {
+ const { services } = useKibana();
+ return (
+
+ );
+};
+
+export { SavedObjectFinder, SavedObjectFinderUi };
diff --git a/src/plugins/share/kibana.json b/src/plugins/share/kibana.json
index bbe393a76c5d..dce2ac9281ab 100644
--- a/src/plugins/share/kibana.json
+++ b/src/plugins/share/kibana.json
@@ -1,6 +1,6 @@
{
"id": "share",
"version": "kibana",
- "server": false,
+ "server": true,
"ui": true
}
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen_directive.ts b/src/plugins/share/server/index.ts
similarity index 66%
rename from src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen_directive.ts
rename to src/plugins/share/server/index.ts
index 5ebefd817ca4..9e574314f800 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen_directive.ts
+++ b/src/plugins/share/server/index.ts
@@ -16,15 +16,10 @@
* specific language governing permissions and limitations
* under the License.
*/
-// @ts-ignore
-import angular from 'angular';
-import { DashboardEmptyScreen } from './dashboard_empty_screen';
-angular
- .module('app/dashboard/emptyScreen', ['react'])
- .directive('dashboardEmptyScreen', function(reactDirective: any) {
- return reactDirective(DashboardEmptyScreen, [
- ['showLinkToVisualize', { watchDepth: 'value' }],
- ['onLinkClick', { watchDepth: 'reference' }],
- ]);
- });
+import { PluginInitializerContext } from '../../../core/server';
+import { SharePlugin } from './plugin';
+
+export function plugin(initializerContext: PluginInitializerContext) {
+ return new SharePlugin(initializerContext);
+}
diff --git a/src/legacy/server/url_shortening/routes/shorten_url.js b/src/plugins/share/server/plugin.ts
similarity index 59%
rename from src/legacy/server/url_shortening/routes/shorten_url.js
rename to src/plugins/share/server/plugin.ts
index 0203e9373384..bcb681a50652 100644
--- a/src/legacy/server/url_shortening/routes/shorten_url.js
+++ b/src/plugins/share/server/plugin.ts
@@ -17,19 +17,21 @@
* under the License.
*/
-import { handleShortUrlError } from './lib/short_url_error';
-import { shortUrlAssertValid } from './lib/short_url_assert_valid';
+import { CoreSetup, Plugin, PluginInitializerContext } from 'kibana/server';
+import { createRoutes } from './routes/create_routes';
-export const createShortenUrlRoute = ({ shortUrlLookup }) => ({
- method: 'POST',
- path: '/api/shorten_url',
- handler: async function (request) {
- try {
- shortUrlAssertValid(request.payload.url);
- const urlId = await shortUrlLookup.generateUrlId(request.payload.url, request);
- return { urlId };
- } catch (err) {
- throw handleShortUrlError(err);
- }
+export class SharePlugin implements Plugin {
+ constructor(private readonly initializerContext: PluginInitializerContext) {}
+
+ public async setup(core: CoreSetup) {
+ createRoutes(core, this.initializerContext.logger.get());
+ }
+
+ public start() {
+ this.initializerContext.logger.get().debug('Starting plugin');
+ }
+
+ public stop() {
+ this.initializerContext.logger.get().debug('Stopping plugin');
}
-});
+}
diff --git a/src/legacy/ui/public/utils/find_by_param.ts b/src/plugins/share/server/routes/create_routes.ts
similarity index 62%
rename from src/legacy/ui/public/utils/find_by_param.ts
rename to src/plugins/share/server/routes/create_routes.ts
index de32fc955a8c..bd4b6fdb0879 100644
--- a/src/legacy/ui/public/utils/find_by_param.ts
+++ b/src/plugins/share/server/routes/create_routes.ts
@@ -17,22 +17,16 @@
* under the License.
*/
-import _ from 'lodash';
+import { CoreSetup, Logger } from 'kibana/server';
-interface AnyObject {
- [key: string]: any;
-}
+import { shortUrlLookupProvider } from './lib/short_url_lookup';
+import { createGotoRoute } from './goto';
+import { createShortenUrlRoute } from './shorten_url';
+
+export function createRoutes({ http }: CoreSetup, logger: Logger) {
+ const shortUrlLookup = shortUrlLookupProvider({ logger });
+ const router = http.createRouter();
-// given an object or array of objects, return the value of the passed param
-// if the param is missing, return undefined
-export function findByParam(values: AnyObject | AnyObject[], param: string) {
- if (Array.isArray(values)) {
- // point series chart
- const index = _.findIndex(values, param);
- if (index === -1) {
- return;
- }
- return values[index][param];
- }
- return values[param]; // pie chart
+ createGotoRoute({ router, shortUrlLookup, http });
+ createShortenUrlRoute({ router, shortUrlLookup });
}
diff --git a/src/plugins/share/server/routes/goto.ts b/src/plugins/share/server/routes/goto.ts
new file mode 100644
index 000000000000..7343dc1bd34a
--- /dev/null
+++ b/src/plugins/share/server/routes/goto.ts
@@ -0,0 +1,64 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { CoreSetup, IRouter } from 'kibana/server';
+import { schema } from '@kbn/config-schema';
+
+import { shortUrlAssertValid } from './lib/short_url_assert_valid';
+import { ShortUrlLookupService } from './lib/short_url_lookup';
+
+export const createGotoRoute = ({
+ router,
+ shortUrlLookup,
+ http,
+}: {
+ router: IRouter;
+ shortUrlLookup: ShortUrlLookupService;
+ http: CoreSetup['http'];
+}) => {
+ router.get(
+ {
+ path: '/goto/{urlId}',
+ validate: {
+ params: schema.object({ urlId: schema.string() }),
+ },
+ },
+ router.handleLegacyErrors(async function(context, request, response) {
+ const url = await shortUrlLookup.getUrl(request.params.urlId, {
+ savedObjects: context.core.savedObjects.client,
+ });
+ shortUrlAssertValid(url);
+
+ const uiSettings = context.core.uiSettings.client;
+ const stateStoreInSessionStorage = await uiSettings.get('state:storeInSessionStorage');
+ if (!stateStoreInSessionStorage) {
+ return response.redirected({
+ headers: {
+ location: http.basePath.prepend(url),
+ },
+ });
+ }
+ return response.redirected({
+ headers: {
+ location: http.basePath.prepend('/goto_LP/' + request.params.urlId),
+ },
+ });
+ })
+ );
+};
diff --git a/src/plugins/share/server/routes/lib/short_url_assert_valid.test.ts b/src/plugins/share/server/routes/lib/short_url_assert_valid.test.ts
new file mode 100644
index 000000000000..f83073e6aefe
--- /dev/null
+++ b/src/plugins/share/server/routes/lib/short_url_assert_valid.test.ts
@@ -0,0 +1,63 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { shortUrlAssertValid } from './short_url_assert_valid';
+
+describe('shortUrlAssertValid()', () => {
+ const invalid = [
+ ['protocol', 'http://localhost:5601/app/kibana'],
+ ['protocol', 'https://localhost:5601/app/kibana'],
+ ['protocol', 'mailto:foo@bar.net'],
+ ['protocol', 'javascript:alert("hi")'], // eslint-disable-line no-script-url
+ ['hostname', 'localhost/app/kibana'],
+ ['hostname and port', 'local.host:5601/app/kibana'],
+ ['hostname and auth', 'user:pass@localhost.net/app/kibana'],
+ ['path traversal', '/app/../../not-kibana'],
+ ['deep path', '/app/kibana/foo'],
+ ['deep path', '/app/kibana/foo/bar'],
+ ['base path', '/base/app/kibana'],
+ ];
+
+ invalid.forEach(([desc, url]) => {
+ it(`fails when url has ${desc}`, () => {
+ try {
+ shortUrlAssertValid(url);
+ throw new Error(`expected assertion to throw`);
+ } catch (err) {
+ if (!err || !err.isBoom) {
+ throw err;
+ }
+ }
+ });
+ });
+
+ const valid = [
+ '/app/kibana',
+ '/app/monitoring#angular/route',
+ '/app/text#document-id',
+ '/app/some?with=query',
+ '/app/some?with=query#and-a-hash',
+ ];
+
+ valid.forEach(url => {
+ it(`allows ${url}`, () => {
+ shortUrlAssertValid(url);
+ });
+ });
+});
diff --git a/src/plugins/share/server/routes/lib/short_url_assert_valid.ts b/src/plugins/share/server/routes/lib/short_url_assert_valid.ts
new file mode 100644
index 000000000000..2f120bbc03cd
--- /dev/null
+++ b/src/plugins/share/server/routes/lib/short_url_assert_valid.ts
@@ -0,0 +1,41 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { parse } from 'url';
+import { trim } from 'lodash';
+import Boom from 'boom';
+
+export function shortUrlAssertValid(url: string) {
+ const { protocol, hostname, pathname } = parse(url);
+
+ if (protocol) {
+ throw Boom.notAcceptable(`Short url targets cannot have a protocol, found "${protocol}"`);
+ }
+
+ if (hostname) {
+ throw Boom.notAcceptable(`Short url targets cannot have a hostname, found "${hostname}"`);
+ }
+
+ const pathnameParts = trim(pathname, '/').split('/');
+ if (pathnameParts.length !== 2) {
+ throw Boom.notAcceptable(
+ `Short url target path must be in the format "/app/{{appId}}", found "${pathname}"`
+ );
+ }
+}
diff --git a/src/plugins/share/server/routes/lib/short_url_lookup.test.ts b/src/plugins/share/server/routes/lib/short_url_lookup.test.ts
new file mode 100644
index 000000000000..87e2b7b726e5
--- /dev/null
+++ b/src/plugins/share/server/routes/lib/short_url_lookup.test.ts
@@ -0,0 +1,125 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { shortUrlLookupProvider, ShortUrlLookupService } from './short_url_lookup';
+import { SavedObjectsClientContract, Logger } from 'kibana/server';
+import { SavedObjectsClient } from '../../../../../core/server';
+
+describe('shortUrlLookupProvider', () => {
+ const ID = 'bf00ad16941fc51420f91a93428b27a0';
+ const TYPE = 'url';
+ const URL = 'http://elastic.co';
+
+ let savedObjects: jest.Mocked;
+ let deps: { savedObjects: SavedObjectsClientContract };
+ let shortUrl: ShortUrlLookupService;
+
+ beforeEach(() => {
+ savedObjects = ({
+ get: jest.fn(),
+ create: jest.fn(() => Promise.resolve({ id: ID })),
+ update: jest.fn(),
+ errors: SavedObjectsClient.errors,
+ } as unknown) as jest.Mocked;
+
+ deps = { savedObjects };
+ shortUrl = shortUrlLookupProvider({ logger: ({ warn: () => {} } as unknown) as Logger });
+ });
+
+ describe('generateUrlId', () => {
+ it('returns the document id', async () => {
+ const id = await shortUrl.generateUrlId(URL, deps);
+ expect(id).toEqual(ID);
+ });
+
+ it('provides correct arguments to savedObjectsClient', async () => {
+ await shortUrl.generateUrlId(URL, { savedObjects });
+
+ expect(savedObjects.create).toHaveBeenCalledTimes(1);
+ const [type, attributes, options] = savedObjects.create.mock.calls[0];
+
+ expect(type).toEqual(TYPE);
+ expect(Object.keys(attributes).sort()).toEqual([
+ 'accessCount',
+ 'accessDate',
+ 'createDate',
+ 'url',
+ ]);
+ expect(attributes.url).toEqual(URL);
+ expect(options!.id).toEqual(ID);
+ });
+
+ it('passes persists attributes', async () => {
+ await shortUrl.generateUrlId(URL, deps);
+
+ expect(savedObjects.create).toHaveBeenCalledTimes(1);
+ const [type, attributes] = savedObjects.create.mock.calls[0];
+
+ expect(type).toEqual(TYPE);
+ expect(Object.keys(attributes).sort()).toEqual([
+ 'accessCount',
+ 'accessDate',
+ 'createDate',
+ 'url',
+ ]);
+ expect(attributes.url).toEqual(URL);
+ });
+
+ it('gracefully handles version conflict', async () => {
+ const error = savedObjects.errors.decorateConflictError(new Error());
+ savedObjects.create.mockImplementation(() => {
+ throw error;
+ });
+ const id = await shortUrl.generateUrlId(URL, deps);
+ expect(id).toEqual(ID);
+ });
+ });
+
+ describe('getUrl', () => {
+ beforeEach(() => {
+ const attributes = { accessCount: 2, url: URL };
+ savedObjects.get.mockResolvedValue({ id: ID, attributes, type: 'url', references: [] });
+ });
+
+ it('provides the ID to savedObjectsClient', async () => {
+ await shortUrl.getUrl(ID, { savedObjects });
+
+ expect(savedObjects.get).toHaveBeenCalledTimes(1);
+ expect(savedObjects.get).toHaveBeenCalledWith(TYPE, ID);
+ });
+
+ it('returns the url', async () => {
+ const response = await shortUrl.getUrl(ID, deps);
+ expect(response).toEqual(URL);
+ });
+
+ it('increments accessCount', async () => {
+ await shortUrl.getUrl(ID, { savedObjects });
+
+ expect(savedObjects.update).toHaveBeenCalledTimes(1);
+
+ const [type, id, attributes] = savedObjects.update.mock.calls[0];
+
+ expect(type).toEqual(TYPE);
+ expect(id).toEqual(ID);
+ expect(Object.keys(attributes).sort()).toEqual(['accessCount', 'accessDate']);
+ expect(attributes.accessCount).toEqual(3);
+ });
+ });
+});
diff --git a/src/plugins/share/server/routes/lib/short_url_lookup.ts b/src/plugins/share/server/routes/lib/short_url_lookup.ts
new file mode 100644
index 000000000000..0d8a9c86621d
--- /dev/null
+++ b/src/plugins/share/server/routes/lib/short_url_lookup.ts
@@ -0,0 +1,84 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import crypto from 'crypto';
+import { get } from 'lodash';
+
+import { Logger, SavedObject, SavedObjectsClientContract } from 'kibana/server';
+
+export interface ShortUrlLookupService {
+ generateUrlId(url: string, deps: { savedObjects: SavedObjectsClientContract }): Promise;
+ getUrl(url: string, deps: { savedObjects: SavedObjectsClientContract }): Promise;
+}
+
+export function shortUrlLookupProvider({ logger }: { logger: Logger }): ShortUrlLookupService {
+ async function updateMetadata(
+ doc: SavedObject,
+ { savedObjects }: { savedObjects: SavedObjectsClientContract }
+ ) {
+ try {
+ await savedObjects.update('url', doc.id, {
+ accessDate: new Date().valueOf(),
+ accessCount: get(doc, 'attributes.accessCount', 0) + 1,
+ });
+ } catch (error) {
+ logger.warn('Warning: Error updating url metadata');
+ logger.warn(error);
+ // swallow errors. It isn't critical if there is no update.
+ }
+ }
+
+ return {
+ async generateUrlId(url, { savedObjects }) {
+ const id = crypto
+ .createHash('md5')
+ .update(url)
+ .digest('hex');
+ const { isConflictError } = savedObjects.errors;
+
+ try {
+ const doc = await savedObjects.create(
+ 'url',
+ {
+ url,
+ accessCount: 0,
+ createDate: new Date().valueOf(),
+ accessDate: new Date().valueOf(),
+ },
+ { id }
+ );
+
+ return doc.id;
+ } catch (error) {
+ if (isConflictError(error)) {
+ return id;
+ }
+
+ throw error;
+ }
+ },
+
+ async getUrl(id, { savedObjects }) {
+ const doc = await savedObjects.get('url', id);
+ updateMetadata(doc, { savedObjects });
+
+ return doc.attributes.url;
+ },
+ };
+}
diff --git a/src/plugins/share/server/routes/shorten_url.ts b/src/plugins/share/server/routes/shorten_url.ts
new file mode 100644
index 000000000000..116b90c6971c
--- /dev/null
+++ b/src/plugins/share/server/routes/shorten_url.ts
@@ -0,0 +1,48 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { IRouter } from 'kibana/server';
+import { schema } from '@kbn/config-schema';
+
+import { shortUrlAssertValid } from './lib/short_url_assert_valid';
+import { ShortUrlLookupService } from './lib/short_url_lookup';
+
+export const createShortenUrlRoute = ({
+ shortUrlLookup,
+ router,
+}: {
+ shortUrlLookup: ShortUrlLookupService;
+ router: IRouter;
+}) => {
+ router.post(
+ {
+ path: '/api/shorten_url',
+ validate: {
+ body: schema.object({ url: schema.string() }),
+ },
+ },
+ router.handleLegacyErrors(async function(context, request, response) {
+ shortUrlAssertValid(request.body.url);
+ const urlId = await shortUrlLookup.generateUrlId(request.body.url, {
+ savedObjects: context.core.savedObjects.client,
+ });
+ return response.ok({ body: { urlId } });
+ })
+ );
+};
diff --git a/test/examples/README.md b/test/examples/README.md
new file mode 100644
index 000000000000..44656f949bc7
--- /dev/null
+++ b/test/examples/README.md
@@ -0,0 +1,23 @@
+# Example plugin functional tests
+
+This folder contains functional tests for the example plugins.
+
+## Run the test
+
+To run these tests during development you can use the following commands:
+
+```
+# Start the test server (can continue running)
+node scripts/functional_tests_server.js --config test/examples/config.js
+# Start a test run
+node scripts/functional_test_runner.js --config test/examples/config.js
+```
+
+## Run Kibana with a test plugin
+
+In case you want to start Kibana with the example plugins, you can just run:
+
+```
+yarn start --run-examples
+```
+
diff --git a/test/examples/config.js b/test/examples/config.js
new file mode 100644
index 000000000000..b954390dc54a
--- /dev/null
+++ b/test/examples/config.js
@@ -0,0 +1,55 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import path from 'path';
+import { services } from '../plugin_functional/services';
+
+export default async function ({ readConfigFile }) {
+ const functionalConfig = await readConfigFile(require.resolve('../functional/config'));
+
+ return {
+ testFiles: [
+ require.resolve('./search'),
+ ],
+ services: {
+ ...functionalConfig.get('services'),
+ ...services,
+ },
+ pageObjects: functionalConfig.get('pageObjects'),
+ servers: functionalConfig.get('servers'),
+ esTestCluster: functionalConfig.get('esTestCluster'),
+ apps: functionalConfig.get('apps'),
+ esArchiver: {
+ directory: path.resolve(__dirname, '../es_archives')
+ },
+ screenshots: functionalConfig.get('screenshots'),
+ junit: {
+ reportName: 'Example plugin functional tests',
+ },
+ kbnTestServer: {
+ ...functionalConfig.get('kbnTestServer'),
+ serverArgs: [
+ ...functionalConfig.get('kbnTestServer.serverArgs'),
+ '--run-examples',
+ // Required to run examples
+ '--env.name=development',
+ ],
+ },
+ };
+}
diff --git a/test/plugin_functional/test_suites/search/demo_data.ts b/test/examples/search/demo_data.ts
similarity index 100%
rename from test/plugin_functional/test_suites/search/demo_data.ts
rename to test/examples/search/demo_data.ts
diff --git a/test/plugin_functional/test_suites/search/es_search.ts b/test/examples/search/es_search.ts
similarity index 100%
rename from test/plugin_functional/test_suites/search/es_search.ts
rename to test/examples/search/es_search.ts
diff --git a/test/plugin_functional/test_suites/search/index.ts b/test/examples/search/index.ts
similarity index 100%
rename from test/plugin_functional/test_suites/search/index.ts
rename to test/examples/search/index.ts
diff --git a/test/functional/apps/dashboard/full_screen_mode.js b/test/functional/apps/dashboard/full_screen_mode.js
index e18fd47b39b1..bf549ec21a6d 100644
--- a/test/functional/apps/dashboard/full_screen_mode.js
+++ b/test/functional/apps/dashboard/full_screen_mode.js
@@ -78,7 +78,6 @@ export default function ({ getService, getPageObjects }) {
const logoButton = await PageObjects.dashboard.getExitFullScreenLogoButton();
await logoButton.moveMouseTo();
await PageObjects.dashboard.clickExitFullScreenTextButton();
-
await retry.try(async () => {
const isChromeVisible = await PageObjects.common.isChromeVisible();
expect(isChromeVisible).to.be(true);
diff --git a/test/plugin_functional/config.js b/test/plugin_functional/config.js
index a6316c607a7c..d8ce12d1fc61 100644
--- a/test/plugin_functional/config.js
+++ b/test/plugin_functional/config.js
@@ -33,7 +33,6 @@ export default async function ({ readConfigFile }) {
require.resolve('./test_suites/app_plugins'),
require.resolve('./test_suites/custom_visualizations'),
require.resolve('./test_suites/panel_actions'),
- require.resolve('./test_suites/search'),
/**
* @todo Work on re-enabling this test suite after this is merged. These tests pass
diff --git a/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/legacy.ts b/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/legacy.ts
index a310403c86b5..1928d7ac7231 100644
--- a/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/legacy.ts
+++ b/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/legacy.ts
@@ -22,7 +22,6 @@ import 'uiExports/embeddableFactories';
import 'uiExports/embeddableActions';
import { npSetup, npStart } from 'ui/new_platform';
-import { SavedObjectFinder } from 'ui/saved_objects/components/saved_object_finder';
import { ExitFullScreenButton } from 'ui/exit_full_screen';
import uiRoutes from 'ui/routes';
// @ts-ignore
@@ -39,7 +38,6 @@ export const setup = pluginInstance.setup(npSetup.core, {
embeddable: npSetup.plugins.embeddable,
inspector: npSetup.plugins.inspector,
__LEGACY: {
- SavedObjectFinder,
ExitFullScreenButton,
},
});
@@ -64,7 +62,6 @@ export const start = pluginInstance.start(npStart.core, {
inspector: npStart.plugins.inspector,
uiActions: npStart.plugins.uiActions,
__LEGACY: {
- SavedObjectFinder,
ExitFullScreenButton,
onRenderComplete: (renderCompleteListener: () => void) => {
if (rendered) {
diff --git a/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/plugin.tsx b/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/plugin.tsx
index 6b82a67b9fcd..adf898d9af2c 100644
--- a/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/plugin.tsx
+++ b/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/plugin.tsx
@@ -38,6 +38,10 @@ import {
ContactCardEmbeddableFactory,
} from './embeddable_api';
import { App } from './app';
+import {
+ SavedObjectFinderProps,
+ SavedObjectFinderUi,
+} from '../../../../../../../src/plugins/kibana_react/public/saved_objects';
import {
IEmbeddableStart,
IEmbeddableSetup,
@@ -47,7 +51,6 @@ export interface SetupDependencies {
embeddable: IEmbeddableSetup;
inspector: InspectorSetupContract;
__LEGACY: {
- SavedObjectFinder: React.ComponentType;
ExitFullScreenButton: React.ComponentType;
};
}
@@ -57,7 +60,6 @@ interface StartDependencies {
uiActions: IUiActionsStart;
inspector: InspectorStartContract;
__LEGACY: {
- SavedObjectFinder: React.ComponentType;
ExitFullScreenButton: React.ComponentType;
onRenderComplete: (onRenderComplete: () => void) => void;
};
@@ -99,6 +101,13 @@ export class EmbeddableExplorerPublicPlugin
plugins.__LEGACY.onRenderComplete(() => {
const root = document.getElementById(REACT_ROOT_ID);
+ const SavedObjectFinder = (props: SavedObjectFinderProps) => (
+
+ );
ReactDOM.render(
,
root
diff --git a/x-pack/dev-tools/jest/create_jest_config.js b/x-pack/dev-tools/jest/create_jest_config.js
index 199232262773..f8d07668d0aa 100644
--- a/x-pack/dev-tools/jest/create_jest_config.js
+++ b/x-pack/dev-tools/jest/create_jest_config.js
@@ -20,7 +20,8 @@ export function createJestConfig({ kibanaDirectory, xPackKibanaDirectory }) {
'uiExports/(.*)': fileMockPath,
'^src/core/(.*)': `${kibanaDirectory}/src/core/$1`,
'^src/legacy/(.*)': `${kibanaDirectory}/src/legacy/$1`,
- '^plugins/watcher/models/(.*)': `${xPackKibanaDirectory}/legacy/plugins/watcher/public/models/$1`,
+ '^plugins/watcher/np_ready/application/models/(.*)':
+ `${xPackKibanaDirectory}/legacy/plugins/watcher/public/np_ready/application/models/$1`,
'^plugins/([^/.]*)(.*)': `${kibanaDirectory}/src/legacy/core_plugins/$1/public$2`,
'^legacy/plugins/xpack_main/(.*);': `${xPackKibanaDirectory}/legacy/plugins/xpack_main/public/$1`,
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': fileMockPath,
diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/__jest__/TransactionOverview.test.tsx b/x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/__jest__/TransactionOverview.test.tsx
index a5356be72f5e..91e0ae11a652 100644
--- a/x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/__jest__/TransactionOverview.test.tsx
+++ b/x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/__jest__/TransactionOverview.test.tsx
@@ -18,6 +18,7 @@ import { history } from '../../../../utils/history';
import { TransactionOverview } from '..';
import { IUrlParams } from '../../../../context/UrlParamsContext/types';
import * as useServiceTransactionTypesHook from '../../../../hooks/useServiceTransactionTypes';
+import * as useFetcherHook from '../../../../hooks/useFetcher';
import { fromQuery } from '../../../shared/Links/url_helpers';
import { Router } from 'react-router-dom';
import { UrlParamsProvider } from '../../../../context/UrlParamsContext';
@@ -51,6 +52,8 @@ function setup({
.spyOn(useServiceTransactionTypesHook, 'useServiceTransactionTypes')
.mockReturnValue(serviceTransactionTypes);
+ jest.spyOn(useFetcherHook, 'useFetcher').mockReturnValue({} as any);
+
return render(
diff --git a/x-pack/legacy/plugins/apm/public/components/shared/DatePicker/__test__/DatePicker.test.tsx b/x-pack/legacy/plugins/apm/public/components/shared/DatePicker/__test__/DatePicker.test.tsx
index 05094c59712a..32379325c402 100644
--- a/x-pack/legacy/plugins/apm/public/components/shared/DatePicker/__test__/DatePicker.test.tsx
+++ b/x-pack/legacy/plugins/apm/public/components/shared/DatePicker/__test__/DatePicker.test.tsx
@@ -10,13 +10,13 @@ import {
UrlParamsContext,
useUiFilters
} from '../../../../context/UrlParamsContext';
-import { tick } from '../../../../utils/testHelpers';
import { DatePicker } from '../index';
import { IUrlParams } from '../../../../context/UrlParamsContext/types';
import { history } from '../../../../utils/history';
import { mount } from 'enzyme';
import { EuiSuperDatePicker } from '@elastic/eui';
import { MemoryRouter } from 'react-router-dom';
+import { wait } from '@testing-library/react';
const mockHistoryPush = jest.spyOn(history, 'push');
const mockRefreshTimeRange = jest.fn();
@@ -84,7 +84,7 @@ describe('DatePicker', () => {
});
expect(mockRefreshTimeRange).not.toHaveBeenCalled();
jest.advanceTimersByTime(1000);
- await tick();
+ await wait();
expect(mockRefreshTimeRange).toHaveBeenCalled();
wrapper.unmount();
});
@@ -94,7 +94,7 @@ describe('DatePicker', () => {
mountDatePicker({ refreshPaused: true, refreshInterval: 1000 });
expect(mockRefreshTimeRange).not.toHaveBeenCalled();
jest.advanceTimersByTime(1000);
- await tick();
+ await wait();
expect(mockRefreshTimeRange).not.toHaveBeenCalled();
});
});
diff --git a/x-pack/legacy/plugins/apm/public/components/shared/useDelayedVisibility/Delayed/index.ts b/x-pack/legacy/plugins/apm/public/components/shared/useDelayedVisibility/Delayed/index.ts
index 798e872dbc47..9048afe57153 100644
--- a/x-pack/legacy/plugins/apm/public/components/shared/useDelayedVisibility/Delayed/index.ts
+++ b/x-pack/legacy/plugins/apm/public/components/shared/useDelayedVisibility/Delayed/index.ts
@@ -57,4 +57,10 @@ export class Delayed {
public onChange(onChangeCallback: Callback) {
this.onChangeCallback = onChangeCallback;
}
+
+ public destroy() {
+ if (this.timeoutId) {
+ window.clearTimeout(this.timeoutId);
+ }
+ }
}
diff --git a/x-pack/legacy/plugins/apm/public/components/shared/useDelayedVisibility/index.test.tsx b/x-pack/legacy/plugins/apm/public/components/shared/useDelayedVisibility/index.test.tsx
index 57e634df2283..c55c6ab35184 100644
--- a/x-pack/legacy/plugins/apm/public/components/shared/useDelayedVisibility/index.test.tsx
+++ b/x-pack/legacy/plugins/apm/public/components/shared/useDelayedVisibility/index.test.tsx
@@ -4,11 +4,16 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { renderHook } from '@testing-library/react-hooks';
+import {
+ renderHook,
+ act,
+ RenderHookResult
+} from '@testing-library/react-hooks';
import { useDelayedVisibility } from '.';
describe('useFetcher', () => {
- let hook;
+ let hook: RenderHookResult;
+
beforeEach(() => {
jest.useFakeTimers();
});
@@ -26,9 +31,15 @@ describe('useFetcher', () => {
});
hook.rerender(true);
- jest.advanceTimersByTime(10);
+ act(() => {
+ jest.advanceTimersByTime(10);
+ });
+
expect(hook.result.current).toEqual(false);
- jest.advanceTimersByTime(50);
+ act(() => {
+ jest.advanceTimersByTime(50);
+ });
+
expect(hook.result.current).toEqual(true);
});
@@ -38,8 +49,11 @@ describe('useFetcher', () => {
});
hook.rerender(true);
- jest.advanceTimersByTime(100);
+ act(() => {
+ jest.advanceTimersByTime(100);
+ });
hook.rerender(false);
+
expect(hook.result.current).toEqual(true);
});
@@ -49,11 +63,22 @@ describe('useFetcher', () => {
});
hook.rerender(true);
- jest.advanceTimersByTime(100);
+
+ act(() => {
+ jest.advanceTimersByTime(100);
+ });
+
hook.rerender(false);
- jest.advanceTimersByTime(900);
+ act(() => {
+ jest.advanceTimersByTime(900);
+ });
+
expect(hook.result.current).toEqual(true);
- jest.advanceTimersByTime(100);
+
+ act(() => {
+ jest.advanceTimersByTime(100);
+ });
+
expect(hook.result.current).toEqual(false);
});
});
diff --git a/x-pack/legacy/plugins/apm/public/components/shared/useDelayedVisibility/index.ts b/x-pack/legacy/plugins/apm/public/components/shared/useDelayedVisibility/index.ts
index 5acbbd1d4573..c4465c7b4233 100644
--- a/x-pack/legacy/plugins/apm/public/components/shared/useDelayedVisibility/index.ts
+++ b/x-pack/legacy/plugins/apm/public/components/shared/useDelayedVisibility/index.ts
@@ -26,6 +26,10 @@ export function useDelayedVisibility(
setIsVisible(visibility);
});
delayedRef.current = delayed;
+
+ return () => {
+ delayed.destroy();
+ };
}, [hideDelayMs, showDelayMs, minimumVisibleDuration]);
useEffect(() => {
diff --git a/x-pack/legacy/plugins/apm/public/context/UrlParamsContext/__tests__/UrlParamsContext.test.tsx b/x-pack/legacy/plugins/apm/public/context/UrlParamsContext/__tests__/UrlParamsContext.test.tsx
index 2604a3a12257..d2d8036e864a 100644
--- a/x-pack/legacy/plugins/apm/public/context/UrlParamsContext/__tests__/UrlParamsContext.test.tsx
+++ b/x-pack/legacy/plugins/apm/public/context/UrlParamsContext/__tests__/UrlParamsContext.test.tsx
@@ -11,8 +11,8 @@ import { Location, History } from 'history';
import { MemoryRouter, Router } from 'react-router-dom';
import moment from 'moment-timezone';
import { IUrlParams } from '../types';
-import { tick } from '../../../utils/testHelpers';
import { getParsedDate } from '../helpers';
+import { wait } from '@testing-library/react';
function mountParams(location: Location) {
return mount(
@@ -143,13 +143,13 @@ describe('UrlParamsContext', () => {
);
- await tick();
+ await wait();
expect(calls.length).toBe(1);
wrapper.find('button').simulate('click');
- await tick();
+ await wait();
expect(calls.length).toBe(2);
@@ -194,11 +194,11 @@ describe('UrlParamsContext', () => {
);
- await tick();
+ await wait();
wrapper.find('button').simulate('click');
- await tick();
+ await wait();
const params = getDataFromOutput(wrapper);
expect(params.start).toEqual('2000-06-14T00:00:00.000Z');
diff --git a/x-pack/legacy/plugins/apm/public/hooks/useFetcher.integration.test.tsx b/x-pack/legacy/plugins/apm/public/hooks/useFetcher.integration.test.tsx
index 36a8377c0252..743cf4e01e55 100644
--- a/x-pack/legacy/plugins/apm/public/hooks/useFetcher.integration.test.tsx
+++ b/x-pack/legacy/plugins/apm/public/hooks/useFetcher.integration.test.tsx
@@ -5,8 +5,8 @@
*/
import React from 'react';
-import { render } from '@testing-library/react';
-import { delay, tick } from '../utils/testHelpers';
+import { render, wait } from '@testing-library/react';
+import { delay } from '../utils/testHelpers';
import { useFetcher } from './useFetcher';
import { KibanaCoreContext } from '../../../observability/public/context/kibana_core';
import { LegacyCoreStart } from 'kibana/public';
@@ -76,7 +76,8 @@ describe('when simulating race condition', () => {
it('should render "Hello from Peter" after 200ms', async () => {
jest.advanceTimersByTime(200);
- await tick();
+
+ await wait();
expect(renderSpy).lastCalledWith({
data: 'Hello from Peter',
@@ -87,7 +88,7 @@ describe('when simulating race condition', () => {
it('should render "Hello from Peter" after 600ms', async () => {
jest.advanceTimersByTime(600);
- await tick();
+ await wait();
expect(renderSpy).lastCalledWith({
data: 'Hello from Peter',
@@ -98,7 +99,7 @@ describe('when simulating race condition', () => {
it('should should NOT have rendered "Hello from John" at any point', async () => {
jest.advanceTimersByTime(600);
- await tick();
+ await wait();
expect(renderSpy).not.toHaveBeenCalledWith({
data: 'Hello from John',
@@ -109,7 +110,7 @@ describe('when simulating race condition', () => {
it('should send and receive calls in the right order', async () => {
jest.advanceTimersByTime(600);
- await tick();
+ await wait();
expect(requestCallOrder).toEqual([
['request', 'John', 500],
diff --git a/x-pack/legacy/plugins/apm/public/utils/testHelpers.tsx b/x-pack/legacy/plugins/apm/public/utils/testHelpers.tsx
index b5cee4a78b01..9e3c486715a1 100644
--- a/x-pack/legacy/plugins/apm/public/utils/testHelpers.tsx
+++ b/x-pack/legacy/plugins/apm/public/utils/testHelpers.tsx
@@ -58,7 +58,6 @@ export async function getRenderedHref(Component: React.FC, location: Location) {
);
- await tick();
await waitForElement(() => el.container.querySelector('a'));
const a = el.container.querySelector('a');
@@ -74,9 +73,6 @@ export function delay(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
}
-// Await this when you need to "flush" promises to immediately resolve or throw in tests
-export const tick = () => new Promise(resolve => setImmediate(resolve, 0));
-
export function expectTextsNotInDocument(output: any, texts: string[]) {
texts.forEach(text => {
try {
diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/embeddable.tsx b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/embeddable.tsx
index 8810871e9161..5c7ef1a8c179 100644
--- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/embeddable.tsx
+++ b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/embeddable.tsx
@@ -16,8 +16,11 @@ import {
} from '../../../../../../src/legacy/core_plugins/embeddable_api/public/np_ready/public';
import { start } from '../../../../../../src/legacy/core_plugins/embeddable_api/public/np_ready/public/legacy';
import { EmbeddableExpression } from '../expression_types/embeddable';
-import { SavedObjectFinder } from '../../../../../../src/legacy/ui/public/saved_objects/components/saved_object_finder';
import { RendererStrings } from '../../i18n';
+import {
+ SavedObjectFinderProps,
+ SavedObjectFinderUi,
+} from '../../../../../../src/plugins/kibana_react/public';
const { embeddable: strings } = RendererStrings;
@@ -34,6 +37,13 @@ interface Handlers {
}
const renderEmbeddable = (embeddableObject: IEmbeddable, domNode: HTMLElement) => {
+ const SavedObjectFinder = (props: SavedObjectFinderProps) => (
+
+ );
return (
{
- > {
const { help, args: argHelp } = getFunctionHelp().timelion;
@@ -64,8 +87,8 @@ export function timelion(): ExpressionFunction<'timelion', Filter, Arguments, Pr
// workpad, if it exists. Otherwise fall back on the function args.
const timeFilter = context.and.find(and => and.type === 'time');
const range = timeFilter
- ? { from: timeFilter.from, to: timeFilter.to }
- : { from: args.from, to: args.to };
+ ? { min: timeFilter.from, max: timeFilter.to }
+ : parseDateMath({ from: args.from, to: args.to }, args.timezone);
const body = {
extended: {
@@ -79,8 +102,8 @@ export function timelion(): ExpressionFunction<'timelion', Filter, Arguments, Pr
},
sheet: [args.query],
time: {
- from: range.from,
- to: range.to,
+ from: range.min,
+ to: range.max,
interval: args.interval,
timezone: args.timezone,
},
diff --git a/x-pack/legacy/plugins/graph/public/components/source_picker.tsx b/x-pack/legacy/plugins/graph/public/components/source_picker.tsx
index 2399ac24c199..de920af8a48a 100644
--- a/x-pack/legacy/plugins/graph/public/components/source_picker.tsx
+++ b/x-pack/legacy/plugins/graph/public/components/source_picker.tsx
@@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n';
import React from 'react';
import { CoreStart } from 'src/core/public';
-import { SavedObjectFinder } from '../../../../../../src/plugins/kibana_react/public';
+import { SavedObjectFinderUi } from '../../../../../../src/plugins/kibana_react/public';
import { IndexPatternSavedObject } from '../types';
export interface SourcePickerProps {
@@ -25,7 +25,7 @@ export function SourcePicker({
onIndexPatternSelected,
}: SourcePickerProps) {
return (
- {
diff --git a/x-pack/legacy/plugins/infra/common/http_api/log_analysis/results/log_entry_rate.ts b/x-pack/legacy/plugins/infra/common/http_api/log_analysis/results/log_entry_rate.ts
index 5a1412fd8f3d..dfc3d2aabd11 100644
--- a/x-pack/legacy/plugins/infra/common/http_api/log_analysis/results/log_entry_rate.ts
+++ b/x-pack/legacy/plugins/infra/common/http_api/log_analysis/results/log_entry_rate.ts
@@ -29,7 +29,7 @@ export type GetLogEntryRateRequestPayload = rt.TypeOf;
+
+export const logEntryRateHistogramBucketRT = rt.type({
partitions: rt.array(logEntryRatePartitionRT),
startTime: rt.number,
});
+export type LogEntryRateHistogramBucket = rt.TypeOf;
+
export const getLogEntryRateSuccessReponsePayloadRT = rt.type({
data: rt.type({
bucketDuration: rt.number,
- histogramBuckets: rt.array(logEntryRateHistogramBucket),
+ histogramBuckets: rt.array(logEntryRateHistogramBucketRT),
totalNumberOfLogEntries: rt.number,
}),
});
diff --git a/x-pack/legacy/plugins/infra/common/http_api/log_analysis/validation/index.ts b/x-pack/legacy/plugins/infra/common/http_api/log_analysis/validation/index.ts
index 727faca69298..f23ef7ee7c30 100644
--- a/x-pack/legacy/plugins/infra/common/http_api/log_analysis/validation/index.ts
+++ b/x-pack/legacy/plugins/infra/common/http_api/log_analysis/validation/index.ts
@@ -4,4 +4,4 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export * from './indices';
+export * from './log_entry_rate_indices';
diff --git a/x-pack/legacy/plugins/infra/common/http_api/log_analysis/validation/indices.ts b/x-pack/legacy/plugins/infra/common/http_api/log_analysis/validation/log_entry_rate_indices.ts
similarity index 74%
rename from x-pack/legacy/plugins/infra/common/http_api/log_analysis/validation/indices.ts
rename to x-pack/legacy/plugins/infra/common/http_api/log_analysis/validation/log_entry_rate_indices.ts
index 62d81dc13685..5b2509074f6e 100644
--- a/x-pack/legacy/plugins/infra/common/http_api/log_analysis/validation/indices.ts
+++ b/x-pack/legacy/plugins/infra/common/http_api/log_analysis/validation/log_entry_rate_indices.ts
@@ -6,14 +6,24 @@
import * as rt from 'io-ts';
-export const LOG_ANALYSIS_VALIDATION_INDICES_PATH = '/api/infra/log_analysis/validation/indices';
+export const LOG_ANALYSIS_VALIDATE_INDICES_PATH =
+ '/api/infra/log_analysis/validation/log_entry_rate_indices';
/**
* Request types
*/
+export const validationIndicesFieldSpecificationRT = rt.type({
+ name: rt.string,
+ validTypes: rt.array(rt.string),
+});
+
+export type ValidationIndicesFieldSpecification = rt.TypeOf<
+ typeof validationIndicesFieldSpecificationRT
+>;
+
export const validationIndicesRequestPayloadRT = rt.type({
data: rt.type({
- timestampField: rt.string,
+ fields: rt.array(validationIndicesFieldSpecificationRT),
indices: rt.array(rt.string),
}),
});
diff --git a/x-pack/legacy/plugins/infra/common/log_analysis/job_parameters.ts b/x-pack/legacy/plugins/infra/common/log_analysis/job_parameters.ts
index 5cfe38394a2c..626e90b65a7d 100644
--- a/x-pack/legacy/plugins/infra/common/log_analysis/job_parameters.ts
+++ b/x-pack/legacy/plugins/infra/common/log_analysis/job_parameters.ts
@@ -4,19 +4,25 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { JobType } from './log_analysis';
+import * as rt from 'io-ts';
export const bucketSpan = 900000;
+export const partitionField = 'event.dataset';
+
export const getJobIdPrefix = (spaceId: string, sourceId: string) =>
`kibana-logs-ui-${spaceId}-${sourceId}-`;
-export const getJobId = (spaceId: string, sourceId: string, jobType: JobType) =>
+export const getJobId = (spaceId: string, sourceId: string, jobType: string) =>
`${getJobIdPrefix(spaceId, sourceId)}${jobType}`;
-export const getDatafeedId = (spaceId: string, sourceId: string, jobType: JobType) =>
+export const getDatafeedId = (spaceId: string, sourceId: string, jobType: string) =>
`datafeed-${getJobId(spaceId, sourceId, jobType)}`;
-export const getAllModuleJobIds = (spaceId: string, sourceId: string) => [
- getJobId(spaceId, sourceId, 'log-entry-rate'),
-];
+export const jobSourceConfigurationRT = rt.type({
+ indexPattern: rt.string,
+ timestampField: rt.string,
+ bucketSpan: rt.number,
+});
+
+export type JobSourceConfiguration = rt.TypeOf;
diff --git a/x-pack/legacy/plugins/infra/public/components/formatted_time.tsx b/x-pack/legacy/plugins/infra/public/components/formatted_time.tsx
index 78255c55df12..46b505d4fab5 100644
--- a/x-pack/legacy/plugins/infra/public/components/formatted_time.tsx
+++ b/x-pack/legacy/plugins/infra/public/components/formatted_time.tsx
@@ -37,7 +37,6 @@ export const useFormattedTime = (
const dateFormat = formatMap[format];
const formattedTime = useMemo(() => getFormattedTime(time, dateFormat, fallbackFormat), [
- getFormattedTime,
time,
dateFormat,
fallbackFormat,
diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/analyze_in_ml_button.tsx b/x-pack/legacy/plugins/infra/public/components/logging/log_analysis_results/analyze_in_ml_button.tsx
similarity index 96%
rename from x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/analyze_in_ml_button.tsx
rename to x-pack/legacy/plugins/infra/public/components/logging/log_analysis_results/analyze_in_ml_button.tsx
index ef81f229034b..c5d83e1c205c 100644
--- a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/analyze_in_ml_button.tsx
+++ b/x-pack/legacy/plugins/infra/public/components/logging/log_analysis_results/analyze_in_ml_button.tsx
@@ -4,14 +4,15 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import React from 'react';
-import url from 'url';
import { EuiButton } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
+import React from 'react';
+import { encode } from 'rison-node';
import chrome from 'ui/chrome';
import { QueryString } from 'ui/utils/query_string';
-import { encode } from 'rison-node';
-import { TimeRange } from '../../../../../common/http_api/shared/time_range';
+import url from 'url';
+
+import { TimeRange } from '../../../../common/http_api/shared/time_range';
export const AnalyzeInMlButton: React.FunctionComponent<{
jobId: string;
diff --git a/x-pack/legacy/plugins/watcher/public/lib/documentation_links/index.ts b/x-pack/legacy/plugins/infra/public/components/logging/log_analysis_results/index.ts
similarity index 85%
rename from x-pack/legacy/plugins/watcher/public/lib/documentation_links/index.ts
rename to x-pack/legacy/plugins/infra/public/components/logging/log_analysis_results/index.ts
index 81e0c494e28b..8a4ceb70252a 100644
--- a/x-pack/legacy/plugins/watcher/public/lib/documentation_links/index.ts
+++ b/x-pack/legacy/plugins/infra/public/components/logging/log_analysis_results/index.ts
@@ -4,4 +4,4 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export * from './documentation_links';
+export * from './analyze_in_ml_button';
diff --git a/x-pack/legacy/plugins/infra/public/components/logging/log_entry_flyout/log_entry_actions_menu.tsx b/x-pack/legacy/plugins/infra/public/components/logging/log_entry_flyout/log_entry_actions_menu.tsx
index 92c6ddd19360..d018b3a0f38f 100644
--- a/x-pack/legacy/plugins/infra/public/components/logging/log_entry_flyout/log_entry_actions_menu.tsx
+++ b/x-pack/legacy/plugins/infra/public/components/logging/log_entry_flyout/log_entry_actions_menu.tsx
@@ -51,7 +51,7 @@ export const LogEntryActionsMenu: React.FunctionComponent<{
/>
,
],
- [uptimeLink]
+ [apmLink, uptimeLink]
);
const hasMenuItems = useMemo(() => menuItems.length > 0, [menuItems]);
diff --git a/x-pack/legacy/plugins/infra/public/components/logging/log_highlights_menu.tsx b/x-pack/legacy/plugins/infra/public/components/logging/log_highlights_menu.tsx
index 24a5e8bacb4f..d13ccde7466c 100644
--- a/x-pack/legacy/plugins/infra/public/components/logging/log_highlights_menu.tsx
+++ b/x-pack/legacy/plugins/infra/public/components/logging/log_highlights_menu.tsx
@@ -16,7 +16,7 @@ import {
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { debounce } from 'lodash';
-import React, { useCallback, useEffect, useMemo, useState } from 'react';
+import React, { useCallback, useMemo, useState } from 'react';
import euiStyled from '../../../../../common/eui_styled_components';
import { useVisibilityState } from '../../utils/use_visibility_state';
@@ -47,8 +47,25 @@ export const LogHighlightsMenu: React.FC = ({
} = useVisibilityState(false);
// Input field state
- const [highlightTerm, setHighlightTerm] = useState('');
+ const [highlightTerm, _setHighlightTerm] = useState('');
+
const debouncedOnChange = useMemo(() => debounce(onChange, 275), [onChange]);
+ const setHighlightTerm = useCallback(
+ valueOrUpdater =>
+ _setHighlightTerm(previousHighlightTerm => {
+ const newHighlightTerm =
+ typeof valueOrUpdater === 'function'
+ ? valueOrUpdater(previousHighlightTerm)
+ : valueOrUpdater;
+
+ if (newHighlightTerm !== previousHighlightTerm) {
+ debouncedOnChange([newHighlightTerm]);
+ }
+
+ return newHighlightTerm;
+ }),
+ [debouncedOnChange]
+ );
const changeHighlightTerm = useCallback(
e => {
const value = e.target.value;
@@ -57,9 +74,6 @@ export const LogHighlightsMenu: React.FC = ({
[setHighlightTerm]
);
const clearHighlightTerm = useCallback(() => setHighlightTerm(''), [setHighlightTerm]);
- useEffect(() => {
- debouncedOnChange([highlightTerm]);
- }, [highlightTerm]);
const button = (
diff --git a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/text_styles.tsx b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/text_styles.tsx
index 1d40c88f5d1d..e95ac6aa7923 100644
--- a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/text_styles.tsx
+++ b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/text_styles.tsx
@@ -63,7 +63,7 @@ export const useMeasuredCharacterDimensions = (scale: TextScale) => {
X
),
- [scale]
+ [measureElement, scale]
);
return {
diff --git a/x-pack/legacy/plugins/infra/public/components/metrics_explorer/metrics.tsx b/x-pack/legacy/plugins/infra/public/components/metrics_explorer/metrics.tsx
index d59e709d9a19..42df7c6915a0 100644
--- a/x-pack/legacy/plugins/infra/public/components/metrics_explorer/metrics.tsx
+++ b/x-pack/legacy/plugins/infra/public/components/metrics_explorer/metrics.tsx
@@ -7,7 +7,7 @@
import { EuiComboBox } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
-import React, { useCallback, useState, useEffect } from 'react';
+import React, { useCallback, useState } from 'react';
import { FieldType } from 'ui/index_patterns';
import { colorTransformer, MetricsExplorerColor } from '../../../common/color_palette';
import {
@@ -31,24 +31,19 @@ interface SelectedOption {
export const MetricsExplorerMetrics = ({ options, onChange, fields, autoFocus = false }: Props) => {
const colors = Object.keys(MetricsExplorerColor) as MetricsExplorerColor[];
- const [inputRef, setInputRef] = useState(null);
- const [focusOnce, setFocusState] = useState(false);
+ const [shouldFocus, setShouldFocus] = useState(autoFocus);
- useEffect(() => {
- if (inputRef && autoFocus && !focusOnce) {
- inputRef.focus();
- setFocusState(true);
- }
- }, [inputRef]);
+ // the EuiCombobox forwards the ref to an input element
+ const autoFocusInputElement = useCallback(
+ (inputElement: HTMLInputElement | null) => {
+ if (inputElement && shouldFocus) {
+ inputElement.focus();
+ setShouldFocus(false);
+ }
+ },
+ [shouldFocus]
+ );
- // I tried to use useRef originally but the EUIComboBox component's type definition
- // would only accept an actual input element or a callback function (with the same type).
- // This effectivly does the same thing but is compatible with EuiComboBox.
- const handleInputRef = (ref: HTMLInputElement) => {
- if (ref) {
- setInputRef(ref);
- }
- };
const handleChange = useCallback(
selectedOptions => {
onChange(
@@ -59,7 +54,7 @@ export const MetricsExplorerMetrics = ({ options, onChange, fields, autoFocus =
}))
);
},
- [options, onChange]
+ [onChange, options.aggregation, colors]
);
const comboOptions = fields
@@ -86,7 +81,7 @@ export const MetricsExplorerMetrics = ({ options, onChange, fields, autoFocus =
selectedOptions={selectedOptions}
onChange={handleChange}
isClearable={true}
- inputRef={handleInputRef}
+ inputRef={autoFocusInputElement}
/>
);
};
diff --git a/x-pack/legacy/plugins/infra/public/components/saved_views/create_modal.tsx b/x-pack/legacy/plugins/infra/public/components/saved_views/create_modal.tsx
index 8df479f36e2f..9b8907a1ff9e 100644
--- a/x-pack/legacy/plugins/infra/public/components/saved_views/create_modal.tsx
+++ b/x-pack/legacy/plugins/infra/public/components/saved_views/create_modal.tsx
@@ -36,7 +36,7 @@ export const SavedViewCreateModal = ({ close, save, isInvalid }: Props) => {
const saveView = useCallback(() => {
save(viewName, includeTime);
- }, [viewName, includeTime]);
+ }, [includeTime, save, viewName]);
return (
diff --git a/x-pack/legacy/plugins/infra/public/components/source_configuration/add_log_column_popover.tsx b/x-pack/legacy/plugins/infra/public/components/source_configuration/add_log_column_popover.tsx
index 9b83f62e7856..fc8407c5298e 100644
--- a/x-pack/legacy/plugins/infra/public/components/source_configuration/add_log_column_popover.tsx
+++ b/x-pack/legacy/plugins/infra/public/components/source_configuration/add_log_column_popover.tsx
@@ -94,7 +94,7 @@ export const AddLogColumnButtonAndPopover: React.FunctionComponent<{
addLogColumn(selectedOption.columnConfiguration);
},
- [addLogColumn, availableColumnOptions]
+ [addLogColumn, availableColumnOptions, closePopover]
);
return (
diff --git a/x-pack/legacy/plugins/infra/public/components/source_configuration/fields_configuration_panel.tsx b/x-pack/legacy/plugins/infra/public/components/source_configuration/fields_configuration_panel.tsx
index 771285e8ccee..5f3d1a63e72e 100644
--- a/x-pack/legacy/plugins/infra/public/components/source_configuration/fields_configuration_panel.tsx
+++ b/x-pack/legacy/plugins/infra/public/components/source_configuration/fields_configuration_panel.tsx
@@ -50,10 +50,12 @@ export const FieldsConfigurationPanel = ({
+
+
+
}
description={
+
+
+
}
description={
+
+
+
}
description={
+
+
+
}
description={
+
+
+
}
description={
+
+
+
}
description={
+
+
+
}
description={
+
+
+
}
description={
{
indicesConfigurationFormState.resetForm();
logColumnsConfigurationFormState.resetForm();
- }, [indicesConfigurationFormState.resetForm, logColumnsConfigurationFormState.formState]);
+ }, [indicesConfigurationFormState, logColumnsConfigurationFormState]);
const isFormDirty = useMemo(
() => indicesConfigurationFormState.isFormDirty || logColumnsConfigurationFormState.isFormDirty,
diff --git a/x-pack/legacy/plugins/infra/public/components/waffle/waffle_inventory_switcher.tsx b/x-pack/legacy/plugins/infra/public/components/waffle/waffle_inventory_switcher.tsx
index 38e87038b7c4..c8f03cef4d6a 100644
--- a/x-pack/legacy/plugins/infra/public/components/waffle/waffle_inventory_switcher.tsx
+++ b/x-pack/legacy/plugins/infra/public/components/waffle/waffle_inventory_switcher.tsx
@@ -17,28 +17,33 @@ import {
} from '../../graphql/types';
import { findInventoryModel } from '../../../common/inventory_models';
-interface Props {
+interface WaffleInventorySwitcherProps {
nodeType: InfraNodeType;
changeNodeType: (nodeType: InfraNodeType) => void;
changeGroupBy: (groupBy: InfraSnapshotGroupbyInput[]) => void;
changeMetric: (metric: InfraSnapshotMetricInput) => void;
}
-export const WaffleInventorySwitcher = (props: Props) => {
+export const WaffleInventorySwitcher: React.FC = ({
+ changeNodeType,
+ changeGroupBy,
+ changeMetric,
+ nodeType,
+}) => {
const [isOpen, setIsOpen] = useState(false);
const closePopover = useCallback(() => setIsOpen(false), []);
const openPopover = useCallback(() => setIsOpen(true), []);
const goToNodeType = useCallback(
- (nodeType: InfraNodeType) => {
+ (targetNodeType: InfraNodeType) => {
closePopover();
- props.changeNodeType(nodeType);
- props.changeGroupBy([]);
- const inventoryModel = findInventoryModel(nodeType);
- props.changeMetric({
+ changeNodeType(targetNodeType);
+ changeGroupBy([]);
+ const inventoryModel = findInventoryModel(targetNodeType);
+ changeMetric({
type: inventoryModel.metrics.defaultSnapshot as InfraSnapshotMetricType,
});
},
- [props.changeGroupBy, props.changeNodeType, props.changeMetric]
+ [closePopover, changeNodeType, changeGroupBy, changeMetric]
);
const goToHost = useCallback(() => goToNodeType('host' as InfraNodeType), [goToNodeType]);
const goToK8 = useCallback(() => goToNodeType('pod' as InfraNodeType), [goToNodeType]);
@@ -68,10 +73,10 @@ export const WaffleInventorySwitcher = (props: Props) => {
],
},
],
- []
+ [goToDocker, goToHost, goToK8]
);
const selectedText = useMemo(() => {
- switch (props.nodeType) {
+ switch (nodeType) {
case InfraNodeType.host:
return i18n.translate('xpack.infra.waffle.nodeTypeSwitcher.hostsLabel', {
defaultMessage: 'Hosts',
@@ -81,7 +86,7 @@ export const WaffleInventorySwitcher = (props: Props) => {
case InfraNodeType.container:
return 'Docker';
}
- }, [props.nodeType]);
+ }, [nodeType]);
return (
diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_api_types.ts b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_api_types.ts
index deb3d528e42c..9d4d419ceebe 100644
--- a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_api_types.ts
+++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_api_types.ts
@@ -6,11 +6,30 @@
import * as rt from 'io-ts';
+import { jobSourceConfigurationRT } from '../../../../../common/log_analysis';
+
export const jobCustomSettingsRT = rt.partial({
job_revision: rt.number,
- logs_source_config: rt.partial({
- indexPattern: rt.string,
- timestampField: rt.string,
- bucketSpan: rt.number,
+ logs_source_config: rt.partial(jobSourceConfigurationRT.props),
+});
+
+export const getMlCapabilitiesResponsePayloadRT = rt.type({
+ capabilities: rt.type({
+ canGetJobs: rt.boolean,
+ canCreateJob: rt.boolean,
+ canDeleteJob: rt.boolean,
+ canOpenJob: rt.boolean,
+ canCloseJob: rt.boolean,
+ canForecastJob: rt.boolean,
+ canGetDatafeeds: rt.boolean,
+ canStartStopDatafeed: rt.boolean,
+ canUpdateJob: rt.boolean,
+ canUpdateDatafeed: rt.boolean,
+ canPreviewDatafeed: rt.boolean,
}),
+ isPlatinumOrTrialLicense: rt.boolean,
+ mlFeatureEnabledInSpace: rt.boolean,
+ upgradeInProgress: rt.boolean,
});
+
+export type GetMlCapabilitiesResponsePayload = rt.TypeOf;
diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_cleanup.ts b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_cleanup.ts
index 209da920c4c8..5054f607fa5d 100644
--- a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_cleanup.ts
+++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_cleanup.ts
@@ -9,17 +9,22 @@ import { pipe } from 'fp-ts/lib/pipeable';
import { fold } from 'fp-ts/lib/Either';
import { identity } from 'fp-ts/lib/function';
import { kfetch } from 'ui/kfetch';
-import { getAllModuleJobIds, getDatafeedId } from '../../../../../common/log_analysis';
+
+import { getDatafeedId, getJobId } from '../../../../../common/log_analysis';
import { throwErrors, createPlainError } from '../../../../../common/runtime_types';
-export const callDeleteJobs = async (spaceId: string, sourceId: string) => {
+export const callDeleteJobs = async (
+ spaceId: string,
+ sourceId: string,
+ jobTypes: JobType[]
+) => {
// NOTE: Deleting the jobs via this API will delete the datafeeds at the same time
const deleteJobsResponse = await kfetch({
method: 'POST',
pathname: '/api/ml/jobs/delete_jobs',
body: JSON.stringify(
deleteJobsRequestPayloadRT.encode({
- jobIds: getAllModuleJobIds(spaceId, sourceId),
+ jobIds: jobTypes.map(jobType => getJobId(spaceId, sourceId, jobType)),
})
),
});
@@ -42,15 +47,24 @@ export const callGetJobDeletionTasks = async () => {
);
};
-export const callStopDatafeed = async (spaceId: string, sourceId: string) => {
+export const callStopDatafeeds = async (
+ spaceId: string,
+ sourceId: string,
+ jobTypes: JobType[]
+) => {
// Stop datafeed due to https://github.com/elastic/kibana/issues/44652
const stopDatafeedResponse = await kfetch({
method: 'POST',
- pathname: `/api/ml/datafeeds/${getDatafeedId(spaceId, sourceId, 'log-entry-rate')}/_stop`,
+ pathname: '/api/ml/jobs/stop_datafeeds',
+ body: JSON.stringify(
+ stopDatafeedsRequestPayloadRT.encode({
+ datafeedIds: jobTypes.map(jobType => getDatafeedId(spaceId, sourceId, jobType)),
+ })
+ ),
});
return pipe(
- stopDatafeedResponsePayloadRT.decode(stopDatafeedResponse),
+ stopDatafeedsResponsePayloadRT.decode(stopDatafeedResponse),
fold(throwErrors(createPlainError), identity)
);
};
@@ -68,10 +82,19 @@ export const deleteJobsResponsePayloadRT = rt.record(
})
);
+export type DeleteJobsResponsePayload = rt.TypeOf;
+
export const getJobDeletionTasksResponsePayloadRT = rt.type({
jobIds: rt.array(rt.string),
});
-export const stopDatafeedResponsePayloadRT = rt.type({
- stopped: rt.boolean,
+export const stopDatafeedsRequestPayloadRT = rt.type({
+ datafeedIds: rt.array(rt.string),
});
+
+export const stopDatafeedsResponsePayloadRT = rt.record(
+ rt.string,
+ rt.type({
+ stopped: rt.boolean,
+ })
+);
diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_get_jobs_summary_api.ts b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_get_jobs_summary_api.ts
index 6171d10b5f1a..91e517b0db00 100644
--- a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_get_jobs_summary_api.ts
+++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_get_jobs_summary_api.ts
@@ -12,15 +12,19 @@ import { kfetch } from 'ui/kfetch';
import { jobCustomSettingsRT } from './ml_api_types';
import { throwErrors, createPlainError } from '../../../../../common/runtime_types';
-import { getAllModuleJobIds } from '../../../../../common/log_analysis';
+import { getJobId } from '../../../../../common/log_analysis';
-export const callJobsSummaryAPI = async (spaceId: string, sourceId: string) => {
+export const callJobsSummaryAPI = async (
+ spaceId: string,
+ sourceId: string,
+ jobTypes: JobType[]
+) => {
const response = await kfetch({
method: 'POST',
pathname: '/api/ml/jobs/jobs_summary',
body: JSON.stringify(
fetchJobStatusRequestPayloadRT.encode({
- jobIds: getAllModuleJobIds(spaceId, sourceId),
+ jobIds: jobTypes.map(jobType => getJobId(spaceId, sourceId, jobType)),
})
),
});
diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_setup_module_api.ts b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_setup_module_api.ts
index 1c937513c795..80a4f975cdd5 100644
--- a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_setup_module_api.ts
+++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/ml_setup_module_api.ts
@@ -12,7 +12,6 @@ import { kfetch } from 'ui/kfetch';
import { throwErrors, createPlainError } from '../../../../../common/runtime_types';
import { getJobIdPrefix } from '../../../../../common/log_analysis';
-import { jobCustomSettingsRT } from './ml_api_types';
export const callSetupMlModuleAPI = async (
moduleId: string,
@@ -21,8 +20,8 @@ export const callSetupMlModuleAPI = async (
spaceId: string,
sourceId: string,
indexPattern: string,
- timeField: string,
- bucketSpan: number
+ jobOverrides: SetupMlModuleJobOverrides[] = [],
+ datafeedOverrides: SetupMlModuleDatafeedOverrides[] = []
) => {
const response = await kfetch({
method: 'POST',
@@ -34,25 +33,8 @@ export const callSetupMlModuleAPI = async (
indexPatternName: indexPattern,
prefix: getJobIdPrefix(spaceId, sourceId),
startDatafeed: true,
- jobOverrides: [
- {
- job_id: 'log-entry-rate' as const,
- analysis_config: {
- bucket_span: `${bucketSpan}ms`,
- },
- data_description: {
- time_field: timeField,
- },
- custom_settings: {
- logs_source_config: {
- indexPattern,
- timestampField: timeField,
- bucketSpan,
- },
- },
- },
- ],
- datafeedOverrides: [],
+ jobOverrides,
+ datafeedOverrides,
})
),
});
@@ -68,23 +50,20 @@ const setupMlModuleTimeParamsRT = rt.partial({
end: rt.number,
});
-const setupMlModuleLogEntryRateJobOverridesRT = rt.type({
- job_id: rt.literal('log-entry-rate'),
- analysis_config: rt.type({
- bucket_span: rt.string,
- }),
- data_description: rt.type({
- time_field: rt.string,
- }),
- custom_settings: jobCustomSettingsRT,
-});
+const setupMlModuleJobOverridesRT = rt.object;
+
+export type SetupMlModuleJobOverrides = rt.TypeOf;
+
+const setupMlModuleDatafeedOverridesRT = rt.object;
+
+export type SetupMlModuleDatafeedOverrides = rt.TypeOf;
const setupMlModuleRequestParamsRT = rt.type({
indexPatternName: rt.string,
prefix: rt.string,
startDatafeed: rt.boolean,
- jobOverrides: rt.array(setupMlModuleLogEntryRateJobOverridesRT),
- datafeedOverrides: rt.array(rt.object),
+ jobOverrides: rt.array(setupMlModuleJobOverridesRT),
+ datafeedOverrides: rt.array(setupMlModuleDatafeedOverridesRT),
});
const setupMlModuleRequestPayloadRT = rt.intersection([
diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/index_patterns_validate.ts b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/validate_indices.ts
similarity index 70%
rename from x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/index_patterns_validate.ts
rename to x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/validate_indices.ts
index 440ee10e4223..0d2e9b673488 100644
--- a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/index_patterns_validate.ts
+++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/validate_indices.ts
@@ -10,20 +10,22 @@ import { identity } from 'fp-ts/lib/function';
import { kfetch } from 'ui/kfetch';
import {
- LOG_ANALYSIS_VALIDATION_INDICES_PATH,
+ LOG_ANALYSIS_VALIDATE_INDICES_PATH,
+ ValidationIndicesFieldSpecification,
validationIndicesRequestPayloadRT,
validationIndicesResponsePayloadRT,
} from '../../../../../common/http_api';
import { throwErrors, createPlainError } from '../../../../../common/runtime_types';
-export const callIndexPatternsValidate = async (timestampField: string, indices: string[]) => {
+export const callValidateIndicesAPI = async (
+ indices: string[],
+ fields: ValidationIndicesFieldSpecification[]
+) => {
const response = await kfetch({
method: 'POST',
- pathname: LOG_ANALYSIS_VALIDATION_INDICES_PATH,
- body: JSON.stringify(
- validationIndicesRequestPayloadRT.encode({ data: { timestampField, indices } })
- ),
+ pathname: LOG_ANALYSIS_VALIDATE_INDICES_PATH,
+ body: JSON.stringify(validationIndicesRequestPayloadRT.encode({ data: { indices, fields } })),
});
return pipe(
diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/index.ts b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/index.ts
index cbe3b2ef1e9b..eb044c86e50f 100644
--- a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/index.ts
+++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/index.ts
@@ -6,7 +6,6 @@
export * from './log_analysis_capabilities';
export * from './log_analysis_cleanup';
-export * from './log_analysis_jobs';
-export * from './log_analysis_results';
-export * from './log_analysis_results_url_state';
-export * from './log_analysis_status_state';
+export * from './log_analysis_module';
+export * from './log_analysis_module_status';
+export * from './log_analysis_module_types';
diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_capabilities.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_capabilities.tsx
index 7ac7d051e678..bb01043b0db6 100644
--- a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_capabilities.tsx
+++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_capabilities.tsx
@@ -15,7 +15,7 @@ import { useTrackedPromise } from '../../../utils/use_tracked_promise';
import {
getMlCapabilitiesResponsePayloadRT,
GetMlCapabilitiesResponsePayload,
-} from './ml_api_types';
+} from './api/ml_api_types';
import { throwErrors, createPlainError } from '../../../../common/runtime_types';
export const useLogAnalysisCapabilities = () => {
@@ -46,7 +46,7 @@ export const useLogAnalysisCapabilities = () => {
useEffect(() => {
fetchMlCapabilities();
- }, []);
+ }, [fetchMlCapabilities]);
const isLoading = useMemo(() => fetchMlCapabilitiesRequest.state === 'pending', [
fetchMlCapabilitiesRequest.state,
diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_cleanup.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_cleanup.tsx
index 1b79d3c1ef78..a37d18cc33cf 100644
--- a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_cleanup.tsx
+++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_cleanup.tsx
@@ -4,64 +4,46 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import createContainer from 'constate';
-import { useMemo } from 'react';
-import { useTrackedPromise } from '../../../utils/use_tracked_promise';
-import { callDeleteJobs, callStopDatafeed, callGetJobDeletionTasks } from './api/ml_cleanup';
-import { getAllModuleJobIds } from '../../../../common/log_analysis';
-
-export const useLogAnalysisCleanup = ({
- sourceId,
- spaceId,
-}: {
- sourceId: string;
- spaceId: string;
-}) => {
- const [cleanupMLResourcesRequest, cleanupMLResources] = useTrackedPromise(
- {
- cancelPreviousOn: 'resolution',
- createPromise: async () => {
- try {
- await callStopDatafeed(spaceId, sourceId);
- } catch (err) {
- // Datefeed has been deleted / doesn't exist, proceed with deleting jobs anyway
- if (err && err.res && err.res.status === 404) {
- return await deleteJobs(spaceId, sourceId);
- } else {
- throw err;
- }
- }
-
- return await deleteJobs(spaceId, sourceId);
- },
- },
- [spaceId, sourceId]
- );
-
- const isCleaningUp = useMemo(() => cleanupMLResourcesRequest.state === 'pending', [
- cleanupMLResourcesRequest.state,
- ]);
+import { getJobId } from '../../../../common/log_analysis';
+import { callDeleteJobs, callGetJobDeletionTasks, callStopDatafeeds } from './api/ml_cleanup';
+
+export const cleanUpJobsAndDatafeeds = async (
+ spaceId: string,
+ sourceId: string,
+ jobTypes: JobType[]
+) => {
+ try {
+ await callStopDatafeeds(spaceId, sourceId, jobTypes);
+ } catch (err) {
+ // Proceed only if datafeed has been deleted or didn't exist in the first place
+ if (err?.res?.status !== 404) {
+ throw err;
+ }
+ }
- return {
- cleanupMLResources,
- isCleaningUp,
- };
+ return await deleteJobs(spaceId, sourceId, jobTypes);
};
-export const LogAnalysisCleanup = createContainer(useLogAnalysisCleanup);
-
-const deleteJobs = async (spaceId: string, sourceId: string) => {
- const deleteJobsResponse = await callDeleteJobs(spaceId, sourceId);
- await waitUntilJobsAreDeleted(spaceId, sourceId);
+const deleteJobs = async (
+ spaceId: string,
+ sourceId: string,
+ jobTypes: JobType[]
+) => {
+ const deleteJobsResponse = await callDeleteJobs(spaceId, sourceId, jobTypes);
+ await waitUntilJobsAreDeleted(spaceId, sourceId, jobTypes);
return deleteJobsResponse;
};
-const waitUntilJobsAreDeleted = async (spaceId: string, sourceId: string) => {
+const waitUntilJobsAreDeleted = async (
+ spaceId: string,
+ sourceId: string,
+ jobTypes: JobType[]
+) => {
+ const moduleJobIds = jobTypes.map(jobType => getJobId(spaceId, sourceId, jobType));
while (true) {
- const response = await callGetJobDeletionTasks();
- const jobIdsBeingDeleted = response.jobIds;
- const moduleJobIds = getAllModuleJobIds(spaceId, sourceId);
+ const { jobIds: jobIdsBeingDeleted } = await callGetJobDeletionTasks();
const needToWait = jobIdsBeingDeleted.some(jobId => moduleJobIds.includes(jobId));
+
if (needToWait) {
await timeout(1000);
} else {
diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_jobs.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_jobs.tsx
deleted file mode 100644
index 0f386f416b86..000000000000
--- a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_jobs.tsx
+++ /dev/null
@@ -1,169 +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 createContainer from 'constate';
-import { useMemo, useCallback, useEffect } from 'react';
-
-import { callGetMlModuleAPI } from './api/ml_get_module';
-import { bucketSpan, getJobId } from '../../../../common/log_analysis';
-import { useTrackedPromise } from '../../../utils/use_tracked_promise';
-import { callJobsSummaryAPI } from './api/ml_get_jobs_summary_api';
-import { callSetupMlModuleAPI, SetupMlModuleResponsePayload } from './api/ml_setup_module_api';
-import { useLogAnalysisCleanup } from './log_analysis_cleanup';
-import { useStatusState } from './log_analysis_status_state';
-
-const MODULE_ID = 'logs_ui_analysis';
-
-export const useLogAnalysisJobs = ({
- indexPattern,
- sourceId,
- spaceId,
- timeField,
-}: {
- indexPattern: string;
- sourceId: string;
- spaceId: string;
- timeField: string;
-}) => {
- const { cleanupMLResources } = useLogAnalysisCleanup({ sourceId, spaceId });
- const [statusState, dispatch] = useStatusState({
- bucketSpan,
- indexPattern,
- timestampField: timeField,
- });
-
- const [fetchModuleDefinitionRequest, fetchModuleDefinition] = useTrackedPromise(
- {
- cancelPreviousOn: 'resolution',
- createPromise: async () => {
- dispatch({ type: 'fetchingModuleDefinition' });
- return await callGetMlModuleAPI(MODULE_ID);
- },
- onResolve: response => {
- dispatch({
- type: 'fetchedModuleDefinition',
- spaceId,
- sourceId,
- moduleDefinition: response,
- });
- },
- onReject: () => {
- dispatch({ type: 'failedFetchingModuleDefinition' });
- },
- },
- []
- );
-
- const [setupMlModuleRequest, setupMlModule] = useTrackedPromise(
- {
- cancelPreviousOn: 'resolution',
- createPromise: async (
- indices: string[],
- start: number | undefined,
- end: number | undefined
- ) => {
- dispatch({ type: 'startedSetup' });
- return await callSetupMlModuleAPI(
- MODULE_ID,
- start,
- end,
- spaceId,
- sourceId,
- indices.join(','),
- timeField,
- bucketSpan
- );
- },
- onResolve: ({ datafeeds, jobs }: SetupMlModuleResponsePayload) => {
- dispatch({ type: 'finishedSetup', datafeeds, jobs, spaceId, sourceId });
- },
- onReject: () => {
- dispatch({ type: 'failedSetup' });
- },
- },
- [spaceId, sourceId, timeField, bucketSpan]
- );
-
- const [fetchJobStatusRequest, fetchJobStatus] = useTrackedPromise(
- {
- cancelPreviousOn: 'resolution',
- createPromise: async () => {
- dispatch({ type: 'fetchingJobStatuses' });
- return await callJobsSummaryAPI(spaceId, sourceId);
- },
- onResolve: jobResponse => {
- dispatch({ type: 'fetchedJobStatuses', payload: jobResponse, spaceId, sourceId });
- },
- onReject: err => {
- dispatch({ type: 'failedFetchingJobStatuses' });
- },
- },
- [spaceId, sourceId]
- );
-
- const isLoadingSetupStatus = useMemo(
- () =>
- fetchJobStatusRequest.state === 'pending' || fetchModuleDefinitionRequest.state === 'pending',
- [fetchJobStatusRequest.state, fetchModuleDefinitionRequest.state]
- );
-
- const availableIndices = useMemo(() => indexPattern.split(','), [indexPattern]);
-
- const viewResults = useCallback(() => {
- dispatch({ type: 'viewedResults' });
- }, []);
-
- const cleanupAndSetup = useCallback(
- (indices: string[], start: number | undefined, end: number | undefined) => {
- dispatch({ type: 'startedSetup' });
- cleanupMLResources()
- .then(() => {
- setupMlModule(indices, start, end);
- })
- .catch(() => {
- dispatch({ type: 'failedSetup' });
- });
- },
- [cleanupMLResources, setupMlModule]
- );
-
- const viewSetupForReconfiguration = useCallback(() => {
- dispatch({ type: 'requestedJobConfigurationUpdate' });
- }, []);
-
- const viewSetupForUpdate = useCallback(() => {
- dispatch({ type: 'requestedJobDefinitionUpdate' });
- }, []);
-
- useEffect(() => {
- fetchModuleDefinition();
- }, [fetchModuleDefinition]);
-
- const jobIds = useMemo(() => {
- return {
- 'log-entry-rate': getJobId(spaceId, sourceId, 'log-entry-rate'),
- };
- }, [sourceId, spaceId]);
-
- return {
- availableIndices,
- fetchJobStatus,
- isLoadingSetupStatus,
- jobStatus: statusState.jobStatus,
- lastSetupErrorMessages: statusState.lastSetupErrorMessages,
- cleanupAndSetup,
- setup: setupMlModule,
- setupMlModuleRequest,
- setupStatus: statusState.setupStatus,
- timestampField: timeField,
- viewSetupForReconfiguration,
- viewSetupForUpdate,
- viewResults,
- jobIds,
- };
-};
-
-export const LogAnalysisJobs = createContainer(useLogAnalysisJobs);
diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_module.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_module.tsx
new file mode 100644
index 000000000000..d7d0ecb6f2c8
--- /dev/null
+++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_module.tsx
@@ -0,0 +1,167 @@
+/*
+ * 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 { useCallback, useMemo } from 'react';
+
+import { useTrackedPromise } from '../../../utils/use_tracked_promise';
+import { useModuleStatus } from './log_analysis_module_status';
+import { ModuleDescriptor, ModuleSourceConfiguration } from './log_analysis_module_types';
+
+export const useLogAnalysisModule = ({
+ sourceConfiguration,
+ moduleDescriptor,
+}: {
+ sourceConfiguration: ModuleSourceConfiguration;
+ moduleDescriptor: ModuleDescriptor;
+}) => {
+ const { spaceId, sourceId, timestampField, indices } = sourceConfiguration;
+ const [moduleStatus, dispatchModuleStatus] = useModuleStatus(moduleDescriptor.jobTypes, {
+ bucketSpan: moduleDescriptor.bucketSpan,
+ indexPattern: indices.join(','),
+ timestampField,
+ });
+
+ const [fetchModuleDefinitionRequest, fetchModuleDefinition] = useTrackedPromise(
+ {
+ cancelPreviousOn: 'resolution',
+ createPromise: async () => {
+ dispatchModuleStatus({ type: 'fetchingModuleDefinition' });
+ return await moduleDescriptor.getModuleDefinition();
+ },
+ onResolve: response => {
+ dispatchModuleStatus({
+ type: 'fetchedModuleDefinition',
+ spaceId,
+ sourceId,
+ moduleDefinition: response,
+ });
+ },
+ onReject: () => {
+ dispatchModuleStatus({ type: 'failedFetchingModuleDefinition' });
+ },
+ },
+ [moduleDescriptor.getModuleDefinition, spaceId, sourceId]
+ );
+
+ const [fetchJobStatusRequest, fetchJobStatus] = useTrackedPromise(
+ {
+ cancelPreviousOn: 'resolution',
+ createPromise: async () => {
+ dispatchModuleStatus({ type: 'fetchingJobStatuses' });
+ return await moduleDescriptor.getJobSummary(spaceId, sourceId);
+ },
+ onResolve: jobResponse => {
+ dispatchModuleStatus({
+ type: 'fetchedJobStatuses',
+ payload: jobResponse,
+ spaceId,
+ sourceId,
+ });
+ },
+ onReject: () => {
+ dispatchModuleStatus({ type: 'failedFetchingJobStatuses' });
+ },
+ },
+ [spaceId, sourceId]
+ );
+
+ const isLoadingModuleStatus = useMemo(
+ () =>
+ fetchJobStatusRequest.state === 'pending' || fetchModuleDefinitionRequest.state === 'pending',
+ [fetchJobStatusRequest.state, fetchModuleDefinitionRequest.state]
+ );
+
+ const [, setUpModule] = useTrackedPromise(
+ {
+ cancelPreviousOn: 'resolution',
+ createPromise: async (
+ selectedIndices: string[],
+ start: number | undefined,
+ end: number | undefined
+ ) => {
+ dispatchModuleStatus({ type: 'startedSetup' });
+ return await moduleDescriptor.setUpModule(start, end, {
+ indices: selectedIndices,
+ sourceId,
+ spaceId,
+ timestampField,
+ });
+ },
+ onResolve: ({ datafeeds, jobs }) => {
+ dispatchModuleStatus({ type: 'finishedSetup', datafeeds, jobs, spaceId, sourceId });
+ },
+ onReject: () => {
+ dispatchModuleStatus({ type: 'failedSetup' });
+ },
+ },
+ [moduleDescriptor.setUpModule, spaceId, sourceId, timestampField]
+ );
+
+ const [cleanUpModuleRequest, cleanUpModule] = useTrackedPromise(
+ {
+ cancelPreviousOn: 'resolution',
+ createPromise: async () => {
+ return await moduleDescriptor.cleanUpModule(spaceId, sourceId);
+ },
+ },
+ [spaceId, sourceId]
+ );
+
+ const isCleaningUp = useMemo(() => cleanUpModuleRequest.state === 'pending', [
+ cleanUpModuleRequest.state,
+ ]);
+
+ const cleanUpAndSetUpModule = useCallback(
+ (selectedIndices: string[], start: number | undefined, end: number | undefined) => {
+ dispatchModuleStatus({ type: 'startedSetup' });
+ cleanUpModule()
+ .then(() => {
+ setUpModule(selectedIndices, start, end);
+ })
+ .catch(() => {
+ dispatchModuleStatus({ type: 'failedSetup' });
+ });
+ },
+ [cleanUpModule, dispatchModuleStatus, setUpModule]
+ );
+
+ const viewSetupForReconfiguration = useCallback(() => {
+ dispatchModuleStatus({ type: 'requestedJobConfigurationUpdate' });
+ }, [dispatchModuleStatus]);
+
+ const viewSetupForUpdate = useCallback(() => {
+ dispatchModuleStatus({ type: 'requestedJobDefinitionUpdate' });
+ }, [dispatchModuleStatus]);
+
+ const viewResults = useCallback(() => {
+ dispatchModuleStatus({ type: 'viewedResults' });
+ }, [dispatchModuleStatus]);
+
+ const jobIds = useMemo(() => moduleDescriptor.getJobIds(spaceId, sourceId), [
+ moduleDescriptor,
+ spaceId,
+ sourceId,
+ ]);
+
+ return {
+ cleanUpAndSetUpModule,
+ cleanUpModule,
+ fetchJobStatus,
+ fetchModuleDefinition,
+ isCleaningUp,
+ isLoadingModuleStatus,
+ jobIds,
+ jobStatus: moduleStatus.jobStatus,
+ lastSetupErrorMessages: moduleStatus.lastSetupErrorMessages,
+ moduleDescriptor,
+ setUpModule,
+ setupStatus: moduleStatus.setupStatus,
+ sourceConfiguration,
+ viewResults,
+ viewSetupForReconfiguration,
+ viewSetupForUpdate,
+ };
+};
diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_status_state.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_status.tsx
similarity index 70%
rename from x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_status_state.tsx
rename to x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_status.tsx
index 1f4c924ea3da..6d634538cd7f 100644
--- a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_status_state.tsx
+++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_status.tsx
@@ -7,20 +7,19 @@
import { useReducer } from 'react';
import {
+ JobSourceConfiguration,
+ JobStatus,
+ SetupStatus,
getDatafeedId,
getJobId,
isJobStatusWithResults,
- JobStatus,
- JobType,
- jobTypeRT,
- SetupStatus,
} from '../../../../common/log_analysis';
import { FetchJobStatusResponsePayload, JobSummary } from './api/ml_get_jobs_summary_api';
import { GetMlModuleResponsePayload, JobDefinition } from './api/ml_get_module';
import { SetupMlModuleResponsePayload } from './api/ml_setup_module_api';
import { MandatoryProperty } from '../../../../common/utility_types';
-interface StatusReducerState {
+interface StatusReducerState {
jobDefinitions: JobDefinition[];
jobStatus: Record;
jobSummaries: JobSummary[];
@@ -65,42 +64,60 @@ type StatusReducerAction =
| { type: 'requestedJobDefinitionUpdate' }
| { type: 'viewedResults' };
-const createInitialState = (sourceConfiguration: JobSourceConfiguration): StatusReducerState => ({
+const createInitialState = ({
+ jobTypes,
+ sourceConfiguration,
+}: {
+ jobTypes: JobType[];
+ sourceConfiguration: JobSourceConfiguration;
+}): StatusReducerState => ({
jobDefinitions: [],
- jobStatus: {
- 'log-entry-rate': 'unknown',
- },
+ jobStatus: jobTypes.reduce(
+ (accumulatedJobStatus, jobType) => ({
+ ...accumulatedJobStatus,
+ [jobType]: 'unknown',
+ }),
+ {} as Record
+ ),
jobSummaries: [],
lastSetupErrorMessages: [],
setupStatus: 'initializing',
sourceConfiguration,
});
-function statusReducer(state: StatusReducerState, action: StatusReducerAction): StatusReducerState {
+const createStatusReducer = (jobTypes: JobType[]) => (
+ state: StatusReducerState,
+ action: StatusReducerAction
+): StatusReducerState => {
switch (action.type) {
case 'startedSetup': {
return {
...state,
- jobStatus: {
- 'log-entry-rate': 'initializing',
- },
+ jobStatus: jobTypes.reduce(
+ (accumulatedJobStatus, jobType) => ({
+ ...accumulatedJobStatus,
+ [jobType]: 'initializing',
+ }),
+ {} as Record
+ ),
setupStatus: 'pending',
};
}
case 'finishedSetup': {
const { jobs, datafeeds, spaceId, sourceId } = action;
- const nextJobStatus = {
- ...state.jobStatus,
- 'log-entry-rate':
- hasSuccessfullyCreatedJob(getJobId(spaceId, sourceId, 'log-entry-rate'))(jobs) &&
- hasSuccessfullyStartedDatafeed(getDatafeedId(spaceId, sourceId, 'log-entry-rate'))(
- datafeeds
- )
- ? ('started' as JobStatus)
- : ('failed' as JobStatus),
- };
- const nextSetupStatus = Object.values(nextJobStatus).every(jobState =>
- ['started'].includes(jobState)
+ const nextJobStatus = jobTypes.reduce(
+ (accumulatedJobStatus, jobType) => ({
+ ...accumulatedJobStatus,
+ [jobType]:
+ hasSuccessfullyCreatedJob(getJobId(spaceId, sourceId, jobType))(jobs) &&
+ hasSuccessfullyStartedDatafeed(getDatafeedId(spaceId, sourceId, jobType))(datafeeds)
+ ? 'started'
+ : 'failed',
+ }),
+ {} as Record
+ );
+ const nextSetupStatus = Object.values(nextJobStatus).every(
+ jobState => jobState === 'started'
)
? 'succeeded'
: 'failed';
@@ -122,10 +139,13 @@ function statusReducer(state: StatusReducerState, action: StatusReducerAction):
case 'failedSetup': {
return {
...state,
- jobStatus: {
- ...state.jobStatus,
- 'log-entry-rate': 'failed',
- },
+ jobStatus: jobTypes.reduce(
+ (accumulatedJobStatus, jobType) => ({
+ ...accumulatedJobStatus,
+ [jobType]: 'failed',
+ }),
+ {} as Record
+ ),
setupStatus: 'failed',
};
}
@@ -140,10 +160,13 @@ function statusReducer(state: StatusReducerState, action: StatusReducerAction):
const { payload: jobSummaries, spaceId, sourceId } = action;
const { jobDefinitions, setupStatus, sourceConfiguration } = state;
- const nextJobStatus = {
- ...state.jobStatus,
- 'log-entry-rate': getJobStatus(getJobId(spaceId, sourceId, 'log-entry-rate'))(jobSummaries),
- };
+ const nextJobStatus = jobTypes.reduce(
+ (accumulatedJobStatus, jobType) => ({
+ ...accumulatedJobStatus,
+ [jobType]: getJobStatus(getJobId(spaceId, sourceId, jobType))(jobSummaries),
+ }),
+ {} as Record
+ );
const nextSetupStatus = getSetupStatus(
spaceId,
sourceId,
@@ -164,10 +187,13 @@ function statusReducer(state: StatusReducerState, action: StatusReducerAction):
return {
...state,
setupStatus: 'unknown',
- jobStatus: {
- ...state.jobStatus,
- 'log-entry-rate': 'unknown',
- },
+ jobStatus: jobTypes.reduce(
+ (accumulatedJobStatus, jobType) => ({
+ ...accumulatedJobStatus,
+ [jobType]: 'unknown',
+ }),
+ {} as Record
+ ),
};
}
case 'fetchedModuleDefinition': {
@@ -230,7 +256,7 @@ function statusReducer(state: StatusReducerState, action: StatusReducerAction):
return state;
}
}
-}
+};
const hasSuccessfullyCreatedJob = (jobId: string) => (
jobSetupResponses: SetupMlModuleResponsePayload['jobs']
@@ -281,7 +307,7 @@ const getJobStatus = (jobId: string) => (jobSummaries: FetchJobStatusResponsePay
}
)[0] || 'missing';
-const getSetupStatus = (
+const getSetupStatus = (
spaceId: string,
sourceId: string,
sourceConfiguration: JobSourceConfiguration,
@@ -289,44 +315,43 @@ const getSetupStatus = (
jobDefinitions: JobDefinition[],
jobSummaries: JobSummary[]
) => (previousSetupStatus: SetupStatus) =>
- Object.entries(everyJobStatus).reduce((setupStatus, [jobType, jobStatus]) => {
- if (!jobTypeRT.is(jobType)) {
- return setupStatus;
- }
+ Object.entries(everyJobStatus).reduce(
+ (setupStatus, [jobType, jobStatus]) => {
+ const jobId = getJobId(spaceId, sourceId, jobType);
+ const jobDefinition = jobDefinitions.find(({ id }) => id === jobType);
- const jobId = getJobId(spaceId, sourceId, jobType);
- const jobDefinition = jobDefinitions.find(({ id }) => id === jobType);
+ if (jobStatus === 'missing') {
+ return 'required';
+ } else if (
+ setupStatus === 'required' ||
+ setupStatus === 'requiredForUpdate' ||
+ setupStatus === 'requiredForReconfiguration'
+ ) {
+ return setupStatus;
+ } else if (
+ setupStatus === 'skippedButUpdatable' ||
+ (jobDefinition &&
+ !isJobRevisionCurrent(
+ jobId,
+ jobDefinition.config.custom_settings.job_revision || 0
+ )(jobSummaries))
+ ) {
+ return 'skippedButUpdatable';
+ } else if (
+ setupStatus === 'skippedButReconfigurable' ||
+ !isJobConfigurationConsistent(jobId, sourceConfiguration)(jobSummaries)
+ ) {
+ return 'skippedButReconfigurable';
+ } else if (setupStatus === 'hiddenAfterSuccess') {
+ return setupStatus;
+ } else if (setupStatus === 'skipped' || isJobStatusWithResults(jobStatus)) {
+ return 'skipped';
+ }
- if (jobStatus === 'missing') {
- return 'required';
- } else if (
- setupStatus === 'required' ||
- setupStatus === 'requiredForUpdate' ||
- setupStatus === 'requiredForReconfiguration'
- ) {
return setupStatus;
- } else if (
- setupStatus === 'skippedButUpdatable' ||
- (jobDefinition &&
- !isJobRevisionCurrent(
- jobId,
- jobDefinition.config.custom_settings.job_revision || 0
- )(jobSummaries))
- ) {
- return 'skippedButUpdatable';
- } else if (
- setupStatus === 'skippedButReconfigurable' ||
- !isJobConfigurationConsistent(jobId, sourceConfiguration)(jobSummaries)
- ) {
- return 'skippedButReconfigurable';
- } else if (setupStatus === 'hiddenAfterSuccess') {
- return setupStatus;
- } else if (setupStatus === 'skipped' || isJobStatusWithResults(jobStatus)) {
- return 'skipped';
- }
-
- return setupStatus;
- }, previousSetupStatus);
+ },
+ previousSetupStatus
+ );
const isJobRevisionCurrent = (jobId: string, currentRevision: number) => (
jobSummaries: FetchJobStatusResponsePayload
@@ -377,12 +402,13 @@ const isIndexPatternSubset = (indexPatternSubset: string, indexPatternSuperset:
const hasError = (value: Value): value is MandatoryProperty =>
value.error != null;
-export const useStatusState = (sourceConfiguration: JobSourceConfiguration) => {
- return useReducer(statusReducer, sourceConfiguration, createInitialState);
+export const useModuleStatus = (
+ jobTypes: JobType[],
+ sourceConfiguration: JobSourceConfiguration
+) => {
+ return useReducer(
+ createStatusReducer(jobTypes),
+ { jobTypes, sourceConfiguration },
+ createInitialState
+ );
};
-
-interface JobSourceConfiguration {
- bucketSpan: number;
- indexPattern: string;
- timestampField: string;
-}
diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_types.ts b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_types.ts
new file mode 100644
index 000000000000..dc9f25b49263
--- /dev/null
+++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_types.ts
@@ -0,0 +1,36 @@
+/*
+ * 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 { DeleteJobsResponsePayload } from './api/ml_cleanup';
+import { FetchJobStatusResponsePayload } from './api/ml_get_jobs_summary_api';
+import { GetMlModuleResponsePayload } from './api/ml_get_module';
+import { SetupMlModuleResponsePayload } from './api/ml_setup_module_api';
+import { ValidationIndicesResponsePayload } from '../../../../common/http_api/log_analysis';
+
+export interface ModuleDescriptor {
+ moduleId: string;
+ jobTypes: JobType[];
+ bucketSpan: number;
+ getJobIds: (spaceId: string, sourceId: string) => Record;
+ getJobSummary: (spaceId: string, sourceId: string) => Promise;
+ getModuleDefinition: () => Promise;
+ setUpModule: (
+ start: number | undefined,
+ end: number | undefined,
+ sourceConfiguration: ModuleSourceConfiguration
+ ) => Promise;
+ cleanUpModule: (spaceId: string, sourceId: string) => Promise;
+ validateSetupIndices: (
+ sourceConfiguration: ModuleSourceConfiguration
+ ) => Promise;
+}
+
+export interface ModuleSourceConfiguration {
+ indices: string[];
+ sourceId: string;
+ spaceId: string;
+ timestampField: string;
+}
diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_setup_state.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_setup_state.tsx
index c965c50bedcc..74dbb3c7a806 100644
--- a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_setup_state.tsx
+++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_setup_state.tsx
@@ -4,15 +4,12 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { useState, useCallback, useMemo, useEffect } from 'react';
+import { useCallback, useEffect, useMemo, useState } from 'react';
+import { ValidationIndicesError } from '../../../../common/http_api';
import { isExampleDataIndex } from '../../../../common/log_analysis';
-import {
- ValidationIndicesError,
- ValidationIndicesResponsePayload,
-} from '../../../../common/http_api';
import { useTrackedPromise } from '../../../utils/use_tracked_promise';
-import { callIndexPatternsValidate } from './api/index_patterns_validate';
+import { ModuleDescriptor, ModuleSourceConfiguration } from './log_analysis_module_types';
type SetupHandler = (
indices: string[],
@@ -25,53 +22,69 @@ export type ValidationIndicesUIError =
| { error: 'NETWORK_ERROR' }
| { error: 'TOO_FEW_SELECTED_INDICES' };
-export interface ValidatedIndex {
- index: string;
- errors: ValidationIndicesError[];
+interface ValidIndex {
+ validity: 'valid';
+ name: string;
isSelected: boolean;
}
-interface AnalysisSetupStateArguments {
- availableIndices: string[];
+interface InvalidIndex {
+ validity: 'invalid';
+ name: string;
+ errors: ValidationIndicesError[];
+}
+
+export type ValidatedIndex = ValidIndex | InvalidIndex;
+
+interface AnalysisSetupStateArguments {
cleanupAndSetupModule: SetupHandler;
+ moduleDescriptor: ModuleDescriptor;
setupModule: SetupHandler;
- timestampField: string;
+ sourceConfiguration: ModuleSourceConfiguration;
}
const fourWeeksInMs = 86400000 * 7 * 4;
-export const useAnalysisSetupState = ({
- availableIndices,
+export const useAnalysisSetupState = ({
cleanupAndSetupModule,
+ moduleDescriptor: { validateSetupIndices },
setupModule,
- timestampField,
-}: AnalysisSetupStateArguments) => {
+ sourceConfiguration,
+}: AnalysisSetupStateArguments) => {
const [startTime, setStartTime] = useState(Date.now() - fourWeeksInMs);
const [endTime, setEndTime] = useState(undefined);
- // Prepare the validation
- const [validatedIndices, setValidatedIndices] = useState(
- availableIndices.map(index => ({
- index,
- errors: [],
- isSelected: false,
- }))
- );
+ const [validatedIndices, setValidatedIndices] = useState([]);
+
const [validateIndicesRequest, validateIndices] = useTrackedPromise(
{
cancelPreviousOn: 'resolution',
createPromise: async () => {
- return await callIndexPatternsValidate(timestampField, availableIndices);
+ return await validateSetupIndices(sourceConfiguration);
},
- onResolve: ({ data }: ValidationIndicesResponsePayload) => {
- setValidatedIndices(
- availableIndices.map(index => {
- const errors = data.errors.filter(error => error.index === index);
- return {
- index,
- errors,
- isSelected: errors.length === 0 && !isExampleDataIndex(index),
- };
+ onResolve: ({ data: { errors } }) => {
+ setValidatedIndices(previousValidatedIndices =>
+ sourceConfiguration.indices.map(indexName => {
+ const previousValidatedIndex = previousValidatedIndices.filter(
+ ({ name }) => name === indexName
+ )[0];
+ const indexValiationErrors = errors.filter(({ index }) => index === indexName);
+ if (indexValiationErrors.length > 0) {
+ return {
+ validity: 'invalid',
+ name: indexName,
+ errors: indexValiationErrors,
+ };
+ } else {
+ return {
+ validity: 'valid',
+ name: indexName,
+ isSelected:
+ previousValidatedIndex?.validity === 'valid'
+ ? previousValidatedIndex?.isSelected
+ : !isExampleDataIndex(indexName),
+ };
+ }
})
);
},
@@ -79,7 +92,7 @@ export const useAnalysisSetupState = ({
setValidatedIndices([]);
},
},
- [availableIndices, timestampField]
+ [sourceConfiguration.indices]
);
useEffect(() => {
@@ -87,7 +100,10 @@ export const useAnalysisSetupState = ({
}, [validateIndices]);
const selectedIndexNames = useMemo(
- () => validatedIndices.filter(i => i.isSelected).map(i => i.index),
+ () =>
+ validatedIndices
+ .filter(index => index.validity === 'valid' && index.isSelected)
+ .map(i => i.name),
[validatedIndices]
);
@@ -120,9 +136,11 @@ export const useAnalysisSetupState = ({
}
return validatedIndices.reduce((errors, index) => {
- return selectedIndexNames.includes(index.index) ? errors.concat(index.errors) : errors;
+ return index.validity === 'invalid' && selectedIndexNames.includes(index.name)
+ ? [...errors, ...index.errors]
+ : errors;
}, []);
- }, [selectedIndexNames, validatedIndices, validateIndicesRequest.state]);
+ }, [isValidating, validateIndicesRequest.state, selectedIndexNames, validatedIndices]);
return {
cleanupAndSetup,
diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_entry_rate.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_entry_rate.tsx
deleted file mode 100644
index 8b21a7e82989..000000000000
--- a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_entry_rate.tsx
+++ /dev/null
@@ -1,50 +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 { useMemo, useState } from 'react';
-
-import { GetLogEntryRateSuccessResponsePayload } from '../../../../common/http_api/log_analysis';
-import { useTrackedPromise } from '../../../utils/use_tracked_promise';
-import { callGetLogEntryRateAPI } from './api/get_log_entry_rate';
-
-type LogEntryRateResults = GetLogEntryRateSuccessResponsePayload['data'];
-
-export const useLogEntryRate = ({
- sourceId,
- startTime,
- endTime,
- bucketDuration,
-}: {
- sourceId: string;
- startTime: number;
- endTime: number;
- bucketDuration: number;
-}) => {
- const [logEntryRate, setLogEntryRate] = useState(null);
-
- const [getLogEntryRateRequest, getLogEntryRate] = useTrackedPromise(
- {
- cancelPreviousOn: 'resolution',
- createPromise: async () => {
- return await callGetLogEntryRateAPI(sourceId, startTime, endTime, bucketDuration);
- },
- onResolve: response => {
- setLogEntryRate(response.data);
- },
- },
- [sourceId, startTime, endTime, bucketDuration]
- );
-
- const isLoading = useMemo(() => getLogEntryRateRequest.state === 'pending', [
- getLogEntryRateRequest.state,
- ]);
-
- return {
- getLogEntryRate,
- isLoading,
- logEntryRate,
- };
-};
diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/ml_api_types.ts b/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/ml_api_types.ts
deleted file mode 100644
index ee70edc31d49..000000000000
--- a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/ml_api_types.ts
+++ /dev/null
@@ -1,28 +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 * as rt from 'io-ts';
-
-export const getMlCapabilitiesResponsePayloadRT = rt.type({
- capabilities: rt.type({
- canGetJobs: rt.boolean,
- canCreateJob: rt.boolean,
- canDeleteJob: rt.boolean,
- canOpenJob: rt.boolean,
- canCloseJob: rt.boolean,
- canForecastJob: rt.boolean,
- canGetDatafeeds: rt.boolean,
- canStartStopDatafeed: rt.boolean,
- canUpdateJob: rt.boolean,
- canUpdateDatafeed: rt.boolean,
- canPreviewDatafeed: rt.boolean,
- }),
- isPlatinumOrTrialLicense: rt.boolean,
- mlFeatureEnabledInSpace: rt.boolean,
- upgradeInProgress: rt.boolean,
-});
-
-export type GetMlCapabilitiesResponsePayload = rt.TypeOf;
diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_highlights/log_entry_highlights.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/log_highlights/log_entry_highlights.tsx
index 6ead866fb960..2b19958a9b1a 100644
--- a/x-pack/legacy/plugins/infra/public/containers/logs/log_highlights/log_entry_highlights.tsx
+++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_highlights/log_entry_highlights.tsx
@@ -78,7 +78,7 @@ export const useLogEntryHighlights = (
} else {
setLogEntryHighlights([]);
}
- }, [highlightTerms, startKey, endKey, filterQuery, sourceVersion]);
+ }, [endKey, filterQuery, highlightTerms, loadLogEntryHighlights, sourceVersion, startKey]);
const logEntryHighlightsById = useMemo(
() =>
diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_highlights/log_summary_highlights.ts b/x-pack/legacy/plugins/infra/public/containers/logs/log_highlights/log_summary_highlights.ts
index 34c66afda010..874c70e01649 100644
--- a/x-pack/legacy/plugins/infra/public/containers/logs/log_highlights/log_summary_highlights.ts
+++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_highlights/log_summary_highlights.ts
@@ -74,7 +74,15 @@ export const useLogSummaryHighlights = (
} else {
setLogSummaryHighlights([]);
}
- }, [highlightTerms, start, end, bucketSize, filterQuery, sourceVersion]);
+ }, [
+ bucketSize,
+ debouncedLoadSummaryHighlights,
+ end,
+ filterQuery,
+ highlightTerms,
+ sourceVersion,
+ start,
+ ]);
return {
logSummaryHighlights,
diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_highlights/next_and_previous.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/log_highlights/next_and_previous.tsx
index 95ead50119eb..62a43a541282 100644
--- a/x-pack/legacy/plugins/infra/public/containers/logs/log_highlights/next_and_previous.tsx
+++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_highlights/next_and_previous.tsx
@@ -53,7 +53,7 @@ export const useNextAndPrevious = ({
const initialTimeKey = getUniqueLogEntryKey(entries[initialIndex]);
setCurrentTimeKey(initialTimeKey);
}
- }, [currentTimeKey, entries, setCurrentTimeKey]);
+ }, [currentTimeKey, entries, setCurrentTimeKey, visibleMidpoint]);
const indexOfCurrentTimeKey = useMemo(() => {
if (currentTimeKey && entries.length > 0) {
diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_highlights/redux_bridges.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/log_highlights/redux_bridges.tsx
index 2b60c6edd97a..9ea8987d4f32 100644
--- a/x-pack/legacy/plugins/infra/public/containers/logs/log_highlights/redux_bridges.tsx
+++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_highlights/redux_bridges.tsx
@@ -25,11 +25,11 @@ export const LogHighlightsPositionBridge = withLogPosition(
const { setJumpToTarget, setVisibleMidpoint } = useContext(LogHighlightsState.Context);
useEffect(() => {
setVisibleMidpoint(visibleMidpoint);
- }, [visibleMidpoint]);
+ }, [setVisibleMidpoint, visibleMidpoint]);
useEffect(() => {
setJumpToTarget(() => jumpToTargetPosition);
- }, [jumpToTargetPosition]);
+ }, [jumpToTargetPosition, setJumpToTarget]);
return null;
}
@@ -41,7 +41,7 @@ export const LogHighlightsFilterQueryBridge = withLogFilter(
useEffect(() => {
setFilterQuery(serializedFilterQuery);
- }, [serializedFilterQuery]);
+ }, [serializedFilterQuery, setFilterQuery]);
return null;
}
diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/with_stream_items.ts b/x-pack/legacy/plugins/infra/public/containers/logs/with_stream_items.ts
index da468b4391e4..9b20676486af 100644
--- a/x-pack/legacy/plugins/infra/public/containers/logs/with_stream_items.ts
+++ b/x-pack/legacy/plugins/infra/public/containers/logs/with_stream_items.ts
@@ -35,7 +35,7 @@ export const WithStreamItems: React.FunctionComponent<{
createLogEntryStreamItem(logEntry, logEntryHighlightsById[logEntry.gid] || [])
),
- [logEntries.entries, logEntryHighlightsById]
+ [isAutoReloading, logEntries.entries, logEntries.isReloading, logEntryHighlightsById]
);
return children({
diff --git a/x-pack/legacy/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_data.ts b/x-pack/legacy/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_data.ts
index 1418d6aef67a..c2a599ea1ae7 100644
--- a/x-pack/legacy/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_data.ts
+++ b/x-pack/legacy/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_data.ts
@@ -96,6 +96,9 @@ export function useMetricsExplorerData(
}
setLoading(false);
})();
+
+ // TODO: fix this dependency list while preserving the semantics
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [options, source, timerange, signal, afterKey]);
return { error, loading, data };
}
diff --git a/x-pack/legacy/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_options.ts b/x-pack/legacy/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_options.ts
index 278f3e0a9c17..de7a8d5805ec 100644
--- a/x-pack/legacy/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_options.ts
+++ b/x-pack/legacy/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_options.ts
@@ -102,7 +102,7 @@ function useStateWithLocalStorage(
const [state, setState] = useState(parseJsonOrDefault(storageState, defaultState));
useEffect(() => {
localStorage.setItem(key, JSON.stringify(state));
- }, [state]);
+ }, [key, state]);
return [state, setState];
}
diff --git a/x-pack/legacy/plugins/infra/public/containers/source/index.ts b/x-pack/legacy/plugins/infra/public/containers/source/index.ts
index 9442836f2a6c..5911decf2177 100644
--- a/x-pack/legacy/plugins/infra/public/containers/source/index.ts
+++ b/x-pack/legacy/plugins/infra/public/containers/source/index.ts
@@ -4,4 +4,4 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export { Source, useSource } from './source';
+export * from './source';
diff --git a/x-pack/legacy/plugins/infra/public/containers/source/source.tsx b/x-pack/legacy/plugins/infra/public/containers/source/source.tsx
index 955529c9759c..4729f7aa31f0 100644
--- a/x-pack/legacy/plugins/infra/public/containers/source/source.tsx
+++ b/x-pack/legacy/plugins/infra/public/containers/source/source.tsx
@@ -176,3 +176,4 @@ export const useSource = ({ sourceId }: { sourceId: string }) => {
};
export const Source = createContainer(useSource);
+export const [SourceProvider, useSourceContext] = Source;
diff --git a/x-pack/legacy/plugins/infra/public/hooks/use_saved_view.ts b/x-pack/legacy/plugins/infra/public/hooks/use_saved_view.ts
index 8db0ed28d9b2..4b12b6c51ea0 100644
--- a/x-pack/legacy/plugins/infra/public/hooks/use_saved_view.ts
+++ b/x-pack/legacy/plugins/infra/public/hooks/use_saved_view.ts
@@ -26,29 +26,32 @@ export const useSavedView = (defaultViewState: ViewState, viewType: s
>(viewType);
const { create, error: errorOnCreate, createdId } = useCreateSavedObject(viewType);
const { deleteObject, deletedId } = useDeleteSavedObject(viewType);
- const deleteView = useCallback((id: string) => deleteObject(id), []);
+ const deleteView = useCallback((id: string) => deleteObject(id), [deleteObject]);
const [createError, setCreateError] = useState(null);
- useEffect(() => setCreateError(createError), [errorOnCreate, setCreateError]);
+ useEffect(() => setCreateError(errorOnCreate), [errorOnCreate]);
- const saveView = useCallback((d: { [p: string]: any }) => {
- const doSave = async () => {
- const exists = await hasView(d.name);
- if (exists) {
- setCreateError(
- i18n.translate('xpack.infra.savedView.errorOnCreate.duplicateViewName', {
- defaultMessage: `A view with that name already exists.`,
- })
- );
- return;
- }
- create(d);
- };
- setCreateError(null);
- doSave();
- }, []);
+ const saveView = useCallback(
+ (d: { [p: string]: any }) => {
+ const doSave = async () => {
+ const exists = await hasView(d.name);
+ if (exists) {
+ setCreateError(
+ i18n.translate('xpack.infra.savedView.errorOnCreate.duplicateViewName', {
+ defaultMessage: `A view with that name already exists.`,
+ })
+ );
+ return;
+ }
+ create(d);
+ };
+ setCreateError(null);
+ doSave();
+ },
+ [create, hasView]
+ );
- const savedObjects = data ? data.savedObjects : [];
+ const savedObjects = useMemo(() => (data ? data.savedObjects : []), [data]);
const views = useMemo(() => {
const items: Array> = [
{
@@ -61,19 +64,17 @@ export const useSavedView = (defaultViewState: ViewState, viewType: s
},
];
- if (data) {
- data.savedObjects.forEach(
- o =>
- o.type === viewType &&
- items.push({
- ...o.attributes,
- id: o.id,
- })
- );
- }
+ savedObjects.forEach(
+ o =>
+ o.type === viewType &&
+ items.push({
+ ...o.attributes,
+ id: o.id,
+ })
+ );
return items;
- }, [savedObjects, defaultViewState]);
+ }, [defaultViewState, savedObjects, viewType]);
return {
views,
diff --git a/x-pack/legacy/plugins/infra/public/hooks/use_track_metric.tsx b/x-pack/legacy/plugins/infra/public/hooks/use_track_metric.tsx
index 379b3af3f106..c5945ab80820 100644
--- a/x-pack/legacy/plugins/infra/public/hooks/use_track_metric.tsx
+++ b/x-pack/legacy/plugins/infra/public/hooks/use_track_metric.tsx
@@ -57,6 +57,9 @@ export function useTrackMetric(
const trackUiMetric = getTrackerForApp(app);
const id = setTimeout(() => trackUiMetric(metricType, decoratedMetric), Math.max(delay, 0));
return () => clearTimeout(id);
+
+ // the dependencies are managed externally
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, effectDependencies);
}
diff --git a/x-pack/legacy/plugins/infra/public/pages/infrastructure/index.tsx b/x-pack/legacy/plugins/infra/public/pages/infrastructure/index.tsx
index fe48fcc62f77..9efbbe790abc 100644
--- a/x-pack/legacy/plugins/infra/public/pages/infrastructure/index.tsx
+++ b/x-pack/legacy/plugins/infra/public/pages/infrastructure/index.tsx
@@ -24,6 +24,7 @@ import { MetricsExplorerPage } from './metrics_explorer';
import { SnapshotPage } from './snapshot';
import { SettingsPage } from '../shared/settings';
import { AppNavigation } from '../../components/navigation/app_navigation';
+import { SourceLoadingPage } from '../../components/source_loading_page';
interface InfrastructurePageProps extends RouteComponentProps {
uiCapabilities: UICapabilities;
@@ -95,11 +96,15 @@ export const InfrastructurePage = injectUICapabilities(
{({ configuration, createDerivedIndexPattern }) => (
-
+ {configuration ? (
+
+ ) : (
+
+ )}
)}
diff --git a/x-pack/legacy/plugins/infra/public/pages/infrastructure/metrics_explorer/index.tsx b/x-pack/legacy/plugins/infra/public/pages/infrastructure/metrics_explorer/index.tsx
index 63f5a8196761..4db4319b91d3 100644
--- a/x-pack/legacy/plugins/infra/public/pages/infrastructure/metrics_explorer/index.tsx
+++ b/x-pack/legacy/plugins/infra/public/pages/infrastructure/metrics_explorer/index.tsx
@@ -11,22 +11,17 @@ import { IIndexPattern } from 'src/plugins/data/public';
import { DocumentTitle } from '../../../components/document_title';
import { MetricsExplorerCharts } from '../../../components/metrics_explorer/charts';
import { MetricsExplorerToolbar } from '../../../components/metrics_explorer/toolbar';
-import { SourceLoadingPage } from '../../../components/source_loading_page';
import { SourceQuery } from '../../../../common/graphql/types';
import { NoData } from '../../../components/empty_states';
import { useMetricsExplorerState } from './use_metric_explorer_state';
import { useTrackPageview } from '../../../hooks/use_track_metric';
interface MetricsExplorerPageProps {
- source: SourceQuery.Query['source']['configuration'] | undefined;
+ source: SourceQuery.Query['source']['configuration'];
derivedIndexPattern: IIndexPattern;
}
export const MetricsExplorerPage = ({ source, derivedIndexPattern }: MetricsExplorerPageProps) => {
- if (!source) {
- return ;
- }
-
const {
loading,
error,
diff --git a/x-pack/legacy/plugins/infra/public/pages/infrastructure/metrics_explorer/use_metric_explorer_state.ts b/x-pack/legacy/plugins/infra/public/pages/infrastructure/metrics_explorer/use_metric_explorer_state.ts
index 415a6ae89a8b..57ea88616970 100644
--- a/x-pack/legacy/plugins/infra/public/pages/infrastructure/metrics_explorer/use_metric_explorer_state.ts
+++ b/x-pack/legacy/plugins/infra/public/pages/infrastructure/metrics_explorer/use_metric_explorer_state.ts
@@ -59,7 +59,7 @@ export const useMetricsExplorerState = (
setAfterKey(null);
setTimeRange({ ...currentTimerange, from: start, to: end });
},
- [currentTimerange]
+ [currentTimerange, setTimeRange]
);
const handleGroupByChange = useCallback(
@@ -70,7 +70,7 @@ export const useMetricsExplorerState = (
groupBy: groupBy || void 0,
});
},
- [options]
+ [options, setOptions]
);
const handleFilterQuerySubmit = useCallback(
@@ -81,7 +81,7 @@ export const useMetricsExplorerState = (
filterQuery: query,
});
},
- [options]
+ [options, setOptions]
);
const handleMetricsChange = useCallback(
@@ -92,7 +92,7 @@ export const useMetricsExplorerState = (
metrics,
});
},
- [options]
+ [options, setOptions]
);
const handleAggregationChange = useCallback(
@@ -109,7 +109,7 @@ export const useMetricsExplorerState = (
}));
setOptions({ ...options, aggregation, metrics });
},
- [options]
+ [options, setOptions]
);
const onViewStateChange = useCallback(
@@ -124,7 +124,7 @@ export const useMetricsExplorerState = (
setOptions(vs.options);
}
},
- [setChartOptions, setTimeRange, setTimeRange]
+ [setChartOptions, setOptions, setTimeRange]
);
return {
diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/index.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/index.tsx
index 1630de11bbdf..4eddecf732f7 100644
--- a/x-pack/legacy/plugins/infra/public/pages/logs/index.tsx
+++ b/x-pack/legacy/plugins/infra/public/pages/logs/index.tsx
@@ -21,7 +21,7 @@ import { Source, useSource } from '../../containers/source';
import { StreamPage } from './stream';
import { SettingsPage } from '../shared/settings';
import { AppNavigation } from '../../components/navigation/app_navigation';
-import { AnalysisPage } from './analysis';
+import { LogEntryRatePage } from './log_entry_rate';
import {
useLogAnalysisCapabilities,
LogAnalysisCapabilities,
@@ -98,7 +98,7 @@ export const LogsPage = injectUICapabilities(({ match, uiCapabilities }: LogsPag
-
+
+ jobTypes.reduce(
+ (accumulatedJobIds, jobType) => ({
+ ...accumulatedJobIds,
+ [jobType]: getJobId(spaceId, sourceId, jobType),
+ }),
+ {} as Record
+ );
+
+const getJobSummary = async (spaceId: string, sourceId: string) => {
+ const response = await callJobsSummaryAPI(spaceId, sourceId, jobTypes);
+ const jobIds = Object.values(getJobIds(spaceId, sourceId));
+
+ return response.filter(jobSummary => jobIds.includes(jobSummary.id));
+};
+
+const getModuleDefinition = async () => {
+ return await callGetMlModuleAPI(moduleId);
+};
+
+const setUpModule = async (
+ start: number | undefined,
+ end: number | undefined,
+ { spaceId, sourceId, indices, timestampField }: ModuleSourceConfiguration
+) => {
+ const indexNamePattern = indices.join(',');
+ const jobOverrides = [
+ {
+ job_id: 'log-entry-rate' as const,
+ analysis_config: {
+ bucket_span: `${bucketSpan}ms`,
+ },
+ data_description: {
+ time_field: timestampField,
+ },
+ custom_settings: {
+ logs_source_config: {
+ indexPattern: indexNamePattern,
+ timestampField,
+ bucketSpan,
+ },
+ },
+ },
+ ];
+
+ return callSetupMlModuleAPI(
+ moduleId,
+ start,
+ end,
+ spaceId,
+ sourceId,
+ indexNamePattern,
+ jobOverrides
+ );
+};
+
+const cleanUpModule = async (spaceId: string, sourceId: string) => {
+ return await cleanUpJobsAndDatafeeds(spaceId, sourceId, jobTypes);
+};
+
+const validateSetupIndices = async ({ indices, timestampField }: ModuleSourceConfiguration) => {
+ return await callValidateIndicesAPI(indices, [
+ {
+ name: timestampField,
+ validTypes: ['date'],
+ },
+ {
+ name: partitionField,
+ validTypes: ['keyword'],
+ },
+ ]);
+};
+
+export const logEntryRateModule: ModuleDescriptor = {
+ moduleId,
+ jobTypes,
+ bucketSpan,
+ getJobIds,
+ getJobSummary,
+ getModuleDefinition,
+ setUpModule,
+ cleanUpModule,
+ validateSetupIndices,
+};
diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/page.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/page.tsx
similarity index 53%
rename from x-pack/legacy/plugins/infra/public/pages/logs/analysis/page.tsx
rename to x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/page.tsx
index d82da895f9a5..5ff5cd4db716 100644
--- a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/page.tsx
+++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/page.tsx
@@ -7,15 +7,15 @@
import React from 'react';
import { ColumnarPage } from '../../../components/page';
-import { AnalysisPageContent } from './page_content';
-import { AnalysisPageProviders } from './page_providers';
+import { LogEntryRatePageContent } from './page_content';
+import { LogEntryRatePageProviders } from './page_providers';
-export const AnalysisPage = () => {
+export const LogEntryRatePage = () => {
return (
-
-
-
+
+
+
-
+
);
};
diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/page_content.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/page_content.tsx
similarity index 58%
rename from x-pack/legacy/plugins/infra/public/pages/logs/analysis/page_content.tsx
rename to x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/page_content.tsx
index f0a26eae25ec..e71985f73fbb 100644
--- a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/page_content.tsx
+++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/page_content.tsx
@@ -9,34 +9,37 @@ import React, { useContext, useEffect } from 'react';
import { isSetupStatusWithResults } from '../../../../common/log_analysis';
import { LoadingPage } from '../../../components/loading_page';
-import { LogAnalysisCapabilities, LogAnalysisJobs } from '../../../containers/logs/log_analysis';
+import { LogAnalysisCapabilities } from '../../../containers/logs/log_analysis';
import { Source } from '../../../containers/source';
-import { AnalysisResultsContent } from './page_results_content';
-import { AnalysisSetupContent } from './page_setup_content';
-import { AnalysisUnavailableContent } from './page_unavailable_content';
-import { AnalysisSetupStatusUnknownContent } from './page_setup_status_unknown';
+import { LogEntryRateResultsContent } from './page_results_content';
+import { LogEntryRateSetupContent } from './page_setup_content';
+import { LogEntryRateUnavailableContent } from './page_unavailable_content';
+import { LogEntryRateSetupStatusUnknownContent } from './page_setup_status_unknown';
+import { useLogEntryRateModuleContext } from './use_log_entry_rate_module';
-export const AnalysisPageContent = () => {
+export const LogEntryRatePageContent = () => {
const { sourceId } = useContext(Source.Context);
const { hasLogAnalysisCapabilites } = useContext(LogAnalysisCapabilities.Context);
const {
- availableIndices,
- cleanupAndSetup,
+ cleanUpAndSetUpModule: cleanupAndSetup,
fetchJobStatus,
+ fetchModuleDefinition,
lastSetupErrorMessages,
- setup,
+ moduleDescriptor,
+ setUpModule,
setupStatus,
- timestampField,
+ sourceConfiguration,
viewResults,
- } = useContext(LogAnalysisJobs.Context);
+ } = useLogEntryRateModuleContext();
useEffect(() => {
+ fetchModuleDefinition();
fetchJobStatus();
- }, []);
+ }, [fetchJobStatus, fetchModuleDefinition]);
if (!hasLogAnalysisCapabilites) {
- return ;
+ return ;
} else if (setupStatus === 'initializing') {
return (
{
/>
);
} else if (setupStatus === 'unknown') {
- return ;
+ return ;
} else if (isSetupStatusWithResults(setupStatus)) {
return (
-
);
} else {
return (
-
);
diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/page_providers.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/page_providers.tsx
similarity index 53%
rename from x-pack/legacy/plugins/infra/public/pages/logs/analysis/page_providers.tsx
rename to x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/page_providers.tsx
index fba32f6cbd6d..67c8ea7660a2 100644
--- a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/page_providers.tsx
+++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/page_providers.tsx
@@ -4,24 +4,24 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import React, { useContext } from 'react';
+import React from 'react';
-import { LogAnalysisJobs } from '../../../containers/logs/log_analysis';
-import { Source } from '../../../containers/source';
+import { useSourceContext } from '../../../containers/source';
import { useKibanaSpaceId } from '../../../utils/use_kibana_space_id';
+import { LogEntryRateModuleProvider } from './use_log_entry_rate_module';
-export const AnalysisPageProviders: React.FunctionComponent = ({ children }) => {
- const { sourceId, source } = useContext(Source.Context);
+export const LogEntryRatePageProviders: React.FunctionComponent = ({ children }) => {
+ const { sourceId, source } = useSourceContext();
const spaceId = useKibanaSpaceId();
return (
-
{children}
-
+
);
};
diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/page_results_content.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/page_results_content.tsx
similarity index 78%
rename from x-pack/legacy/plugins/infra/public/pages/logs/analysis/page_results_content.tsx
rename to x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/page_results_content.tsx
index 7fa9ff3c93db..be637bc29a0d 100644
--- a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/page_results_content.tsx
+++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/page_results_content.tsx
@@ -17,36 +17,36 @@ import {
import numeral from '@elastic/numeral';
import { FormattedMessage } from '@kbn/i18n/react';
import moment from 'moment';
-import React, { useCallback, useContext, useMemo, useState } from 'react';
+import React, { useCallback, useMemo, useState, useEffect } from 'react';
import euiStyled from '../../../../../../common/eui_styled_components';
import { TimeRange } from '../../../../common/http_api/shared/time_range';
import { bucketSpan } from '../../../../common/log_analysis';
import { LoadingOverlayWrapper } from '../../../components/loading_overlay_wrapper';
-import {
- LogAnalysisJobs,
- StringTimeRange,
- useLogAnalysisResults,
- useLogAnalysisResultsUrlState,
-} from '../../../containers/logs/log_analysis';
import { useInterval } from '../../../hooks/use_interval';
import { useTrackPageview } from '../../../hooks/use_track_metric';
import { useKibanaUiSetting } from '../../../utils/use_kibana_ui_setting';
import { FirstUseCallout } from './first_use';
import { AnomaliesResults } from './sections/anomalies';
import { LogRateResults } from './sections/log_rate';
+import { useLogEntryRateModuleContext } from './use_log_entry_rate_module';
+import { useLogEntryRateResults } from './use_log_entry_rate_results';
+import {
+ StringTimeRange,
+ useLogAnalysisResultsUrlState,
+} from './use_log_entry_rate_results_url_state';
const JOB_STATUS_POLLING_INTERVAL = 30000;
-export const AnalysisResultsContent = ({
+export const LogEntryRateResultsContent = ({
sourceId,
isFirstUse,
}: {
sourceId: string;
isFirstUse: boolean;
}) => {
- useTrackPageview({ app: 'infra_logs', path: 'analysis_results' });
- useTrackPageview({ app: 'infra_logs', path: 'analysis_results', delay: 15000 });
+ useTrackPageview({ app: 'infra_logs', path: 'log_entry_rate_results' });
+ useTrackPageview({ app: 'infra_logs', path: 'log_entry_rate_results', delay: 15000 });
const [dateFormat] = useKibanaUiSetting('dateFormat', 'MMMM D, YYYY h:mm A');
@@ -65,32 +65,20 @@ export const AnalysisResultsContent = ({
lastChangedTime: Date.now(),
}));
- const bucketDuration = useMemo(() => {
- // This function takes the current time range in ms,
- // works out the bucket interval we'd need to always
- // display 100 data points, and then takes that new
- // value and works out the nearest multiple of
- // 900000 (15 minutes) to it, so that we don't end up with
- // jaggy bucket boundaries between the ML buckets and our
- // aggregation buckets.
- const msRange = moment(queryTimeRange.value.endTime).diff(
- moment(queryTimeRange.value.startTime)
- );
- const bucketIntervalInMs = msRange / 100;
- const result = bucketSpan * Math.round(bucketIntervalInMs / bucketSpan);
- const roundedResult = parseInt(Number(result).toFixed(0), 10);
- return roundedResult < bucketSpan ? bucketSpan : roundedResult;
- }, [queryTimeRange.value.startTime, queryTimeRange.value.endTime]);
+ const bucketDuration = useMemo(
+ () => getBucketDuration(queryTimeRange.value.startTime, queryTimeRange.value.endTime),
+ [queryTimeRange.value.endTime, queryTimeRange.value.startTime]
+ );
- const { isLoading, logRateResults } = useLogAnalysisResults({
+ const { getLogEntryRate, isLoading, logEntryRate } = useLogEntryRateResults({
sourceId,
startTime: queryTimeRange.value.startTime,
endTime: queryTimeRange.value.endTime,
bucketDuration,
- lastRequestTime: queryTimeRange.lastChangedTime,
});
- const hasResults = useMemo(() => logRateResults && logRateResults.histogramBuckets.length > 0, [
- logRateResults,
+
+ const hasResults = useMemo(() => (logEntryRate?.histogramBuckets?.length ?? 0) > 0, [
+ logEntryRate,
]);
const handleQueryTimeRangeChange = useCallback(
@@ -145,7 +133,11 @@ export const AnalysisResultsContent = ({
viewSetupForReconfiguration,
viewSetupForUpdate,
jobIds,
- } = useContext(LogAnalysisJobs.Context);
+ } = useLogEntryRateModuleContext();
+
+ useEffect(() => {
+ getLogEntryRate();
+ }, [getLogEntryRate, queryTimeRange.lastChangedTime]);
useInterval(() => {
fetchJobStatus();
@@ -168,7 +160,7 @@ export const AnalysisResultsContent = ({
- {logRateResults ? (
+ {logEntryRate ? (
- {numeral(logRateResults.totalNumberOfLogEntries).format('0.00a')}
+ {numeral(logEntryRate.totalNumberOfLogEntries).format('0.00a')}
),
@@ -210,7 +202,7 @@ export const AnalysisResultsContent = ({
{isFirstUse && !hasResults ? : null}
@@ -223,7 +215,7 @@ export const AnalysisResultsContent = ({
jobStatus={jobStatus['log-entry-rate']}
viewSetupForReconfiguration={viewSetupForReconfiguration}
viewSetupForUpdate={viewSetupForUpdate}
- results={logRateResults}
+ results={logEntryRate}
setTimeRange={handleChartTimeRangeChange}
setupStatus={setupStatus}
timeRange={queryTimeRange.value}
@@ -250,6 +242,23 @@ const stringToNumericTimeRange = (timeRange: StringTimeRange): TimeRange => ({
).valueOf(),
});
+/**
+ * This function takes the current time range in ms,
+ * works out the bucket interval we'd need to always
+ * display 100 data points, and then takes that new
+ * value and works out the nearest multiple of
+ * 900000 (15 minutes) to it, so that we don't end up with
+ * jaggy bucket boundaries between the ML buckets and our
+ * aggregation buckets.
+ */
+const getBucketDuration = (startTime: number, endTime: number) => {
+ const msRange = moment(endTime).diff(moment(startTime));
+ const bucketIntervalInMs = msRange / 100;
+ const result = bucketSpan * Math.round(bucketIntervalInMs / bucketSpan);
+ const roundedResult = parseInt(Number(result).toFixed(0), 10);
+ return roundedResult < bucketSpan ? bucketSpan : roundedResult;
+};
+
// This is needed due to the flex-basis: 100% !important; rule that
// kicks in on small screens via media queries breaking when using direction="column"
export const ResultsContentPage = euiStyled(EuiPage)`
diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/page_setup_content.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/page_setup_content.tsx
similarity index 70%
rename from x-pack/legacy/plugins/infra/public/pages/logs/analysis/page_setup_content.tsx
rename to x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/page_setup_content.tsx
index 7ae174c4a789..6c04404b9123 100644
--- a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/page_setup_content.tsx
+++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/page_setup_content.tsx
@@ -4,23 +4,25 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import React from 'react';
import {
EuiPage,
EuiPageBody,
EuiPageContent,
+ EuiPageContentBody,
EuiPageContentHeader,
EuiPageContentHeaderSection,
- EuiPageContentBody,
+ EuiSpacer,
EuiText,
EuiTitle,
- EuiSpacer,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
+import React from 'react';
+
import euiStyled from '../../../../../../common/eui_styled_components';
import { SetupStatus } from '../../../../common/log_analysis';
+import { ModuleDescriptor, ModuleSourceConfiguration } from '../../../containers/logs/log_analysis';
import { useTrackPageview } from '../../../hooks/use_track_metric';
-import { AnalysisSetupSteps } from './setup';
+import { LogEntryRateSetupSteps } from './setup';
type SetupHandler = (
indices: string[],
@@ -28,32 +30,32 @@ type SetupHandler = (
endTime: number | undefined
) => void;
-interface AnalysisSetupContentProps {
- availableIndices: string[];
+interface LogEntryRateSetupContentProps {
cleanupAndSetup: SetupHandler;
errorMessages: string[];
+ moduleDescriptor: ModuleDescriptor;
setup: SetupHandler;
setupStatus: SetupStatus;
- timestampField: string;
+ sourceConfiguration: ModuleSourceConfiguration;
viewResults: () => void;
}
-export const AnalysisSetupContent: React.FunctionComponent = ({
- availableIndices,
+export const LogEntryRateSetupContent = ({
cleanupAndSetup,
errorMessages,
setup,
setupStatus,
- timestampField,
viewResults,
-}) => {
- useTrackPageview({ app: 'infra_logs', path: 'analysis_setup' });
- useTrackPageview({ app: 'infra_logs', path: 'analysis_setup', delay: 15000 });
+ moduleDescriptor,
+ sourceConfiguration,
+}: LogEntryRateSetupContentProps) => {
+ useTrackPageview({ app: 'infra_logs', path: 'log_entry_rate_setup' });
+ useTrackPageview({ app: 'infra_logs', path: 'log_entry_rate_setup', delay: 15000 });
return (
-
+
-
-
-
+
-
+
);
};
// !important due to https://github.com/elastic/eui/issues/2232
-const AnalysisPageContent = euiStyled(EuiPageContent)`
+const LogEntryRateSetupPageContent = euiStyled(EuiPageContent)`
max-width: 768px !important;
`;
-const AnalysisSetupPage = euiStyled(EuiPage)`
+const LogEntryRateSetupPage = euiStyled(EuiPage)`
height: 100%;
`;
diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/page_setup_status_unknown.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/page_setup_status_unknown.tsx
similarity index 92%
rename from x-pack/legacy/plugins/infra/public/pages/logs/analysis/page_setup_status_unknown.tsx
rename to x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/page_setup_status_unknown.tsx
index 953b0841ffe9..4c685bd42b93 100644
--- a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/page_setup_status_unknown.tsx
+++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/page_setup_status_unknown.tsx
@@ -14,7 +14,7 @@ interface Props {
retry: () => void;
}
-export const AnalysisSetupStatusUnknownContent: React.FunctionComponent = ({
+export const LogEntryRateSetupStatusUnknownContent: React.FunctionComponent = ({
retry,
}: Props) => (
= () => (
+export const LogEntryRateUnavailableContent: React.FunctionComponent<{}> = () => (
diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/anomalies/chart.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/chart.tsx
similarity index 100%
rename from x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/anomalies/chart.tsx
rename to x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/chart.tsx
diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/anomalies/expanded_row.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/expanded_row.tsx
similarity index 84%
rename from x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/anomalies/expanded_row.tsx
rename to x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/expanded_row.tsx
index 0586f5282ddf..f8a7f12364cf 100644
--- a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/anomalies/expanded_row.tsx
+++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/expanded_row.tsx
@@ -4,38 +4,37 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import React, { useMemo } from 'react';
-import { i18n } from '@kbn/i18n';
+import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiStat } from '@elastic/eui';
import numeral from '@elastic/numeral';
-import { EuiFlexGroup, EuiFlexItem, EuiStat, EuiSpacer } from '@elastic/eui';
-import { AnomaliesChart } from './chart';
-import { LogRateResults } from '../../../../../containers/logs/log_analysis/log_analysis_results';
+import { i18n } from '@kbn/i18n';
+import React, { useMemo } from 'react';
+
import { TimeRange } from '../../../../../../common/http_api/shared/time_range';
+import { AnalyzeInMlButton } from '../../../../../components/logging/log_analysis_results';
+import { LogEntryRateResults } from '../../use_log_entry_rate_results';
import {
- getLogEntryRateSeriesForPartition,
getAnnotationsForPartition,
+ getLogEntryRateSeriesForPartition,
getTotalNumberOfLogEntriesForPartition,
} from '../helpers/data_formatters';
-import { AnalyzeInMlButton } from '../analyze_in_ml_button';
+import { AnomaliesChart } from './chart';
export const AnomaliesTableExpandedRow: React.FunctionComponent<{
partitionId: string;
topAnomalyScore: number;
- results: LogRateResults;
+ results: LogEntryRateResults;
setTimeRange: (timeRange: TimeRange) => void;
timeRange: TimeRange;
jobId: string;
}> = ({ results, timeRange, setTimeRange, partitionId, jobId }) => {
const logEntryRateSeries = useMemo(
() =>
- results && results.histogramBuckets
- ? getLogEntryRateSeriesForPartition(results, partitionId)
- : [],
+ results?.histogramBuckets ? getLogEntryRateSeriesForPartition(results, partitionId) : [],
[results, partitionId]
);
const anomalyAnnotations = useMemo(
() =>
- results && results.histogramBuckets
+ results?.histogramBuckets
? getAnnotationsForPartition(results, partitionId)
: {
warning: [],
@@ -47,7 +46,7 @@ export const AnomaliesTableExpandedRow: React.FunctionComponent<{
);
const totalNumberOfLogEntries = useMemo(
() =>
- results && results.histogramBuckets
+ results?.histogramBuckets
? getTotalNumberOfLogEntriesForPartition(results, partitionId)
: undefined,
[results, partitionId]
diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/anomalies/index.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/index.tsx
similarity index 97%
rename from x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/anomalies/index.tsx
rename to x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/index.tsx
index e870c2d44271..38aa4b068c9e 100644
--- a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/anomalies/index.tsx
+++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/index.tsx
@@ -18,7 +18,7 @@ import { i18n } from '@kbn/i18n';
import React, { useMemo } from 'react';
import euiStyled from '../../../../../../../../common/eui_styled_components';
-import { LogRateResults } from '../../../../../containers/logs/log_analysis/log_analysis_results';
+import { LogEntryRateResults } from '../../use_log_entry_rate_results';
import { TimeRange } from '../../../../../../common/http_api/shared/time_range';
import { JobStatus, SetupStatus } from '../../../../../../common/log_analysis';
import {
@@ -30,13 +30,13 @@ import {
import { AnomaliesChart } from './chart';
import { AnomaliesTable } from './table';
import { LogAnalysisJobProblemIndicator } from '../../../../../components/logging/log_analysis_job_status';
-import { AnalyzeInMlButton } from '../analyze_in_ml_button';
+import { AnalyzeInMlButton } from '../../../../../components/logging/log_analysis_results';
import { LoadingOverlayWrapper } from '../../../../../components/loading_overlay_wrapper';
export const AnomaliesResults: React.FunctionComponent<{
isLoading: boolean;
jobStatus: JobStatus;
- results: LogRateResults | null;
+ results: LogEntryRateResults | null;
setTimeRange: (timeRange: TimeRange) => void;
setupStatus: SetupStatus;
timeRange: TimeRange;
diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/anomalies/table.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/table.tsx
similarity index 95%
rename from x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/anomalies/table.tsx
rename to x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/table.tsx
index c0016d07c290..86760cf2da7d 100644
--- a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/anomalies/table.tsx
+++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/table.tsx
@@ -9,7 +9,7 @@ import { EuiBasicTable, EuiButtonIcon } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { RIGHT_ALIGNMENT } from '@elastic/eui/lib/services';
import { TimeRange } from '../../../../../../common/http_api/shared/time_range';
-import { LogRateResults } from '../../../../../containers/logs/log_analysis/log_analysis_results';
+import { LogEntryRateResults } from '../../use_log_entry_rate_results';
import { AnomaliesTableExpandedRow } from './expanded_row';
import { formatAnomalyScore, getFriendlyNameForPartitionId } from '../helpers/data_formatters';
import euiStyled from '../../../../../../../../common/eui_styled_components';
@@ -50,7 +50,7 @@ const maxAnomalyScoreColumnName = i18n.translate(
);
export const AnomaliesTable: React.FunctionComponent<{
- results: LogRateResults;
+ results: LogEntryRateResults;
setTimeRange: (timeRange: TimeRange) => void;
timeRange: TimeRange;
jobId: string;
@@ -124,7 +124,7 @@ export const AnomaliesTable: React.FunctionComponent<{
setItemIdToExpandedRowMap(newItemIdToExpandedRowMap);
}
},
- [results, setTimeRange, timeRange, itemIdToExpandedRowMap, setItemIdToExpandedRowMap]
+ [itemIdToExpandedRowMap, jobId, results, setTimeRange, timeRange]
);
const columns = [
diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/helpers/data_formatters.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/sections/helpers/data_formatters.tsx
similarity index 88%
rename from x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/helpers/data_formatters.tsx
rename to x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/sections/helpers/data_formatters.tsx
index 74a3b5f80a57..f9b85fc4e20c 100644
--- a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/helpers/data_formatters.tsx
+++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/sections/helpers/data_formatters.tsx
@@ -6,18 +6,19 @@
import { RectAnnotationDatum } from '@elastic/charts';
import { i18n } from '@kbn/i18n';
-import { LogRateResults } from '../../../../../containers/logs/log_analysis/log_analysis_results';
-export type MLSeverityScoreCategories = 'warning' | 'minor' | 'major' | 'critical';
-type MLSeverityScores = Record;
-const ML_SEVERITY_SCORES: MLSeverityScores = {
+import { LogEntryRateResults } from '../../use_log_entry_rate_results';
+
+const ML_SEVERITY_SCORES = {
warning: 3,
minor: 25,
major: 50,
critical: 75,
};
-export const getLogEntryRatePartitionedSeries = (results: LogRateResults) => {
+export type MLSeverityScoreCategories = keyof typeof ML_SEVERITY_SCORES;
+
+export const getLogEntryRatePartitionedSeries = (results: LogEntryRateResults) => {
return results.histogramBuckets.reduce>(
(buckets, bucket) => {
return [
@@ -33,7 +34,7 @@ export const getLogEntryRatePartitionedSeries = (results: LogRateResults) => {
);
};
-export const getLogEntryRateCombinedSeries = (results: LogRateResults) => {
+export const getLogEntryRateCombinedSeries = (results: LogEntryRateResults) => {
return results.histogramBuckets.reduce>(
(buckets, bucket) => {
return [
@@ -50,7 +51,10 @@ export const getLogEntryRateCombinedSeries = (results: LogRateResults) => {
);
};
-export const getLogEntryRateSeriesForPartition = (results: LogRateResults, partitionId: string) => {
+export const getLogEntryRateSeriesForPartition = (
+ results: LogEntryRateResults,
+ partitionId: string
+) => {
return results.partitionBuckets[partitionId].buckets.reduce<
Array<{ time: number; value: number }>
>((buckets, bucket) => {
@@ -64,7 +68,7 @@ export const getLogEntryRateSeriesForPartition = (results: LogRateResults, parti
}, []);
};
-export const getAnnotationsForPartition = (results: LogRateResults, partitionId: string) => {
+export const getAnnotationsForPartition = (results: LogEntryRateResults, partitionId: string) => {
return results.partitionBuckets[partitionId].buckets.reduce<
Record
>(
@@ -106,13 +110,13 @@ export const getAnnotationsForPartition = (results: LogRateResults, partitionId:
};
export const getTotalNumberOfLogEntriesForPartition = (
- results: LogRateResults,
+ results: LogEntryRateResults,
partitionId: string
) => {
return results.partitionBuckets[partitionId].totalNumberOfLogEntries;
};
-export const getAnnotationsForAll = (results: LogRateResults) => {
+export const getAnnotationsForAll = (results: LogEntryRateResults) => {
return results.histogramBuckets.reduce>(
(annotatedBucketsBySeverity, bucket) => {
const maxAnomalyScoresByPartition = bucket.partitions.reduce<
@@ -169,7 +173,7 @@ export const getAnnotationsForAll = (results: LogRateResults) => {
);
};
-export const getTopAnomalyScoreAcrossAllPartitions = (results: LogRateResults) => {
+export const getTopAnomalyScoreAcrossAllPartitions = (results: LogEntryRateResults) => {
const allTopScores = Object.values(results.partitionBuckets).reduce(
(scores: number[], partition) => {
return [...scores, partition.topAnomalyScore];
diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/log_rate/bar_chart.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/sections/log_rate/bar_chart.tsx
similarity index 100%
rename from x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/log_rate/bar_chart.tsx
rename to x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/sections/log_rate/bar_chart.tsx
diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/log_rate/index.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/sections/log_rate/index.tsx
similarity index 96%
rename from x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/log_rate/index.tsx
rename to x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/sections/log_rate/index.tsx
index 44805520f3b9..a11dc9d4d607 100644
--- a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/sections/log_rate/index.tsx
+++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/sections/log_rate/index.tsx
@@ -8,7 +8,7 @@ import { EuiEmptyPrompt, EuiLoadingSpinner, EuiSpacer, EuiTitle, EuiText } from
import { i18n } from '@kbn/i18n';
import React, { useMemo } from 'react';
-import { LogRateResults as Results } from '../../../../../containers/logs/log_analysis/log_analysis_results';
+import { LogEntryRateResults as Results } from '../../use_log_entry_rate_results';
import { TimeRange } from '../../../../../../common/http_api/shared/time_range';
import { LogEntryRateBarChart } from './bar_chart';
import { getLogEntryRatePartitionedSeries } from '../helpers/data_formatters';
diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/get_log_entry_rate.ts b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_rate.ts
similarity index 100%
rename from x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/api/get_log_entry_rate.ts
rename to x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_rate.ts
diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/setup/index.ts b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/setup/index.ts
similarity index 100%
rename from x-pack/legacy/plugins/infra/public/pages/logs/analysis/setup/index.ts
rename to x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/setup/index.ts
diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/setup/initial_configuration_step/analysis_setup_indices_form.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/setup/initial_configuration_step/analysis_setup_indices_form.tsx
similarity index 87%
rename from x-pack/legacy/plugins/infra/public/pages/logs/analysis/setup/initial_configuration_step/analysis_setup_indices_form.tsx
rename to x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/setup/initial_configuration_step/analysis_setup_indices_form.tsx
index 585a65b9ad1c..5a4c21670191 100644
--- a/x-pack/legacy/plugins/infra/public/pages/logs/analysis/setup/initial_configuration_step/analysis_setup_indices_form.tsx
+++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/setup/initial_configuration_step/analysis_setup_indices_form.tsx
@@ -25,7 +25,7 @@ export const AnalysisSetupIndicesForm: React.FunctionComponent<{
onChangeSelectedIndices(
indices.map(index => {
const checkbox = event.currentTarget;
- return index.index === checkbox.id ? { ...index, isSelected: checkbox.checked } : index;
+ return index.name === checkbox.id ? { ...index, isSelected: checkbox.checked } : index;
})
);
},
@@ -35,37 +35,38 @@ export const AnalysisSetupIndicesForm: React.FunctionComponent<{
const choices = useMemo(
() =>
indices.map(index => {
- const validIndex = index.errors.length === 0;
const checkbox = (
{index.index}}
+ key={index.name}
+ id={index.name}
+ label={{index.name} }
onChange={handleCheckboxChange}
- checked={index.isSelected}
- disabled={!validIndex}
+ checked={index.validity === 'valid' && index.isSelected}
+ disabled={index.validity === 'invalid'}
/>
);
- return validIndex ? (
+ return index.validity === 'valid' ? (
checkbox
) : (
-
+
{checkbox}
);
}),
- [indices]
+ [handleCheckboxChange, indices]
);
return (
+
+
+
}
description={
+
+
+
}
description={
void;
-interface AnalysisSetupStepsProps {
- availableIndices: string[];
+interface LogEntryRateSetupStepsProps {
cleanupAndSetup: SetupHandler;
errorMessages: string[];
setup: SetupHandler;
setupStatus: SetupStatus;
- timestampField: string;
viewResults: () => void;
+ moduleDescriptor: ModuleDescriptor;
+ sourceConfiguration: ModuleSourceConfiguration;
}
-export const AnalysisSetupSteps: React.FunctionComponent = ({
- availableIndices,
+export const LogEntryRateSetupSteps = ({
cleanupAndSetup: cleanupAndSetupModule,
errorMessages,
setup: setupModule,
setupStatus,
- timestampField,
viewResults,
-}: AnalysisSetupStepsProps) => {
+ moduleDescriptor,
+ sourceConfiguration,
+}: LogEntryRateSetupStepsProps) => {
const {
setup,
cleanupAndSetup,
@@ -50,10 +54,10 @@ export const AnalysisSetupSteps: React.FunctionComponent {
+ const sourceConfiguration: ModuleSourceConfiguration = useMemo(
+ () => ({
+ indices: indexPattern.split(','),
+ sourceId,
+ spaceId,
+ timestampField,
+ }),
+ [indexPattern, sourceId, spaceId, timestampField]
+ );
+
+ return useLogAnalysisModule({
+ moduleDescriptor: logEntryRateModule,
+ sourceConfiguration,
+ });
+};
+
+export const [LogEntryRateModuleProvider, useLogEntryRateModuleContext] = createContainer(
+ useLogEntryRateModule
+);
diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_results.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_rate_results.ts
similarity index 58%
rename from x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_results.tsx
rename to x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_rate_results.ts
index 81a80fb565a4..de2b873001cc 100644
--- a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_results.tsx
+++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_rate_results.ts
@@ -4,75 +4,77 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import createContainer from 'constate';
-import { useMemo, useEffect } from 'react';
+import { useMemo, useState } from 'react';
-import { useLogEntryRate } from './log_entry_rate';
-import { GetLogEntryRateSuccessResponsePayload } from '../../../../common/http_api/log_analysis';
+import {
+ GetLogEntryRateSuccessResponsePayload,
+ LogEntryRateHistogramBucket,
+ LogEntryRatePartition,
+} from '../../../../common/http_api/log_analysis';
+import { useTrackedPromise } from '../../../utils/use_tracked_promise';
+import { callGetLogEntryRateAPI } from './service_calls/get_log_entry_rate';
-type PartitionBucket = {
+type PartitionBucket = LogEntryRatePartition & {
startTime: number;
-} & GetLogEntryRateSuccessResponsePayload['data']['histogramBuckets'][0]['partitions'][0];
+};
type PartitionRecord = Record<
string,
{ buckets: PartitionBucket[]; topAnomalyScore: number; totalNumberOfLogEntries: number }
>;
-export interface LogRateResults {
+export interface LogEntryRateResults {
bucketDuration: number;
totalNumberOfLogEntries: number;
- histogramBuckets: GetLogEntryRateSuccessResponsePayload['data']['histogramBuckets'];
+ histogramBuckets: LogEntryRateHistogramBucket[];
partitionBuckets: PartitionRecord;
}
-export const useLogAnalysisResults = ({
+export const useLogEntryRateResults = ({
sourceId,
startTime,
endTime,
bucketDuration = 15 * 60 * 1000,
- lastRequestTime,
}: {
sourceId: string;
startTime: number;
endTime: number;
- bucketDuration?: number;
- lastRequestTime: number;
+ bucketDuration: number;
}) => {
- const { isLoading: isLoadingLogEntryRate, logEntryRate, getLogEntryRate } = useLogEntryRate({
- sourceId,
- startTime,
- endTime,
- bucketDuration,
- });
-
- const isLoading = useMemo(() => isLoadingLogEntryRate, [isLoadingLogEntryRate]);
+ const [logEntryRate, setLogEntryRate] = useState(null);
- useEffect(() => {
- getLogEntryRate();
- }, [sourceId, startTime, endTime, bucketDuration, lastRequestTime]);
+ const [getLogEntryRateRequest, getLogEntryRate] = useTrackedPromise(
+ {
+ cancelPreviousOn: 'resolution',
+ createPromise: async () => {
+ return await callGetLogEntryRateAPI(sourceId, startTime, endTime, bucketDuration);
+ },
+ onResolve: ({ data }) => {
+ setLogEntryRate({
+ bucketDuration: data.bucketDuration,
+ totalNumberOfLogEntries: data.totalNumberOfLogEntries,
+ histogramBuckets: data.histogramBuckets,
+ partitionBuckets: formatLogEntryRateResultsByPartition(data),
+ });
+ },
+ onReject: () => {
+ setLogEntryRate(null);
+ },
+ },
+ [sourceId, startTime, endTime, bucketDuration]
+ );
- const logRateResults: LogRateResults | null = useMemo(() => {
- if (logEntryRate) {
- return {
- bucketDuration: logEntryRate.bucketDuration,
- totalNumberOfLogEntries: logEntryRate.totalNumberOfLogEntries,
- histogramBuckets: logEntryRate.histogramBuckets,
- partitionBuckets: formatLogEntryRateResultsByPartition(logEntryRate),
- };
- } else {
- return null;
- }
- }, [logEntryRate]);
+ const isLoading = useMemo(() => getLogEntryRateRequest.state === 'pending', [
+ getLogEntryRateRequest.state,
+ ]);
return {
+ getLogEntryRate,
isLoading,
- logRateResults,
+ logEntryRate,
};
};
-export const LogAnalysisResults = createContainer(useLogAnalysisResults);
-
const formatLogEntryRateResultsByPartition = (
results: GetLogEntryRateSuccessResponsePayload['data']
): PartitionRecord => {
diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_results_url_state.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_rate_results_url_state.tsx
similarity index 88%
rename from x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_results_url_state.tsx
rename to x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_rate_results_url_state.tsx
index 19fb7f238fc0..6d4495c8d9e0 100644
--- a/x-pack/legacy/plugins/infra/public/containers/logs/log_analysis/log_analysis_results_url_state.tsx
+++ b/x-pack/legacy/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_rate_results_url_state.tsx
@@ -4,11 +4,11 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { useEffect } from 'react';
-import * as rt from 'io-ts';
-import { identity, constant } from 'fp-ts/lib/function';
import { fold } from 'fp-ts/lib/Either';
+import { constant, identity } from 'fp-ts/lib/function';
import { pipe } from 'fp-ts/lib/pipeable';
+import * as rt from 'io-ts';
+
import { useUrlState } from '../../../utils/use_url_state';
const autoRefreshRT = rt.union([
@@ -40,12 +40,9 @@ export const useLogAnalysisResultsUrlState = () => {
pipe(urlTimeRangeRT.decode(value), fold(constant(undefined), identity)),
encodeUrlState: urlTimeRangeRT.encode,
urlStateKey: TIME_RANGE_URL_STATE_KEY,
+ writeDefaultState: true,
});
- useEffect(() => {
- setTimeRange(timeRange);
- }, []);
-
const [autoRefresh, setAutoRefresh] = useUrlState({
defaultState: {
isPaused: false,
@@ -55,12 +52,9 @@ export const useLogAnalysisResultsUrlState = () => {
pipe(autoRefreshRT.decode(value), fold(constant(undefined), identity)),
encodeUrlState: autoRefreshRT.encode,
urlStateKey: AUTOREFRESH_URL_STATE_KEY,
+ writeDefaultState: true,
});
- useEffect(() => {
- setAutoRefresh(autoRefresh);
- }, []);
-
return {
timeRange,
setTimeRange,
diff --git a/x-pack/legacy/plugins/infra/public/pages/metrics/components/chart_section_vis.tsx b/x-pack/legacy/plugins/infra/public/pages/metrics/components/chart_section_vis.tsx
index 425b5a43f793..309961cc3902 100644
--- a/x-pack/legacy/plugins/infra/public/pages/metrics/components/chart_section_vis.tsx
+++ b/x-pack/legacy/plugins/infra/public/pages/metrics/components/chart_section_vis.tsx
@@ -3,7 +3,7 @@
* 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, { useCallback } from 'react';
+import React, { useCallback, useMemo } from 'react';
import moment from 'moment';
import { i18n } from '@kbn/i18n';
import {
@@ -42,15 +42,15 @@ export const ChartSectionVis = ({
seriesOverrides,
type,
}: VisSectionProps) => {
- if (!metric || !id) {
- return null;
- }
const [dateFormat] = useKibanaUiSetting('dateFormat');
const valueFormatter = useCallback(getFormatter(formatter, formatterTemplate), [
formatter,
formatterTemplate,
]);
- const dateFormatter = useCallback(niceTimeFormatter(getMaxMinTimestamp(metric)), [metric]);
+ const dateFormatter = useMemo(
+ () => (metric != null ? niceTimeFormatter(getMaxMinTimestamp(metric)) : undefined),
+ [metric]
+ );
const handleTimeChange = useCallback(
(from: number, to: number) => {
if (onChangeRangeTime) {
@@ -73,7 +73,9 @@ export const ChartSectionVis = ({
),
};
- if (!metric) {
+ if (!id) {
+ return null;
+ } else if (!metric) {
return (
);
- }
-
- if (metric.series.some(seriesHasLessThen2DataPoints)) {
+ } else if (metric.series.some(seriesHasLessThen2DataPoints)) {
return (
{
- if (!props.metadata) {
- return null;
- }
-
const { parsedTimeRange } = props;
const { metrics, loading, makeRequest, error } = useNodeDetails(
props.requiredMetrics,
@@ -65,11 +61,11 @@ export const NodeDetailsPage = (props: Props) => {
const refetch = useCallback(() => {
makeRequest();
- }, []);
+ }, [makeRequest]);
useEffect(() => {
makeRequest();
- }, [parsedTimeRange]);
+ }, [makeRequest, parsedTimeRange]);
if (error) {
return ;
diff --git a/x-pack/legacy/plugins/infra/public/pages/metrics/components/section.tsx b/x-pack/legacy/plugins/infra/public/pages/metrics/components/section.tsx
index 32d2e2eff8ab..2f9ed9f54df8 100644
--- a/x-pack/legacy/plugins/infra/public/pages/metrics/components/section.tsx
+++ b/x-pack/legacy/plugins/infra/public/pages/metrics/components/section.tsx
@@ -4,15 +4,15 @@
* you may not use this file except in compliance with the Elastic License.
*/
+import { EuiTitle } from '@elastic/eui';
import React, {
- useContext,
Children,
- isValidElement,
cloneElement,
FunctionComponent,
- useMemo,
+ isValidElement,
+ useContext,
} from 'react';
-import { EuiTitle } from '@elastic/eui';
+
import { SideNavContext, SubNavItem } from '../lib/side_nav_context';
import { LayoutProps } from '../types';
@@ -31,35 +31,42 @@ export const Section: FunctionComponent = ({
stopLiveStreaming,
}) => {
const { addNavItem } = useContext(SideNavContext);
- const subNavItems: SubNavItem[] = [];
- const childrenWithProps = useMemo(
- () =>
- Children.map(children, child => {
- if (isValidElement(child)) {
- const metric = (metrics && metrics.find(m => m.id === child.props.id)) || null;
- if (metric) {
- subNavItems.push({
- id: child.props.id,
- name: child.props.label,
- onClick: () => {
- const el = document.getElementById(child.props.id);
- if (el) {
- el.scrollIntoView();
- }
- },
- });
- }
- return cloneElement(child, {
- metrics,
- onChangeRangeTime,
- isLiveStreaming,
- stopLiveStreaming,
- });
- }
- return null;
- }),
- [children, metrics, onChangeRangeTime, isLiveStreaming, stopLiveStreaming]
+ const subNavItems = Children.toArray(children).reduce(
+ (accumulatedChildren, child) => {
+ if (!isValidElement(child)) {
+ return accumulatedChildren;
+ }
+ const metric = metrics?.find(m => m.id === child.props.id) ?? null;
+ if (metric === null) {
+ return accumulatedChildren;
+ }
+ return [
+ ...accumulatedChildren,
+ {
+ id: child.props.id,
+ name: child.props.label,
+ onClick: () => {
+ const el = document.getElementById(child.props.id);
+ if (el) {
+ el.scrollIntoView();
+ }
+ },
+ },
+ ];
+ },
+ []
+ );
+
+ const childrenWithProps = Children.map(children, child =>
+ isValidElement(child)
+ ? cloneElement(child, {
+ metrics,
+ onChangeRangeTime,
+ isLiveStreaming,
+ stopLiveStreaming,
+ })
+ : null
);
if (metrics && subNavItems.length) {
diff --git a/x-pack/legacy/plugins/infra/public/pages/metrics/components/sub_section.tsx b/x-pack/legacy/plugins/infra/public/pages/metrics/components/sub_section.tsx
index f3db3b167019..325d51029313 100644
--- a/x-pack/legacy/plugins/infra/public/pages/metrics/components/sub_section.tsx
+++ b/x-pack/legacy/plugins/infra/public/pages/metrics/components/sub_section.tsx
@@ -23,29 +23,25 @@ export const SubSection: FunctionComponent = ({
isLiveStreaming,
stopLiveStreaming,
}) => {
- if (!children || !metrics) {
+ const metric = useMemo(() => metrics?.find(m => m.id === id), [id, metrics]);
+
+ if (!children || !metric) {
return null;
}
- const metric = metrics.find(m => m.id === id);
- if (!metric) {
+
+ const childrenWithProps = Children.map(children, child => {
+ if (isValidElement(child)) {
+ return cloneElement(child, {
+ metric,
+ id,
+ onChangeRangeTime,
+ isLiveStreaming,
+ stopLiveStreaming,
+ });
+ }
return null;
- }
- const childrenWithProps = useMemo(
- () =>
- Children.map(children, child => {
- if (isValidElement(child)) {
- return cloneElement(child, {
- metric,
- id,
- onChangeRangeTime,
- isLiveStreaming,
- stopLiveStreaming,
- });
- }
- return null;
- }),
- [children, metric, id, onChangeRangeTime, isLiveStreaming, stopLiveStreaming]
- );
+ });
+
return (
{label ? (
diff --git a/x-pack/legacy/plugins/infra/public/pages/metrics/containers/with_metrics_time.tsx b/x-pack/legacy/plugins/infra/public/pages/metrics/containers/with_metrics_time.tsx
index 432725b6f62b..64d2ddb67139 100644
--- a/x-pack/legacy/plugins/infra/public/pages/metrics/containers/with_metrics_time.tsx
+++ b/x-pack/legacy/plugins/infra/public/pages/metrics/containers/with_metrics_time.tsx
@@ -59,13 +59,10 @@ export const useMetricsTime = () => {
const [parsedTimeRange, setParsedTimeRange] = useState(parseRange(defaultRange));
- const updateTimeRange = useCallback(
- (range: MetricsTimeInput) => {
- setTimeRange(range);
- setParsedTimeRange(parseRange(range));
- },
- [setParsedTimeRange]
- );
+ const updateTimeRange = useCallback((range: MetricsTimeInput) => {
+ setTimeRange(range);
+ setParsedTimeRange(parseRange(range));
+ }, []);
return {
timeRange,
diff --git a/x-pack/legacy/plugins/infra/public/pages/metrics/index.tsx b/x-pack/legacy/plugins/infra/public/pages/metrics/index.tsx
index 93253406aec2..b330ad02f102 100644
--- a/x-pack/legacy/plugins/infra/public/pages/metrics/index.tsx
+++ b/x-pack/legacy/plugins/infra/public/pages/metrics/index.tsx
@@ -112,26 +112,28 @@ export const MetricDetail = withMetricPageProviders(
})}
/>
-
+ {metadata ? (
+
+ ) : null}
)}
diff --git a/x-pack/legacy/plugins/infra/public/utils/cancellable_effect.ts b/x-pack/legacy/plugins/infra/public/utils/cancellable_effect.ts
index bb7d253ea155..a986af07f0c9 100644
--- a/x-pack/legacy/plugins/infra/public/utils/cancellable_effect.ts
+++ b/x-pack/legacy/plugins/infra/public/utils/cancellable_effect.ts
@@ -27,5 +27,8 @@ export const useCancellableEffect = (
effect(() => cancellationSignal.isCancelled);
return cancellationSignal.cancel;
+
+ // the dependencies are managed externally
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, deps);
};
diff --git a/x-pack/legacy/plugins/infra/public/utils/use_kibana_ui_setting.ts b/x-pack/legacy/plugins/infra/public/utils/use_kibana_ui_setting.ts
index c48f95a6521c..1b08fb423124 100644
--- a/x-pack/legacy/plugins/infra/public/utils/use_kibana_ui_setting.ts
+++ b/x-pack/legacy/plugins/infra/public/utils/use_kibana_ui_setting.ts
@@ -28,10 +28,15 @@ import { useObservable } from './use_observable';
export const useKibanaUiSetting = (key: string, defaultValue?: any) => {
const uiSettingsClient = npSetup.core.uiSettings;
- const uiSetting$ = useMemo(() => uiSettingsClient.get$(key, defaultValue), [uiSettingsClient]);
+ const uiSetting$ = useMemo(() => uiSettingsClient.get$(key, defaultValue), [
+ defaultValue,
+ key,
+ uiSettingsClient,
+ ]);
const uiSetting = useObservable(uiSetting$);
const setUiSetting = useCallback((value: any) => uiSettingsClient.set(key, value), [
+ key,
uiSettingsClient,
]);
diff --git a/x-pack/legacy/plugins/infra/public/utils/use_tracked_promise.ts b/x-pack/legacy/plugins/infra/public/utils/use_tracked_promise.ts
index 366caf0dfb15..c23bab7026aa 100644
--- a/x-pack/legacy/plugins/infra/public/utils/use_tracked_promise.ts
+++ b/x-pack/legacy/plugins/infra/public/utils/use_tracked_promise.ts
@@ -190,6 +190,8 @@ export const useTrackedPromise =
(
return newPendingPromise.promise;
},
+ // the dependencies are managed by the caller
+ // eslint-disable-next-line react-hooks/exhaustive-deps
dependencies
);
diff --git a/x-pack/legacy/plugins/infra/public/utils/use_url_state.ts b/x-pack/legacy/plugins/infra/public/utils/use_url_state.ts
index d03a5aaa9d69..79a5d552bcd7 100644
--- a/x-pack/legacy/plugins/infra/public/utils/use_url_state.ts
+++ b/x-pack/legacy/plugins/infra/public/utils/use_url_state.ts
@@ -5,10 +5,10 @@
*/
import { Location } from 'history';
-import { useMemo, useCallback } from 'react';
+import { useCallback, useEffect, useMemo, useState } from 'react';
import { decode, encode, RisonValue } from 'rison-node';
-
import { QueryString } from 'ui/utils/query_string';
+
import { useHistory } from './history_context';
export const useUrlState = ({
@@ -16,21 +16,26 @@ export const useUrlState = ({
decodeUrlState,
encodeUrlState,
urlStateKey,
+ writeDefaultState = false,
}: {
defaultState: State;
decodeUrlState: (value: RisonValue | undefined) => State | undefined;
encodeUrlState: (value: State) => RisonValue | undefined;
urlStateKey: string;
+ writeDefaultState?: boolean;
}) => {
const history = useHistory();
+ // history.location is mutable so we can't reliably use useMemo
+ const queryString = history?.location ? getQueryStringFromLocation(history.location) : '';
+
const urlStateString = useMemo(() => {
- if (!history) {
+ if (!queryString) {
return;
}
- return getParamFromQueryString(getQueryStringFromLocation(history.location), urlStateKey);
- }, [history && history.location, urlStateKey]);
+ return getParamFromQueryString(queryString, urlStateKey);
+ }, [queryString, urlStateKey]);
const decodedState = useMemo(() => decodeUrlState(decodeRisonUrlState(urlStateString)), [
decodeUrlState,
@@ -44,27 +49,38 @@ export const useUrlState = ({
const setState = useCallback(
(newState: State | undefined) => {
- if (!history) {
+ if (!history || !history.location) {
return;
}
- const location = history.location;
+ const currentLocation = history.location;
const newLocation = replaceQueryStringInLocation(
- location,
+ currentLocation,
replaceStateKeyInQueryString(
urlStateKey,
typeof newState !== 'undefined' ? encodeUrlState(newState) : undefined
- )(getQueryStringFromLocation(location))
+ )(getQueryStringFromLocation(currentLocation))
);
- if (newLocation !== location) {
+ if (newLocation !== currentLocation) {
history.replace(newLocation);
}
},
- [encodeUrlState, history, history && history.location, urlStateKey]
+ [encodeUrlState, history, urlStateKey]
);
+ const [shouldInitialize, setShouldInitialize] = useState(
+ writeDefaultState && typeof decodedState === 'undefined'
+ );
+
+ useEffect(() => {
+ if (shouldInitialize) {
+ setShouldInitialize(false);
+ setState(defaultState);
+ }
+ }, [shouldInitialize, setState, defaultState]);
+
return [state, setState] as [typeof state, typeof setState];
};
diff --git a/x-pack/legacy/plugins/infra/public/utils/use_visibility_state.ts b/x-pack/legacy/plugins/infra/public/utils/use_visibility_state.ts
index 5763834b1cc2..f4d8b572e4f7 100644
--- a/x-pack/legacy/plugins/infra/public/utils/use_visibility_state.ts
+++ b/x-pack/legacy/plugins/infra/public/utils/use_visibility_state.ts
@@ -20,6 +20,6 @@ export const useVisibilityState = (initialState: boolean) => {
show,
toggle,
}),
- [isVisible, show, hide]
+ [hide, isVisible, show, toggle]
);
};
diff --git a/x-pack/legacy/plugins/infra/server/infra_server.ts b/x-pack/legacy/plugins/infra/server/infra_server.ts
index 845e54e18c7c..e0c8f607daa9 100644
--- a/x-pack/legacy/plugins/infra/server/infra_server.ts
+++ b/x-pack/legacy/plugins/infra/server/infra_server.ts
@@ -12,8 +12,8 @@ import { createSourceStatusResolvers } from './graphql/source_status';
import { createSourcesResolvers } from './graphql/sources';
import { InfraBackendLibs } from './lib/infra_types';
import {
- initLogAnalysisGetLogEntryRateRoute,
- initIndexPatternsValidateRoute,
+ initGetLogEntryRateRoute,
+ initValidateLogAnalysisIndicesRoute,
} from './routes/log_analysis';
import { initMetricExplorerRoute } from './routes/metrics_explorer';
import { initMetadataRoute } from './routes/metadata';
@@ -33,10 +33,10 @@ export const initInfraServer = (libs: InfraBackendLibs) => {
libs.framework.registerGraphQLEndpoint('/graphql', schema);
initIpToHostName(libs);
- initLogAnalysisGetLogEntryRateRoute(libs);
+ initGetLogEntryRateRoute(libs);
initSnapshotRoute(libs);
initNodeDetailsRoute(libs);
- initIndexPatternsValidateRoute(libs);
+ initValidateLogAnalysisIndicesRoute(libs);
initMetricExplorerRoute(libs);
initMetadataRoute(libs);
};
diff --git a/x-pack/legacy/plugins/infra/server/lib/adapters/framework/adapter_types.ts b/x-pack/legacy/plugins/infra/server/lib/adapters/framework/adapter_types.ts
index 625607c09802..e88736b08b95 100644
--- a/x-pack/legacy/plugins/infra/server/lib/adapters/framework/adapter_types.ts
+++ b/x-pack/legacy/plugins/infra/server/lib/adapters/framework/adapter_types.ts
@@ -29,12 +29,12 @@ export interface InfraServerPluginDeps {
export interface CallWithRequestParams extends GenericParams {
max_concurrent_shard_requests?: number;
name?: string;
- index?: string;
+ index?: string | string[];
ignore_unavailable?: boolean;
allow_no_indices?: boolean;
size?: number;
terminate_after?: number;
- fields?: string;
+ fields?: string | string[];
}
export type InfraResponse = Lifecycle.ReturnValue;
diff --git a/x-pack/legacy/plugins/infra/server/routes/log_analysis/index.ts b/x-pack/legacy/plugins/infra/server/routes/log_analysis/index.ts
index 7364d167efe4..378e32cb3582 100644
--- a/x-pack/legacy/plugins/infra/server/routes/log_analysis/index.ts
+++ b/x-pack/legacy/plugins/infra/server/routes/log_analysis/index.ts
@@ -5,4 +5,4 @@
*/
export * from './results';
-export * from './index_patterns';
+export * from './validation';
diff --git a/x-pack/legacy/plugins/infra/server/routes/log_analysis/results/log_entry_rate.ts b/x-pack/legacy/plugins/infra/server/routes/log_analysis/results/log_entry_rate.ts
index 973080c880e6..02866e797e30 100644
--- a/x-pack/legacy/plugins/infra/server/routes/log_analysis/results/log_entry_rate.ts
+++ b/x-pack/legacy/plugins/infra/server/routes/log_analysis/results/log_entry_rate.ts
@@ -22,10 +22,7 @@ import { NoLogRateResultsIndexError } from '../../../lib/log_analysis';
const anyObject = schema.object({}, { allowUnknowns: true });
-export const initLogAnalysisGetLogEntryRateRoute = ({
- framework,
- logAnalysis,
-}: InfraBackendLibs) => {
+export const initGetLogEntryRateRoute = ({ framework, logAnalysis }: InfraBackendLibs) => {
framework.registerRoute(
{
method: 'post',
diff --git a/x-pack/legacy/plugins/infra/server/routes/log_analysis/index_patterns/index.ts b/x-pack/legacy/plugins/infra/server/routes/log_analysis/validation/index.ts
similarity index 89%
rename from x-pack/legacy/plugins/infra/server/routes/log_analysis/index_patterns/index.ts
rename to x-pack/legacy/plugins/infra/server/routes/log_analysis/validation/index.ts
index a85e119e7318..727faca69298 100644
--- a/x-pack/legacy/plugins/infra/server/routes/log_analysis/index_patterns/index.ts
+++ b/x-pack/legacy/plugins/infra/server/routes/log_analysis/validation/index.ts
@@ -4,4 +4,4 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export * from './validate';
+export * from './indices';
diff --git a/x-pack/legacy/plugins/infra/server/routes/log_analysis/index_patterns/validate.ts b/x-pack/legacy/plugins/infra/server/routes/log_analysis/validation/indices.ts
similarity index 77%
rename from x-pack/legacy/plugins/infra/server/routes/log_analysis/index_patterns/validate.ts
rename to x-pack/legacy/plugins/infra/server/routes/log_analysis/validation/indices.ts
index 1f64da1859b5..ba143a597b66 100644
--- a/x-pack/legacy/plugins/infra/server/routes/log_analysis/index_patterns/validate.ts
+++ b/x-pack/legacy/plugins/infra/server/routes/log_analysis/validation/indices.ts
@@ -11,7 +11,7 @@ import { identity } from 'fp-ts/lib/function';
import { schema } from '@kbn/config-schema';
import { InfraBackendLibs } from '../../../lib/infra_types';
import {
- LOG_ANALYSIS_VALIDATION_INDICES_PATH,
+ LOG_ANALYSIS_VALIDATE_INDICES_PATH,
validationIndicesRequestPayloadRT,
validationIndicesResponsePayloadRT,
ValidationIndicesError,
@@ -19,14 +19,13 @@ import {
import { throwErrors } from '../../../../common/runtime_types';
-const partitionField = 'event.dataset';
const escapeHatch = schema.object({}, { allowUnknowns: true });
-export const initIndexPatternsValidateRoute = ({ framework }: InfraBackendLibs) => {
+export const initValidateLogAnalysisIndicesRoute = ({ framework }: InfraBackendLibs) => {
framework.registerRoute(
{
method: 'post',
- path: LOG_ANALYSIS_VALIDATION_INDICES_PATH,
+ path: LOG_ANALYSIS_VALIDATE_INDICES_PATH,
validate: { body: escapeHatch },
},
async (requestContext, request, response) => {
@@ -36,7 +35,7 @@ export const initIndexPatternsValidateRoute = ({ framework }: InfraBackendLibs)
fold(throwErrors(Boom.badRequest), identity)
);
- const { timestampField, indices } = payload.data;
+ const { fields, indices } = payload.data;
const errors: ValidationIndicesError[] = [];
// Query each pattern individually, to map correctly the errors
@@ -44,7 +43,7 @@ export const initIndexPatternsValidateRoute = ({ framework }: InfraBackendLibs)
indices.map(async index => {
const fieldCaps = await framework.callWithRequest(requestContext, 'fieldCaps', {
index,
- fields: `${timestampField},${partitionField}`,
+ fields: fields.map(field => field.name),
});
if (fieldCaps.indices.length === 0) {
@@ -55,32 +54,30 @@ export const initIndexPatternsValidateRoute = ({ framework }: InfraBackendLibs)
return;
}
- ([
- [timestampField, 'date'],
- [partitionField, 'keyword'],
- ] as const).forEach(([field, fieldType]) => {
- const fieldMetadata = fieldCaps.fields[field];
+ fields.forEach(({ name: fieldName, validTypes }) => {
+ const fieldMetadata = fieldCaps.fields[fieldName];
if (fieldMetadata === undefined) {
errors.push({
error: 'FIELD_NOT_FOUND',
index,
- field,
+ field: fieldName,
});
} else {
const fieldTypes = Object.keys(fieldMetadata);
- if (fieldTypes.length > 1 || fieldTypes[0] !== fieldType) {
+ if (!fieldTypes.every(fieldType => validTypes.includes(fieldType))) {
errors.push({
error: `FIELD_NOT_VALID`,
index,
- field,
+ field: fieldName,
});
}
}
});
})
);
+
return response.ok({
body: validationIndicesResponsePayloadRT.encode({ data: { errors } }),
});
diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/index_or_search/page.tsx b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/index_or_search/page.tsx
index 68013bd243a9..cb311f04dd1d 100644
--- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/index_or_search/page.tsx
+++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/index_or_search/page.tsx
@@ -15,7 +15,8 @@ import {
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
-import { SavedObjectFinder } from 'ui/saved_objects/components/saved_object_finder';
+import { npStart } from 'ui/new_platform';
+import { SavedObjectFinderUi } from '../../../../../../../../../../src/plugins/kibana_react/public';
export interface PageProps {
nextStepPath: string;
@@ -46,7 +47,7 @@ export const Page: FC = ({ nextStepPath }) => {
- = ({ nextStepPath }) => {
},
]}
fixedPageSize={RESULTS_PER_PAGE}
+ uiSettings={npStart.core.uiSettings}
+ savedObjects={npStart.core.savedObjects}
/>
diff --git a/x-pack/legacy/plugins/oss_telemetry/index.d.ts b/x-pack/legacy/plugins/oss_telemetry/index.d.ts
deleted file mode 100644
index 1b592dabf205..000000000000
--- a/x-pack/legacy/plugins/oss_telemetry/index.d.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-export interface VisState {
- type: string;
-}
-
-export interface Visualization {
- visState: string;
-}
-
-export interface SavedObjectDoc {
- _id: string;
- _source: {
- visualization: Visualization;
- type: string;
- };
-}
-
-export interface ESQueryResponse {
- hits: {
- hits: SavedObjectDoc[];
- };
-}
-
-export interface TaskInstance {
- state: {
- runs: number;
- stats: any;
- };
- error?: any;
-}
-
-export interface HapiServer {
- plugins: {
- xpack_main: any;
- elasticsearch: {
- getCluster: (
- cluster: string
- ) => {
- callWithInternalUser: () => Promise;
- };
- };
- task_manager: {
- registerTaskDefinitions: (opts: any) => void;
- ensureScheduled: (opts: any) => Promise;
- fetch: (
- opts: any
- ) => Promise<{
- docs: TaskInstance[];
- }>;
- };
- };
- config: () => {
- get: (prop: string) => any;
- };
- log: (context: string[], message: string) => void;
-}
diff --git a/x-pack/legacy/plugins/oss_telemetry/index.js b/x-pack/legacy/plugins/oss_telemetry/index.js
deleted file mode 100644
index f86baef020aa..000000000000
--- a/x-pack/legacy/plugins/oss_telemetry/index.js
+++ /dev/null
@@ -1,24 +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 { registerCollectors } from './server/lib/collectors';
-import { registerTasks, scheduleTasks } from './server/lib/tasks';
-import { PLUGIN_ID } from './constants';
-
-export const ossTelemetry = (kibana) => {
- return new kibana.Plugin({
- id: PLUGIN_ID,
- require: ['elasticsearch', 'xpack_main'],
- configPrefix: 'xpack.oss_telemetry',
-
- init(server) {
- const { usageCollection } = server.newPlatform.setup.plugins;
- registerCollectors(usageCollection, server);
- registerTasks(server);
- scheduleTasks(server);
- }
- });
-};
diff --git a/x-pack/legacy/plugins/oss_telemetry/index.ts b/x-pack/legacy/plugins/oss_telemetry/index.ts
new file mode 100644
index 000000000000..8b16c7cf13ca
--- /dev/null
+++ b/x-pack/legacy/plugins/oss_telemetry/index.ts
@@ -0,0 +1,41 @@
+/*
+ * 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 { Logger, PluginInitializerContext } from 'kibana/server';
+import { PLUGIN_ID } from './constants';
+import { OssTelemetryPlugin } from './server/plugin';
+import { LegacyPluginInitializer } from '../../../../src/legacy/plugin_discovery/types';
+
+export const ossTelemetry: LegacyPluginInitializer = kibana => {
+ return new kibana.Plugin({
+ id: PLUGIN_ID,
+ require: ['elasticsearch', 'xpack_main'],
+ configPrefix: 'xpack.oss_telemetry',
+
+ init(server) {
+ const plugin = new OssTelemetryPlugin({
+ logger: {
+ get: () =>
+ ({
+ info: (message: string) => server.log(['info', 'task_manager'], message),
+ debug: (message: string) => server.log(['debug', 'task_manager'], message),
+ warn: (message: string) => server.log(['warn', 'task_manager'], message),
+ error: (message: string) => server.log(['error', 'task_manager'], message),
+ } as Logger),
+ },
+ } as PluginInitializerContext);
+ plugin.setup(server.newPlatform.setup.core, {
+ usageCollection: server.newPlatform.setup.plugins.usageCollection,
+ taskManager: server.plugins.task_manager,
+ __LEGACY: {
+ config: server.config(),
+ xpackMainStatus: ((server.plugins.xpack_main as unknown) as { status: any }).status
+ .plugin,
+ },
+ });
+ },
+ });
+};
diff --git a/x-pack/legacy/plugins/oss_telemetry/server/lib/collectors/index.ts b/x-pack/legacy/plugins/oss_telemetry/server/lib/collectors/index.ts
index 0121ed4304d2..3b47099fdc46 100644
--- a/x-pack/legacy/plugins/oss_telemetry/server/lib/collectors/index.ts
+++ b/x-pack/legacy/plugins/oss_telemetry/server/lib/collectors/index.ts
@@ -4,10 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
-import { HapiServer } from '../../../';
import { registerVisualizationsCollector } from './visualizations/register_usage_collector';
+import { OssTelemetrySetupDependencies } from '../../plugin';
-export function registerCollectors(usageCollection: UsageCollectionSetup, server: HapiServer) {
- registerVisualizationsCollector(usageCollection, server);
+export function registerCollectors(deps: OssTelemetrySetupDependencies) {
+ registerVisualizationsCollector(deps.usageCollection, deps.taskManager);
}
diff --git a/x-pack/legacy/plugins/oss_telemetry/server/lib/collectors/visualizations/get_usage_collector.test.ts b/x-pack/legacy/plugins/oss_telemetry/server/lib/collectors/visualizations/get_usage_collector.test.ts
index d316562c826d..ec3526664665 100644
--- a/x-pack/legacy/plugins/oss_telemetry/server/lib/collectors/visualizations/get_usage_collector.test.ts
+++ b/x-pack/legacy/plugins/oss_telemetry/server/lib/collectors/visualizations/get_usage_collector.test.ts
@@ -4,24 +4,12 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import sinon from 'sinon';
-import { HapiServer } from '../../../../';
-import {
- getMockCallWithInternal,
- getMockKbnServer,
- getMockTaskFetch,
-} from '../../../../test_utils';
+import { getMockTaskFetch, getMockTaskManager } from '../../../../test_utils';
import { getUsageCollector } from './get_usage_collector';
describe('getVisualizationsCollector#fetch', () => {
- let mockKbnServer: HapiServer;
-
- beforeEach(() => {
- mockKbnServer = getMockKbnServer(getMockCallWithInternal(), getMockTaskFetch());
- });
-
test('can return empty stats', async () => {
- const { type, fetch } = getUsageCollector(mockKbnServer);
+ const { type, fetch } = getUsageCollector(getMockTaskManager());
expect(type).toBe('visualization_types');
const fetchResult = await fetch();
expect(fetchResult).toEqual({});
@@ -34,11 +22,11 @@ describe('getVisualizationsCollector#fetch', () => {
runs: 1,
stats: { comic_books: { total: 16, max: 12, min: 2, avg: 6 } },
},
+ taskType: 'test',
+ params: {},
},
]);
- mockKbnServer = getMockKbnServer(getMockCallWithInternal(), mockTaskFetch);
-
- const { type, fetch } = getUsageCollector(mockKbnServer);
+ const { type, fetch } = getUsageCollector(getMockTaskManager(mockTaskFetch));
expect(type).toBe('visualization_types');
const fetchResult = await fetch();
expect(fetchResult).toEqual({ comic_books: { avg: 6, max: 12, min: 2, total: 16 } });
@@ -46,23 +34,21 @@ describe('getVisualizationsCollector#fetch', () => {
describe('Error handling', () => {
test('Silently handles Task Manager NotInitialized', async () => {
- const mockTaskFetch = sinon.stub();
- mockTaskFetch.rejects(
- new Error('NotInitialized taskManager is still waiting for plugins to load')
- );
- mockKbnServer = getMockKbnServer(getMockCallWithInternal(), mockTaskFetch);
-
- const { fetch } = getUsageCollector(mockKbnServer);
- await expect(fetch()).resolves.toBe(undefined);
+ const mockTaskFetch = jest.fn(() => {
+ throw new Error('NotInitialized taskManager is still waiting for plugins to load');
+ });
+ const { fetch } = getUsageCollector(getMockTaskManager(mockTaskFetch));
+ const result = await fetch();
+ expect(result).toBe(undefined);
});
// In real life, the CollectorSet calls fetch and handles errors
test('defers the errors', async () => {
- const mockTaskFetch = sinon.stub();
- mockTaskFetch.rejects(new Error('BOOM'));
- mockKbnServer = getMockKbnServer(getMockCallWithInternal(), mockTaskFetch);
+ const mockTaskFetch = jest.fn(() => {
+ throw new Error('BOOM');
+ });
- const { fetch } = getUsageCollector(mockKbnServer);
- await expect(fetch()).rejects.toMatchObject(new Error('BOOM'));
+ const { fetch } = getUsageCollector(getMockTaskManager(mockTaskFetch));
+ await expect(fetch()).rejects.toThrowErrorMatchingInlineSnapshot(`"BOOM"`);
});
});
});
diff --git a/x-pack/legacy/plugins/oss_telemetry/server/lib/collectors/visualizations/get_usage_collector.ts b/x-pack/legacy/plugins/oss_telemetry/server/lib/collectors/visualizations/get_usage_collector.ts
index 63640c87f80a..680cb97e0fda 100644
--- a/x-pack/legacy/plugins/oss_telemetry/server/lib/collectors/visualizations/get_usage_collector.ts
+++ b/x-pack/legacy/plugins/oss_telemetry/server/lib/collectors/visualizations/get_usage_collector.ts
@@ -5,17 +5,15 @@
*/
import { get } from 'lodash';
-import { HapiServer } from '../../../../';
+import { PluginSetupContract as TaskManagerPluginSetupContract } from '../../../../../task_manager/plugin';
import { PLUGIN_ID, VIS_TELEMETRY_TASK, VIS_USAGE_TYPE } from '../../../../constants';
-async function isTaskManagerReady(server: HapiServer) {
- const result = await fetch(server);
+async function isTaskManagerReady(taskManager: TaskManagerPluginSetupContract | undefined) {
+ const result = await fetch(taskManager);
return result !== null;
}
-async function fetch(server: HapiServer) {
- const taskManager = server.plugins.task_manager;
-
+async function fetch(taskManager: TaskManagerPluginSetupContract | undefined) {
if (!taskManager) {
return null;
}
@@ -40,12 +38,12 @@ async function fetch(server: HapiServer) {
return docs;
}
-export function getUsageCollector(server: HapiServer) {
+export function getUsageCollector(taskManager: TaskManagerPluginSetupContract | undefined) {
let isCollectorReady = false;
async function determineIfTaskManagerIsReady() {
let isReady = false;
try {
- isReady = await isTaskManagerReady(server);
+ isReady = await isTaskManagerReady(taskManager);
} catch (err) {} // eslint-disable-line
if (isReady) {
@@ -60,7 +58,7 @@ export function getUsageCollector(server: HapiServer) {
type: VIS_USAGE_TYPE,
isReady: () => isCollectorReady,
fetch: async () => {
- const docs = await fetch(server);
+ const docs = await fetch(taskManager);
// get the accumulated state from the recurring task
return get(docs, '[0].state.stats');
},
diff --git a/x-pack/legacy/plugins/oss_telemetry/server/lib/collectors/visualizations/register_usage_collector.ts b/x-pack/legacy/plugins/oss_telemetry/server/lib/collectors/visualizations/register_usage_collector.ts
index 09843a6f87ad..1a47f68adcc5 100644
--- a/x-pack/legacy/plugins/oss_telemetry/server/lib/collectors/visualizations/register_usage_collector.ts
+++ b/x-pack/legacy/plugins/oss_telemetry/server/lib/collectors/visualizations/register_usage_collector.ts
@@ -5,13 +5,13 @@
*/
import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
-import { HapiServer } from '../../../../';
+import { PluginSetupContract as TaskManagerPluginSetupContract } from '../../../../../task_manager/plugin';
import { getUsageCollector } from './get_usage_collector';
export function registerVisualizationsCollector(
- usageCollection: UsageCollectionSetup,
- server: HapiServer
+ collectorSet: UsageCollectionSetup,
+ taskManager: TaskManagerPluginSetupContract | undefined
): void {
- const collector = usageCollection.makeUsageCollector(getUsageCollector(server));
- usageCollection.registerCollector(collector);
+ const collector = collectorSet.makeUsageCollector(getUsageCollector(taskManager));
+ collectorSet.registerCollector(collector);
}
diff --git a/x-pack/legacy/plugins/oss_telemetry/server/lib/tasks/index.ts b/x-pack/legacy/plugins/oss_telemetry/server/lib/tasks/index.ts
index 16e83a7938e6..cb6b4eab0974 100644
--- a/x-pack/legacy/plugins/oss_telemetry/server/lib/tasks/index.ts
+++ b/x-pack/legacy/plugins/oss_telemetry/server/lib/tasks/index.ts
@@ -4,15 +4,27 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { HapiServer } from '../../../';
+import { CoreSetup, Logger } from 'kibana/server';
+import { PluginSetupContract as TaskManagerPluginSetupContract } from '../../../../task_manager/plugin';
import { PLUGIN_ID, VIS_TELEMETRY_TASK } from '../../../constants';
import { visualizationsTaskRunner } from './visualizations/task_runner';
+import KbnServer from '../../../../../../../src/legacy/server/kbn_server';
+import { LegacyConfig } from '../../plugin';
+import { TaskInstance } from '../../../../task_manager';
-export function registerTasks(server: HapiServer) {
- const taskManager = server.plugins.task_manager;
-
+export function registerTasks({
+ taskManager,
+ logger,
+ elasticsearch,
+ config,
+}: {
+ taskManager?: TaskManagerPluginSetupContract;
+ logger: Logger;
+ elasticsearch: CoreSetup['elasticsearch'];
+ config: LegacyConfig;
+}) {
if (!taskManager) {
- server.log(['debug', 'telemetry'], `Task manager is not available`);
+ logger.debug('Task manager is not available');
return;
}
@@ -20,18 +32,30 @@ export function registerTasks(server: HapiServer) {
[VIS_TELEMETRY_TASK]: {
title: 'X-Pack telemetry calculator for Visualizations',
type: VIS_TELEMETRY_TASK,
- createTaskRunner({ taskInstance }: { taskInstance: any }) {
+ createTaskRunner({ taskInstance }: { taskInstance: TaskInstance }) {
return {
- run: visualizationsTaskRunner(taskInstance, server),
+ run: visualizationsTaskRunner(taskInstance, config, elasticsearch),
};
},
},
});
}
-export function scheduleTasks(server: HapiServer) {
- const taskManager = server.plugins.task_manager;
- const { kbnServer } = server.plugins.xpack_main.status.plugin;
+export function scheduleTasks({
+ taskManager,
+ xpackMainStatus,
+ logger,
+}: {
+ taskManager?: TaskManagerPluginSetupContract;
+ xpackMainStatus: { kbnServer: KbnServer };
+ logger: Logger;
+}) {
+ if (!taskManager) {
+ logger.debug('Task manager is not available');
+ return;
+ }
+
+ const { kbnServer } = xpackMainStatus;
kbnServer.afterPluginsInit(() => {
// The code block below can't await directly within "afterPluginsInit"
@@ -46,9 +70,10 @@ export function scheduleTasks(server: HapiServer) {
id: `${PLUGIN_ID}-${VIS_TELEMETRY_TASK}`,
taskType: VIS_TELEMETRY_TASK,
state: { stats: {}, runs: 0 },
+ params: {},
});
} catch (e) {
- server.log(['debug', 'telemetry'], `Error scheduling task, received ${e.message}`);
+ logger.debug(`Error scheduling task, received ${e.message}`);
}
})();
});
diff --git a/x-pack/legacy/plugins/oss_telemetry/server/lib/tasks/visualizations/task_runner.test.ts b/x-pack/legacy/plugins/oss_telemetry/server/lib/tasks/visualizations/task_runner.test.ts
index 5db08ed291d6..0663a5bd330c 100644
--- a/x-pack/legacy/plugins/oss_telemetry/server/lib/tasks/visualizations/task_runner.test.ts
+++ b/x-pack/legacy/plugins/oss_telemetry/server/lib/tasks/visualizations/task_runner.test.ts
@@ -5,28 +5,30 @@
*/
import moment from 'moment';
-import { HapiServer, TaskInstance } from '../../../../';
import {
getMockCallWithInternal,
- getMockKbnServer,
+ getMockConfig,
+ getMockEs,
getMockTaskInstance,
} from '../../../../test_utils';
import { visualizationsTaskRunner } from './task_runner';
+import { TaskInstance } from '../../../../../task_manager';
describe('visualizationsTaskRunner', () => {
let mockTaskInstance: TaskInstance;
- let mockKbnServer: HapiServer;
beforeEach(() => {
mockTaskInstance = getMockTaskInstance();
- mockKbnServer = getMockKbnServer();
});
describe('Error handling', () => {
test('catches its own errors', async () => {
const mockCallWithInternal = () => Promise.reject(new Error('Things did not go well!'));
- mockKbnServer = getMockKbnServer(mockCallWithInternal);
- const runner = visualizationsTaskRunner(mockTaskInstance, mockKbnServer);
+ const runner = visualizationsTaskRunner(
+ mockTaskInstance,
+ getMockConfig(),
+ getMockEs(mockCallWithInternal)
+ );
const result = await runner();
expect(result).toMatchObject({
error: 'Things did not go well!',
@@ -45,7 +47,7 @@ describe('visualizationsTaskRunner', () => {
.startOf('day')
.toDate();
- const runner = visualizationsTaskRunner(mockTaskInstance, mockKbnServer);
+ const runner = visualizationsTaskRunner(mockTaskInstance, getMockConfig(), getMockEs());
const result = await runner();
expect(result).toMatchObject({
@@ -123,9 +125,12 @@ describe('visualizationsTaskRunner', () => {
},
},
]);
- mockKbnServer = getMockKbnServer(mockCallWithInternal);
- const runner = visualizationsTaskRunner(mockTaskInstance, mockKbnServer);
+ const runner = visualizationsTaskRunner(
+ mockTaskInstance,
+ getMockConfig(),
+ getMockEs(mockCallWithInternal)
+ );
const result = await runner();
expect(result).toMatchObject({
diff --git a/x-pack/legacy/plugins/oss_telemetry/server/lib/tasks/visualizations/task_runner.ts b/x-pack/legacy/plugins/oss_telemetry/server/lib/tasks/visualizations/task_runner.ts
index 3372101c2b45..9d8f76f6a10d 100644
--- a/x-pack/legacy/plugins/oss_telemetry/server/lib/tasks/visualizations/task_runner.ts
+++ b/x-pack/legacy/plugins/oss_telemetry/server/lib/tasks/visualizations/task_runner.ts
@@ -5,15 +5,12 @@
*/
import _, { countBy, groupBy, mapValues } from 'lodash';
-import {
- ESQueryResponse,
- HapiServer,
- SavedObjectDoc,
- TaskInstance,
- VisState,
- Visualization,
-} from '../../../../';
+import { APICaller, CoreSetup } from 'kibana/server';
import { getNextMidnight } from '../../get_next_midnight';
+import { VisState } from '../../../../../../../../src/legacy/core_plugins/visualizations/public';
+import { TaskInstance } from '../../../../../task_manager';
+import { ESSearchHit } from '../../../../../apm/typings/elasticsearch';
+import { LegacyConfig } from '../../../plugin';
interface VisSummary {
type: string;
@@ -23,7 +20,7 @@ interface VisSummary {
/*
* Parse the response data into telemetry payload
*/
-async function getStats(callCluster: (method: string, params: any) => Promise, index: string) {
+async function getStats(callCluster: APICaller, index: string) {
const searchParams = {
size: 10000, // elasticsearch index.max_result_window default value
index,
@@ -35,24 +32,26 @@ async function getStats(callCluster: (method: string, params: any) => Promise(esResponse, 'hits.hits.length');
if (size < 1) {
return;
}
// `map` to get the raw types
- const visSummaries: VisSummary[] = esResponse.hits.hits.map((hit: SavedObjectDoc) => {
- const spacePhrases: string[] = hit._id.split(':');
- const space = spacePhrases.length === 3 ? spacePhrases[0] : 'default'; // if in a custom space, the format of a saved object ID is space:type:id
- const visualization: Visualization = _.get(hit, '_source.visualization', { visState: '{}' });
- const visState: VisState = JSON.parse(visualization.visState);
+ const visSummaries: VisSummary[] = esResponse.hits.hits.map(
+ (hit: ESSearchHit<{ visState: string }>) => {
+ const spacePhrases: string[] = hit._id.split(':');
+ const space = spacePhrases.length === 3 ? spacePhrases[0] : 'default'; // if in a custom space, the format of a saved object ID is space:type:id
+ const visualization = _.get(hit, '_source.visualization', { visState: '{}' });
+ const visState: VisState = JSON.parse(visualization.visState);
- return {
- type: visState.type || '_na_',
- space,
- };
- });
+ return {
+ type: visState.type || '_na_',
+ space,
+ };
+ }
+ );
// organize stats per type
const visTypes = groupBy(visSummaries, 'type');
@@ -72,9 +71,12 @@ async function getStats(callCluster: (method: string, params: any) => Promise {
diff --git a/x-pack/legacy/plugins/oss_telemetry/server/plugin.ts b/x-pack/legacy/plugins/oss_telemetry/server/plugin.ts
new file mode 100644
index 000000000000..f661311fc24b
--- /dev/null
+++ b/x-pack/legacy/plugins/oss_telemetry/server/plugin.ts
@@ -0,0 +1,50 @@
+/*
+ * 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 { CoreSetup, Logger, Plugin, PluginInitializerContext } from 'kibana/server';
+import { PluginSetupContract as TaskManagerPluginSetupContract } from '../../task_manager/plugin';
+import { registerCollectors } from './lib/collectors';
+import { registerTasks, scheduleTasks } from './lib/tasks';
+import KbnServer from '../../../../../src/legacy/server/kbn_server';
+import { UsageCollectionSetup } from '../../../../../src/plugins/usage_collection/server';
+
+export interface LegacyConfig {
+ get: (key: string) => string | number | boolean;
+}
+
+export interface OssTelemetrySetupDependencies {
+ usageCollection: UsageCollectionSetup;
+ __LEGACY: {
+ config: LegacyConfig;
+ xpackMainStatus: { kbnServer: KbnServer };
+ };
+ taskManager?: TaskManagerPluginSetupContract;
+}
+
+export class OssTelemetryPlugin implements Plugin {
+ private logger: Logger;
+
+ constructor(initializerContext: PluginInitializerContext) {
+ this.logger = initializerContext.logger.get();
+ }
+
+ public setup(core: CoreSetup, deps: OssTelemetrySetupDependencies) {
+ registerCollectors(deps);
+ registerTasks({
+ taskManager: deps.taskManager,
+ logger: this.logger,
+ elasticsearch: core.elasticsearch,
+ config: deps.__LEGACY.config,
+ });
+ scheduleTasks({
+ taskManager: deps.taskManager,
+ xpackMainStatus: deps.__LEGACY.xpackMainStatus,
+ logger: this.logger,
+ });
+ }
+
+ public start() {}
+}
diff --git a/x-pack/legacy/plugins/oss_telemetry/test_utils/index.ts b/x-pack/legacy/plugins/oss_telemetry/test_utils/index.ts
index 1cebe78b9c7f..04e248d28b57 100644
--- a/x-pack/legacy/plugins/oss_telemetry/test_utils/index.ts
+++ b/x-pack/legacy/plugins/oss_telemetry/test_utils/index.ts
@@ -4,9 +4,16 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { ESQueryResponse, HapiServer, SavedObjectDoc, TaskInstance } from '../';
+import { APICaller, CoreSetup } from 'kibana/server';
-export const getMockTaskInstance = (): TaskInstance => ({ state: { runs: 0, stats: {} } });
+import { TaskInstance } from '../../task_manager';
+import { PluginSetupContract as TaskManagerPluginSetupContract } from '../../task_manager/plugin';
+
+export const getMockTaskInstance = (): TaskInstance => ({
+ state: { runs: 0, stats: {} },
+ taskType: 'test',
+ params: {},
+});
const defaultMockSavedObjects = [
{
@@ -20,10 +27,15 @@ const defaultMockSavedObjects = [
const defaultMockTaskDocs = [getMockTaskInstance()];
-export const getMockCallWithInternal = (hits: SavedObjectDoc[] = defaultMockSavedObjects) => {
- return (): Promise => {
+export const getMockEs = (mockCallWithInternal: APICaller = getMockCallWithInternal()) =>
+ (({
+ createClient: () => ({ callAsInternalUser: mockCallWithInternal }),
+ } as unknown) as CoreSetup['elasticsearch']);
+
+export const getMockCallWithInternal = (hits: unknown[] = defaultMockSavedObjects): APICaller => {
+ return ((() => {
return Promise.resolve({ hits: { hits } });
- };
+ }) as unknown) as APICaller;
};
export const getMockTaskFetch = (docs: TaskInstance[] = defaultMockTaskDocs) => {
@@ -36,24 +48,13 @@ export const getMockConfig = () => {
};
};
-export const getMockKbnServer = (
- mockCallWithInternal = getMockCallWithInternal(),
- mockTaskFetch = getMockTaskFetch(),
- mockConfig = getMockConfig()
-): HapiServer => ({
- plugins: {
- elasticsearch: {
- getCluster: (cluster: string) => ({
- callWithInternalUser: mockCallWithInternal,
- }),
- },
- xpack_main: {},
- task_manager: {
- registerTaskDefinitions: (opts: any) => undefined,
- ensureScheduled: (opts: any) => Promise.resolve(),
- fetch: mockTaskFetch,
- },
- },
- config: () => mockConfig,
- log: () => undefined,
+export const getMockTaskManager = (fetch: any = getMockTaskFetch()) =>
+ (({
+ registerTaskDefinitions: () => undefined,
+ ensureScheduled: () => Promise.resolve(),
+ fetch,
+ } as unknown) as TaskManagerPluginSetupContract);
+
+export const getCluster = () => ({
+ callWithInternalUser: getMockCallWithInternal(),
});
diff --git a/x-pack/legacy/plugins/reporting/server/browsers/chromium/driver_factory/index.ts b/x-pack/legacy/plugins/reporting/server/browsers/chromium/driver_factory/index.ts
index ca26f7d41c12..daa7df343f8a 100644
--- a/x-pack/legacy/plugins/reporting/server/browsers/chromium/driver_factory/index.ts
+++ b/x-pack/legacy/plugins/reporting/server/browsers/chromium/driver_factory/index.ts
@@ -15,7 +15,7 @@ import {
} from 'puppeteer';
import del from 'del';
import * as Rx from 'rxjs';
-import { ignoreElements, mergeMap, tap } from 'rxjs/operators';
+import { ignoreElements, map, mergeMap, tap } from 'rxjs/operators';
import { InnerSubscriber } from 'rxjs/internal/InnerSubscriber';
import { BrowserConfig, NetworkPolicy } from '../../../../types';
@@ -144,7 +144,7 @@ export class HeadlessChromiumDriverFactory {
terminate$
.pipe(
tap(signal => {
- this.logger.debug(`Observer got signal: ${signal}`);
+ this.logger.debug(`Termination signal received: ${signal}`);
}),
ignoreElements()
)
@@ -156,7 +156,6 @@ export class HeadlessChromiumDriverFactory {
this.getProcessLogger(browser).subscribe();
const driver$ = Rx.of(new HeadlessChromiumDriver(page, { inspect: this.browserConfig.inspect, networkPolicy: this.networkPolicy })); // prettier-ignore
-
const exit$ = this.getPageExit(browser, page);
observer.next({ driver$, exit$ });
@@ -173,9 +172,9 @@ export class HeadlessChromiumDriverFactory {
});
}
- getBrowserLogger(page: Page): Rx.Observable {
- return Rx.fromEvent(page, 'console').pipe(
- tap(line => {
+ getBrowserLogger(page: Page): Rx.Observable {
+ const consoleMessages$ = Rx.fromEvent(page, 'console').pipe(
+ map(line => {
if (line.type() === 'error') {
this.logger.error(line.text(), ['headless-browser-console']);
} else {
@@ -183,6 +182,19 @@ export class HeadlessChromiumDriverFactory {
}
})
);
+
+ const pageRequestFailed$ = Rx.fromEvent(page, 'requestfailed').pipe(
+ map(req => {
+ const failure = req.failure && req.failure();
+ if (failure) {
+ this.logger.warning(
+ `Request to [${req.url()}] failed! [${failure.errorText}]. This error will be ignored.`
+ );
+ }
+ })
+ );
+
+ return Rx.merge(consoleMessages$, pageRequestFailed$);
}
getProcessLogger(browser: Browser) {
@@ -208,18 +220,6 @@ export class HeadlessChromiumDriverFactory {
mergeMap(err => Rx.throwError(err))
);
- const pageRequestFailed$ = Rx.fromEvent(page, 'requestfailed').pipe(
- mergeMap(req => {
- const failure = req.failure && req.failure();
- if (failure) {
- return Rx.throwError(
- new Error(`Request to [${req.url()}] failed! [${failure.errorText}]`)
- );
- }
- return Rx.throwError(new Error(`Unknown failure!`));
- })
- );
-
const browserDisconnect$ = Rx.fromEvent(browser, 'disconnected').pipe(
mergeMap(() =>
Rx.throwError(
@@ -230,11 +230,6 @@ export class HeadlessChromiumDriverFactory {
)
);
- return Rx.merge(
- pageError$,
- uncaughtExceptionPageError$,
- pageRequestFailed$,
- browserDisconnect$
- );
+ return Rx.merge(pageError$, uncaughtExceptionPageError$, browserDisconnect$);
}
}
diff --git a/x-pack/legacy/plugins/security/index.js b/x-pack/legacy/plugins/security/index.js
index 1d798a4a2bc4..115dd8b9b820 100644
--- a/x-pack/legacy/plugins/security/index.js
+++ b/x-pack/legacy/plugins/security/index.js
@@ -132,7 +132,6 @@ export const security = (kibana) => new kibana.Plugin({
server.plugins.kibana.systemApi
),
cspRules: createCSPRuleString(config.get('csp.rules')),
- kibanaIndexName: config.get('kibana.index'),
});
// Legacy xPack Info endpoint returns whatever we return in a callback for `registerLicenseCheckResultsGenerator`
diff --git a/x-pack/legacy/plugins/siem/package.json b/x-pack/legacy/plugins/siem/package.json
index d239961ee75d..ef6431327b5a 100644
--- a/x-pack/legacy/plugins/siem/package.json
+++ b/x-pack/legacy/plugins/siem/package.json
@@ -5,6 +5,7 @@
"private": true,
"license": "Elastic-License",
"scripts": {
+ "extract-mitre-attacks": "node scripts/extract_tactics_techniques_mitre.js & node ../../../../scripts/eslint ./public/pages/detection_engine/mitre/mitre_tactics_techniques.ts --fix",
"build-graphql-types": "node scripts/generate_types_from_graphql.js",
"cypress:open": "../../../node_modules/.bin/cypress open",
"cypress:run": "../../../node_modules/.bin/cypress run --spec ./cypress/integration/**/*.spec.ts --reporter ../../../node_modules/cypress-multi-reporters --reporter-options configFile=./reporter_config.json; status=$?; ../../../node_modules/.bin/mochawesome-merge --reportDir ../../../../target/kibana-siem/cypress/results > ../../../../target/kibana-siem/cypress/results/output.json; ../../../../node_modules/.bin/marge ../../../../target/kibana-siem/cypress/results/output.json --reportDir ../../../../target/kibana-siem/cypress/results; mkdir -p ../../../../target/junit && cp ../../../../target/kibana-siem/cypress/results/*.xml ../../../../target/junit/ && exit $status;"
diff --git a/x-pack/legacy/plugins/siem/public/components/embeddables/embedded_map.tsx b/x-pack/legacy/plugins/siem/public/components/embeddables/embedded_map.tsx
index cb73cf73b8d0..1658002408fb 100644
--- a/x-pack/legacy/plugins/siem/public/components/embeddables/embedded_map.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/embeddables/embedded_map.tsx
@@ -9,7 +9,6 @@ import React, { useEffect, useState } from 'react';
import { createPortalNode, InPortal } from 'react-reverse-portal';
import styled, { css } from 'styled-components';
import { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } from 'ui/documentation_links';
-import { SavedObjectFinder } from 'ui/saved_objects/components/saved_object_finder';
import { EmbeddablePanel } from '../../../../../../../src/legacy/core_plugins/embeddable_api/public/np_ready/public';
import { start } from '../../../../../../../src/legacy/core_plugins/embeddable_api/public/np_ready/public/legacy';
@@ -29,6 +28,10 @@ import { MapToolTip } from './map_tool_tip/map_tool_tip';
import * as i18n from './translations';
import { MapEmbeddable, SetQuery } from './types';
import { Query, esFilters } from '../../../../../../../src/plugins/data/public';
+import {
+ SavedObjectFinderProps,
+ SavedObjectFinderUi,
+} from '../../../../../../../src/plugins/kibana_react/public';
interface EmbeddableMapProps {
maintainRatio?: boolean;
@@ -176,6 +179,10 @@ export const EmbeddedMapComponent = ({
}
}, [startDate, endDate]);
+ const SavedObjectFinder = (props: SavedObjectFinderProps) => (
+
+ );
+
return isError ? null : (
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/add_item_form/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/add_item_form/index.tsx
index 04bca0cdbd61..e972cd21b6be 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/add_item_form/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/add_item_form/index.tsx
@@ -9,7 +9,7 @@ import { isEmpty } from 'lodash/fp';
import React, { ChangeEvent, useCallback, useEffect, useState, useRef } from 'react';
import { FieldHook, getFieldValidityAndErrorMessage } from '../shared_imports';
-import * as I18n from './translations';
+import * as CreateRuleI18n from '../../translations';
interface AddItemProps {
addText: string;
@@ -34,18 +34,21 @@ export const AddItem = ({ addText, dataTestSubj, field, idAria, isDisabled }: Ad
...inputsRef.current.slice(0, index),
...inputsRef.current.slice(index + 1),
];
- if (inputsRef.current[index] != null) {
- inputsRef.current[index].value = 're-render';
- }
+ inputsRef.current = inputsRef.current.map((ref, i) => {
+ if (i >= index && inputsRef.current[index] != null) {
+ ref.value = 're-render';
+ }
+ return ref;
+ });
},
[field]
);
const addItem = useCallback(() => {
const values = field.value as string[];
- if (!isEmpty(values[values.length - 1])) {
+ if (!isEmpty(values) && values[values.length - 1]) {
field.setValue([...values, '']);
- } else {
+ } else if (isEmpty(values)) {
field.setValue(['']);
}
}, [field]);
@@ -62,9 +65,12 @@ export const AddItem = ({ addText, dataTestSubj, field, idAria, isDisabled }: Ad
...inputsRef.current.slice(index + 1),
];
setHaveBeenKeyboardDeleted(inputsRef.current.length - 1);
- if (inputsRef.current[index] != null) {
- inputsRef.current[index].value = 're-render';
- }
+ inputsRef.current = inputsRef.current.map((ref, i) => {
+ if (i >= index && inputsRef.current[index] != null) {
+ ref.value = 're-render';
+ }
+ return ref;
+ });
} else {
field.setValue([...values.slice(0, index), value, ...values.slice(index + 1)]);
}
@@ -114,7 +120,8 @@ export const AddItem = ({ addText, dataTestSubj, field, idAria, isDisabled }: Ad
...(index === values.length - 1
? { inputRef: handleLastInputRef.bind(null, index) }
: {}),
- ...(inputsRef.current[index] != null && inputsRef.current[index].value !== item
+ ...((inputsRef.current[index] != null && inputsRef.current[index].value !== item) ||
+ inputsRef.current[index] == null
? { value: item }
: {}),
};
@@ -127,7 +134,7 @@ export const AddItem = ({ addText, dataTestSubj, field, idAria, isDisabled }: Ad
iconType="trash"
isDisabled={isDisabled}
onClick={() => removeItem(index)}
- aria-label={I18n.DELETE}
+ aria-label={CreateRuleI18n.DELETE}
/>
}
onChange={e => updateItem(e, index)}
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/description_step/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/description_step/index.tsx
index 3e8147e5ca3c..29e1bc228e06 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/description_step/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/description_step/index.tsx
@@ -4,7 +4,16 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { EuiBadge, EuiDescriptionList, EuiFlexGroup, EuiFlexItem, EuiTextArea } from '@elastic/eui';
+import {
+ EuiBadge,
+ EuiDescriptionList,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiTextArea,
+ EuiLink,
+ EuiText,
+ EuiListGroup,
+} from '@elastic/eui';
import { isEmpty, chunk, get, pick } from 'lodash/fp';
import React, { memo, ReactNode } from 'react';
import styled from 'styled-components';
@@ -20,6 +29,9 @@ import { FilterLabel } from './filter_label';
import { FormSchema } from '../shared_imports';
import * as I18n from './translations';
+import { IMitreEnterpriseAttack } from '../../types';
+import { tacticsOptions, techniquesOptions } from '../../../mitre/mitre_tactics_techniques';
+
interface StepRuleDescriptionProps {
data: unknown;
indexPatterns?: IIndexPattern;
@@ -36,16 +48,34 @@ const EuiFlexItemWidth = styled(EuiFlexItem)`
width: 50%;
`;
+const MyEuiListGroup = styled(EuiListGroup)`
+ padding: 0px;
+ .euiListGroupItem__button {
+ padding: 0px;
+ }
+`;
+
+const ThreatsEuiFlexGroup = styled(EuiFlexGroup)`
+ .euiFlexItem {
+ margin-bottom: 0px;
+ }
+`;
+
export const StepRuleDescription = memo(
({ data, indexPatterns, schema }) => {
const keys = Object.keys(schema);
+ const listItems = keys.reduce(
+ (acc: ListItems[], key: string) => [
+ ...acc,
+ ...buildListItems(data, pick(key, schema), indexPatterns),
+ ],
+ []
+ );
return (
- {chunk(keys.includes('queryBar') ? 3 : Math.ceil(keys.length / 2), keys).map(key => (
-
-
+ {chunk(Math.ceil(listItems.length / 2), listItems).map((chunckListItems, index) => (
+
+
))}
@@ -77,7 +107,9 @@ const getDescriptionItem = (
value: unknown,
indexPatterns?: IIndexPattern
): ListItems[] => {
- if (field === 'queryBar' && indexPatterns != null) {
+ if (field === 'useIndicesConfig') {
+ return [];
+ } else if (field === 'queryBar' && indexPatterns != null) {
const filters = get('queryBar.filters', value) as esFilters.Filter[];
const query = get('queryBar.query', value) as Query;
const savedId = get('queryBar.saved_id', value);
@@ -123,6 +155,50 @@ const getDescriptionItem = (
];
}
return items;
+ } else if (field === 'threats') {
+ const threats: IMitreEnterpriseAttack[] = get(field, value).filter(
+ (threat: IMitreEnterpriseAttack) => threat.tactic.name !== 'none'
+ );
+ if (threats.length > 0) {
+ return [
+ {
+ title: label,
+ description: (
+
+ {threats.map((threat, index) => {
+ const tactic = tacticsOptions.find(t => t.name === threat.tactic.name);
+ return (
+
+
+
+
+ {tactic != null ? tactic.text : ''}
+
+
+ {
+ const myTechnique = techniquesOptions.find(
+ t => t.name === technique.name
+ );
+ return {
+ label: myTechnique != null ? myTechnique.label : '',
+ href: technique.reference,
+ target: '_blank',
+ };
+ })}
+ />
+
+
+ );
+ })}
+
+ ),
+ },
+ ];
+ }
+ return [];
} else if (field === 'description') {
return [
{
@@ -131,20 +207,26 @@ const getDescriptionItem = (
},
];
} else if (Array.isArray(get(field, value))) {
- return [
- {
- title: label,
- description: (
-
- {get(field, value).map((val: string) => (
-
- {val}
-
- ))}
-
- ),
- },
- ];
+ const values: string[] = get(field, value);
+ if (!isEmpty(values) && values.filter(val => !isEmpty(val)).length > 0) {
+ return [
+ {
+ title: label,
+ description: (
+
+ {values.map((val: string) =>
+ isEmpty(val) ? null : (
+
+ {val}
+
+ )
+ )}
+
+ ),
+ },
+ ];
+ }
+ return [];
}
return [
{
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/mitre/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/mitre/index.tsx
new file mode 100644
index 000000000000..6ab4ca4b5144
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/mitre/index.tsx
@@ -0,0 +1,171 @@
+/*
+ * 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 {
+ EuiButtonEmpty,
+ EuiButtonIcon,
+ EuiFormRow,
+ EuiSelect,
+ EuiSpacer,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiComboBox,
+ EuiFormControlLayout,
+} from '@elastic/eui';
+import { isEmpty, kebabCase, camelCase } from 'lodash/fp';
+import React, { ChangeEvent, useCallback } from 'react';
+import styled from 'styled-components';
+
+import { tacticsOptions, techniquesOptions } from '../../../mitre/mitre_tactics_techniques';
+import * as CreateRuleI18n from '../../translations';
+import { FieldHook, getFieldValidityAndErrorMessage } from '../shared_imports';
+import * as I18n from './translations';
+import { IMitreEnterpriseAttack } from '../../types';
+
+const MyEuiFormControlLayout = styled(EuiFormControlLayout)`
+ &.euiFormControlLayout--compressed {
+ height: fit-content !important;
+ }
+`;
+interface AddItemProps {
+ field: FieldHook;
+ dataTestSubj: string;
+ idAria: string;
+ isDisabled: boolean;
+}
+
+export const AddMitreThreat = ({ dataTestSubj, field, idAria, isDisabled }: AddItemProps) => {
+ const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field);
+
+ const removeItem = useCallback(
+ (index: number) => {
+ const values = field.value as string[];
+ field.setValue([...values.slice(0, index), ...values.slice(index + 1)]);
+ },
+ [field]
+ );
+
+ const addItem = useCallback(() => {
+ const values = field.value as IMitreEnterpriseAttack[];
+ if (!isEmpty(values[values.length - 1])) {
+ field.setValue([
+ ...values,
+ { tactic: { id: 'none', name: 'none', reference: 'none' }, techniques: [] },
+ ]);
+ } else {
+ field.setValue([{ tactic: { id: 'none', name: 'none', reference: 'none' }, techniques: [] }]);
+ }
+ }, [field]);
+
+ const updateTactic = useCallback(
+ (index: number, event: ChangeEvent) => {
+ const values = field.value as IMitreEnterpriseAttack[];
+ const { id, reference, name } = tacticsOptions.find(t => t.value === event.target.value) || {
+ id: '',
+ name: '',
+ reference: '',
+ };
+ field.setValue([
+ ...values.slice(0, index),
+ {
+ ...values[index],
+ tactic: { id, reference, name },
+ techniques: [],
+ },
+ ...values.slice(index + 1),
+ ]);
+ },
+ [field]
+ );
+
+ const updateTechniques = useCallback(
+ (index: number, selectedOptions: unknown[]) => {
+ field.setValue([
+ ...values.slice(0, index),
+ {
+ ...values[index],
+ techniques: selectedOptions,
+ },
+ ...values.slice(index + 1),
+ ]);
+ },
+ [field]
+ );
+
+ const values = field.value as IMitreEnterpriseAttack[];
+
+ return (
+
+ <>
+ {values.map((item, index) => {
+ const euiSelectFieldProps = {
+ disabled: isDisabled,
+ };
+ return (
+
+
+
+ ({ text: t.text, value: t.value })),
+ ]}
+ aria-label=""
+ onChange={updateTactic.bind(null, index)}
+ prepend={I18n.TACTIC}
+ compressed
+ fullWidth={false}
+ value={camelCase(item.tactic.name)}
+ {...euiSelectFieldProps}
+ />
+
+
+
+
+ t.tactics.includes(kebabCase(item.tactic.name))
+ )}
+ selectedOptions={item.techniques}
+ onChange={updateTechniques.bind(null, index)}
+ isDisabled={isDisabled}
+ fullWidth={true}
+ />
+
+
+
+ removeItem(index)}
+ aria-label={CreateRuleI18n.DELETE}
+ />
+
+
+ {values.length - 1 !== index && }
+
+ );
+ })}
+
+ {I18n.ADD_MITRE_ATTACK}
+
+ >
+
+ );
+};
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/mitre/translations.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/mitre/translations.ts
new file mode 100644
index 000000000000..22ee6cc3ef91
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/mitre/translations.ts
@@ -0,0 +1,36 @@
+/*
+ * 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';
+
+export const TACTIC = i18n.translate('xpack.siem.detectionEngine.mitreAttack.tacticsDescription', {
+ defaultMessage: 'Tactic',
+});
+
+export const TECHNIQUES = i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttack.techniquesDescription',
+ {
+ defaultMessage: 'Techniques',
+ }
+);
+
+export const ADD_MITRE_ATTACK = i18n.translate('xpack.siem.detectionEngine.mitreAttack.addTitle', {
+ defaultMessage: 'Add MITRE ATT&CK threat',
+});
+
+export const TECHNIQUES_PLACEHOLDER = i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttack.techniquesPlaceHolderDescription',
+ {
+ defaultMessage: 'Select techniques ...',
+ }
+);
+
+export const TACTIC_PLACEHOLDER = i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttack.tacticPlaceHolderDescription',
+ {
+ defaultMessage: 'Select tactic ...',
+ }
+);
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/query_bar/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/query_bar/index.tsx
index 92b2f557d4ce..8dc402f00e62 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/query_bar/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/query_bar/index.tsx
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { EuiFormRow } from '@elastic/eui';
+import { EuiFormRow, EuiMutationObserver } from '@elastic/eui';
import { isEqual } from 'lodash/fp';
import React, { useCallback, useEffect, useState } from 'react';
import { Subscription } from 'rxjs';
@@ -36,6 +36,7 @@ interface QueryBarDefineRuleProps {
idAria: string;
isLoading: boolean;
indexPattern: IIndexPattern;
+ resizeParentContainer?: (height: number) => void;
}
const StyledEuiFormRow = styled(EuiFormRow)`
@@ -60,7 +61,9 @@ export const QueryBarDefineRule = ({
idAria,
indexPattern,
isLoading = false,
+ resizeParentContainer,
}: QueryBarDefineRuleProps) => {
+ const [originalHeight, setOriginalHeight] = useState(-1);
const [savedQuery, setSavedQuery] = useState(null);
const [queryDraft, setQueryDraft] = useState({ query: '', language: 'kuery' });
const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field);
@@ -165,6 +168,27 @@ export const QueryBarDefineRule = ({
[field.value]
);
+ const onMutation = (event: unknown, observer: unknown) => {
+ if (resizeParentContainer != null) {
+ const suggestionContainer = document.getElementById('kbnTypeahead__items');
+ if (suggestionContainer != null) {
+ const box = suggestionContainer.getBoundingClientRect();
+ const accordionContainer = document.getElementById('define-rule');
+ if (accordionContainer != null) {
+ const accordionBox = accordionContainer.getBoundingClientRect();
+ if (originalHeight === -1 || accordionBox.height < originalHeight + box.height) {
+ resizeParentContainer(originalHeight + box.height - 100);
+ }
+ if (originalHeight === -1) {
+ setOriginalHeight(accordionBox.height);
+ }
+ }
+ } else {
+ resizeParentContainer(-1);
+ }
+ }
+ };
+
return (
-
+
+ {mutationRef => (
+
+
+
+ )}
+
);
};
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/step_about_rule/default_value.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/step_about_rule/default_value.ts
index 7c4d78f36447..504b5ca85a3a 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/step_about_rule/default_value.ts
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/step_about_rule/default_value.ts
@@ -15,4 +15,11 @@ export const defaultValue: AboutStepRule = {
references: [''],
falsePositives: [''],
tags: [],
+ threats: [
+ {
+ framework: 'MITRE ATT&CK',
+ tactic: { id: 'none', name: 'none', reference: 'none' },
+ techniques: [],
+ },
+ ],
};
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/step_about_rule/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/step_about_rule/index.tsx
index 56830f252748..aeb70061c44b 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/step_about_rule/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/step_about_rule/index.tsx
@@ -16,6 +16,7 @@ import { defaultValue } from './default_value';
import { schema } from './schema';
import * as I18n from './translations';
import { StepRuleDescription } from '../description_step';
+import { AddMitreThreat } from '../mitre';
const CommonUseField = getUseField({ component: Field });
@@ -114,6 +115,16 @@ export const StepAboutRule = memo(({ isEditView, isLoading, setSt
dataTestSubj: 'detectionEngineStepAboutRuleFalsePositives',
}}
/>
+
{CreateRuleI18n.OPTIONAL_FIELD},
},
+ threats: {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.createRule.stepAboutRule.fieldMitreThreatLabel',
+ {
+ defaultMessage: 'MITRE ATT&CK',
+ }
+ ),
+ labelAppend: {CreateRuleI18n.OPTIONAL_FIELD} ,
+ validations: [
+ {
+ validator: (
+ ...args: Parameters
+ ): ReturnType> | undefined => {
+ const [{ value, path }] = args;
+ let hasError = false;
+ (value as IMitreEnterpriseAttack[]).forEach(v => {
+ if (isEmpty(v.tactic.name) || (v.tactic.name !== 'none' && isEmpty(v.techniques))) {
+ hasError = true;
+ }
+ });
+ return hasError
+ ? {
+ code: 'ERR_FIELD_MISSING',
+ path,
+ message: I18n.CUSTOM_MITRE_ATTACK_TECHNIQUES_REQUIRED,
+ }
+ : undefined;
+ },
+ },
+ ],
+ },
tags: {
type: FIELD_TYPES.COMBO_BOX,
label: i18n.translate('xpack.siem.detectionEngine.createRule.stepAboutRule.fieldTagsLabel', {
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/step_about_rule/translations.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/step_about_rule/translations.ts
index bd759b345d70..017d4fe6fdf4 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/step_about_rule/translations.ts
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/step_about_rule/translations.ts
@@ -47,3 +47,10 @@ export const CRITICAL = i18n.translate(
defaultMessage: 'Critical',
}
);
+
+export const CUSTOM_MITRE_ATTACK_TECHNIQUES_REQUIRED = i18n.translate(
+ 'xpack.siem.detectionEngine.createRule.stepDefineRule.customMitreAttackTechniquesFieldRequiredError',
+ {
+ defaultMessage: 'At least one Technique is required with a Tactic.',
+ }
+);
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/step_define_rule/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/step_define_rule/index.tsx
index 26306d357392..6954bd6bf733 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/step_define_rule/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/step_define_rule/index.tsx
@@ -6,11 +6,11 @@
import { EuiHorizontalRule, EuiFlexGroup, EuiFlexItem, EuiButton } from '@elastic/eui';
import { isEqual } from 'lodash/fp';
-import React, { memo, useCallback, useEffect, useState } from 'react';
+import React, { memo, useCallback, useState } from 'react';
import { IIndexPattern } from '../../../../../../../../../../src/plugins/data/public';
import { useFetchIndexPatterns } from '../../../../../containers/detection_engine/rules/fetch_index_patterns';
-import { DEFAULT_INDEX_KEY, DEFAULT_SIGNALS_INDEX_KEY } from '../../../../../../common/constants';
+import { DEFAULT_INDEX_KEY } from '../../../../../../common/constants';
import { useKibanaUiSetting } from '../../../../../lib/settings/use_kibana_ui_setting';
import * as CreateRuleI18n from '../../translations';
import { DefineStepRule, RuleStep, RuleStepProps } from '../../types';
@@ -22,148 +22,133 @@ import * as I18n from './translations';
const CommonUseField = getUseField({ component: Field });
-export const StepDefineRule = memo(({ isEditView, isLoading, setStepData }) => {
- const [initializeOutputIndex, setInitializeOutputIndex] = useState(true);
- const [localUseIndicesConfig, setLocalUseIndicesConfig] = useState('');
- const [
- { indexPatterns: indexPatternQueryBar, isLoading: indexPatternLoadingQueryBar },
- setIndices,
- ] = useFetchIndexPatterns();
- const [indicesConfig] = useKibanaUiSetting(DEFAULT_INDEX_KEY);
- const [signalIndexConfig] = useKibanaUiSetting(DEFAULT_SIGNALS_INDEX_KEY);
- const [myStepData, setMyStepData] = useState({
- index: indicesConfig || [],
- isNew: true,
- outputIndex: signalIndexConfig,
- queryBar: {
- query: { query: '', language: 'kuery' },
- filters: [],
- saved_id: null,
- },
- useIndicesConfig: 'true',
- });
- const { form } = useForm({
- schema,
- defaultValue: myStepData,
- options: { stripEmptyFields: false },
- });
+export const StepDefineRule = memo(
+ ({ isEditView, isLoading, resizeParentContainer, setStepData }) => {
+ const [localUseIndicesConfig, setLocalUseIndicesConfig] = useState('');
+ const [
+ { indexPatterns: indexPatternQueryBar, isLoading: indexPatternLoadingQueryBar },
+ setIndices,
+ ] = useFetchIndexPatterns();
+ const [indicesConfig] = useKibanaUiSetting(DEFAULT_INDEX_KEY);
+ const [myStepData, setMyStepData] = useState({
+ index: indicesConfig || [],
+ isNew: true,
+ queryBar: {
+ query: { query: '', language: 'kuery' },
+ filters: [],
+ saved_id: null,
+ },
+ useIndicesConfig: 'true',
+ });
+ const { form } = useForm({
+ schema,
+ defaultValue: myStepData,
+ options: { stripEmptyFields: false },
+ });
- const onSubmit = useCallback(async () => {
- const { isValid, data } = await form.submit();
- if (isValid) {
- setStepData(RuleStep.defineRule, data, isValid);
- setMyStepData({ ...data, isNew: false } as DefineStepRule);
- }
- }, [form]);
+ const onSubmit = useCallback(async () => {
+ const { isValid, data } = await form.submit();
+ if (isValid) {
+ setStepData(RuleStep.defineRule, data, isValid);
+ setMyStepData({ ...data, isNew: false } as DefineStepRule);
+ }
+ }, [form]);
- useEffect(() => {
- if (signalIndexConfig != null && initializeOutputIndex) {
- const outputIndexField = form.getFields().outputIndex;
- outputIndexField.setValue(signalIndexConfig);
- setInitializeOutputIndex(false);
- }
- }, [initializeOutputIndex, signalIndexConfig, form]);
-
- return isEditView && myStepData != null ? (
-
- ) : (
- <>
-
-
-
-
-
- {myStepData.isNew ? CreateRuleI18n.CONTINUE : CreateRuleI18n.UPDATE}
-
-
-
- >
- );
-});
+ return null;
+ }}
+
+
+
+
+
+
+ {myStepData.isNew ? CreateRuleI18n.CONTINUE : CreateRuleI18n.UPDATE}
+
+
+
+ >
+ );
+ }
+);
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/step_define_rule/schema.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/step_define_rule/schema.tsx
index 9f1644e73bf0..0f6c5f72e168 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/step_define_rule/schema.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/step_define_rule/schema.tsx
@@ -26,27 +26,6 @@ import { CUSTOM_QUERY_REQUIRED, INVALID_CUSTOM_QUERY } from './translations';
const { emptyField } = fieldValidators;
export const schema: FormSchema = {
- outputIndex: {
- type: FIELD_TYPES.TEXT,
- label: i18n.translate(
- 'xpack.siem.detectionEngine.createRule.stepDefineRule.fieldOutputIndiceNameLabel',
- {
- defaultMessage: 'Output index name',
- }
- ),
- validations: [
- {
- validator: emptyField(
- i18n.translate(
- 'xpack.siem.detectionEngine.createRule.stepDefineRule.outputIndiceNameFieldRequiredError',
- {
- defaultMessage: 'An output indice name for signals is required.',
- }
- )
- ),
- },
- ],
- },
useIndicesConfig: {
type: FIELD_TYPES.RADIO_GROUP,
label: i18n.translate(
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/helpers.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/helpers.ts
index b864260dd333..f6546a680ad8 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/helpers.ts
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/helpers.ts
@@ -40,13 +40,12 @@ const getTimeTypeValue = (time: string): { unit: string; value: number } => {
};
const formatDefineStepData = (defineStepData: DefineStepRule): DefineStepRuleJson => {
- const { queryBar, useIndicesConfig, outputIndex, ...rest } = defineStepData;
+ const { queryBar, useIndicesConfig, ...rest } = defineStepData;
const { filters, query, saved_id: savedId } = queryBar;
return {
...rest,
language: query.language,
filters,
- output_index: outputIndex,
query: query.query as string,
...(savedId != null ? { saved_id: savedId } : {}),
};
@@ -69,12 +68,22 @@ const formatScheduleStepData = (scheduleData: ScheduleStepRule): ScheduleStepRul
};
const formatAboutStepData = (aboutStepData: AboutStepRule): AboutStepRuleJson => {
- const { falsePositives, references, riskScore, ...rest } = aboutStepData;
+ const { falsePositives, references, riskScore, threats, ...rest } = aboutStepData;
return {
false_positives: falsePositives.filter(item => !isEmpty(item)),
references: references.filter(item => !isEmpty(item)),
risk_score: riskScore,
+ threats: threats
+ .filter(threat => threat.tactic.name !== 'none')
+ .map(threat => ({
+ ...threat,
+ framework: 'MITRE ATT&CK',
+ techniques: threat.techniques.map(technique => {
+ const { id, name, reference } = technique;
+ return { id, name, reference };
+ }),
+ })),
...rest,
};
};
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/index.tsx
index 878c7171d19e..393b72d16b0a 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/index.tsx
@@ -7,6 +7,7 @@
import { EuiButtonEmpty, EuiAccordion, EuiHorizontalRule, EuiPanel, EuiSpacer } from '@elastic/eui';
import React, { useCallback, useRef, useState } from 'react';
import { Redirect } from 'react-router-dom';
+import styled from 'styled-components';
import { HeaderPage } from '../../../components/header_page';
import { WrapperPage } from '../../../components/wrapper_page';
@@ -24,7 +25,16 @@ import { DETECTION_ENGINE_PAGE_NAME } from '../../../components/link_to/redirect
const stepsRuleOrder = [RuleStep.defineRule, RuleStep.aboutRule, RuleStep.scheduleRule];
+const ResizeEuiPanel = styled(EuiPanel)<{
+ height?: number;
+}>`
+ .euiAccordion__childWrapper {
+ height: ${props => (props.height !== -1 ? `${props.height}px !important` : 'auto')};
+ }
+`;
+
export const CreateRuleComponent = React.memo(() => {
+ const [heightAccordion, setHeightAccordion] = useState(-1);
const [openAccordionId, setOpenAccordionId] = useState(RuleStep.defineRule);
const defineRuleRef = useRef(null);
const aboutRuleRef = useRef(null);
@@ -169,7 +179,7 @@ export const CreateRuleComponent = React.memo(() => {
isLoading={isLoading}
title={i18n.PAGE_TITLE}
/>
-
+
{
isEditView={isStepRuleInEditView[RuleStep.defineRule]}
isLoading={isLoading}
setStepData={setStepData}
+ resizeParentContainer={height => setHeightAccordion(height)}
/>
-
+
void;
isEditView: boolean;
isLoading: boolean;
+ resizeParentContainer?: (height: number) => void;
}
interface StepRuleData {
@@ -36,10 +37,10 @@ export interface AboutStepRule extends StepRuleData {
references: string[];
falsePositives: string[];
tags: string[];
+ threats: IMitreEnterpriseAttack[];
}
export interface DefineStepRule extends StepRuleData {
- outputIndex: string;
useIndicesConfig: string;
index: string[];
queryBar: FieldValueQueryBar;
@@ -53,7 +54,6 @@ export interface ScheduleStepRule extends StepRuleData {
}
export interface DefineStepRuleJson {
- output_index: string;
index: string[];
filters: esFilters.Filter[];
saved_id?: string;
@@ -69,8 +69,20 @@ export interface AboutStepRuleJson {
references: string[];
false_positives: string[];
tags: string[];
+ threats: IMitreEnterpriseAttack[];
}
export type ScheduleStepRuleJson = ScheduleStepRule;
export type FormatRuleType = 'query' | 'saved_query';
+
+export interface IMitreAttack {
+ id: string;
+ name: string;
+ reference: string;
+}
+export interface IMitreEnterpriseAttack {
+ framework: string;
+ tactic: IMitreAttack;
+ techniques: IMitreAttack[];
+}
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/mitre/mitre_tactics_techniques.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/mitre/mitre_tactics_techniques.ts
new file mode 100644
index 000000000000..160e006c4d26
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/mitre/mitre_tactics_techniques.ts
@@ -0,0 +1,4696 @@
+/*
+ * 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';
+
+import { MitreTacticsOptions, MitreTechniquesOptions } from './types';
+
+export const tactics = [
+ {
+ name: 'Collection',
+ id: 'TA0009',
+ reference: 'https://attack.mitre.org/tactics/TA0009',
+ },
+ {
+ name: 'Command and Control',
+ id: 'TA0011',
+ reference: 'https://attack.mitre.org/tactics/TA0011',
+ },
+ {
+ name: 'Credential Access',
+ id: 'TA0006',
+ reference: 'https://attack.mitre.org/tactics/TA0006',
+ },
+ {
+ name: 'Defense Evasion',
+ id: 'TA0005',
+ reference: 'https://attack.mitre.org/tactics/TA0005',
+ },
+ {
+ name: 'Discovery',
+ id: 'TA0007',
+ reference: 'https://attack.mitre.org/tactics/TA0007',
+ },
+ {
+ name: 'Execution',
+ id: 'TA0002',
+ reference: 'https://attack.mitre.org/tactics/TA0002',
+ },
+ {
+ name: 'Exfiltration',
+ id: 'TA0010',
+ reference: 'https://attack.mitre.org/tactics/TA0010',
+ },
+ {
+ name: 'Impact',
+ id: 'TA0040',
+ reference: 'https://attack.mitre.org/tactics/TA0040',
+ },
+ {
+ name: 'Initial Access',
+ id: 'TA0001',
+ reference: 'https://attack.mitre.org/tactics/TA0001',
+ },
+ {
+ name: 'Lateral Movement',
+ id: 'TA0008',
+ reference: 'https://attack.mitre.org/tactics/TA0008',
+ },
+ {
+ name: 'Persistence',
+ id: 'TA0003',
+ reference: 'https://attack.mitre.org/tactics/TA0003',
+ },
+ {
+ name: 'Privilege Escalation',
+ id: 'TA0004',
+ reference: 'https://attack.mitre.org/tactics/TA0004',
+ },
+];
+
+export const tacticsOptions: MitreTacticsOptions[] = [
+ {
+ id: 'TA0009',
+ name: 'Collection',
+ reference: 'https://attack.mitre.org/tactics/TA0009',
+ text: i18n.translate('xpack.siem.detectionEngine.mitreAttackTactics.collectionDescription', {
+ defaultMessage: 'Collection (TA0009)',
+ }),
+ value: 'collection',
+ },
+ {
+ id: 'TA0011',
+ name: 'Command and Control',
+ reference: 'https://attack.mitre.org/tactics/TA0011',
+ text: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTactics.commandAndControlDescription',
+ { defaultMessage: 'Command and Control (TA0011)' }
+ ),
+ value: 'commandAndControl',
+ },
+ {
+ id: 'TA0006',
+ name: 'Credential Access',
+ reference: 'https://attack.mitre.org/tactics/TA0006',
+ text: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTactics.credentialAccessDescription',
+ { defaultMessage: 'Credential Access (TA0006)' }
+ ),
+ value: 'credentialAccess',
+ },
+ {
+ id: 'TA0005',
+ name: 'Defense Evasion',
+ reference: 'https://attack.mitre.org/tactics/TA0005',
+ text: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTactics.defenseEvasionDescription',
+ { defaultMessage: 'Defense Evasion (TA0005)' }
+ ),
+ value: 'defenseEvasion',
+ },
+ {
+ id: 'TA0007',
+ name: 'Discovery',
+ reference: 'https://attack.mitre.org/tactics/TA0007',
+ text: i18n.translate('xpack.siem.detectionEngine.mitreAttackTactics.discoveryDescription', {
+ defaultMessage: 'Discovery (TA0007)',
+ }),
+ value: 'discovery',
+ },
+ {
+ id: 'TA0002',
+ name: 'Execution',
+ reference: 'https://attack.mitre.org/tactics/TA0002',
+ text: i18n.translate('xpack.siem.detectionEngine.mitreAttackTactics.executionDescription', {
+ defaultMessage: 'Execution (TA0002)',
+ }),
+ value: 'execution',
+ },
+ {
+ id: 'TA0010',
+ name: 'Exfiltration',
+ reference: 'https://attack.mitre.org/tactics/TA0010',
+ text: i18n.translate('xpack.siem.detectionEngine.mitreAttackTactics.exfiltrationDescription', {
+ defaultMessage: 'Exfiltration (TA0010)',
+ }),
+ value: 'exfiltration',
+ },
+ {
+ id: 'TA0040',
+ name: 'Impact',
+ reference: 'https://attack.mitre.org/tactics/TA0040',
+ text: i18n.translate('xpack.siem.detectionEngine.mitreAttackTactics.impactDescription', {
+ defaultMessage: 'Impact (TA0040)',
+ }),
+ value: 'impact',
+ },
+ {
+ id: 'TA0001',
+ name: 'Initial Access',
+ reference: 'https://attack.mitre.org/tactics/TA0001',
+ text: i18n.translate('xpack.siem.detectionEngine.mitreAttackTactics.initialAccessDescription', {
+ defaultMessage: 'Initial Access (TA0001)',
+ }),
+ value: 'initialAccess',
+ },
+ {
+ id: 'TA0008',
+ name: 'Lateral Movement',
+ reference: 'https://attack.mitre.org/tactics/TA0008',
+ text: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTactics.lateralMovementDescription',
+ { defaultMessage: 'Lateral Movement (TA0008)' }
+ ),
+ value: 'lateralMovement',
+ },
+ {
+ id: 'TA0003',
+ name: 'Persistence',
+ reference: 'https://attack.mitre.org/tactics/TA0003',
+ text: i18n.translate('xpack.siem.detectionEngine.mitreAttackTactics.persistenceDescription', {
+ defaultMessage: 'Persistence (TA0003)',
+ }),
+ value: 'persistence',
+ },
+ {
+ id: 'TA0004',
+ name: 'Privilege Escalation',
+ reference: 'https://attack.mitre.org/tactics/TA0004',
+ text: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTactics.privilegeEscalationDescription',
+ { defaultMessage: 'Privilege Escalation (TA0004)' }
+ ),
+ value: 'privilegeEscalation',
+ },
+];
+
+export const techniques = [
+ {
+ name: '.bash_profile and .bashrc',
+ id: 'T1156',
+ reference: 'https://attack.mitre.org/techniques/T1156',
+ tactics: ['persistence'],
+ },
+ {
+ name: 'Access Token Manipulation',
+ id: 'T1134',
+ reference: 'https://attack.mitre.org/techniques/T1134',
+ tactics: ['defense-evasion', 'privilege-escalation'],
+ },
+ {
+ name: 'Accessibility Features',
+ id: 'T1015',
+ reference: 'https://attack.mitre.org/techniques/T1015',
+ tactics: ['persistence', 'privilege-escalation'],
+ },
+ {
+ name: 'Account Access Removal',
+ id: 'T1531',
+ reference: 'https://attack.mitre.org/techniques/T1531',
+ tactics: ['impact'],
+ },
+ {
+ name: 'Account Discovery',
+ id: 'T1087',
+ reference: 'https://attack.mitre.org/techniques/T1087',
+ tactics: ['discovery'],
+ },
+ {
+ name: 'Account Manipulation',
+ id: 'T1098',
+ reference: 'https://attack.mitre.org/techniques/T1098',
+ tactics: ['credential-access', 'persistence'],
+ },
+ {
+ name: 'AppCert DLLs',
+ id: 'T1182',
+ reference: 'https://attack.mitre.org/techniques/T1182',
+ tactics: ['persistence', 'privilege-escalation'],
+ },
+ {
+ name: 'AppInit DLLs',
+ id: 'T1103',
+ reference: 'https://attack.mitre.org/techniques/T1103',
+ tactics: ['persistence', 'privilege-escalation'],
+ },
+ {
+ name: 'AppleScript',
+ id: 'T1155',
+ reference: 'https://attack.mitre.org/techniques/T1155',
+ tactics: ['execution', 'lateral-movement'],
+ },
+ {
+ name: 'Application Access Token',
+ id: 'T1527',
+ reference: 'https://attack.mitre.org/techniques/T1527',
+ tactics: ['defense-evasion', 'lateral-movement'],
+ },
+ {
+ name: 'Application Deployment Software',
+ id: 'T1017',
+ reference: 'https://attack.mitre.org/techniques/T1017',
+ tactics: ['lateral-movement'],
+ },
+ {
+ name: 'Application Shimming',
+ id: 'T1138',
+ reference: 'https://attack.mitre.org/techniques/T1138',
+ tactics: ['persistence', 'privilege-escalation'],
+ },
+ {
+ name: 'Application Window Discovery',
+ id: 'T1010',
+ reference: 'https://attack.mitre.org/techniques/T1010',
+ tactics: ['discovery'],
+ },
+ {
+ name: 'Audio Capture',
+ id: 'T1123',
+ reference: 'https://attack.mitre.org/techniques/T1123',
+ tactics: ['collection'],
+ },
+ {
+ name: 'Authentication Package',
+ id: 'T1131',
+ reference: 'https://attack.mitre.org/techniques/T1131',
+ tactics: ['persistence'],
+ },
+ {
+ name: 'Automated Collection',
+ id: 'T1119',
+ reference: 'https://attack.mitre.org/techniques/T1119',
+ tactics: ['collection'],
+ },
+ {
+ name: 'Automated Exfiltration',
+ id: 'T1020',
+ reference: 'https://attack.mitre.org/techniques/T1020',
+ tactics: ['exfiltration'],
+ },
+ {
+ name: 'BITS Jobs',
+ id: 'T1197',
+ reference: 'https://attack.mitre.org/techniques/T1197',
+ tactics: ['defense-evasion', 'persistence'],
+ },
+ {
+ name: 'Bash History',
+ id: 'T1139',
+ reference: 'https://attack.mitre.org/techniques/T1139',
+ tactics: ['credential-access'],
+ },
+ {
+ name: 'Binary Padding',
+ id: 'T1009',
+ reference: 'https://attack.mitre.org/techniques/T1009',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Bootkit',
+ id: 'T1067',
+ reference: 'https://attack.mitre.org/techniques/T1067',
+ tactics: ['persistence'],
+ },
+ {
+ name: 'Browser Bookmark Discovery',
+ id: 'T1217',
+ reference: 'https://attack.mitre.org/techniques/T1217',
+ tactics: ['discovery'],
+ },
+ {
+ name: 'Browser Extensions',
+ id: 'T1176',
+ reference: 'https://attack.mitre.org/techniques/T1176',
+ tactics: ['persistence'],
+ },
+ {
+ name: 'Brute Force',
+ id: 'T1110',
+ reference: 'https://attack.mitre.org/techniques/T1110',
+ tactics: ['credential-access'],
+ },
+ {
+ name: 'Bypass User Account Control',
+ id: 'T1088',
+ reference: 'https://attack.mitre.org/techniques/T1088',
+ tactics: ['defense-evasion', 'privilege-escalation'],
+ },
+ {
+ name: 'CMSTP',
+ id: 'T1191',
+ reference: 'https://attack.mitre.org/techniques/T1191',
+ tactics: ['defense-evasion', 'execution'],
+ },
+ {
+ name: 'Change Default File Association',
+ id: 'T1042',
+ reference: 'https://attack.mitre.org/techniques/T1042',
+ tactics: ['persistence'],
+ },
+ {
+ name: 'Clear Command History',
+ id: 'T1146',
+ reference: 'https://attack.mitre.org/techniques/T1146',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Clipboard Data',
+ id: 'T1115',
+ reference: 'https://attack.mitre.org/techniques/T1115',
+ tactics: ['collection'],
+ },
+ {
+ name: 'Cloud Instance Metadata API',
+ id: 'T1522',
+ reference: 'https://attack.mitre.org/techniques/T1522',
+ tactics: ['credential-access'],
+ },
+ {
+ name: 'Cloud Service Dashboard',
+ id: 'T1538',
+ reference: 'https://attack.mitre.org/techniques/T1538',
+ tactics: ['discovery'],
+ },
+ {
+ name: 'Cloud Service Discovery',
+ id: 'T1526',
+ reference: 'https://attack.mitre.org/techniques/T1526',
+ tactics: ['discovery'],
+ },
+ {
+ name: 'Code Signing',
+ id: 'T1116',
+ reference: 'https://attack.mitre.org/techniques/T1116',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Command-Line Interface',
+ id: 'T1059',
+ reference: 'https://attack.mitre.org/techniques/T1059',
+ tactics: ['execution'],
+ },
+ {
+ name: 'Commonly Used Port',
+ id: 'T1043',
+ reference: 'https://attack.mitre.org/techniques/T1043',
+ tactics: ['command-and-control'],
+ },
+ {
+ name: 'Communication Through Removable Media',
+ id: 'T1092',
+ reference: 'https://attack.mitre.org/techniques/T1092',
+ tactics: ['command-and-control'],
+ },
+ {
+ name: 'Compile After Delivery',
+ id: 'T1500',
+ reference: 'https://attack.mitre.org/techniques/T1500',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Compiled HTML File',
+ id: 'T1223',
+ reference: 'https://attack.mitre.org/techniques/T1223',
+ tactics: ['defense-evasion', 'execution'],
+ },
+ {
+ name: 'Component Firmware',
+ id: 'T1109',
+ reference: 'https://attack.mitre.org/techniques/T1109',
+ tactics: ['defense-evasion', 'persistence'],
+ },
+ {
+ name: 'Component Object Model Hijacking',
+ id: 'T1122',
+ reference: 'https://attack.mitre.org/techniques/T1122',
+ tactics: ['defense-evasion', 'persistence'],
+ },
+ {
+ name: 'Component Object Model and Distributed COM',
+ id: 'T1175',
+ reference: 'https://attack.mitre.org/techniques/T1175',
+ tactics: ['lateral-movement', 'execution'],
+ },
+ {
+ name: 'Connection Proxy',
+ id: 'T1090',
+ reference: 'https://attack.mitre.org/techniques/T1090',
+ tactics: ['command-and-control', 'defense-evasion'],
+ },
+ {
+ name: 'Control Panel Items',
+ id: 'T1196',
+ reference: 'https://attack.mitre.org/techniques/T1196',
+ tactics: ['defense-evasion', 'execution'],
+ },
+ {
+ name: 'Create Account',
+ id: 'T1136',
+ reference: 'https://attack.mitre.org/techniques/T1136',
+ tactics: ['persistence'],
+ },
+ {
+ name: 'Credential Dumping',
+ id: 'T1003',
+ reference: 'https://attack.mitre.org/techniques/T1003',
+ tactics: ['credential-access'],
+ },
+ {
+ name: 'Credentials from Web Browsers',
+ id: 'T1503',
+ reference: 'https://attack.mitre.org/techniques/T1503',
+ tactics: ['credential-access'],
+ },
+ {
+ name: 'Credentials in Files',
+ id: 'T1081',
+ reference: 'https://attack.mitre.org/techniques/T1081',
+ tactics: ['credential-access'],
+ },
+ {
+ name: 'Credentials in Registry',
+ id: 'T1214',
+ reference: 'https://attack.mitre.org/techniques/T1214',
+ tactics: ['credential-access'],
+ },
+ {
+ name: 'Custom Command and Control Protocol',
+ id: 'T1094',
+ reference: 'https://attack.mitre.org/techniques/T1094',
+ tactics: ['command-and-control'],
+ },
+ {
+ name: 'Custom Cryptographic Protocol',
+ id: 'T1024',
+ reference: 'https://attack.mitre.org/techniques/T1024',
+ tactics: ['command-and-control'],
+ },
+ {
+ name: 'DCShadow',
+ id: 'T1207',
+ reference: 'https://attack.mitre.org/techniques/T1207',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'DLL Search Order Hijacking',
+ id: 'T1038',
+ reference: 'https://attack.mitre.org/techniques/T1038',
+ tactics: ['persistence', 'privilege-escalation', 'defense-evasion'],
+ },
+ {
+ name: 'DLL Side-Loading',
+ id: 'T1073',
+ reference: 'https://attack.mitre.org/techniques/T1073',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Data Compressed',
+ id: 'T1002',
+ reference: 'https://attack.mitre.org/techniques/T1002',
+ tactics: ['exfiltration'],
+ },
+ {
+ name: 'Data Destruction',
+ id: 'T1485',
+ reference: 'https://attack.mitre.org/techniques/T1485',
+ tactics: ['impact'],
+ },
+ {
+ name: 'Data Encoding',
+ id: 'T1132',
+ reference: 'https://attack.mitre.org/techniques/T1132',
+ tactics: ['command-and-control'],
+ },
+ {
+ name: 'Data Encrypted',
+ id: 'T1022',
+ reference: 'https://attack.mitre.org/techniques/T1022',
+ tactics: ['exfiltration'],
+ },
+ {
+ name: 'Data Encrypted for Impact',
+ id: 'T1486',
+ reference: 'https://attack.mitre.org/techniques/T1486',
+ tactics: ['impact'],
+ },
+ {
+ name: 'Data Obfuscation',
+ id: 'T1001',
+ reference: 'https://attack.mitre.org/techniques/T1001',
+ tactics: ['command-and-control'],
+ },
+ {
+ name: 'Data Staged',
+ id: 'T1074',
+ reference: 'https://attack.mitre.org/techniques/T1074',
+ tactics: ['collection'],
+ },
+ {
+ name: 'Data Transfer Size Limits',
+ id: 'T1030',
+ reference: 'https://attack.mitre.org/techniques/T1030',
+ tactics: ['exfiltration'],
+ },
+ {
+ name: 'Data from Cloud Storage Object',
+ id: 'T1530',
+ reference: 'https://attack.mitre.org/techniques/T1530',
+ tactics: ['collection'],
+ },
+ {
+ name: 'Data from Information Repositories',
+ id: 'T1213',
+ reference: 'https://attack.mitre.org/techniques/T1213',
+ tactics: ['collection'],
+ },
+ {
+ name: 'Data from Local System',
+ id: 'T1005',
+ reference: 'https://attack.mitre.org/techniques/T1005',
+ tactics: ['collection'],
+ },
+ {
+ name: 'Data from Network Shared Drive',
+ id: 'T1039',
+ reference: 'https://attack.mitre.org/techniques/T1039',
+ tactics: ['collection'],
+ },
+ {
+ name: 'Data from Removable Media',
+ id: 'T1025',
+ reference: 'https://attack.mitre.org/techniques/T1025',
+ tactics: ['collection'],
+ },
+ {
+ name: 'Defacement',
+ id: 'T1491',
+ reference: 'https://attack.mitre.org/techniques/T1491',
+ tactics: ['impact'],
+ },
+ {
+ name: 'Deobfuscate/Decode Files or Information',
+ id: 'T1140',
+ reference: 'https://attack.mitre.org/techniques/T1140',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Disabling Security Tools',
+ id: 'T1089',
+ reference: 'https://attack.mitre.org/techniques/T1089',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Disk Content Wipe',
+ id: 'T1488',
+ reference: 'https://attack.mitre.org/techniques/T1488',
+ tactics: ['impact'],
+ },
+ {
+ name: 'Disk Structure Wipe',
+ id: 'T1487',
+ reference: 'https://attack.mitre.org/techniques/T1487',
+ tactics: ['impact'],
+ },
+ {
+ name: 'Domain Fronting',
+ id: 'T1172',
+ reference: 'https://attack.mitre.org/techniques/T1172',
+ tactics: ['command-and-control'],
+ },
+ {
+ name: 'Domain Generation Algorithms',
+ id: 'T1483',
+ reference: 'https://attack.mitre.org/techniques/T1483',
+ tactics: ['command-and-control'],
+ },
+ {
+ name: 'Domain Trust Discovery',
+ id: 'T1482',
+ reference: 'https://attack.mitre.org/techniques/T1482',
+ tactics: ['discovery'],
+ },
+ {
+ name: 'Drive-by Compromise',
+ id: 'T1189',
+ reference: 'https://attack.mitre.org/techniques/T1189',
+ tactics: ['initial-access'],
+ },
+ {
+ name: 'Dylib Hijacking',
+ id: 'T1157',
+ reference: 'https://attack.mitre.org/techniques/T1157',
+ tactics: ['persistence', 'privilege-escalation'],
+ },
+ {
+ name: 'Dynamic Data Exchange',
+ id: 'T1173',
+ reference: 'https://attack.mitre.org/techniques/T1173',
+ tactics: ['execution'],
+ },
+ {
+ name: 'Elevated Execution with Prompt',
+ id: 'T1514',
+ reference: 'https://attack.mitre.org/techniques/T1514',
+ tactics: ['privilege-escalation'],
+ },
+ {
+ name: 'Email Collection',
+ id: 'T1114',
+ reference: 'https://attack.mitre.org/techniques/T1114',
+ tactics: ['collection'],
+ },
+ {
+ name: 'Emond',
+ id: 'T1519',
+ reference: 'https://attack.mitre.org/techniques/T1519',
+ tactics: ['persistence', 'privilege-escalation'],
+ },
+ {
+ name: 'Endpoint Denial of Service',
+ id: 'T1499',
+ reference: 'https://attack.mitre.org/techniques/T1499',
+ tactics: ['impact'],
+ },
+ {
+ name: 'Execution Guardrails',
+ id: 'T1480',
+ reference: 'https://attack.mitre.org/techniques/T1480',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Execution through API',
+ id: 'T1106',
+ reference: 'https://attack.mitre.org/techniques/T1106',
+ tactics: ['execution'],
+ },
+ {
+ name: 'Execution through Module Load',
+ id: 'T1129',
+ reference: 'https://attack.mitre.org/techniques/T1129',
+ tactics: ['execution'],
+ },
+ {
+ name: 'Exfiltration Over Alternative Protocol',
+ id: 'T1048',
+ reference: 'https://attack.mitre.org/techniques/T1048',
+ tactics: ['exfiltration'],
+ },
+ {
+ name: 'Exfiltration Over Command and Control Channel',
+ id: 'T1041',
+ reference: 'https://attack.mitre.org/techniques/T1041',
+ tactics: ['exfiltration'],
+ },
+ {
+ name: 'Exfiltration Over Other Network Medium',
+ id: 'T1011',
+ reference: 'https://attack.mitre.org/techniques/T1011',
+ tactics: ['exfiltration'],
+ },
+ {
+ name: 'Exfiltration Over Physical Medium',
+ id: 'T1052',
+ reference: 'https://attack.mitre.org/techniques/T1052',
+ tactics: ['exfiltration'],
+ },
+ {
+ name: 'Exploit Public-Facing Application',
+ id: 'T1190',
+ reference: 'https://attack.mitre.org/techniques/T1190',
+ tactics: ['initial-access'],
+ },
+ {
+ name: 'Exploitation for Client Execution',
+ id: 'T1203',
+ reference: 'https://attack.mitre.org/techniques/T1203',
+ tactics: ['execution'],
+ },
+ {
+ name: 'Exploitation for Credential Access',
+ id: 'T1212',
+ reference: 'https://attack.mitre.org/techniques/T1212',
+ tactics: ['credential-access'],
+ },
+ {
+ name: 'Exploitation for Defense Evasion',
+ id: 'T1211',
+ reference: 'https://attack.mitre.org/techniques/T1211',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Exploitation for Privilege Escalation',
+ id: 'T1068',
+ reference: 'https://attack.mitre.org/techniques/T1068',
+ tactics: ['privilege-escalation'],
+ },
+ {
+ name: 'Exploitation of Remote Services',
+ id: 'T1210',
+ reference: 'https://attack.mitre.org/techniques/T1210',
+ tactics: ['lateral-movement'],
+ },
+ {
+ name: 'External Remote Services',
+ id: 'T1133',
+ reference: 'https://attack.mitre.org/techniques/T1133',
+ tactics: ['persistence', 'initial-access'],
+ },
+ {
+ name: 'Extra Window Memory Injection',
+ id: 'T1181',
+ reference: 'https://attack.mitre.org/techniques/T1181',
+ tactics: ['defense-evasion', 'privilege-escalation'],
+ },
+ {
+ name: 'Fallback Channels',
+ id: 'T1008',
+ reference: 'https://attack.mitre.org/techniques/T1008',
+ tactics: ['command-and-control'],
+ },
+ {
+ name: 'File Deletion',
+ id: 'T1107',
+ reference: 'https://attack.mitre.org/techniques/T1107',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'File System Logical Offsets',
+ id: 'T1006',
+ reference: 'https://attack.mitre.org/techniques/T1006',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'File System Permissions Weakness',
+ id: 'T1044',
+ reference: 'https://attack.mitre.org/techniques/T1044',
+ tactics: ['persistence', 'privilege-escalation'],
+ },
+ {
+ name: 'File and Directory Discovery',
+ id: 'T1083',
+ reference: 'https://attack.mitre.org/techniques/T1083',
+ tactics: ['discovery'],
+ },
+ {
+ name: 'File and Directory Permissions Modification',
+ id: 'T1222',
+ reference: 'https://attack.mitre.org/techniques/T1222',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Firmware Corruption',
+ id: 'T1495',
+ reference: 'https://attack.mitre.org/techniques/T1495',
+ tactics: ['impact'],
+ },
+ {
+ name: 'Forced Authentication',
+ id: 'T1187',
+ reference: 'https://attack.mitre.org/techniques/T1187',
+ tactics: ['credential-access'],
+ },
+ {
+ name: 'Gatekeeper Bypass',
+ id: 'T1144',
+ reference: 'https://attack.mitre.org/techniques/T1144',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Graphical User Interface',
+ id: 'T1061',
+ reference: 'https://attack.mitre.org/techniques/T1061',
+ tactics: ['execution'],
+ },
+ {
+ name: 'Group Policy Modification',
+ id: 'T1484',
+ reference: 'https://attack.mitre.org/techniques/T1484',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'HISTCONTROL',
+ id: 'T1148',
+ reference: 'https://attack.mitre.org/techniques/T1148',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Hardware Additions',
+ id: 'T1200',
+ reference: 'https://attack.mitre.org/techniques/T1200',
+ tactics: ['initial-access'],
+ },
+ {
+ name: 'Hidden Files and Directories',
+ id: 'T1158',
+ reference: 'https://attack.mitre.org/techniques/T1158',
+ tactics: ['defense-evasion', 'persistence'],
+ },
+ {
+ name: 'Hidden Users',
+ id: 'T1147',
+ reference: 'https://attack.mitre.org/techniques/T1147',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Hidden Window',
+ id: 'T1143',
+ reference: 'https://attack.mitre.org/techniques/T1143',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Hooking',
+ id: 'T1179',
+ reference: 'https://attack.mitre.org/techniques/T1179',
+ tactics: ['persistence', 'privilege-escalation', 'credential-access'],
+ },
+ {
+ name: 'Hypervisor',
+ id: 'T1062',
+ reference: 'https://attack.mitre.org/techniques/T1062',
+ tactics: ['persistence'],
+ },
+ {
+ name: 'Image File Execution Options Injection',
+ id: 'T1183',
+ reference: 'https://attack.mitre.org/techniques/T1183',
+ tactics: ['privilege-escalation', 'persistence', 'defense-evasion'],
+ },
+ {
+ name: 'Implant Container Image',
+ id: 'T1525',
+ reference: 'https://attack.mitre.org/techniques/T1525',
+ tactics: ['persistence'],
+ },
+ {
+ name: 'Indicator Blocking',
+ id: 'T1054',
+ reference: 'https://attack.mitre.org/techniques/T1054',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Indicator Removal from Tools',
+ id: 'T1066',
+ reference: 'https://attack.mitre.org/techniques/T1066',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Indicator Removal on Host',
+ id: 'T1070',
+ reference: 'https://attack.mitre.org/techniques/T1070',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Indirect Command Execution',
+ id: 'T1202',
+ reference: 'https://attack.mitre.org/techniques/T1202',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Inhibit System Recovery',
+ id: 'T1490',
+ reference: 'https://attack.mitre.org/techniques/T1490',
+ tactics: ['impact'],
+ },
+ {
+ name: 'Input Capture',
+ id: 'T1056',
+ reference: 'https://attack.mitre.org/techniques/T1056',
+ tactics: ['collection', 'credential-access'],
+ },
+ {
+ name: 'Input Prompt',
+ id: 'T1141',
+ reference: 'https://attack.mitre.org/techniques/T1141',
+ tactics: ['credential-access'],
+ },
+ {
+ name: 'Install Root Certificate',
+ id: 'T1130',
+ reference: 'https://attack.mitre.org/techniques/T1130',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'InstallUtil',
+ id: 'T1118',
+ reference: 'https://attack.mitre.org/techniques/T1118',
+ tactics: ['defense-evasion', 'execution'],
+ },
+ {
+ name: 'Internal Spearphishing',
+ id: 'T1534',
+ reference: 'https://attack.mitre.org/techniques/T1534',
+ tactics: ['lateral-movement'],
+ },
+ {
+ name: 'Kerberoasting',
+ id: 'T1208',
+ reference: 'https://attack.mitre.org/techniques/T1208',
+ tactics: ['credential-access'],
+ },
+ {
+ name: 'Kernel Modules and Extensions',
+ id: 'T1215',
+ reference: 'https://attack.mitre.org/techniques/T1215',
+ tactics: ['persistence'],
+ },
+ {
+ name: 'Keychain',
+ id: 'T1142',
+ reference: 'https://attack.mitre.org/techniques/T1142',
+ tactics: ['credential-access'],
+ },
+ {
+ name: 'LC_LOAD_DYLIB Addition',
+ id: 'T1161',
+ reference: 'https://attack.mitre.org/techniques/T1161',
+ tactics: ['persistence'],
+ },
+ {
+ name: 'LC_MAIN Hijacking',
+ id: 'T1149',
+ reference: 'https://attack.mitre.org/techniques/T1149',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'LLMNR/NBT-NS Poisoning and Relay',
+ id: 'T1171',
+ reference: 'https://attack.mitre.org/techniques/T1171',
+ tactics: ['credential-access'],
+ },
+ {
+ name: 'LSASS Driver',
+ id: 'T1177',
+ reference: 'https://attack.mitre.org/techniques/T1177',
+ tactics: ['execution', 'persistence'],
+ },
+ {
+ name: 'Launch Agent',
+ id: 'T1159',
+ reference: 'https://attack.mitre.org/techniques/T1159',
+ tactics: ['persistence'],
+ },
+ {
+ name: 'Launch Daemon',
+ id: 'T1160',
+ reference: 'https://attack.mitre.org/techniques/T1160',
+ tactics: ['persistence', 'privilege-escalation'],
+ },
+ {
+ name: 'Launchctl',
+ id: 'T1152',
+ reference: 'https://attack.mitre.org/techniques/T1152',
+ tactics: ['defense-evasion', 'execution', 'persistence'],
+ },
+ {
+ name: 'Local Job Scheduling',
+ id: 'T1168',
+ reference: 'https://attack.mitre.org/techniques/T1168',
+ tactics: ['persistence', 'execution'],
+ },
+ {
+ name: 'Login Item',
+ id: 'T1162',
+ reference: 'https://attack.mitre.org/techniques/T1162',
+ tactics: ['persistence'],
+ },
+ {
+ name: 'Logon Scripts',
+ id: 'T1037',
+ reference: 'https://attack.mitre.org/techniques/T1037',
+ tactics: ['lateral-movement', 'persistence'],
+ },
+ {
+ name: 'Man in the Browser',
+ id: 'T1185',
+ reference: 'https://attack.mitre.org/techniques/T1185',
+ tactics: ['collection'],
+ },
+ {
+ name: 'Masquerading',
+ id: 'T1036',
+ reference: 'https://attack.mitre.org/techniques/T1036',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Modify Existing Service',
+ id: 'T1031',
+ reference: 'https://attack.mitre.org/techniques/T1031',
+ tactics: ['persistence'],
+ },
+ {
+ name: 'Modify Registry',
+ id: 'T1112',
+ reference: 'https://attack.mitre.org/techniques/T1112',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Mshta',
+ id: 'T1170',
+ reference: 'https://attack.mitre.org/techniques/T1170',
+ tactics: ['defense-evasion', 'execution'],
+ },
+ {
+ name: 'Multi-Stage Channels',
+ id: 'T1104',
+ reference: 'https://attack.mitre.org/techniques/T1104',
+ tactics: ['command-and-control'],
+ },
+ {
+ name: 'Multi-hop Proxy',
+ id: 'T1188',
+ reference: 'https://attack.mitre.org/techniques/T1188',
+ tactics: ['command-and-control'],
+ },
+ {
+ name: 'Multiband Communication',
+ id: 'T1026',
+ reference: 'https://attack.mitre.org/techniques/T1026',
+ tactics: ['command-and-control'],
+ },
+ {
+ name: 'Multilayer Encryption',
+ id: 'T1079',
+ reference: 'https://attack.mitre.org/techniques/T1079',
+ tactics: ['command-and-control'],
+ },
+ {
+ name: 'NTFS File Attributes',
+ id: 'T1096',
+ reference: 'https://attack.mitre.org/techniques/T1096',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Netsh Helper DLL',
+ id: 'T1128',
+ reference: 'https://attack.mitre.org/techniques/T1128',
+ tactics: ['persistence'],
+ },
+ {
+ name: 'Network Denial of Service',
+ id: 'T1498',
+ reference: 'https://attack.mitre.org/techniques/T1498',
+ tactics: ['impact'],
+ },
+ {
+ name: 'Network Service Scanning',
+ id: 'T1046',
+ reference: 'https://attack.mitre.org/techniques/T1046',
+ tactics: ['discovery'],
+ },
+ {
+ name: 'Network Share Connection Removal',
+ id: 'T1126',
+ reference: 'https://attack.mitre.org/techniques/T1126',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Network Share Discovery',
+ id: 'T1135',
+ reference: 'https://attack.mitre.org/techniques/T1135',
+ tactics: ['discovery'],
+ },
+ {
+ name: 'Network Sniffing',
+ id: 'T1040',
+ reference: 'https://attack.mitre.org/techniques/T1040',
+ tactics: ['credential-access', 'discovery'],
+ },
+ {
+ name: 'New Service',
+ id: 'T1050',
+ reference: 'https://attack.mitre.org/techniques/T1050',
+ tactics: ['persistence', 'privilege-escalation'],
+ },
+ {
+ name: 'Obfuscated Files or Information',
+ id: 'T1027',
+ reference: 'https://attack.mitre.org/techniques/T1027',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Office Application Startup',
+ id: 'T1137',
+ reference: 'https://attack.mitre.org/techniques/T1137',
+ tactics: ['persistence'],
+ },
+ {
+ name: 'Parent PID Spoofing',
+ id: 'T1502',
+ reference: 'https://attack.mitre.org/techniques/T1502',
+ tactics: ['defense-evasion', 'privilege-escalation'],
+ },
+ {
+ name: 'Pass the Hash',
+ id: 'T1075',
+ reference: 'https://attack.mitre.org/techniques/T1075',
+ tactics: ['lateral-movement'],
+ },
+ {
+ name: 'Pass the Ticket',
+ id: 'T1097',
+ reference: 'https://attack.mitre.org/techniques/T1097',
+ tactics: ['lateral-movement'],
+ },
+ {
+ name: 'Password Filter DLL',
+ id: 'T1174',
+ reference: 'https://attack.mitre.org/techniques/T1174',
+ tactics: ['credential-access'],
+ },
+ {
+ name: 'Password Policy Discovery',
+ id: 'T1201',
+ reference: 'https://attack.mitre.org/techniques/T1201',
+ tactics: ['discovery'],
+ },
+ {
+ name: 'Path Interception',
+ id: 'T1034',
+ reference: 'https://attack.mitre.org/techniques/T1034',
+ tactics: ['persistence', 'privilege-escalation'],
+ },
+ {
+ name: 'Peripheral Device Discovery',
+ id: 'T1120',
+ reference: 'https://attack.mitre.org/techniques/T1120',
+ tactics: ['discovery'],
+ },
+ {
+ name: 'Permission Groups Discovery',
+ id: 'T1069',
+ reference: 'https://attack.mitre.org/techniques/T1069',
+ tactics: ['discovery'],
+ },
+ {
+ name: 'Plist Modification',
+ id: 'T1150',
+ reference: 'https://attack.mitre.org/techniques/T1150',
+ tactics: ['defense-evasion', 'persistence', 'privilege-escalation'],
+ },
+ {
+ name: 'Port Knocking',
+ id: 'T1205',
+ reference: 'https://attack.mitre.org/techniques/T1205',
+ tactics: ['defense-evasion', 'persistence', 'command-and-control'],
+ },
+ {
+ name: 'Port Monitors',
+ id: 'T1013',
+ reference: 'https://attack.mitre.org/techniques/T1013',
+ tactics: ['persistence', 'privilege-escalation'],
+ },
+ {
+ name: 'PowerShell',
+ id: 'T1086',
+ reference: 'https://attack.mitre.org/techniques/T1086',
+ tactics: ['execution'],
+ },
+ {
+ name: 'PowerShell Profile',
+ id: 'T1504',
+ reference: 'https://attack.mitre.org/techniques/T1504',
+ tactics: ['persistence', 'privilege-escalation'],
+ },
+ {
+ name: 'Private Keys',
+ id: 'T1145',
+ reference: 'https://attack.mitre.org/techniques/T1145',
+ tactics: ['credential-access'],
+ },
+ {
+ name: 'Process Discovery',
+ id: 'T1057',
+ reference: 'https://attack.mitre.org/techniques/T1057',
+ tactics: ['discovery'],
+ },
+ {
+ name: 'Process Doppelgänging',
+ id: 'T1186',
+ reference: 'https://attack.mitre.org/techniques/T1186',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Process Hollowing',
+ id: 'T1093',
+ reference: 'https://attack.mitre.org/techniques/T1093',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Process Injection',
+ id: 'T1055',
+ reference: 'https://attack.mitre.org/techniques/T1055',
+ tactics: ['defense-evasion', 'privilege-escalation'],
+ },
+ {
+ name: 'Query Registry',
+ id: 'T1012',
+ reference: 'https://attack.mitre.org/techniques/T1012',
+ tactics: ['discovery'],
+ },
+ {
+ name: 'Rc.common',
+ id: 'T1163',
+ reference: 'https://attack.mitre.org/techniques/T1163',
+ tactics: ['persistence'],
+ },
+ {
+ name: 'Re-opened Applications',
+ id: 'T1164',
+ reference: 'https://attack.mitre.org/techniques/T1164',
+ tactics: ['persistence'],
+ },
+ {
+ name: 'Redundant Access',
+ id: 'T1108',
+ reference: 'https://attack.mitre.org/techniques/T1108',
+ tactics: ['defense-evasion', 'persistence'],
+ },
+ {
+ name: 'Registry Run Keys / Startup Folder',
+ id: 'T1060',
+ reference: 'https://attack.mitre.org/techniques/T1060',
+ tactics: ['persistence'],
+ },
+ {
+ name: 'Regsvcs/Regasm',
+ id: 'T1121',
+ reference: 'https://attack.mitre.org/techniques/T1121',
+ tactics: ['defense-evasion', 'execution'],
+ },
+ {
+ name: 'Regsvr32',
+ id: 'T1117',
+ reference: 'https://attack.mitre.org/techniques/T1117',
+ tactics: ['defense-evasion', 'execution'],
+ },
+ {
+ name: 'Remote Access Tools',
+ id: 'T1219',
+ reference: 'https://attack.mitre.org/techniques/T1219',
+ tactics: ['command-and-control'],
+ },
+ {
+ name: 'Remote Desktop Protocol',
+ id: 'T1076',
+ reference: 'https://attack.mitre.org/techniques/T1076',
+ tactics: ['lateral-movement'],
+ },
+ {
+ name: 'Remote File Copy',
+ id: 'T1105',
+ reference: 'https://attack.mitre.org/techniques/T1105',
+ tactics: ['command-and-control', 'lateral-movement'],
+ },
+ {
+ name: 'Remote Services',
+ id: 'T1021',
+ reference: 'https://attack.mitre.org/techniques/T1021',
+ tactics: ['lateral-movement'],
+ },
+ {
+ name: 'Remote System Discovery',
+ id: 'T1018',
+ reference: 'https://attack.mitre.org/techniques/T1018',
+ tactics: ['discovery'],
+ },
+ {
+ name: 'Replication Through Removable Media',
+ id: 'T1091',
+ reference: 'https://attack.mitre.org/techniques/T1091',
+ tactics: ['lateral-movement', 'initial-access'],
+ },
+ {
+ name: 'Resource Hijacking',
+ id: 'T1496',
+ reference: 'https://attack.mitre.org/techniques/T1496',
+ tactics: ['impact'],
+ },
+ {
+ name: 'Revert Cloud Instance',
+ id: 'T1536',
+ reference: 'https://attack.mitre.org/techniques/T1536',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Rootkit',
+ id: 'T1014',
+ reference: 'https://attack.mitre.org/techniques/T1014',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Rundll32',
+ id: 'T1085',
+ reference: 'https://attack.mitre.org/techniques/T1085',
+ tactics: ['defense-evasion', 'execution'],
+ },
+ {
+ name: 'Runtime Data Manipulation',
+ id: 'T1494',
+ reference: 'https://attack.mitre.org/techniques/T1494',
+ tactics: ['impact'],
+ },
+ {
+ name: 'SID-History Injection',
+ id: 'T1178',
+ reference: 'https://attack.mitre.org/techniques/T1178',
+ tactics: ['privilege-escalation'],
+ },
+ {
+ name: 'SIP and Trust Provider Hijacking',
+ id: 'T1198',
+ reference: 'https://attack.mitre.org/techniques/T1198',
+ tactics: ['defense-evasion', 'persistence'],
+ },
+ {
+ name: 'SSH Hijacking',
+ id: 'T1184',
+ reference: 'https://attack.mitre.org/techniques/T1184',
+ tactics: ['lateral-movement'],
+ },
+ {
+ name: 'Scheduled Task',
+ id: 'T1053',
+ reference: 'https://attack.mitre.org/techniques/T1053',
+ tactics: ['execution', 'persistence', 'privilege-escalation'],
+ },
+ {
+ name: 'Scheduled Transfer',
+ id: 'T1029',
+ reference: 'https://attack.mitre.org/techniques/T1029',
+ tactics: ['exfiltration'],
+ },
+ {
+ name: 'Screen Capture',
+ id: 'T1113',
+ reference: 'https://attack.mitre.org/techniques/T1113',
+ tactics: ['collection'],
+ },
+ {
+ name: 'Screensaver',
+ id: 'T1180',
+ reference: 'https://attack.mitre.org/techniques/T1180',
+ tactics: ['persistence'],
+ },
+ {
+ name: 'Scripting',
+ id: 'T1064',
+ reference: 'https://attack.mitre.org/techniques/T1064',
+ tactics: ['defense-evasion', 'execution'],
+ },
+ {
+ name: 'Security Software Discovery',
+ id: 'T1063',
+ reference: 'https://attack.mitre.org/techniques/T1063',
+ tactics: ['discovery'],
+ },
+ {
+ name: 'Security Support Provider',
+ id: 'T1101',
+ reference: 'https://attack.mitre.org/techniques/T1101',
+ tactics: ['persistence'],
+ },
+ {
+ name: 'Securityd Memory',
+ id: 'T1167',
+ reference: 'https://attack.mitre.org/techniques/T1167',
+ tactics: ['credential-access'],
+ },
+ {
+ name: 'Server Software Component',
+ id: 'T1505',
+ reference: 'https://attack.mitre.org/techniques/T1505',
+ tactics: ['persistence'],
+ },
+ {
+ name: 'Service Execution',
+ id: 'T1035',
+ reference: 'https://attack.mitre.org/techniques/T1035',
+ tactics: ['execution'],
+ },
+ {
+ name: 'Service Registry Permissions Weakness',
+ id: 'T1058',
+ reference: 'https://attack.mitre.org/techniques/T1058',
+ tactics: ['persistence', 'privilege-escalation'],
+ },
+ {
+ name: 'Service Stop',
+ id: 'T1489',
+ reference: 'https://attack.mitre.org/techniques/T1489',
+ tactics: ['impact'],
+ },
+ {
+ name: 'Setuid and Setgid',
+ id: 'T1166',
+ reference: 'https://attack.mitre.org/techniques/T1166',
+ tactics: ['privilege-escalation', 'persistence'],
+ },
+ {
+ name: 'Shared Webroot',
+ id: 'T1051',
+ reference: 'https://attack.mitre.org/techniques/T1051',
+ tactics: ['lateral-movement'],
+ },
+ {
+ name: 'Shortcut Modification',
+ id: 'T1023',
+ reference: 'https://attack.mitre.org/techniques/T1023',
+ tactics: ['persistence'],
+ },
+ {
+ name: 'Signed Binary Proxy Execution',
+ id: 'T1218',
+ reference: 'https://attack.mitre.org/techniques/T1218',
+ tactics: ['defense-evasion', 'execution'],
+ },
+ {
+ name: 'Signed Script Proxy Execution',
+ id: 'T1216',
+ reference: 'https://attack.mitre.org/techniques/T1216',
+ tactics: ['defense-evasion', 'execution'],
+ },
+ {
+ name: 'Software Discovery',
+ id: 'T1518',
+ reference: 'https://attack.mitre.org/techniques/T1518',
+ tactics: ['discovery'],
+ },
+ {
+ name: 'Software Packing',
+ id: 'T1045',
+ reference: 'https://attack.mitre.org/techniques/T1045',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Source',
+ id: 'T1153',
+ reference: 'https://attack.mitre.org/techniques/T1153',
+ tactics: ['execution'],
+ },
+ {
+ name: 'Space after Filename',
+ id: 'T1151',
+ reference: 'https://attack.mitre.org/techniques/T1151',
+ tactics: ['defense-evasion', 'execution'],
+ },
+ {
+ name: 'Spearphishing Attachment',
+ id: 'T1193',
+ reference: 'https://attack.mitre.org/techniques/T1193',
+ tactics: ['initial-access'],
+ },
+ {
+ name: 'Spearphishing Link',
+ id: 'T1192',
+ reference: 'https://attack.mitre.org/techniques/T1192',
+ tactics: ['initial-access'],
+ },
+ {
+ name: 'Spearphishing via Service',
+ id: 'T1194',
+ reference: 'https://attack.mitre.org/techniques/T1194',
+ tactics: ['initial-access'],
+ },
+ {
+ name: 'Standard Application Layer Protocol',
+ id: 'T1071',
+ reference: 'https://attack.mitre.org/techniques/T1071',
+ tactics: ['command-and-control'],
+ },
+ {
+ name: 'Standard Cryptographic Protocol',
+ id: 'T1032',
+ reference: 'https://attack.mitre.org/techniques/T1032',
+ tactics: ['command-and-control'],
+ },
+ {
+ name: 'Standard Non-Application Layer Protocol',
+ id: 'T1095',
+ reference: 'https://attack.mitre.org/techniques/T1095',
+ tactics: ['command-and-control'],
+ },
+ {
+ name: 'Startup Items',
+ id: 'T1165',
+ reference: 'https://attack.mitre.org/techniques/T1165',
+ tactics: ['persistence', 'privilege-escalation'],
+ },
+ {
+ name: 'Steal Application Access Token',
+ id: 'T1528',
+ reference: 'https://attack.mitre.org/techniques/T1528',
+ tactics: ['credential-access'],
+ },
+ {
+ name: 'Steal Web Session Cookie',
+ id: 'T1539',
+ reference: 'https://attack.mitre.org/techniques/T1539',
+ tactics: ['credential-access'],
+ },
+ {
+ name: 'Stored Data Manipulation',
+ id: 'T1492',
+ reference: 'https://attack.mitre.org/techniques/T1492',
+ tactics: ['impact'],
+ },
+ {
+ name: 'Sudo',
+ id: 'T1169',
+ reference: 'https://attack.mitre.org/techniques/T1169',
+ tactics: ['privilege-escalation'],
+ },
+ {
+ name: 'Sudo Caching',
+ id: 'T1206',
+ reference: 'https://attack.mitre.org/techniques/T1206',
+ tactics: ['privilege-escalation'],
+ },
+ {
+ name: 'Supply Chain Compromise',
+ id: 'T1195',
+ reference: 'https://attack.mitre.org/techniques/T1195',
+ tactics: ['initial-access'],
+ },
+ {
+ name: 'System Firmware',
+ id: 'T1019',
+ reference: 'https://attack.mitre.org/techniques/T1019',
+ tactics: ['persistence'],
+ },
+ {
+ name: 'System Information Discovery',
+ id: 'T1082',
+ reference: 'https://attack.mitre.org/techniques/T1082',
+ tactics: ['discovery'],
+ },
+ {
+ name: 'System Network Configuration Discovery',
+ id: 'T1016',
+ reference: 'https://attack.mitre.org/techniques/T1016',
+ tactics: ['discovery'],
+ },
+ {
+ name: 'System Network Connections Discovery',
+ id: 'T1049',
+ reference: 'https://attack.mitre.org/techniques/T1049',
+ tactics: ['discovery'],
+ },
+ {
+ name: 'System Owner/User Discovery',
+ id: 'T1033',
+ reference: 'https://attack.mitre.org/techniques/T1033',
+ tactics: ['discovery'],
+ },
+ {
+ name: 'System Service Discovery',
+ id: 'T1007',
+ reference: 'https://attack.mitre.org/techniques/T1007',
+ tactics: ['discovery'],
+ },
+ {
+ name: 'System Shutdown/Reboot',
+ id: 'T1529',
+ reference: 'https://attack.mitre.org/techniques/T1529',
+ tactics: ['impact'],
+ },
+ {
+ name: 'System Time Discovery',
+ id: 'T1124',
+ reference: 'https://attack.mitre.org/techniques/T1124',
+ tactics: ['discovery'],
+ },
+ {
+ name: 'Systemd Service',
+ id: 'T1501',
+ reference: 'https://attack.mitre.org/techniques/T1501',
+ tactics: ['persistence'],
+ },
+ {
+ name: 'Taint Shared Content',
+ id: 'T1080',
+ reference: 'https://attack.mitre.org/techniques/T1080',
+ tactics: ['lateral-movement'],
+ },
+ {
+ name: 'Template Injection',
+ id: 'T1221',
+ reference: 'https://attack.mitre.org/techniques/T1221',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Third-party Software',
+ id: 'T1072',
+ reference: 'https://attack.mitre.org/techniques/T1072',
+ tactics: ['execution', 'lateral-movement'],
+ },
+ {
+ name: 'Time Providers',
+ id: 'T1209',
+ reference: 'https://attack.mitre.org/techniques/T1209',
+ tactics: ['persistence'],
+ },
+ {
+ name: 'Timestomp',
+ id: 'T1099',
+ reference: 'https://attack.mitre.org/techniques/T1099',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'Transfer Data to Cloud Account',
+ id: 'T1537',
+ reference: 'https://attack.mitre.org/techniques/T1537',
+ tactics: ['exfiltration'],
+ },
+ {
+ name: 'Transmitted Data Manipulation',
+ id: 'T1493',
+ reference: 'https://attack.mitre.org/techniques/T1493',
+ tactics: ['impact'],
+ },
+ {
+ name: 'Trap',
+ id: 'T1154',
+ reference: 'https://attack.mitre.org/techniques/T1154',
+ tactics: ['execution', 'persistence'],
+ },
+ {
+ name: 'Trusted Developer Utilities',
+ id: 'T1127',
+ reference: 'https://attack.mitre.org/techniques/T1127',
+ tactics: ['defense-evasion', 'execution'],
+ },
+ {
+ name: 'Trusted Relationship',
+ id: 'T1199',
+ reference: 'https://attack.mitre.org/techniques/T1199',
+ tactics: ['initial-access'],
+ },
+ {
+ name: 'Two-Factor Authentication Interception',
+ id: 'T1111',
+ reference: 'https://attack.mitre.org/techniques/T1111',
+ tactics: ['credential-access'],
+ },
+ {
+ name: 'Uncommonly Used Port',
+ id: 'T1065',
+ reference: 'https://attack.mitre.org/techniques/T1065',
+ tactics: ['command-and-control'],
+ },
+ {
+ name: 'Unused/Unsupported Cloud Regions',
+ id: 'T1535',
+ reference: 'https://attack.mitre.org/techniques/T1535',
+ tactics: ['defense-evasion'],
+ },
+ {
+ name: 'User Execution',
+ id: 'T1204',
+ reference: 'https://attack.mitre.org/techniques/T1204',
+ tactics: ['execution'],
+ },
+ {
+ name: 'Valid Accounts',
+ id: 'T1078',
+ reference: 'https://attack.mitre.org/techniques/T1078',
+ tactics: ['defense-evasion', 'persistence', 'privilege-escalation', 'initial-access'],
+ },
+ {
+ name: 'Video Capture',
+ id: 'T1125',
+ reference: 'https://attack.mitre.org/techniques/T1125',
+ tactics: ['collection'],
+ },
+ {
+ name: 'Virtualization/Sandbox Evasion',
+ id: 'T1497',
+ reference: 'https://attack.mitre.org/techniques/T1497',
+ tactics: ['defense-evasion', 'discovery'],
+ },
+ {
+ name: 'Web Service',
+ id: 'T1102',
+ reference: 'https://attack.mitre.org/techniques/T1102',
+ tactics: ['command-and-control', 'defense-evasion'],
+ },
+ {
+ name: 'Web Session Cookie',
+ id: 'T1506',
+ reference: 'https://attack.mitre.org/techniques/T1506',
+ tactics: ['defense-evasion', 'lateral-movement'],
+ },
+ {
+ name: 'Web Shell',
+ id: 'T1100',
+ reference: 'https://attack.mitre.org/techniques/T1100',
+ tactics: ['persistence', 'privilege-escalation'],
+ },
+ {
+ name: 'Windows Admin Shares',
+ id: 'T1077',
+ reference: 'https://attack.mitre.org/techniques/T1077',
+ tactics: ['lateral-movement'],
+ },
+ {
+ name: 'Windows Management Instrumentation',
+ id: 'T1047',
+ reference: 'https://attack.mitre.org/techniques/T1047',
+ tactics: ['execution'],
+ },
+ {
+ name: 'Windows Management Instrumentation Event Subscription',
+ id: 'T1084',
+ reference: 'https://attack.mitre.org/techniques/T1084',
+ tactics: ['persistence'],
+ },
+ {
+ name: 'Windows Remote Management',
+ id: 'T1028',
+ reference: 'https://attack.mitre.org/techniques/T1028',
+ tactics: ['execution', 'lateral-movement'],
+ },
+ {
+ name: 'Winlogon Helper DLL',
+ id: 'T1004',
+ reference: 'https://attack.mitre.org/techniques/T1004',
+ tactics: ['persistence'],
+ },
+ {
+ name: 'XSL Script Processing',
+ id: 'T1220',
+ reference: 'https://attack.mitre.org/techniques/T1220',
+ tactics: ['defense-evasion', 'execution'],
+ },
+];
+
+export const techniquesOptions: MitreTechniquesOptions[] = [
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.bashProfileAndBashrcDescription',
+ { defaultMessage: '.bash_profile and .bashrc (T1156)' }
+ ),
+ id: 'T1156',
+ name: '.bash_profile and .bashrc',
+ reference: 'https://attack.mitre.org/techniques/T1156',
+ tactics: 'persistence',
+ value: 'bashProfileAndBashrc',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.accessTokenManipulationDescription',
+ { defaultMessage: 'Access Token Manipulation (T1134)' }
+ ),
+ id: 'T1134',
+ name: 'Access Token Manipulation',
+ reference: 'https://attack.mitre.org/techniques/T1134',
+ tactics: 'defense-evasion,privilege-escalation',
+ value: 'accessTokenManipulation',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.accessibilityFeaturesDescription',
+ { defaultMessage: 'Accessibility Features (T1015)' }
+ ),
+ id: 'T1015',
+ name: 'Accessibility Features',
+ reference: 'https://attack.mitre.org/techniques/T1015',
+ tactics: 'persistence,privilege-escalation',
+ value: 'accessibilityFeatures',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.accountAccessRemovalDescription',
+ { defaultMessage: 'Account Access Removal (T1531)' }
+ ),
+ id: 'T1531',
+ name: 'Account Access Removal',
+ reference: 'https://attack.mitre.org/techniques/T1531',
+ tactics: 'impact',
+ value: 'accountAccessRemoval',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.accountDiscoveryDescription',
+ { defaultMessage: 'Account Discovery (T1087)' }
+ ),
+ id: 'T1087',
+ name: 'Account Discovery',
+ reference: 'https://attack.mitre.org/techniques/T1087',
+ tactics: 'discovery',
+ value: 'accountDiscovery',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.accountManipulationDescription',
+ { defaultMessage: 'Account Manipulation (T1098)' }
+ ),
+ id: 'T1098',
+ name: 'Account Manipulation',
+ reference: 'https://attack.mitre.org/techniques/T1098',
+ tactics: 'credential-access,persistence',
+ value: 'accountManipulation',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.appCertDlLsDescription',
+ { defaultMessage: 'AppCert DLLs (T1182)' }
+ ),
+ id: 'T1182',
+ name: 'AppCert DLLs',
+ reference: 'https://attack.mitre.org/techniques/T1182',
+ tactics: 'persistence,privilege-escalation',
+ value: 'appCertDlLs',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.appInitDlLsDescription',
+ { defaultMessage: 'AppInit DLLs (T1103)' }
+ ),
+ id: 'T1103',
+ name: 'AppInit DLLs',
+ reference: 'https://attack.mitre.org/techniques/T1103',
+ tactics: 'persistence,privilege-escalation',
+ value: 'appInitDlLs',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.appleScriptDescription',
+ { defaultMessage: 'AppleScript (T1155)' }
+ ),
+ id: 'T1155',
+ name: 'AppleScript',
+ reference: 'https://attack.mitre.org/techniques/T1155',
+ tactics: 'execution,lateral-movement',
+ value: 'appleScript',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.applicationAccessTokenDescription',
+ { defaultMessage: 'Application Access Token (T1527)' }
+ ),
+ id: 'T1527',
+ name: 'Application Access Token',
+ reference: 'https://attack.mitre.org/techniques/T1527',
+ tactics: 'defense-evasion,lateral-movement',
+ value: 'applicationAccessToken',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.applicationDeploymentSoftwareDescription',
+ { defaultMessage: 'Application Deployment Software (T1017)' }
+ ),
+ id: 'T1017',
+ name: 'Application Deployment Software',
+ reference: 'https://attack.mitre.org/techniques/T1017',
+ tactics: 'lateral-movement',
+ value: 'applicationDeploymentSoftware',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.applicationShimmingDescription',
+ { defaultMessage: 'Application Shimming (T1138)' }
+ ),
+ id: 'T1138',
+ name: 'Application Shimming',
+ reference: 'https://attack.mitre.org/techniques/T1138',
+ tactics: 'persistence,privilege-escalation',
+ value: 'applicationShimming',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.applicationWindowDiscoveryDescription',
+ { defaultMessage: 'Application Window Discovery (T1010)' }
+ ),
+ id: 'T1010',
+ name: 'Application Window Discovery',
+ reference: 'https://attack.mitre.org/techniques/T1010',
+ tactics: 'discovery',
+ value: 'applicationWindowDiscovery',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.audioCaptureDescription',
+ { defaultMessage: 'Audio Capture (T1123)' }
+ ),
+ id: 'T1123',
+ name: 'Audio Capture',
+ reference: 'https://attack.mitre.org/techniques/T1123',
+ tactics: 'collection',
+ value: 'audioCapture',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.authenticationPackageDescription',
+ { defaultMessage: 'Authentication Package (T1131)' }
+ ),
+ id: 'T1131',
+ name: 'Authentication Package',
+ reference: 'https://attack.mitre.org/techniques/T1131',
+ tactics: 'persistence',
+ value: 'authenticationPackage',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.automatedCollectionDescription',
+ { defaultMessage: 'Automated Collection (T1119)' }
+ ),
+ id: 'T1119',
+ name: 'Automated Collection',
+ reference: 'https://attack.mitre.org/techniques/T1119',
+ tactics: 'collection',
+ value: 'automatedCollection',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.automatedExfiltrationDescription',
+ { defaultMessage: 'Automated Exfiltration (T1020)' }
+ ),
+ id: 'T1020',
+ name: 'Automated Exfiltration',
+ reference: 'https://attack.mitre.org/techniques/T1020',
+ tactics: 'exfiltration',
+ value: 'automatedExfiltration',
+ },
+ {
+ label: i18n.translate('xpack.siem.detectionEngine.mitreAttackTechniques.bitsJobsDescription', {
+ defaultMessage: 'BITS Jobs (T1197)',
+ }),
+ id: 'T1197',
+ name: 'BITS Jobs',
+ reference: 'https://attack.mitre.org/techniques/T1197',
+ tactics: 'defense-evasion,persistence',
+ value: 'bitsJobs',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.bashHistoryDescription',
+ { defaultMessage: 'Bash History (T1139)' }
+ ),
+ id: 'T1139',
+ name: 'Bash History',
+ reference: 'https://attack.mitre.org/techniques/T1139',
+ tactics: 'credential-access',
+ value: 'bashHistory',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.binaryPaddingDescription',
+ { defaultMessage: 'Binary Padding (T1009)' }
+ ),
+ id: 'T1009',
+ name: 'Binary Padding',
+ reference: 'https://attack.mitre.org/techniques/T1009',
+ tactics: 'defense-evasion',
+ value: 'binaryPadding',
+ },
+ {
+ label: i18n.translate('xpack.siem.detectionEngine.mitreAttackTechniques.bootkitDescription', {
+ defaultMessage: 'Bootkit (T1067)',
+ }),
+ id: 'T1067',
+ name: 'Bootkit',
+ reference: 'https://attack.mitre.org/techniques/T1067',
+ tactics: 'persistence',
+ value: 'bootkit',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.browserBookmarkDiscoveryDescription',
+ { defaultMessage: 'Browser Bookmark Discovery (T1217)' }
+ ),
+ id: 'T1217',
+ name: 'Browser Bookmark Discovery',
+ reference: 'https://attack.mitre.org/techniques/T1217',
+ tactics: 'discovery',
+ value: 'browserBookmarkDiscovery',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.browserExtensionsDescription',
+ { defaultMessage: 'Browser Extensions (T1176)' }
+ ),
+ id: 'T1176',
+ name: 'Browser Extensions',
+ reference: 'https://attack.mitre.org/techniques/T1176',
+ tactics: 'persistence',
+ value: 'browserExtensions',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.bruteForceDescription',
+ { defaultMessage: 'Brute Force (T1110)' }
+ ),
+ id: 'T1110',
+ name: 'Brute Force',
+ reference: 'https://attack.mitre.org/techniques/T1110',
+ tactics: 'credential-access',
+ value: 'bruteForce',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.bypassUserAccountControlDescription',
+ { defaultMessage: 'Bypass User Account Control (T1088)' }
+ ),
+ id: 'T1088',
+ name: 'Bypass User Account Control',
+ reference: 'https://attack.mitre.org/techniques/T1088',
+ tactics: 'defense-evasion,privilege-escalation',
+ value: 'bypassUserAccountControl',
+ },
+ {
+ label: i18n.translate('xpack.siem.detectionEngine.mitreAttackTechniques.cmstpDescription', {
+ defaultMessage: 'CMSTP (T1191)',
+ }),
+ id: 'T1191',
+ name: 'CMSTP',
+ reference: 'https://attack.mitre.org/techniques/T1191',
+ tactics: 'defense-evasion,execution',
+ value: 'cmstp',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.changeDefaultFileAssociationDescription',
+ { defaultMessage: 'Change Default File Association (T1042)' }
+ ),
+ id: 'T1042',
+ name: 'Change Default File Association',
+ reference: 'https://attack.mitre.org/techniques/T1042',
+ tactics: 'persistence',
+ value: 'changeDefaultFileAssociation',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.clearCommandHistoryDescription',
+ { defaultMessage: 'Clear Command History (T1146)' }
+ ),
+ id: 'T1146',
+ name: 'Clear Command History',
+ reference: 'https://attack.mitre.org/techniques/T1146',
+ tactics: 'defense-evasion',
+ value: 'clearCommandHistory',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.clipboardDataDescription',
+ { defaultMessage: 'Clipboard Data (T1115)' }
+ ),
+ id: 'T1115',
+ name: 'Clipboard Data',
+ reference: 'https://attack.mitre.org/techniques/T1115',
+ tactics: 'collection',
+ value: 'clipboardData',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.cloudInstanceMetadataApiDescription',
+ { defaultMessage: 'Cloud Instance Metadata API (T1522)' }
+ ),
+ id: 'T1522',
+ name: 'Cloud Instance Metadata API',
+ reference: 'https://attack.mitre.org/techniques/T1522',
+ tactics: 'credential-access',
+ value: 'cloudInstanceMetadataApi',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.cloudServiceDashboardDescription',
+ { defaultMessage: 'Cloud Service Dashboard (T1538)' }
+ ),
+ id: 'T1538',
+ name: 'Cloud Service Dashboard',
+ reference: 'https://attack.mitre.org/techniques/T1538',
+ tactics: 'discovery',
+ value: 'cloudServiceDashboard',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.cloudServiceDiscoveryDescription',
+ { defaultMessage: 'Cloud Service Discovery (T1526)' }
+ ),
+ id: 'T1526',
+ name: 'Cloud Service Discovery',
+ reference: 'https://attack.mitre.org/techniques/T1526',
+ tactics: 'discovery',
+ value: 'cloudServiceDiscovery',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.codeSigningDescription',
+ { defaultMessage: 'Code Signing (T1116)' }
+ ),
+ id: 'T1116',
+ name: 'Code Signing',
+ reference: 'https://attack.mitre.org/techniques/T1116',
+ tactics: 'defense-evasion',
+ value: 'codeSigning',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.commandLineInterfaceDescription',
+ { defaultMessage: 'Command-Line Interface (T1059)' }
+ ),
+ id: 'T1059',
+ name: 'Command-Line Interface',
+ reference: 'https://attack.mitre.org/techniques/T1059',
+ tactics: 'execution',
+ value: 'commandLineInterface',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.commonlyUsedPortDescription',
+ { defaultMessage: 'Commonly Used Port (T1043)' }
+ ),
+ id: 'T1043',
+ name: 'Commonly Used Port',
+ reference: 'https://attack.mitre.org/techniques/T1043',
+ tactics: 'command-and-control',
+ value: 'commonlyUsedPort',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.communicationThroughRemovableMediaDescription',
+ { defaultMessage: 'Communication Through Removable Media (T1092)' }
+ ),
+ id: 'T1092',
+ name: 'Communication Through Removable Media',
+ reference: 'https://attack.mitre.org/techniques/T1092',
+ tactics: 'command-and-control',
+ value: 'communicationThroughRemovableMedia',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.compileAfterDeliveryDescription',
+ { defaultMessage: 'Compile After Delivery (T1500)' }
+ ),
+ id: 'T1500',
+ name: 'Compile After Delivery',
+ reference: 'https://attack.mitre.org/techniques/T1500',
+ tactics: 'defense-evasion',
+ value: 'compileAfterDelivery',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.compiledHtmlFileDescription',
+ { defaultMessage: 'Compiled HTML File (T1223)' }
+ ),
+ id: 'T1223',
+ name: 'Compiled HTML File',
+ reference: 'https://attack.mitre.org/techniques/T1223',
+ tactics: 'defense-evasion,execution',
+ value: 'compiledHtmlFile',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.componentFirmwareDescription',
+ { defaultMessage: 'Component Firmware (T1109)' }
+ ),
+ id: 'T1109',
+ name: 'Component Firmware',
+ reference: 'https://attack.mitre.org/techniques/T1109',
+ tactics: 'defense-evasion,persistence',
+ value: 'componentFirmware',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.componentObjectModelHijackingDescription',
+ { defaultMessage: 'Component Object Model Hijacking (T1122)' }
+ ),
+ id: 'T1122',
+ name: 'Component Object Model Hijacking',
+ reference: 'https://attack.mitre.org/techniques/T1122',
+ tactics: 'defense-evasion,persistence',
+ value: 'componentObjectModelHijacking',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.componentObjectModelAndDistributedComDescription',
+ { defaultMessage: 'Component Object Model and Distributed COM (T1175)' }
+ ),
+ id: 'T1175',
+ name: 'Component Object Model and Distributed COM',
+ reference: 'https://attack.mitre.org/techniques/T1175',
+ tactics: 'lateral-movement,execution',
+ value: 'componentObjectModelAndDistributedCom',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.connectionProxyDescription',
+ { defaultMessage: 'Connection Proxy (T1090)' }
+ ),
+ id: 'T1090',
+ name: 'Connection Proxy',
+ reference: 'https://attack.mitre.org/techniques/T1090',
+ tactics: 'command-and-control,defense-evasion',
+ value: 'connectionProxy',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.controlPanelItemsDescription',
+ { defaultMessage: 'Control Panel Items (T1196)' }
+ ),
+ id: 'T1196',
+ name: 'Control Panel Items',
+ reference: 'https://attack.mitre.org/techniques/T1196',
+ tactics: 'defense-evasion,execution',
+ value: 'controlPanelItems',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.createAccountDescription',
+ { defaultMessage: 'Create Account (T1136)' }
+ ),
+ id: 'T1136',
+ name: 'Create Account',
+ reference: 'https://attack.mitre.org/techniques/T1136',
+ tactics: 'persistence',
+ value: 'createAccount',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.credentialDumpingDescription',
+ { defaultMessage: 'Credential Dumping (T1003)' }
+ ),
+ id: 'T1003',
+ name: 'Credential Dumping',
+ reference: 'https://attack.mitre.org/techniques/T1003',
+ tactics: 'credential-access',
+ value: 'credentialDumping',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.credentialsFromWebBrowsersDescription',
+ { defaultMessage: 'Credentials from Web Browsers (T1503)' }
+ ),
+ id: 'T1503',
+ name: 'Credentials from Web Browsers',
+ reference: 'https://attack.mitre.org/techniques/T1503',
+ tactics: 'credential-access',
+ value: 'credentialsFromWebBrowsers',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.credentialsInFilesDescription',
+ { defaultMessage: 'Credentials in Files (T1081)' }
+ ),
+ id: 'T1081',
+ name: 'Credentials in Files',
+ reference: 'https://attack.mitre.org/techniques/T1081',
+ tactics: 'credential-access',
+ value: 'credentialsInFiles',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.credentialsInRegistryDescription',
+ { defaultMessage: 'Credentials in Registry (T1214)' }
+ ),
+ id: 'T1214',
+ name: 'Credentials in Registry',
+ reference: 'https://attack.mitre.org/techniques/T1214',
+ tactics: 'credential-access',
+ value: 'credentialsInRegistry',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.customCommandAndControlProtocolDescription',
+ { defaultMessage: 'Custom Command and Control Protocol (T1094)' }
+ ),
+ id: 'T1094',
+ name: 'Custom Command and Control Protocol',
+ reference: 'https://attack.mitre.org/techniques/T1094',
+ tactics: 'command-and-control',
+ value: 'customCommandAndControlProtocol',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.customCryptographicProtocolDescription',
+ { defaultMessage: 'Custom Cryptographic Protocol (T1024)' }
+ ),
+ id: 'T1024',
+ name: 'Custom Cryptographic Protocol',
+ reference: 'https://attack.mitre.org/techniques/T1024',
+ tactics: 'command-and-control',
+ value: 'customCryptographicProtocol',
+ },
+ {
+ label: i18n.translate('xpack.siem.detectionEngine.mitreAttackTechniques.dcShadowDescription', {
+ defaultMessage: 'DCShadow (T1207)',
+ }),
+ id: 'T1207',
+ name: 'DCShadow',
+ reference: 'https://attack.mitre.org/techniques/T1207',
+ tactics: 'defense-evasion',
+ value: 'dcShadow',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.dllSearchOrderHijackingDescription',
+ { defaultMessage: 'DLL Search Order Hijacking (T1038)' }
+ ),
+ id: 'T1038',
+ name: 'DLL Search Order Hijacking',
+ reference: 'https://attack.mitre.org/techniques/T1038',
+ tactics: 'persistence,privilege-escalation,defense-evasion',
+ value: 'dllSearchOrderHijacking',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.dllSideLoadingDescription',
+ { defaultMessage: 'DLL Side-Loading (T1073)' }
+ ),
+ id: 'T1073',
+ name: 'DLL Side-Loading',
+ reference: 'https://attack.mitre.org/techniques/T1073',
+ tactics: 'defense-evasion',
+ value: 'dllSideLoading',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.dataCompressedDescription',
+ { defaultMessage: 'Data Compressed (T1002)' }
+ ),
+ id: 'T1002',
+ name: 'Data Compressed',
+ reference: 'https://attack.mitre.org/techniques/T1002',
+ tactics: 'exfiltration',
+ value: 'dataCompressed',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.dataDestructionDescription',
+ { defaultMessage: 'Data Destruction (T1485)' }
+ ),
+ id: 'T1485',
+ name: 'Data Destruction',
+ reference: 'https://attack.mitre.org/techniques/T1485',
+ tactics: 'impact',
+ value: 'dataDestruction',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.dataEncodingDescription',
+ { defaultMessage: 'Data Encoding (T1132)' }
+ ),
+ id: 'T1132',
+ name: 'Data Encoding',
+ reference: 'https://attack.mitre.org/techniques/T1132',
+ tactics: 'command-and-control',
+ value: 'dataEncoding',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.dataEncryptedDescription',
+ { defaultMessage: 'Data Encrypted (T1022)' }
+ ),
+ id: 'T1022',
+ name: 'Data Encrypted',
+ reference: 'https://attack.mitre.org/techniques/T1022',
+ tactics: 'exfiltration',
+ value: 'dataEncrypted',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.dataEncryptedForImpactDescription',
+ { defaultMessage: 'Data Encrypted for Impact (T1486)' }
+ ),
+ id: 'T1486',
+ name: 'Data Encrypted for Impact',
+ reference: 'https://attack.mitre.org/techniques/T1486',
+ tactics: 'impact',
+ value: 'dataEncryptedForImpact',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.dataObfuscationDescription',
+ { defaultMessage: 'Data Obfuscation (T1001)' }
+ ),
+ id: 'T1001',
+ name: 'Data Obfuscation',
+ reference: 'https://attack.mitre.org/techniques/T1001',
+ tactics: 'command-and-control',
+ value: 'dataObfuscation',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.dataStagedDescription',
+ { defaultMessage: 'Data Staged (T1074)' }
+ ),
+ id: 'T1074',
+ name: 'Data Staged',
+ reference: 'https://attack.mitre.org/techniques/T1074',
+ tactics: 'collection',
+ value: 'dataStaged',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.dataTransferSizeLimitsDescription',
+ { defaultMessage: 'Data Transfer Size Limits (T1030)' }
+ ),
+ id: 'T1030',
+ name: 'Data Transfer Size Limits',
+ reference: 'https://attack.mitre.org/techniques/T1030',
+ tactics: 'exfiltration',
+ value: 'dataTransferSizeLimits',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.dataFromCloudStorageObjectDescription',
+ { defaultMessage: 'Data from Cloud Storage Object (T1530)' }
+ ),
+ id: 'T1530',
+ name: 'Data from Cloud Storage Object',
+ reference: 'https://attack.mitre.org/techniques/T1530',
+ tactics: 'collection',
+ value: 'dataFromCloudStorageObject',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.dataFromInformationRepositoriesDescription',
+ { defaultMessage: 'Data from Information Repositories (T1213)' }
+ ),
+ id: 'T1213',
+ name: 'Data from Information Repositories',
+ reference: 'https://attack.mitre.org/techniques/T1213',
+ tactics: 'collection',
+ value: 'dataFromInformationRepositories',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.dataFromLocalSystemDescription',
+ { defaultMessage: 'Data from Local System (T1005)' }
+ ),
+ id: 'T1005',
+ name: 'Data from Local System',
+ reference: 'https://attack.mitre.org/techniques/T1005',
+ tactics: 'collection',
+ value: 'dataFromLocalSystem',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.dataFromNetworkSharedDriveDescription',
+ { defaultMessage: 'Data from Network Shared Drive (T1039)' }
+ ),
+ id: 'T1039',
+ name: 'Data from Network Shared Drive',
+ reference: 'https://attack.mitre.org/techniques/T1039',
+ tactics: 'collection',
+ value: 'dataFromNetworkSharedDrive',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.dataFromRemovableMediaDescription',
+ { defaultMessage: 'Data from Removable Media (T1025)' }
+ ),
+ id: 'T1025',
+ name: 'Data from Removable Media',
+ reference: 'https://attack.mitre.org/techniques/T1025',
+ tactics: 'collection',
+ value: 'dataFromRemovableMedia',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.defacementDescription',
+ { defaultMessage: 'Defacement (T1491)' }
+ ),
+ id: 'T1491',
+ name: 'Defacement',
+ reference: 'https://attack.mitre.org/techniques/T1491',
+ tactics: 'impact',
+ value: 'defacement',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.deobfuscateDecodeFilesOrInformationDescription',
+ { defaultMessage: 'Deobfuscate/Decode Files or Information (T1140)' }
+ ),
+ id: 'T1140',
+ name: 'Deobfuscate/Decode Files or Information',
+ reference: 'https://attack.mitre.org/techniques/T1140',
+ tactics: 'defense-evasion',
+ value: 'deobfuscateDecodeFilesOrInformation',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.disablingSecurityToolsDescription',
+ { defaultMessage: 'Disabling Security Tools (T1089)' }
+ ),
+ id: 'T1089',
+ name: 'Disabling Security Tools',
+ reference: 'https://attack.mitre.org/techniques/T1089',
+ tactics: 'defense-evasion',
+ value: 'disablingSecurityTools',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.diskContentWipeDescription',
+ { defaultMessage: 'Disk Content Wipe (T1488)' }
+ ),
+ id: 'T1488',
+ name: 'Disk Content Wipe',
+ reference: 'https://attack.mitre.org/techniques/T1488',
+ tactics: 'impact',
+ value: 'diskContentWipe',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.diskStructureWipeDescription',
+ { defaultMessage: 'Disk Structure Wipe (T1487)' }
+ ),
+ id: 'T1487',
+ name: 'Disk Structure Wipe',
+ reference: 'https://attack.mitre.org/techniques/T1487',
+ tactics: 'impact',
+ value: 'diskStructureWipe',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.domainFrontingDescription',
+ { defaultMessage: 'Domain Fronting (T1172)' }
+ ),
+ id: 'T1172',
+ name: 'Domain Fronting',
+ reference: 'https://attack.mitre.org/techniques/T1172',
+ tactics: 'command-and-control',
+ value: 'domainFronting',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.domainGenerationAlgorithmsDescription',
+ { defaultMessage: 'Domain Generation Algorithms (T1483)' }
+ ),
+ id: 'T1483',
+ name: 'Domain Generation Algorithms',
+ reference: 'https://attack.mitre.org/techniques/T1483',
+ tactics: 'command-and-control',
+ value: 'domainGenerationAlgorithms',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.domainTrustDiscoveryDescription',
+ { defaultMessage: 'Domain Trust Discovery (T1482)' }
+ ),
+ id: 'T1482',
+ name: 'Domain Trust Discovery',
+ reference: 'https://attack.mitre.org/techniques/T1482',
+ tactics: 'discovery',
+ value: 'domainTrustDiscovery',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.driveByCompromiseDescription',
+ { defaultMessage: 'Drive-by Compromise (T1189)' }
+ ),
+ id: 'T1189',
+ name: 'Drive-by Compromise',
+ reference: 'https://attack.mitre.org/techniques/T1189',
+ tactics: 'initial-access',
+ value: 'driveByCompromise',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.dylibHijackingDescription',
+ { defaultMessage: 'Dylib Hijacking (T1157)' }
+ ),
+ id: 'T1157',
+ name: 'Dylib Hijacking',
+ reference: 'https://attack.mitre.org/techniques/T1157',
+ tactics: 'persistence,privilege-escalation',
+ value: 'dylibHijacking',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.dynamicDataExchangeDescription',
+ { defaultMessage: 'Dynamic Data Exchange (T1173)' }
+ ),
+ id: 'T1173',
+ name: 'Dynamic Data Exchange',
+ reference: 'https://attack.mitre.org/techniques/T1173',
+ tactics: 'execution',
+ value: 'dynamicDataExchange',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.elevatedExecutionWithPromptDescription',
+ { defaultMessage: 'Elevated Execution with Prompt (T1514)' }
+ ),
+ id: 'T1514',
+ name: 'Elevated Execution with Prompt',
+ reference: 'https://attack.mitre.org/techniques/T1514',
+ tactics: 'privilege-escalation',
+ value: 'elevatedExecutionWithPrompt',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.emailCollectionDescription',
+ { defaultMessage: 'Email Collection (T1114)' }
+ ),
+ id: 'T1114',
+ name: 'Email Collection',
+ reference: 'https://attack.mitre.org/techniques/T1114',
+ tactics: 'collection',
+ value: 'emailCollection',
+ },
+ {
+ label: i18n.translate('xpack.siem.detectionEngine.mitreAttackTechniques.emondDescription', {
+ defaultMessage: 'Emond (T1519)',
+ }),
+ id: 'T1519',
+ name: 'Emond',
+ reference: 'https://attack.mitre.org/techniques/T1519',
+ tactics: 'persistence,privilege-escalation',
+ value: 'emond',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.endpointDenialOfServiceDescription',
+ { defaultMessage: 'Endpoint Denial of Service (T1499)' }
+ ),
+ id: 'T1499',
+ name: 'Endpoint Denial of Service',
+ reference: 'https://attack.mitre.org/techniques/T1499',
+ tactics: 'impact',
+ value: 'endpointDenialOfService',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.executionGuardrailsDescription',
+ { defaultMessage: 'Execution Guardrails (T1480)' }
+ ),
+ id: 'T1480',
+ name: 'Execution Guardrails',
+ reference: 'https://attack.mitre.org/techniques/T1480',
+ tactics: 'defense-evasion',
+ value: 'executionGuardrails',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.executionThroughApiDescription',
+ { defaultMessage: 'Execution through API (T1106)' }
+ ),
+ id: 'T1106',
+ name: 'Execution through API',
+ reference: 'https://attack.mitre.org/techniques/T1106',
+ tactics: 'execution',
+ value: 'executionThroughApi',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.executionThroughModuleLoadDescription',
+ { defaultMessage: 'Execution through Module Load (T1129)' }
+ ),
+ id: 'T1129',
+ name: 'Execution through Module Load',
+ reference: 'https://attack.mitre.org/techniques/T1129',
+ tactics: 'execution',
+ value: 'executionThroughModuleLoad',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.exfiltrationOverAlternativeProtocolDescription',
+ { defaultMessage: 'Exfiltration Over Alternative Protocol (T1048)' }
+ ),
+ id: 'T1048',
+ name: 'Exfiltration Over Alternative Protocol',
+ reference: 'https://attack.mitre.org/techniques/T1048',
+ tactics: 'exfiltration',
+ value: 'exfiltrationOverAlternativeProtocol',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.exfiltrationOverCommandAndControlChannelDescription',
+ { defaultMessage: 'Exfiltration Over Command and Control Channel (T1041)' }
+ ),
+ id: 'T1041',
+ name: 'Exfiltration Over Command and Control Channel',
+ reference: 'https://attack.mitre.org/techniques/T1041',
+ tactics: 'exfiltration',
+ value: 'exfiltrationOverCommandAndControlChannel',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.exfiltrationOverOtherNetworkMediumDescription',
+ { defaultMessage: 'Exfiltration Over Other Network Medium (T1011)' }
+ ),
+ id: 'T1011',
+ name: 'Exfiltration Over Other Network Medium',
+ reference: 'https://attack.mitre.org/techniques/T1011',
+ tactics: 'exfiltration',
+ value: 'exfiltrationOverOtherNetworkMedium',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.exfiltrationOverPhysicalMediumDescription',
+ { defaultMessage: 'Exfiltration Over Physical Medium (T1052)' }
+ ),
+ id: 'T1052',
+ name: 'Exfiltration Over Physical Medium',
+ reference: 'https://attack.mitre.org/techniques/T1052',
+ tactics: 'exfiltration',
+ value: 'exfiltrationOverPhysicalMedium',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.exploitPublicFacingApplicationDescription',
+ { defaultMessage: 'Exploit Public-Facing Application (T1190)' }
+ ),
+ id: 'T1190',
+ name: 'Exploit Public-Facing Application',
+ reference: 'https://attack.mitre.org/techniques/T1190',
+ tactics: 'initial-access',
+ value: 'exploitPublicFacingApplication',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.exploitationForClientExecutionDescription',
+ { defaultMessage: 'Exploitation for Client Execution (T1203)' }
+ ),
+ id: 'T1203',
+ name: 'Exploitation for Client Execution',
+ reference: 'https://attack.mitre.org/techniques/T1203',
+ tactics: 'execution',
+ value: 'exploitationForClientExecution',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.exploitationForCredentialAccessDescription',
+ { defaultMessage: 'Exploitation for Credential Access (T1212)' }
+ ),
+ id: 'T1212',
+ name: 'Exploitation for Credential Access',
+ reference: 'https://attack.mitre.org/techniques/T1212',
+ tactics: 'credential-access',
+ value: 'exploitationForCredentialAccess',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.exploitationForDefenseEvasionDescription',
+ { defaultMessage: 'Exploitation for Defense Evasion (T1211)' }
+ ),
+ id: 'T1211',
+ name: 'Exploitation for Defense Evasion',
+ reference: 'https://attack.mitre.org/techniques/T1211',
+ tactics: 'defense-evasion',
+ value: 'exploitationForDefenseEvasion',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.exploitationForPrivilegeEscalationDescription',
+ { defaultMessage: 'Exploitation for Privilege Escalation (T1068)' }
+ ),
+ id: 'T1068',
+ name: 'Exploitation for Privilege Escalation',
+ reference: 'https://attack.mitre.org/techniques/T1068',
+ tactics: 'privilege-escalation',
+ value: 'exploitationForPrivilegeEscalation',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.exploitationOfRemoteServicesDescription',
+ { defaultMessage: 'Exploitation of Remote Services (T1210)' }
+ ),
+ id: 'T1210',
+ name: 'Exploitation of Remote Services',
+ reference: 'https://attack.mitre.org/techniques/T1210',
+ tactics: 'lateral-movement',
+ value: 'exploitationOfRemoteServices',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.externalRemoteServicesDescription',
+ { defaultMessage: 'External Remote Services (T1133)' }
+ ),
+ id: 'T1133',
+ name: 'External Remote Services',
+ reference: 'https://attack.mitre.org/techniques/T1133',
+ tactics: 'persistence,initial-access',
+ value: 'externalRemoteServices',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.extraWindowMemoryInjectionDescription',
+ { defaultMessage: 'Extra Window Memory Injection (T1181)' }
+ ),
+ id: 'T1181',
+ name: 'Extra Window Memory Injection',
+ reference: 'https://attack.mitre.org/techniques/T1181',
+ tactics: 'defense-evasion,privilege-escalation',
+ value: 'extraWindowMemoryInjection',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.fallbackChannelsDescription',
+ { defaultMessage: 'Fallback Channels (T1008)' }
+ ),
+ id: 'T1008',
+ name: 'Fallback Channels',
+ reference: 'https://attack.mitre.org/techniques/T1008',
+ tactics: 'command-and-control',
+ value: 'fallbackChannels',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.fileDeletionDescription',
+ { defaultMessage: 'File Deletion (T1107)' }
+ ),
+ id: 'T1107',
+ name: 'File Deletion',
+ reference: 'https://attack.mitre.org/techniques/T1107',
+ tactics: 'defense-evasion',
+ value: 'fileDeletion',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.fileSystemLogicalOffsetsDescription',
+ { defaultMessage: 'File System Logical Offsets (T1006)' }
+ ),
+ id: 'T1006',
+ name: 'File System Logical Offsets',
+ reference: 'https://attack.mitre.org/techniques/T1006',
+ tactics: 'defense-evasion',
+ value: 'fileSystemLogicalOffsets',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.fileSystemPermissionsWeaknessDescription',
+ { defaultMessage: 'File System Permissions Weakness (T1044)' }
+ ),
+ id: 'T1044',
+ name: 'File System Permissions Weakness',
+ reference: 'https://attack.mitre.org/techniques/T1044',
+ tactics: 'persistence,privilege-escalation',
+ value: 'fileSystemPermissionsWeakness',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.fileAndDirectoryDiscoveryDescription',
+ { defaultMessage: 'File and Directory Discovery (T1083)' }
+ ),
+ id: 'T1083',
+ name: 'File and Directory Discovery',
+ reference: 'https://attack.mitre.org/techniques/T1083',
+ tactics: 'discovery',
+ value: 'fileAndDirectoryDiscovery',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.fileAndDirectoryPermissionsModificationDescription',
+ { defaultMessage: 'File and Directory Permissions Modification (T1222)' }
+ ),
+ id: 'T1222',
+ name: 'File and Directory Permissions Modification',
+ reference: 'https://attack.mitre.org/techniques/T1222',
+ tactics: 'defense-evasion',
+ value: 'fileAndDirectoryPermissionsModification',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.firmwareCorruptionDescription',
+ { defaultMessage: 'Firmware Corruption (T1495)' }
+ ),
+ id: 'T1495',
+ name: 'Firmware Corruption',
+ reference: 'https://attack.mitre.org/techniques/T1495',
+ tactics: 'impact',
+ value: 'firmwareCorruption',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.forcedAuthenticationDescription',
+ { defaultMessage: 'Forced Authentication (T1187)' }
+ ),
+ id: 'T1187',
+ name: 'Forced Authentication',
+ reference: 'https://attack.mitre.org/techniques/T1187',
+ tactics: 'credential-access',
+ value: 'forcedAuthentication',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.gatekeeperBypassDescription',
+ { defaultMessage: 'Gatekeeper Bypass (T1144)' }
+ ),
+ id: 'T1144',
+ name: 'Gatekeeper Bypass',
+ reference: 'https://attack.mitre.org/techniques/T1144',
+ tactics: 'defense-evasion',
+ value: 'gatekeeperBypass',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.graphicalUserInterfaceDescription',
+ { defaultMessage: 'Graphical User Interface (T1061)' }
+ ),
+ id: 'T1061',
+ name: 'Graphical User Interface',
+ reference: 'https://attack.mitre.org/techniques/T1061',
+ tactics: 'execution',
+ value: 'graphicalUserInterface',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.groupPolicyModificationDescription',
+ { defaultMessage: 'Group Policy Modification (T1484)' }
+ ),
+ id: 'T1484',
+ name: 'Group Policy Modification',
+ reference: 'https://attack.mitre.org/techniques/T1484',
+ tactics: 'defense-evasion',
+ value: 'groupPolicyModification',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.histcontrolDescription',
+ { defaultMessage: 'HISTCONTROL (T1148)' }
+ ),
+ id: 'T1148',
+ name: 'HISTCONTROL',
+ reference: 'https://attack.mitre.org/techniques/T1148',
+ tactics: 'defense-evasion',
+ value: 'histcontrol',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.hardwareAdditionsDescription',
+ { defaultMessage: 'Hardware Additions (T1200)' }
+ ),
+ id: 'T1200',
+ name: 'Hardware Additions',
+ reference: 'https://attack.mitre.org/techniques/T1200',
+ tactics: 'initial-access',
+ value: 'hardwareAdditions',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.hiddenFilesAndDirectoriesDescription',
+ { defaultMessage: 'Hidden Files and Directories (T1158)' }
+ ),
+ id: 'T1158',
+ name: 'Hidden Files and Directories',
+ reference: 'https://attack.mitre.org/techniques/T1158',
+ tactics: 'defense-evasion,persistence',
+ value: 'hiddenFilesAndDirectories',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.hiddenUsersDescription',
+ { defaultMessage: 'Hidden Users (T1147)' }
+ ),
+ id: 'T1147',
+ name: 'Hidden Users',
+ reference: 'https://attack.mitre.org/techniques/T1147',
+ tactics: 'defense-evasion',
+ value: 'hiddenUsers',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.hiddenWindowDescription',
+ { defaultMessage: 'Hidden Window (T1143)' }
+ ),
+ id: 'T1143',
+ name: 'Hidden Window',
+ reference: 'https://attack.mitre.org/techniques/T1143',
+ tactics: 'defense-evasion',
+ value: 'hiddenWindow',
+ },
+ {
+ label: i18n.translate('xpack.siem.detectionEngine.mitreAttackTechniques.hookingDescription', {
+ defaultMessage: 'Hooking (T1179)',
+ }),
+ id: 'T1179',
+ name: 'Hooking',
+ reference: 'https://attack.mitre.org/techniques/T1179',
+ tactics: 'persistence,privilege-escalation,credential-access',
+ value: 'hooking',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.hypervisorDescription',
+ { defaultMessage: 'Hypervisor (T1062)' }
+ ),
+ id: 'T1062',
+ name: 'Hypervisor',
+ reference: 'https://attack.mitre.org/techniques/T1062',
+ tactics: 'persistence',
+ value: 'hypervisor',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.imageFileExecutionOptionsInjectionDescription',
+ { defaultMessage: 'Image File Execution Options Injection (T1183)' }
+ ),
+ id: 'T1183',
+ name: 'Image File Execution Options Injection',
+ reference: 'https://attack.mitre.org/techniques/T1183',
+ tactics: 'privilege-escalation,persistence,defense-evasion',
+ value: 'imageFileExecutionOptionsInjection',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.implantContainerImageDescription',
+ { defaultMessage: 'Implant Container Image (T1525)' }
+ ),
+ id: 'T1525',
+ name: 'Implant Container Image',
+ reference: 'https://attack.mitre.org/techniques/T1525',
+ tactics: 'persistence',
+ value: 'implantContainerImage',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.indicatorBlockingDescription',
+ { defaultMessage: 'Indicator Blocking (T1054)' }
+ ),
+ id: 'T1054',
+ name: 'Indicator Blocking',
+ reference: 'https://attack.mitre.org/techniques/T1054',
+ tactics: 'defense-evasion',
+ value: 'indicatorBlocking',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.indicatorRemovalFromToolsDescription',
+ { defaultMessage: 'Indicator Removal from Tools (T1066)' }
+ ),
+ id: 'T1066',
+ name: 'Indicator Removal from Tools',
+ reference: 'https://attack.mitre.org/techniques/T1066',
+ tactics: 'defense-evasion',
+ value: 'indicatorRemovalFromTools',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.indicatorRemovalOnHostDescription',
+ { defaultMessage: 'Indicator Removal on Host (T1070)' }
+ ),
+ id: 'T1070',
+ name: 'Indicator Removal on Host',
+ reference: 'https://attack.mitre.org/techniques/T1070',
+ tactics: 'defense-evasion',
+ value: 'indicatorRemovalOnHost',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.indirectCommandExecutionDescription',
+ { defaultMessage: 'Indirect Command Execution (T1202)' }
+ ),
+ id: 'T1202',
+ name: 'Indirect Command Execution',
+ reference: 'https://attack.mitre.org/techniques/T1202',
+ tactics: 'defense-evasion',
+ value: 'indirectCommandExecution',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.inhibitSystemRecoveryDescription',
+ { defaultMessage: 'Inhibit System Recovery (T1490)' }
+ ),
+ id: 'T1490',
+ name: 'Inhibit System Recovery',
+ reference: 'https://attack.mitre.org/techniques/T1490',
+ tactics: 'impact',
+ value: 'inhibitSystemRecovery',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.inputCaptureDescription',
+ { defaultMessage: 'Input Capture (T1056)' }
+ ),
+ id: 'T1056',
+ name: 'Input Capture',
+ reference: 'https://attack.mitre.org/techniques/T1056',
+ tactics: 'collection,credential-access',
+ value: 'inputCapture',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.inputPromptDescription',
+ { defaultMessage: 'Input Prompt (T1141)' }
+ ),
+ id: 'T1141',
+ name: 'Input Prompt',
+ reference: 'https://attack.mitre.org/techniques/T1141',
+ tactics: 'credential-access',
+ value: 'inputPrompt',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.installRootCertificateDescription',
+ { defaultMessage: 'Install Root Certificate (T1130)' }
+ ),
+ id: 'T1130',
+ name: 'Install Root Certificate',
+ reference: 'https://attack.mitre.org/techniques/T1130',
+ tactics: 'defense-evasion',
+ value: 'installRootCertificate',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.installUtilDescription',
+ { defaultMessage: 'InstallUtil (T1118)' }
+ ),
+ id: 'T1118',
+ name: 'InstallUtil',
+ reference: 'https://attack.mitre.org/techniques/T1118',
+ tactics: 'defense-evasion,execution',
+ value: 'installUtil',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.internalSpearphishingDescription',
+ { defaultMessage: 'Internal Spearphishing (T1534)' }
+ ),
+ id: 'T1534',
+ name: 'Internal Spearphishing',
+ reference: 'https://attack.mitre.org/techniques/T1534',
+ tactics: 'lateral-movement',
+ value: 'internalSpearphishing',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.kerberoastingDescription',
+ { defaultMessage: 'Kerberoasting (T1208)' }
+ ),
+ id: 'T1208',
+ name: 'Kerberoasting',
+ reference: 'https://attack.mitre.org/techniques/T1208',
+ tactics: 'credential-access',
+ value: 'kerberoasting',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.kernelModulesAndExtensionsDescription',
+ { defaultMessage: 'Kernel Modules and Extensions (T1215)' }
+ ),
+ id: 'T1215',
+ name: 'Kernel Modules and Extensions',
+ reference: 'https://attack.mitre.org/techniques/T1215',
+ tactics: 'persistence',
+ value: 'kernelModulesAndExtensions',
+ },
+ {
+ label: i18n.translate('xpack.siem.detectionEngine.mitreAttackTechniques.keychainDescription', {
+ defaultMessage: 'Keychain (T1142)',
+ }),
+ id: 'T1142',
+ name: 'Keychain',
+ reference: 'https://attack.mitre.org/techniques/T1142',
+ tactics: 'credential-access',
+ value: 'keychain',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.lcLoadDylibAdditionDescription',
+ { defaultMessage: 'LC_LOAD_DYLIB Addition (T1161)' }
+ ),
+ id: 'T1161',
+ name: 'LC_LOAD_DYLIB Addition',
+ reference: 'https://attack.mitre.org/techniques/T1161',
+ tactics: 'persistence',
+ value: 'lcLoadDylibAddition',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.lcMainHijackingDescription',
+ { defaultMessage: 'LC_MAIN Hijacking (T1149)' }
+ ),
+ id: 'T1149',
+ name: 'LC_MAIN Hijacking',
+ reference: 'https://attack.mitre.org/techniques/T1149',
+ tactics: 'defense-evasion',
+ value: 'lcMainHijacking',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.llmnrNbtNsPoisoningAndRelayDescription',
+ { defaultMessage: 'LLMNR/NBT-NS Poisoning and Relay (T1171)' }
+ ),
+ id: 'T1171',
+ name: 'LLMNR/NBT-NS Poisoning and Relay',
+ reference: 'https://attack.mitre.org/techniques/T1171',
+ tactics: 'credential-access',
+ value: 'llmnrNbtNsPoisoningAndRelay',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.lsassDriverDescription',
+ { defaultMessage: 'LSASS Driver (T1177)' }
+ ),
+ id: 'T1177',
+ name: 'LSASS Driver',
+ reference: 'https://attack.mitre.org/techniques/T1177',
+ tactics: 'execution,persistence',
+ value: 'lsassDriver',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.launchAgentDescription',
+ { defaultMessage: 'Launch Agent (T1159)' }
+ ),
+ id: 'T1159',
+ name: 'Launch Agent',
+ reference: 'https://attack.mitre.org/techniques/T1159',
+ tactics: 'persistence',
+ value: 'launchAgent',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.launchDaemonDescription',
+ { defaultMessage: 'Launch Daemon (T1160)' }
+ ),
+ id: 'T1160',
+ name: 'Launch Daemon',
+ reference: 'https://attack.mitre.org/techniques/T1160',
+ tactics: 'persistence,privilege-escalation',
+ value: 'launchDaemon',
+ },
+ {
+ label: i18n.translate('xpack.siem.detectionEngine.mitreAttackTechniques.launchctlDescription', {
+ defaultMessage: 'Launchctl (T1152)',
+ }),
+ id: 'T1152',
+ name: 'Launchctl',
+ reference: 'https://attack.mitre.org/techniques/T1152',
+ tactics: 'defense-evasion,execution,persistence',
+ value: 'launchctl',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.localJobSchedulingDescription',
+ { defaultMessage: 'Local Job Scheduling (T1168)' }
+ ),
+ id: 'T1168',
+ name: 'Local Job Scheduling',
+ reference: 'https://attack.mitre.org/techniques/T1168',
+ tactics: 'persistence,execution',
+ value: 'localJobScheduling',
+ },
+ {
+ label: i18n.translate('xpack.siem.detectionEngine.mitreAttackTechniques.loginItemDescription', {
+ defaultMessage: 'Login Item (T1162)',
+ }),
+ id: 'T1162',
+ name: 'Login Item',
+ reference: 'https://attack.mitre.org/techniques/T1162',
+ tactics: 'persistence',
+ value: 'loginItem',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.logonScriptsDescription',
+ { defaultMessage: 'Logon Scripts (T1037)' }
+ ),
+ id: 'T1037',
+ name: 'Logon Scripts',
+ reference: 'https://attack.mitre.org/techniques/T1037',
+ tactics: 'lateral-movement,persistence',
+ value: 'logonScripts',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.manInTheBrowserDescription',
+ { defaultMessage: 'Man in the Browser (T1185)' }
+ ),
+ id: 'T1185',
+ name: 'Man in the Browser',
+ reference: 'https://attack.mitre.org/techniques/T1185',
+ tactics: 'collection',
+ value: 'manInTheBrowser',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.masqueradingDescription',
+ { defaultMessage: 'Masquerading (T1036)' }
+ ),
+ id: 'T1036',
+ name: 'Masquerading',
+ reference: 'https://attack.mitre.org/techniques/T1036',
+ tactics: 'defense-evasion',
+ value: 'masquerading',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.modifyExistingServiceDescription',
+ { defaultMessage: 'Modify Existing Service (T1031)' }
+ ),
+ id: 'T1031',
+ name: 'Modify Existing Service',
+ reference: 'https://attack.mitre.org/techniques/T1031',
+ tactics: 'persistence',
+ value: 'modifyExistingService',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.modifyRegistryDescription',
+ { defaultMessage: 'Modify Registry (T1112)' }
+ ),
+ id: 'T1112',
+ name: 'Modify Registry',
+ reference: 'https://attack.mitre.org/techniques/T1112',
+ tactics: 'defense-evasion',
+ value: 'modifyRegistry',
+ },
+ {
+ label: i18n.translate('xpack.siem.detectionEngine.mitreAttackTechniques.mshtaDescription', {
+ defaultMessage: 'Mshta (T1170)',
+ }),
+ id: 'T1170',
+ name: 'Mshta',
+ reference: 'https://attack.mitre.org/techniques/T1170',
+ tactics: 'defense-evasion,execution',
+ value: 'mshta',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.multiStageChannelsDescription',
+ { defaultMessage: 'Multi-Stage Channels (T1104)' }
+ ),
+ id: 'T1104',
+ name: 'Multi-Stage Channels',
+ reference: 'https://attack.mitre.org/techniques/T1104',
+ tactics: 'command-and-control',
+ value: 'multiStageChannels',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.multiHopProxyDescription',
+ { defaultMessage: 'Multi-hop Proxy (T1188)' }
+ ),
+ id: 'T1188',
+ name: 'Multi-hop Proxy',
+ reference: 'https://attack.mitre.org/techniques/T1188',
+ tactics: 'command-and-control',
+ value: 'multiHopProxy',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.multibandCommunicationDescription',
+ { defaultMessage: 'Multiband Communication (T1026)' }
+ ),
+ id: 'T1026',
+ name: 'Multiband Communication',
+ reference: 'https://attack.mitre.org/techniques/T1026',
+ tactics: 'command-and-control',
+ value: 'multibandCommunication',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.multilayerEncryptionDescription',
+ { defaultMessage: 'Multilayer Encryption (T1079)' }
+ ),
+ id: 'T1079',
+ name: 'Multilayer Encryption',
+ reference: 'https://attack.mitre.org/techniques/T1079',
+ tactics: 'command-and-control',
+ value: 'multilayerEncryption',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.ntfsFileAttributesDescription',
+ { defaultMessage: 'NTFS File Attributes (T1096)' }
+ ),
+ id: 'T1096',
+ name: 'NTFS File Attributes',
+ reference: 'https://attack.mitre.org/techniques/T1096',
+ tactics: 'defense-evasion',
+ value: 'ntfsFileAttributes',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.netshHelperDllDescription',
+ { defaultMessage: 'Netsh Helper DLL (T1128)' }
+ ),
+ id: 'T1128',
+ name: 'Netsh Helper DLL',
+ reference: 'https://attack.mitre.org/techniques/T1128',
+ tactics: 'persistence',
+ value: 'netshHelperDll',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.networkDenialOfServiceDescription',
+ { defaultMessage: 'Network Denial of Service (T1498)' }
+ ),
+ id: 'T1498',
+ name: 'Network Denial of Service',
+ reference: 'https://attack.mitre.org/techniques/T1498',
+ tactics: 'impact',
+ value: 'networkDenialOfService',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.networkServiceScanningDescription',
+ { defaultMessage: 'Network Service Scanning (T1046)' }
+ ),
+ id: 'T1046',
+ name: 'Network Service Scanning',
+ reference: 'https://attack.mitre.org/techniques/T1046',
+ tactics: 'discovery',
+ value: 'networkServiceScanning',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.networkShareConnectionRemovalDescription',
+ { defaultMessage: 'Network Share Connection Removal (T1126)' }
+ ),
+ id: 'T1126',
+ name: 'Network Share Connection Removal',
+ reference: 'https://attack.mitre.org/techniques/T1126',
+ tactics: 'defense-evasion',
+ value: 'networkShareConnectionRemoval',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.networkShareDiscoveryDescription',
+ { defaultMessage: 'Network Share Discovery (T1135)' }
+ ),
+ id: 'T1135',
+ name: 'Network Share Discovery',
+ reference: 'https://attack.mitre.org/techniques/T1135',
+ tactics: 'discovery',
+ value: 'networkShareDiscovery',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.networkSniffingDescription',
+ { defaultMessage: 'Network Sniffing (T1040)' }
+ ),
+ id: 'T1040',
+ name: 'Network Sniffing',
+ reference: 'https://attack.mitre.org/techniques/T1040',
+ tactics: 'credential-access,discovery',
+ value: 'networkSniffing',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.newServiceDescription',
+ { defaultMessage: 'New Service (T1050)' }
+ ),
+ id: 'T1050',
+ name: 'New Service',
+ reference: 'https://attack.mitre.org/techniques/T1050',
+ tactics: 'persistence,privilege-escalation',
+ value: 'newService',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.obfuscatedFilesOrInformationDescription',
+ { defaultMessage: 'Obfuscated Files or Information (T1027)' }
+ ),
+ id: 'T1027',
+ name: 'Obfuscated Files or Information',
+ reference: 'https://attack.mitre.org/techniques/T1027',
+ tactics: 'defense-evasion',
+ value: 'obfuscatedFilesOrInformation',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.officeApplicationStartupDescription',
+ { defaultMessage: 'Office Application Startup (T1137)' }
+ ),
+ id: 'T1137',
+ name: 'Office Application Startup',
+ reference: 'https://attack.mitre.org/techniques/T1137',
+ tactics: 'persistence',
+ value: 'officeApplicationStartup',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.parentPidSpoofingDescription',
+ { defaultMessage: 'Parent PID Spoofing (T1502)' }
+ ),
+ id: 'T1502',
+ name: 'Parent PID Spoofing',
+ reference: 'https://attack.mitre.org/techniques/T1502',
+ tactics: 'defense-evasion,privilege-escalation',
+ value: 'parentPidSpoofing',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.passTheHashDescription',
+ { defaultMessage: 'Pass the Hash (T1075)' }
+ ),
+ id: 'T1075',
+ name: 'Pass the Hash',
+ reference: 'https://attack.mitre.org/techniques/T1075',
+ tactics: 'lateral-movement',
+ value: 'passTheHash',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.passTheTicketDescription',
+ { defaultMessage: 'Pass the Ticket (T1097)' }
+ ),
+ id: 'T1097',
+ name: 'Pass the Ticket',
+ reference: 'https://attack.mitre.org/techniques/T1097',
+ tactics: 'lateral-movement',
+ value: 'passTheTicket',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.passwordFilterDllDescription',
+ { defaultMessage: 'Password Filter DLL (T1174)' }
+ ),
+ id: 'T1174',
+ name: 'Password Filter DLL',
+ reference: 'https://attack.mitre.org/techniques/T1174',
+ tactics: 'credential-access',
+ value: 'passwordFilterDll',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.passwordPolicyDiscoveryDescription',
+ { defaultMessage: 'Password Policy Discovery (T1201)' }
+ ),
+ id: 'T1201',
+ name: 'Password Policy Discovery',
+ reference: 'https://attack.mitre.org/techniques/T1201',
+ tactics: 'discovery',
+ value: 'passwordPolicyDiscovery',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.pathInterceptionDescription',
+ { defaultMessage: 'Path Interception (T1034)' }
+ ),
+ id: 'T1034',
+ name: 'Path Interception',
+ reference: 'https://attack.mitre.org/techniques/T1034',
+ tactics: 'persistence,privilege-escalation',
+ value: 'pathInterception',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.peripheralDeviceDiscoveryDescription',
+ { defaultMessage: 'Peripheral Device Discovery (T1120)' }
+ ),
+ id: 'T1120',
+ name: 'Peripheral Device Discovery',
+ reference: 'https://attack.mitre.org/techniques/T1120',
+ tactics: 'discovery',
+ value: 'peripheralDeviceDiscovery',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.permissionGroupsDiscoveryDescription',
+ { defaultMessage: 'Permission Groups Discovery (T1069)' }
+ ),
+ id: 'T1069',
+ name: 'Permission Groups Discovery',
+ reference: 'https://attack.mitre.org/techniques/T1069',
+ tactics: 'discovery',
+ value: 'permissionGroupsDiscovery',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.plistModificationDescription',
+ { defaultMessage: 'Plist Modification (T1150)' }
+ ),
+ id: 'T1150',
+ name: 'Plist Modification',
+ reference: 'https://attack.mitre.org/techniques/T1150',
+ tactics: 'defense-evasion,persistence,privilege-escalation',
+ value: 'plistModification',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.portKnockingDescription',
+ { defaultMessage: 'Port Knocking (T1205)' }
+ ),
+ id: 'T1205',
+ name: 'Port Knocking',
+ reference: 'https://attack.mitre.org/techniques/T1205',
+ tactics: 'defense-evasion,persistence,command-and-control',
+ value: 'portKnocking',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.portMonitorsDescription',
+ { defaultMessage: 'Port Monitors (T1013)' }
+ ),
+ id: 'T1013',
+ name: 'Port Monitors',
+ reference: 'https://attack.mitre.org/techniques/T1013',
+ tactics: 'persistence,privilege-escalation',
+ value: 'portMonitors',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.powerShellDescription',
+ { defaultMessage: 'PowerShell (T1086)' }
+ ),
+ id: 'T1086',
+ name: 'PowerShell',
+ reference: 'https://attack.mitre.org/techniques/T1086',
+ tactics: 'execution',
+ value: 'powerShell',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.powerShellProfileDescription',
+ { defaultMessage: 'PowerShell Profile (T1504)' }
+ ),
+ id: 'T1504',
+ name: 'PowerShell Profile',
+ reference: 'https://attack.mitre.org/techniques/T1504',
+ tactics: 'persistence,privilege-escalation',
+ value: 'powerShellProfile',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.privateKeysDescription',
+ { defaultMessage: 'Private Keys (T1145)' }
+ ),
+ id: 'T1145',
+ name: 'Private Keys',
+ reference: 'https://attack.mitre.org/techniques/T1145',
+ tactics: 'credential-access',
+ value: 'privateKeys',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.processDiscoveryDescription',
+ { defaultMessage: 'Process Discovery (T1057)' }
+ ),
+ id: 'T1057',
+ name: 'Process Discovery',
+ reference: 'https://attack.mitre.org/techniques/T1057',
+ tactics: 'discovery',
+ value: 'processDiscovery',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.processDoppelgangingDescription',
+ { defaultMessage: 'Process Doppelgänging (T1186)' }
+ ),
+ id: 'T1186',
+ name: 'Process Doppelgänging',
+ reference: 'https://attack.mitre.org/techniques/T1186',
+ tactics: 'defense-evasion',
+ value: 'processDoppelganging',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.processHollowingDescription',
+ { defaultMessage: 'Process Hollowing (T1093)' }
+ ),
+ id: 'T1093',
+ name: 'Process Hollowing',
+ reference: 'https://attack.mitre.org/techniques/T1093',
+ tactics: 'defense-evasion',
+ value: 'processHollowing',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.processInjectionDescription',
+ { defaultMessage: 'Process Injection (T1055)' }
+ ),
+ id: 'T1055',
+ name: 'Process Injection',
+ reference: 'https://attack.mitre.org/techniques/T1055',
+ tactics: 'defense-evasion,privilege-escalation',
+ value: 'processInjection',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.queryRegistryDescription',
+ { defaultMessage: 'Query Registry (T1012)' }
+ ),
+ id: 'T1012',
+ name: 'Query Registry',
+ reference: 'https://attack.mitre.org/techniques/T1012',
+ tactics: 'discovery',
+ value: 'queryRegistry',
+ },
+ {
+ label: i18n.translate('xpack.siem.detectionEngine.mitreAttackTechniques.rcCommonDescription', {
+ defaultMessage: 'Rc.common (T1163)',
+ }),
+ id: 'T1163',
+ name: 'Rc.common',
+ reference: 'https://attack.mitre.org/techniques/T1163',
+ tactics: 'persistence',
+ value: 'rcCommon',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.reOpenedApplicationsDescription',
+ { defaultMessage: 'Re-opened Applications (T1164)' }
+ ),
+ id: 'T1164',
+ name: 'Re-opened Applications',
+ reference: 'https://attack.mitre.org/techniques/T1164',
+ tactics: 'persistence',
+ value: 'reOpenedApplications',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.redundantAccessDescription',
+ { defaultMessage: 'Redundant Access (T1108)' }
+ ),
+ id: 'T1108',
+ name: 'Redundant Access',
+ reference: 'https://attack.mitre.org/techniques/T1108',
+ tactics: 'defense-evasion,persistence',
+ value: 'redundantAccess',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.registryRunKeysStartupFolderDescription',
+ { defaultMessage: 'Registry Run Keys / Startup Folder (T1060)' }
+ ),
+ id: 'T1060',
+ name: 'Registry Run Keys / Startup Folder',
+ reference: 'https://attack.mitre.org/techniques/T1060',
+ tactics: 'persistence',
+ value: 'registryRunKeysStartupFolder',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.regsvcsRegasmDescription',
+ { defaultMessage: 'Regsvcs/Regasm (T1121)' }
+ ),
+ id: 'T1121',
+ name: 'Regsvcs/Regasm',
+ reference: 'https://attack.mitre.org/techniques/T1121',
+ tactics: 'defense-evasion,execution',
+ value: 'regsvcsRegasm',
+ },
+ {
+ label: i18n.translate('xpack.siem.detectionEngine.mitreAttackTechniques.regsvr32Description', {
+ defaultMessage: 'Regsvr32 (T1117)',
+ }),
+ id: 'T1117',
+ name: 'Regsvr32',
+ reference: 'https://attack.mitre.org/techniques/T1117',
+ tactics: 'defense-evasion,execution',
+ value: 'regsvr32',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.remoteAccessToolsDescription',
+ { defaultMessage: 'Remote Access Tools (T1219)' }
+ ),
+ id: 'T1219',
+ name: 'Remote Access Tools',
+ reference: 'https://attack.mitre.org/techniques/T1219',
+ tactics: 'command-and-control',
+ value: 'remoteAccessTools',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.remoteDesktopProtocolDescription',
+ { defaultMessage: 'Remote Desktop Protocol (T1076)' }
+ ),
+ id: 'T1076',
+ name: 'Remote Desktop Protocol',
+ reference: 'https://attack.mitre.org/techniques/T1076',
+ tactics: 'lateral-movement',
+ value: 'remoteDesktopProtocol',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.remoteFileCopyDescription',
+ { defaultMessage: 'Remote File Copy (T1105)' }
+ ),
+ id: 'T1105',
+ name: 'Remote File Copy',
+ reference: 'https://attack.mitre.org/techniques/T1105',
+ tactics: 'command-and-control,lateral-movement',
+ value: 'remoteFileCopy',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.remoteServicesDescription',
+ { defaultMessage: 'Remote Services (T1021)' }
+ ),
+ id: 'T1021',
+ name: 'Remote Services',
+ reference: 'https://attack.mitre.org/techniques/T1021',
+ tactics: 'lateral-movement',
+ value: 'remoteServices',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.remoteSystemDiscoveryDescription',
+ { defaultMessage: 'Remote System Discovery (T1018)' }
+ ),
+ id: 'T1018',
+ name: 'Remote System Discovery',
+ reference: 'https://attack.mitre.org/techniques/T1018',
+ tactics: 'discovery',
+ value: 'remoteSystemDiscovery',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.replicationThroughRemovableMediaDescription',
+ { defaultMessage: 'Replication Through Removable Media (T1091)' }
+ ),
+ id: 'T1091',
+ name: 'Replication Through Removable Media',
+ reference: 'https://attack.mitre.org/techniques/T1091',
+ tactics: 'lateral-movement,initial-access',
+ value: 'replicationThroughRemovableMedia',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.resourceHijackingDescription',
+ { defaultMessage: 'Resource Hijacking (T1496)' }
+ ),
+ id: 'T1496',
+ name: 'Resource Hijacking',
+ reference: 'https://attack.mitre.org/techniques/T1496',
+ tactics: 'impact',
+ value: 'resourceHijacking',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.revertCloudInstanceDescription',
+ { defaultMessage: 'Revert Cloud Instance (T1536)' }
+ ),
+ id: 'T1536',
+ name: 'Revert Cloud Instance',
+ reference: 'https://attack.mitre.org/techniques/T1536',
+ tactics: 'defense-evasion',
+ value: 'revertCloudInstance',
+ },
+ {
+ label: i18n.translate('xpack.siem.detectionEngine.mitreAttackTechniques.rootkitDescription', {
+ defaultMessage: 'Rootkit (T1014)',
+ }),
+ id: 'T1014',
+ name: 'Rootkit',
+ reference: 'https://attack.mitre.org/techniques/T1014',
+ tactics: 'defense-evasion',
+ value: 'rootkit',
+ },
+ {
+ label: i18n.translate('xpack.siem.detectionEngine.mitreAttackTechniques.rundll32Description', {
+ defaultMessage: 'Rundll32 (T1085)',
+ }),
+ id: 'T1085',
+ name: 'Rundll32',
+ reference: 'https://attack.mitre.org/techniques/T1085',
+ tactics: 'defense-evasion,execution',
+ value: 'rundll32',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.runtimeDataManipulationDescription',
+ { defaultMessage: 'Runtime Data Manipulation (T1494)' }
+ ),
+ id: 'T1494',
+ name: 'Runtime Data Manipulation',
+ reference: 'https://attack.mitre.org/techniques/T1494',
+ tactics: 'impact',
+ value: 'runtimeDataManipulation',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.sidHistoryInjectionDescription',
+ { defaultMessage: 'SID-History Injection (T1178)' }
+ ),
+ id: 'T1178',
+ name: 'SID-History Injection',
+ reference: 'https://attack.mitre.org/techniques/T1178',
+ tactics: 'privilege-escalation',
+ value: 'sidHistoryInjection',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.sipAndTrustProviderHijackingDescription',
+ { defaultMessage: 'SIP and Trust Provider Hijacking (T1198)' }
+ ),
+ id: 'T1198',
+ name: 'SIP and Trust Provider Hijacking',
+ reference: 'https://attack.mitre.org/techniques/T1198',
+ tactics: 'defense-evasion,persistence',
+ value: 'sipAndTrustProviderHijacking',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.sshHijackingDescription',
+ { defaultMessage: 'SSH Hijacking (T1184)' }
+ ),
+ id: 'T1184',
+ name: 'SSH Hijacking',
+ reference: 'https://attack.mitre.org/techniques/T1184',
+ tactics: 'lateral-movement',
+ value: 'sshHijacking',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.scheduledTaskDescription',
+ { defaultMessage: 'Scheduled Task (T1053)' }
+ ),
+ id: 'T1053',
+ name: 'Scheduled Task',
+ reference: 'https://attack.mitre.org/techniques/T1053',
+ tactics: 'execution,persistence,privilege-escalation',
+ value: 'scheduledTask',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.scheduledTransferDescription',
+ { defaultMessage: 'Scheduled Transfer (T1029)' }
+ ),
+ id: 'T1029',
+ name: 'Scheduled Transfer',
+ reference: 'https://attack.mitre.org/techniques/T1029',
+ tactics: 'exfiltration',
+ value: 'scheduledTransfer',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.screenCaptureDescription',
+ { defaultMessage: 'Screen Capture (T1113)' }
+ ),
+ id: 'T1113',
+ name: 'Screen Capture',
+ reference: 'https://attack.mitre.org/techniques/T1113',
+ tactics: 'collection',
+ value: 'screenCapture',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.screensaverDescription',
+ { defaultMessage: 'Screensaver (T1180)' }
+ ),
+ id: 'T1180',
+ name: 'Screensaver',
+ reference: 'https://attack.mitre.org/techniques/T1180',
+ tactics: 'persistence',
+ value: 'screensaver',
+ },
+ {
+ label: i18n.translate('xpack.siem.detectionEngine.mitreAttackTechniques.scriptingDescription', {
+ defaultMessage: 'Scripting (T1064)',
+ }),
+ id: 'T1064',
+ name: 'Scripting',
+ reference: 'https://attack.mitre.org/techniques/T1064',
+ tactics: 'defense-evasion,execution',
+ value: 'scripting',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.securitySoftwareDiscoveryDescription',
+ { defaultMessage: 'Security Software Discovery (T1063)' }
+ ),
+ id: 'T1063',
+ name: 'Security Software Discovery',
+ reference: 'https://attack.mitre.org/techniques/T1063',
+ tactics: 'discovery',
+ value: 'securitySoftwareDiscovery',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.securitySupportProviderDescription',
+ { defaultMessage: 'Security Support Provider (T1101)' }
+ ),
+ id: 'T1101',
+ name: 'Security Support Provider',
+ reference: 'https://attack.mitre.org/techniques/T1101',
+ tactics: 'persistence',
+ value: 'securitySupportProvider',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.securitydMemoryDescription',
+ { defaultMessage: 'Securityd Memory (T1167)' }
+ ),
+ id: 'T1167',
+ name: 'Securityd Memory',
+ reference: 'https://attack.mitre.org/techniques/T1167',
+ tactics: 'credential-access',
+ value: 'securitydMemory',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.serverSoftwareComponentDescription',
+ { defaultMessage: 'Server Software Component (T1505)' }
+ ),
+ id: 'T1505',
+ name: 'Server Software Component',
+ reference: 'https://attack.mitre.org/techniques/T1505',
+ tactics: 'persistence',
+ value: 'serverSoftwareComponent',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.serviceExecutionDescription',
+ { defaultMessage: 'Service Execution (T1035)' }
+ ),
+ id: 'T1035',
+ name: 'Service Execution',
+ reference: 'https://attack.mitre.org/techniques/T1035',
+ tactics: 'execution',
+ value: 'serviceExecution',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.serviceRegistryPermissionsWeaknessDescription',
+ { defaultMessage: 'Service Registry Permissions Weakness (T1058)' }
+ ),
+ id: 'T1058',
+ name: 'Service Registry Permissions Weakness',
+ reference: 'https://attack.mitre.org/techniques/T1058',
+ tactics: 'persistence,privilege-escalation',
+ value: 'serviceRegistryPermissionsWeakness',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.serviceStopDescription',
+ { defaultMessage: 'Service Stop (T1489)' }
+ ),
+ id: 'T1489',
+ name: 'Service Stop',
+ reference: 'https://attack.mitre.org/techniques/T1489',
+ tactics: 'impact',
+ value: 'serviceStop',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.setuidAndSetgidDescription',
+ { defaultMessage: 'Setuid and Setgid (T1166)' }
+ ),
+ id: 'T1166',
+ name: 'Setuid and Setgid',
+ reference: 'https://attack.mitre.org/techniques/T1166',
+ tactics: 'privilege-escalation,persistence',
+ value: 'setuidAndSetgid',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.sharedWebrootDescription',
+ { defaultMessage: 'Shared Webroot (T1051)' }
+ ),
+ id: 'T1051',
+ name: 'Shared Webroot',
+ reference: 'https://attack.mitre.org/techniques/T1051',
+ tactics: 'lateral-movement',
+ value: 'sharedWebroot',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.shortcutModificationDescription',
+ { defaultMessage: 'Shortcut Modification (T1023)' }
+ ),
+ id: 'T1023',
+ name: 'Shortcut Modification',
+ reference: 'https://attack.mitre.org/techniques/T1023',
+ tactics: 'persistence',
+ value: 'shortcutModification',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.signedBinaryProxyExecutionDescription',
+ { defaultMessage: 'Signed Binary Proxy Execution (T1218)' }
+ ),
+ id: 'T1218',
+ name: 'Signed Binary Proxy Execution',
+ reference: 'https://attack.mitre.org/techniques/T1218',
+ tactics: 'defense-evasion,execution',
+ value: 'signedBinaryProxyExecution',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.signedScriptProxyExecutionDescription',
+ { defaultMessage: 'Signed Script Proxy Execution (T1216)' }
+ ),
+ id: 'T1216',
+ name: 'Signed Script Proxy Execution',
+ reference: 'https://attack.mitre.org/techniques/T1216',
+ tactics: 'defense-evasion,execution',
+ value: 'signedScriptProxyExecution',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.softwareDiscoveryDescription',
+ { defaultMessage: 'Software Discovery (T1518)' }
+ ),
+ id: 'T1518',
+ name: 'Software Discovery',
+ reference: 'https://attack.mitre.org/techniques/T1518',
+ tactics: 'discovery',
+ value: 'softwareDiscovery',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.softwarePackingDescription',
+ { defaultMessage: 'Software Packing (T1045)' }
+ ),
+ id: 'T1045',
+ name: 'Software Packing',
+ reference: 'https://attack.mitre.org/techniques/T1045',
+ tactics: 'defense-evasion',
+ value: 'softwarePacking',
+ },
+ {
+ label: i18n.translate('xpack.siem.detectionEngine.mitreAttackTechniques.sourceDescription', {
+ defaultMessage: 'Source (T1153)',
+ }),
+ id: 'T1153',
+ name: 'Source',
+ reference: 'https://attack.mitre.org/techniques/T1153',
+ tactics: 'execution',
+ value: 'source',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.spaceAfterFilenameDescription',
+ { defaultMessage: 'Space after Filename (T1151)' }
+ ),
+ id: 'T1151',
+ name: 'Space after Filename',
+ reference: 'https://attack.mitre.org/techniques/T1151',
+ tactics: 'defense-evasion,execution',
+ value: 'spaceAfterFilename',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.spearphishingAttachmentDescription',
+ { defaultMessage: 'Spearphishing Attachment (T1193)' }
+ ),
+ id: 'T1193',
+ name: 'Spearphishing Attachment',
+ reference: 'https://attack.mitre.org/techniques/T1193',
+ tactics: 'initial-access',
+ value: 'spearphishingAttachment',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.spearphishingLinkDescription',
+ { defaultMessage: 'Spearphishing Link (T1192)' }
+ ),
+ id: 'T1192',
+ name: 'Spearphishing Link',
+ reference: 'https://attack.mitre.org/techniques/T1192',
+ tactics: 'initial-access',
+ value: 'spearphishingLink',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.spearphishingViaServiceDescription',
+ { defaultMessage: 'Spearphishing via Service (T1194)' }
+ ),
+ id: 'T1194',
+ name: 'Spearphishing via Service',
+ reference: 'https://attack.mitre.org/techniques/T1194',
+ tactics: 'initial-access',
+ value: 'spearphishingViaService',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.standardApplicationLayerProtocolDescription',
+ { defaultMessage: 'Standard Application Layer Protocol (T1071)' }
+ ),
+ id: 'T1071',
+ name: 'Standard Application Layer Protocol',
+ reference: 'https://attack.mitre.org/techniques/T1071',
+ tactics: 'command-and-control',
+ value: 'standardApplicationLayerProtocol',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.standardCryptographicProtocolDescription',
+ { defaultMessage: 'Standard Cryptographic Protocol (T1032)' }
+ ),
+ id: 'T1032',
+ name: 'Standard Cryptographic Protocol',
+ reference: 'https://attack.mitre.org/techniques/T1032',
+ tactics: 'command-and-control',
+ value: 'standardCryptographicProtocol',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.standardNonApplicationLayerProtocolDescription',
+ { defaultMessage: 'Standard Non-Application Layer Protocol (T1095)' }
+ ),
+ id: 'T1095',
+ name: 'Standard Non-Application Layer Protocol',
+ reference: 'https://attack.mitre.org/techniques/T1095',
+ tactics: 'command-and-control',
+ value: 'standardNonApplicationLayerProtocol',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.startupItemsDescription',
+ { defaultMessage: 'Startup Items (T1165)' }
+ ),
+ id: 'T1165',
+ name: 'Startup Items',
+ reference: 'https://attack.mitre.org/techniques/T1165',
+ tactics: 'persistence,privilege-escalation',
+ value: 'startupItems',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.stealApplicationAccessTokenDescription',
+ { defaultMessage: 'Steal Application Access Token (T1528)' }
+ ),
+ id: 'T1528',
+ name: 'Steal Application Access Token',
+ reference: 'https://attack.mitre.org/techniques/T1528',
+ tactics: 'credential-access',
+ value: 'stealApplicationAccessToken',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.stealWebSessionCookieDescription',
+ { defaultMessage: 'Steal Web Session Cookie (T1539)' }
+ ),
+ id: 'T1539',
+ name: 'Steal Web Session Cookie',
+ reference: 'https://attack.mitre.org/techniques/T1539',
+ tactics: 'credential-access',
+ value: 'stealWebSessionCookie',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.storedDataManipulationDescription',
+ { defaultMessage: 'Stored Data Manipulation (T1492)' }
+ ),
+ id: 'T1492',
+ name: 'Stored Data Manipulation',
+ reference: 'https://attack.mitre.org/techniques/T1492',
+ tactics: 'impact',
+ value: 'storedDataManipulation',
+ },
+ {
+ label: i18n.translate('xpack.siem.detectionEngine.mitreAttackTechniques.sudoDescription', {
+ defaultMessage: 'Sudo (T1169)',
+ }),
+ id: 'T1169',
+ name: 'Sudo',
+ reference: 'https://attack.mitre.org/techniques/T1169',
+ tactics: 'privilege-escalation',
+ value: 'sudo',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.sudoCachingDescription',
+ { defaultMessage: 'Sudo Caching (T1206)' }
+ ),
+ id: 'T1206',
+ name: 'Sudo Caching',
+ reference: 'https://attack.mitre.org/techniques/T1206',
+ tactics: 'privilege-escalation',
+ value: 'sudoCaching',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.supplyChainCompromiseDescription',
+ { defaultMessage: 'Supply Chain Compromise (T1195)' }
+ ),
+ id: 'T1195',
+ name: 'Supply Chain Compromise',
+ reference: 'https://attack.mitre.org/techniques/T1195',
+ tactics: 'initial-access',
+ value: 'supplyChainCompromise',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.systemFirmwareDescription',
+ { defaultMessage: 'System Firmware (T1019)' }
+ ),
+ id: 'T1019',
+ name: 'System Firmware',
+ reference: 'https://attack.mitre.org/techniques/T1019',
+ tactics: 'persistence',
+ value: 'systemFirmware',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.systemInformationDiscoveryDescription',
+ { defaultMessage: 'System Information Discovery (T1082)' }
+ ),
+ id: 'T1082',
+ name: 'System Information Discovery',
+ reference: 'https://attack.mitre.org/techniques/T1082',
+ tactics: 'discovery',
+ value: 'systemInformationDiscovery',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.systemNetworkConfigurationDiscoveryDescription',
+ { defaultMessage: 'System Network Configuration Discovery (T1016)' }
+ ),
+ id: 'T1016',
+ name: 'System Network Configuration Discovery',
+ reference: 'https://attack.mitre.org/techniques/T1016',
+ tactics: 'discovery',
+ value: 'systemNetworkConfigurationDiscovery',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.systemNetworkConnectionsDiscoveryDescription',
+ { defaultMessage: 'System Network Connections Discovery (T1049)' }
+ ),
+ id: 'T1049',
+ name: 'System Network Connections Discovery',
+ reference: 'https://attack.mitre.org/techniques/T1049',
+ tactics: 'discovery',
+ value: 'systemNetworkConnectionsDiscovery',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.systemOwnerUserDiscoveryDescription',
+ { defaultMessage: 'System Owner/User Discovery (T1033)' }
+ ),
+ id: 'T1033',
+ name: 'System Owner/User Discovery',
+ reference: 'https://attack.mitre.org/techniques/T1033',
+ tactics: 'discovery',
+ value: 'systemOwnerUserDiscovery',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.systemServiceDiscoveryDescription',
+ { defaultMessage: 'System Service Discovery (T1007)' }
+ ),
+ id: 'T1007',
+ name: 'System Service Discovery',
+ reference: 'https://attack.mitre.org/techniques/T1007',
+ tactics: 'discovery',
+ value: 'systemServiceDiscovery',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.systemShutdownRebootDescription',
+ { defaultMessage: 'System Shutdown/Reboot (T1529)' }
+ ),
+ id: 'T1529',
+ name: 'System Shutdown/Reboot',
+ reference: 'https://attack.mitre.org/techniques/T1529',
+ tactics: 'impact',
+ value: 'systemShutdownReboot',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.systemTimeDiscoveryDescription',
+ { defaultMessage: 'System Time Discovery (T1124)' }
+ ),
+ id: 'T1124',
+ name: 'System Time Discovery',
+ reference: 'https://attack.mitre.org/techniques/T1124',
+ tactics: 'discovery',
+ value: 'systemTimeDiscovery',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.systemdServiceDescription',
+ { defaultMessage: 'Systemd Service (T1501)' }
+ ),
+ id: 'T1501',
+ name: 'Systemd Service',
+ reference: 'https://attack.mitre.org/techniques/T1501',
+ tactics: 'persistence',
+ value: 'systemdService',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.taintSharedContentDescription',
+ { defaultMessage: 'Taint Shared Content (T1080)' }
+ ),
+ id: 'T1080',
+ name: 'Taint Shared Content',
+ reference: 'https://attack.mitre.org/techniques/T1080',
+ tactics: 'lateral-movement',
+ value: 'taintSharedContent',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.templateInjectionDescription',
+ { defaultMessage: 'Template Injection (T1221)' }
+ ),
+ id: 'T1221',
+ name: 'Template Injection',
+ reference: 'https://attack.mitre.org/techniques/T1221',
+ tactics: 'defense-evasion',
+ value: 'templateInjection',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.thirdPartySoftwareDescription',
+ { defaultMessage: 'Third-party Software (T1072)' }
+ ),
+ id: 'T1072',
+ name: 'Third-party Software',
+ reference: 'https://attack.mitre.org/techniques/T1072',
+ tactics: 'execution,lateral-movement',
+ value: 'thirdPartySoftware',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.timeProvidersDescription',
+ { defaultMessage: 'Time Providers (T1209)' }
+ ),
+ id: 'T1209',
+ name: 'Time Providers',
+ reference: 'https://attack.mitre.org/techniques/T1209',
+ tactics: 'persistence',
+ value: 'timeProviders',
+ },
+ {
+ label: i18n.translate('xpack.siem.detectionEngine.mitreAttackTechniques.timestompDescription', {
+ defaultMessage: 'Timestomp (T1099)',
+ }),
+ id: 'T1099',
+ name: 'Timestomp',
+ reference: 'https://attack.mitre.org/techniques/T1099',
+ tactics: 'defense-evasion',
+ value: 'timestomp',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.transferDataToCloudAccountDescription',
+ { defaultMessage: 'Transfer Data to Cloud Account (T1537)' }
+ ),
+ id: 'T1537',
+ name: 'Transfer Data to Cloud Account',
+ reference: 'https://attack.mitre.org/techniques/T1537',
+ tactics: 'exfiltration',
+ value: 'transferDataToCloudAccount',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.transmittedDataManipulationDescription',
+ { defaultMessage: 'Transmitted Data Manipulation (T1493)' }
+ ),
+ id: 'T1493',
+ name: 'Transmitted Data Manipulation',
+ reference: 'https://attack.mitre.org/techniques/T1493',
+ tactics: 'impact',
+ value: 'transmittedDataManipulation',
+ },
+ {
+ label: i18n.translate('xpack.siem.detectionEngine.mitreAttackTechniques.trapDescription', {
+ defaultMessage: 'Trap (T1154)',
+ }),
+ id: 'T1154',
+ name: 'Trap',
+ reference: 'https://attack.mitre.org/techniques/T1154',
+ tactics: 'execution,persistence',
+ value: 'trap',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.trustedDeveloperUtilitiesDescription',
+ { defaultMessage: 'Trusted Developer Utilities (T1127)' }
+ ),
+ id: 'T1127',
+ name: 'Trusted Developer Utilities',
+ reference: 'https://attack.mitre.org/techniques/T1127',
+ tactics: 'defense-evasion,execution',
+ value: 'trustedDeveloperUtilities',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.trustedRelationshipDescription',
+ { defaultMessage: 'Trusted Relationship (T1199)' }
+ ),
+ id: 'T1199',
+ name: 'Trusted Relationship',
+ reference: 'https://attack.mitre.org/techniques/T1199',
+ tactics: 'initial-access',
+ value: 'trustedRelationship',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.twoFactorAuthenticationInterceptionDescription',
+ { defaultMessage: 'Two-Factor Authentication Interception (T1111)' }
+ ),
+ id: 'T1111',
+ name: 'Two-Factor Authentication Interception',
+ reference: 'https://attack.mitre.org/techniques/T1111',
+ tactics: 'credential-access',
+ value: 'twoFactorAuthenticationInterception',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.uncommonlyUsedPortDescription',
+ { defaultMessage: 'Uncommonly Used Port (T1065)' }
+ ),
+ id: 'T1065',
+ name: 'Uncommonly Used Port',
+ reference: 'https://attack.mitre.org/techniques/T1065',
+ tactics: 'command-and-control',
+ value: 'uncommonlyUsedPort',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.unusedUnsupportedCloudRegionsDescription',
+ { defaultMessage: 'Unused/Unsupported Cloud Regions (T1535)' }
+ ),
+ id: 'T1535',
+ name: 'Unused/Unsupported Cloud Regions',
+ reference: 'https://attack.mitre.org/techniques/T1535',
+ tactics: 'defense-evasion',
+ value: 'unusedUnsupportedCloudRegions',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.userExecutionDescription',
+ { defaultMessage: 'User Execution (T1204)' }
+ ),
+ id: 'T1204',
+ name: 'User Execution',
+ reference: 'https://attack.mitre.org/techniques/T1204',
+ tactics: 'execution',
+ value: 'userExecution',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.validAccountsDescription',
+ { defaultMessage: 'Valid Accounts (T1078)' }
+ ),
+ id: 'T1078',
+ name: 'Valid Accounts',
+ reference: 'https://attack.mitre.org/techniques/T1078',
+ tactics: 'defense-evasion,persistence,privilege-escalation,initial-access',
+ value: 'validAccounts',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.videoCaptureDescription',
+ { defaultMessage: 'Video Capture (T1125)' }
+ ),
+ id: 'T1125',
+ name: 'Video Capture',
+ reference: 'https://attack.mitre.org/techniques/T1125',
+ tactics: 'collection',
+ value: 'videoCapture',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.virtualizationSandboxEvasionDescription',
+ { defaultMessage: 'Virtualization/Sandbox Evasion (T1497)' }
+ ),
+ id: 'T1497',
+ name: 'Virtualization/Sandbox Evasion',
+ reference: 'https://attack.mitre.org/techniques/T1497',
+ tactics: 'defense-evasion,discovery',
+ value: 'virtualizationSandboxEvasion',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.webServiceDescription',
+ { defaultMessage: 'Web Service (T1102)' }
+ ),
+ id: 'T1102',
+ name: 'Web Service',
+ reference: 'https://attack.mitre.org/techniques/T1102',
+ tactics: 'command-and-control,defense-evasion',
+ value: 'webService',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.webSessionCookieDescription',
+ { defaultMessage: 'Web Session Cookie (T1506)' }
+ ),
+ id: 'T1506',
+ name: 'Web Session Cookie',
+ reference: 'https://attack.mitre.org/techniques/T1506',
+ tactics: 'defense-evasion,lateral-movement',
+ value: 'webSessionCookie',
+ },
+ {
+ label: i18n.translate('xpack.siem.detectionEngine.mitreAttackTechniques.webShellDescription', {
+ defaultMessage: 'Web Shell (T1100)',
+ }),
+ id: 'T1100',
+ name: 'Web Shell',
+ reference: 'https://attack.mitre.org/techniques/T1100',
+ tactics: 'persistence,privilege-escalation',
+ value: 'webShell',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.windowsAdminSharesDescription',
+ { defaultMessage: 'Windows Admin Shares (T1077)' }
+ ),
+ id: 'T1077',
+ name: 'Windows Admin Shares',
+ reference: 'https://attack.mitre.org/techniques/T1077',
+ tactics: 'lateral-movement',
+ value: 'windowsAdminShares',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.windowsManagementInstrumentationDescription',
+ { defaultMessage: 'Windows Management Instrumentation (T1047)' }
+ ),
+ id: 'T1047',
+ name: 'Windows Management Instrumentation',
+ reference: 'https://attack.mitre.org/techniques/T1047',
+ tactics: 'execution',
+ value: 'windowsManagementInstrumentation',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.windowsManagementInstrumentationEventSubscriptionDescription',
+ { defaultMessage: 'Windows Management Instrumentation Event Subscription (T1084)' }
+ ),
+ id: 'T1084',
+ name: 'Windows Management Instrumentation Event Subscription',
+ reference: 'https://attack.mitre.org/techniques/T1084',
+ tactics: 'persistence',
+ value: 'windowsManagementInstrumentationEventSubscription',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.windowsRemoteManagementDescription',
+ { defaultMessage: 'Windows Remote Management (T1028)' }
+ ),
+ id: 'T1028',
+ name: 'Windows Remote Management',
+ reference: 'https://attack.mitre.org/techniques/T1028',
+ tactics: 'execution,lateral-movement',
+ value: 'windowsRemoteManagement',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.winlogonHelperDllDescription',
+ { defaultMessage: 'Winlogon Helper DLL (T1004)' }
+ ),
+ id: 'T1004',
+ name: 'Winlogon Helper DLL',
+ reference: 'https://attack.mitre.org/techniques/T1004',
+ tactics: 'persistence',
+ value: 'winlogonHelperDll',
+ },
+ {
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.xslScriptProcessingDescription',
+ { defaultMessage: 'XSL Script Processing (T1220)' }
+ ),
+ id: 'T1220',
+ name: 'XSL Script Processing',
+ reference: 'https://attack.mitre.org/techniques/T1220',
+ tactics: 'defense-evasion,execution',
+ value: 'xslScriptProcessing',
+ },
+];
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/mitre/types.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/mitre/types.ts
new file mode 100644
index 000000000000..a1e7a2e66ab8
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/mitre/types.ts
@@ -0,0 +1,21 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export interface MitreOptions {
+ id: string;
+ name: string;
+ reference: string;
+ value: string;
+}
+
+export interface MitreTacticsOptions extends MitreOptions {
+ text: string;
+}
+
+export interface MitreTechniquesOptions extends MitreOptions {
+ label: string;
+ tactics: string;
+}
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/signals/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/signals/index.tsx
index ca178db9cd97..74b7b9349c2c 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/signals/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/signals/index.tsx
@@ -64,7 +64,7 @@ export const SignalsTable = React.memo(() => {
{({ to, from, setQuery, deleteQuery, isInitializing }) => (
tactics.map(t => `{
+ id: '${t.id}',
+ name: '${t.name}',
+ reference: '${t.reference}',
+ text: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTactics.${camelCase(t.name)}Description', {
+ defaultMessage: '${t.name} (${t.id})'
+ }),
+ value: '${camelCase(t.name)}'
+}`.replace(/(\r\n|\n|\r)/gm, ' '));
+
+const getTechniquesOptions = techniques => techniques.map(t => `{
+ label: i18n.translate(
+ 'xpack.siem.detectionEngine.mitreAttackTechniques.${camelCase(t.name)}Description', {
+ defaultMessage: '${t.name} (${t.id})'
+ }),
+ id: '${t.id}',
+ name: '${t.name}',
+ reference: '${t.reference}',
+ tactics: '${t.tactics.join()}',
+ value: '${camelCase(t.name)}'
+}`.replace(/(\r\n|\n|\r)/gm, ' '));
+
+const getIdReference = references => references.reduce((obj, extRef) => {
+ if (extRef.source_name === 'mitre-attack') {
+ return {
+ id: extRef.external_id, reference: extRef.url
+ };
+ }
+ return obj;
+}, { id: '', reference: '' });
+
+async function main() {
+ fetch(MITRE_ENTREPRISE_ATTACK_URL)
+ .then(res => res.json())
+ .then(json => {
+ const mitreData = json.objects;
+ const tactics = mitreData.filter(obj => obj.type === 'x-mitre-tactic').reduce((acc, item) => {
+ const { id, reference } = getIdReference(item.external_references);
+
+ return [...acc, {
+ name: item.name,
+ id,
+ reference,
+ }];
+ }, []);
+ const techniques = mitreData.filter(obj => obj.type === 'attack-pattern').reduce((acc, item) => {
+ let tactics = [];
+ const { id, reference } = getIdReference(item.external_references);
+ if (item.kill_chain_phases != null && item.kill_chain_phases.length > 0) {
+ item.kill_chain_phases.forEach(tactic => {
+ tactics = [...tactics, tactic.phase_name];
+ });
+ }
+
+ return [...acc, {
+ name: item.name,
+ id,
+ reference,
+ tactics,
+ }];
+ }, []);
+
+ const body =
+ `/*
+ * 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';
+
+ import { MitreTacticsOptions, MitreTechniquesOptions } from './types';
+
+ export const tactics = ${JSON.stringify(tactics, null, 2)};
+
+ export const tacticsOptions: MitreTacticsOptions[] =
+ ${JSON.stringify(getTacticsOptions(tactics), null, 2).replace(/}"/g, '}').replace(/"{/g, '{')};
+
+ export const techniques = ${JSON.stringify(techniques, null, 2)};
+
+ export const techniquesOptions: MitreTechniquesOptions[] =
+ ${JSON.stringify(getTechniquesOptions(techniques), null, 2).replace(/}"/g, '}').replace(/"{/g, '{')};
+ `;
+
+ fs.writeFileSync(`${OUTPUT_DIRECTORY}/mitre_tactics_techniques.ts`, body, 'utf-8');
+
+ });
+}
+
+if (require.main === module) {
+ main();
+}
diff --git a/x-pack/legacy/plugins/siem/server/kibana.index.ts b/x-pack/legacy/plugins/siem/server/kibana.index.ts
index bb0958b32fa1..f56e6b3c3f55 100644
--- a/x-pack/legacy/plugins/siem/server/kibana.index.ts
+++ b/x-pack/legacy/plugins/siem/server/kibana.index.ts
@@ -6,18 +6,18 @@
import { PluginInitializerContext } from 'src/core/server';
-import { rulesAlertType } from './lib/detection_engine/alerts/rules_alert_type';
-import { isAlertExecutor } from './lib/detection_engine/alerts/types';
-import { createRulesRoute } from './lib/detection_engine/routes/create_rules_route';
+import { signalRulesAlertType } from './lib/detection_engine/signals/signal_rule_alert_type';
+import { createRulesRoute } from './lib/detection_engine/routes/rules/create_rules_route';
import { createIndexRoute } from './lib/detection_engine/routes/index/create_index_route';
import { readIndexRoute } from './lib/detection_engine/routes/index/read_index_route';
-import { readRulesRoute } from './lib/detection_engine/routes/read_rules_route';
-import { findRulesRoute } from './lib/detection_engine/routes/find_rules_route';
-import { deleteRulesRoute } from './lib/detection_engine/routes/delete_rules_route';
-import { updateRulesRoute } from './lib/detection_engine/routes/update_rules_route';
+import { readRulesRoute } from './lib/detection_engine/routes/rules/read_rules_route';
+import { findRulesRoute } from './lib/detection_engine/routes/rules/find_rules_route';
+import { deleteRulesRoute } from './lib/detection_engine/routes/rules/delete_rules_route';
+import { updateRulesRoute } from './lib/detection_engine/routes/rules/update_rules_route';
import { setSignalsStatusRoute } from './lib/detection_engine/routes/signals/open_close_signals_route';
import { ServerFacade } from './types';
import { deleteIndexRoute } from './lib/detection_engine/routes/index/delete_index_route';
+import { isAlertExecutor } from './lib/detection_engine/signals/types';
const APP_ID = 'siem';
@@ -26,7 +26,7 @@ export const initServerWithKibana = (context: PluginInitializerContext, __legacy
const version = context.env.packageInfo.version;
if (__legacy.plugins.alerting != null) {
- const type = rulesAlertType({ logger, version });
+ const type = signalRulesAlertType({ logger, version });
if (isAlertExecutor(type)) {
__legacy.plugins.alerting.setup.registerType(type);
}
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/alerts/types.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/alerts/types.ts
deleted file mode 100644
index c9d265ebffac..000000000000
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/alerts/types.ts
+++ /dev/null
@@ -1,264 +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 { get } from 'lodash/fp';
-
-import { SIGNALS_ID } from '../../../../common/constants';
-import {
- Alert,
- AlertType,
- State,
- AlertExecutorOptions,
-} from '../../../../../alerting/server/types';
-import { AlertsClient } from '../../../../../alerting/server/alerts_client';
-import { ActionsClient } from '../../../../../actions/server/actions_client';
-import { RequestFacade } from '../../../types';
-import { SearchResponse } from '../../types';
-import { esFilters } from '../../../../../../../../src/plugins/data/server';
-
-export type PartialFilter = Partial;
-
-export interface IMitreAttack {
- id: string;
- name: string;
- reference: string;
-}
-export interface ThreatParams {
- framework: string;
- tactic: IMitreAttack;
- techniques: IMitreAttack[];
-}
-export interface RuleAlertParams {
- description: string;
- enabled: boolean;
- falsePositives: string[];
- filters: PartialFilter[] | undefined | null;
- from: string;
- immutable: boolean;
- index: string[];
- interval: string;
- ruleId: string | undefined | null;
- language: string | undefined | null;
- maxSignals: number;
- riskScore: number;
- outputIndex: string;
- name: string;
- query: string | undefined | null;
- references: string[];
- savedId: string | undefined | null;
- meta: Record | undefined | null;
- severity: string;
- tags: string[];
- to: string;
- threats: ThreatParams[] | undefined | null;
- type: 'query' | 'saved_query';
-}
-
-export type RuleAlertParamsRest = Omit<
- RuleAlertParams,
- 'ruleId' | 'falsePositives' | 'maxSignals' | 'savedId' | 'riskScore' | 'outputIndex'
-> & {
- rule_id: RuleAlertParams['ruleId'];
- false_positives: RuleAlertParams['falsePositives'];
- saved_id: RuleAlertParams['savedId'];
- max_signals: RuleAlertParams['maxSignals'];
- risk_score: RuleAlertParams['riskScore'];
- output_index: RuleAlertParams['outputIndex'];
-};
-
-export interface SignalsParams {
- signalIds: string[] | undefined | null;
- query: object | undefined | null;
- status: 'open' | 'closed';
-}
-
-export type SignalsRestParams = Omit & {
- signal_ids: SignalsParams['signalIds'];
-};
-
-export type OutputRuleAlertRest = RuleAlertParamsRest & {
- id: string;
- created_by: string | undefined | null;
- updated_by: string | undefined | null;
-};
-
-export type UpdateRuleAlertParamsRest = Partial & {
- id: string | undefined;
- rule_id: RuleAlertParams['ruleId'] | undefined;
-};
-
-export interface FindParamsRest {
- per_page: number;
- page: number;
- sort_field: string;
- sort_order: 'asc' | 'desc';
- fields: string[];
- filter: string;
-}
-
-export interface Clients {
- alertsClient: AlertsClient;
- actionsClient: ActionsClient;
-}
-
-export type RuleParams = RuleAlertParams & Clients;
-
-export type UpdateRuleParams = Partial & {
- id: string | undefined | null;
-} & Clients;
-
-export type DeleteRuleParams = Clients & {
- id: string | undefined;
- ruleId: string | undefined | null;
-};
-
-export interface FindRulesRequest extends Omit {
- query: {
- per_page: number;
- page: number;
- search?: string;
- sort_field?: string;
- filter?: string;
- fields?: string[];
- sort_order?: 'asc' | 'desc';
- };
-}
-
-export interface FindRuleParams {
- alertsClient: AlertsClient;
- perPage?: number;
- page?: number;
- sortField?: string;
- filter?: string;
- fields?: string[];
- sortOrder?: 'asc' | 'desc';
-}
-
-export interface ReadRuleParams {
- alertsClient: AlertsClient;
- id?: string | undefined | null;
- ruleId?: string | undefined | null;
-}
-
-export interface ReadRuleByRuleId {
- alertsClient: AlertsClient;
- ruleId: string;
-}
-
-export type RuleTypeParams = Omit;
-
-export type RuleAlertType = Alert & {
- id: string;
- params: RuleTypeParams;
-};
-
-export interface RulesRequest extends RequestFacade {
- payload: RuleAlertParamsRest;
-}
-
-export interface SignalsRequest extends RequestFacade {
- payload: SignalsRestParams;
-}
-
-export interface UpdateRulesRequest extends RequestFacade {
- payload: UpdateRuleAlertParamsRest;
-}
-
-export type RuleExecutorOptions = Omit & {
- params: RuleAlertParams & {
- scrollSize: number;
- scrollLock: string;
- };
-};
-
-export type SearchTypes =
- | string
- | string[]
- | number
- | number[]
- | boolean
- | boolean[]
- | object
- | object[];
-
-export interface SignalSource {
- [key: string]: SearchTypes;
- '@timestamp': string;
-}
-
-export interface BulkResponse {
- took: number;
- errors: boolean;
- items: [
- {
- create: {
- _index: string;
- _type?: string;
- _id: string;
- _version: number;
- result?: string;
- _shards?: {
- total: number;
- successful: number;
- failed: number;
- };
- _seq_no?: number;
- _primary_term?: number;
- status: number;
- error?: {
- type: string;
- reason: string;
- index_uuid?: string;
- shard: string;
- index: string;
- };
- };
- }
- ];
-}
-
-export interface MGetResponse {
- docs: GetResponse[];
-}
-export interface GetResponse {
- _index: string;
- _type: string;
- _id: string;
- _version: number;
- _seq_no: number;
- _primary_term: number;
- found: boolean;
- _source: SearchTypes;
-}
-
-export type SignalSearchResponse = SearchResponse;
-export type SignalSourceHit = SignalSearchResponse['hits']['hits'][0];
-
-export type QueryRequest = Omit & {
- query: { id: string | undefined; rule_id: string | undefined };
-};
-
-// This returns true because by default a RuleAlertTypeDefinition is an AlertType
-// since we are only increasing the strictness of params.
-export const isAlertExecutor = (obj: RuleAlertTypeDefinition): obj is AlertType => {
- return true;
-};
-
-export type RuleAlertTypeDefinition = Omit & {
- executor: ({ services, params, state }: RuleExecutorOptions) => Promise;
-};
-
-export const isAlertTypes = (obj: unknown[]): obj is RuleAlertType[] => {
- return obj.every(rule => isAlertType(rule));
-};
-
-export const isAlertType = (obj: unknown): obj is RuleAlertType => {
- return get('alertTypeId', obj) === SIGNALS_ID;
-};
-
-export const isAlertTypeArray = (objArray: unknown[]): objArray is RuleAlertType[] => {
- return objArray.length === 0 || isAlertType(objArray[0]);
-};
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/alerts/utils.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/alerts/utils.test.ts
deleted file mode 100644
index 41052ab4bbb1..000000000000
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/alerts/utils.test.ts
+++ /dev/null
@@ -1,1107 +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 { savedObjectsClientMock } from 'src/core/server/mocks';
-
-import { Logger } from '../../../../../../../../src/core/server';
-import {
- buildBulkBody,
- generateId,
- singleBulkCreate,
- singleSearchAfter,
- searchAfterAndBulkCreate,
- buildEventTypeSignal,
- buildSignal,
- buildRule,
-} from './utils';
-import {
- sampleDocNoSortId,
- sampleRuleAlertParams,
- sampleDocSearchResultsNoSortId,
- sampleDocSearchResultsNoSortIdNoHits,
- sampleDocSearchResultsNoSortIdNoVersion,
- sampleDocSearchResultsWithSortId,
- sampleEmptyDocSearchResults,
- repeatedSearchResultsWithSortId,
- sampleBulkCreateDuplicateResult,
- sampleRuleGuid,
- sampleRule,
- sampleIdGuid,
-} from './__mocks__/es_results';
-import { DEFAULT_SIGNALS_INDEX } from '../../../../common/constants';
-import { OutputRuleAlertRest } from './types';
-import { Signal } from '../../types';
-
-const mockLogger: Logger = {
- log: jest.fn(),
- trace: jest.fn(),
- debug: jest.fn(),
- info: jest.fn(),
- warn: jest.fn(),
- error: jest.fn(),
- fatal: jest.fn(),
-};
-
-const mockService = {
- callCluster: jest.fn(),
- alertInstanceFactory: jest.fn(),
- savedObjectsClient: savedObjectsClientMock.create(),
-};
-
-describe('utils', () => {
- beforeEach(() => {
- jest.clearAllMocks();
- });
- describe('buildBulkBody', () => {
- test('if bulk body builds well-defined body', () => {
- const sampleParams = sampleRuleAlertParams();
- const fakeSignalSourceHit = buildBulkBody({
- doc: sampleDocNoSortId(),
- ruleParams: sampleParams,
- id: sampleRuleGuid,
- name: 'rule-name',
- createdBy: 'elastic',
- updatedBy: 'elastic',
- interval: '5m',
- enabled: true,
- tags: ['some fake tag 1', 'some fake tag 2'],
- });
- // Timestamp will potentially always be different so remove it for the test
- delete fakeSignalSourceHit['@timestamp'];
- expect(fakeSignalSourceHit).toEqual({
- someKey: 'someValue',
- event: {
- kind: 'signal',
- },
- signal: {
- parent: {
- id: sampleIdGuid,
- type: 'event',
- index: 'myFakeSignalIndex',
- depth: 1,
- },
- original_time: 'someTimeStamp',
- status: 'open',
- rule: {
- id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
- rule_id: 'rule-1',
- false_positives: [],
- max_signals: 10000,
- risk_score: 50,
- output_index: '.siem-signals',
- description: 'Detecting root and admin users',
- from: 'now-6m',
- immutable: false,
- index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
- interval: '5m',
- language: 'kuery',
- name: 'rule-name',
- query: 'user.name: root or user.name: admin',
- references: ['http://google.com'],
- severity: 'high',
- tags: ['some fake tag 1', 'some fake tag 2'],
- type: 'query',
- to: 'now',
- enabled: true,
- created_by: 'elastic',
- updated_by: 'elastic',
- },
- },
- });
- });
-
- test('if bulk body builds original_event if it exists on the event to begin with', () => {
- const sampleParams = sampleRuleAlertParams();
- const doc = sampleDocNoSortId();
- doc._source.event = {
- action: 'socket_opened',
- module: 'system',
- dataset: 'socket',
- kind: 'event',
- };
- const fakeSignalSourceHit = buildBulkBody({
- doc,
- ruleParams: sampleParams,
- id: sampleRuleGuid,
- name: 'rule-name',
- createdBy: 'elastic',
- updatedBy: 'elastic',
- interval: '5m',
- enabled: true,
- tags: ['some fake tag 1', 'some fake tag 2'],
- });
- // Timestamp will potentially always be different so remove it for the test
- delete fakeSignalSourceHit['@timestamp'];
- expect(fakeSignalSourceHit).toEqual({
- someKey: 'someValue',
- event: {
- action: 'socket_opened',
- dataset: 'socket',
- kind: 'signal',
- module: 'system',
- },
- signal: {
- original_event: {
- action: 'socket_opened',
- dataset: 'socket',
- kind: 'event',
- module: 'system',
- },
- parent: {
- id: sampleIdGuid,
- type: 'event',
- index: 'myFakeSignalIndex',
- depth: 1,
- },
- original_time: 'someTimeStamp',
- status: 'open',
- rule: {
- id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
- rule_id: 'rule-1',
- false_positives: [],
- max_signals: 10000,
- risk_score: 50,
- output_index: '.siem-signals',
- description: 'Detecting root and admin users',
- from: 'now-6m',
- immutable: false,
- index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
- interval: '5m',
- language: 'kuery',
- name: 'rule-name',
- query: 'user.name: root or user.name: admin',
- references: ['http://google.com'],
- severity: 'high',
- tags: ['some fake tag 1', 'some fake tag 2'],
- type: 'query',
- to: 'now',
- enabled: true,
- created_by: 'elastic',
- updated_by: 'elastic',
- },
- },
- });
- });
-
- test('if bulk body builds original_event if it exists on the event to begin with but no kind information', () => {
- const sampleParams = sampleRuleAlertParams();
- const doc = sampleDocNoSortId();
- doc._source.event = {
- action: 'socket_opened',
- module: 'system',
- dataset: 'socket',
- };
- const fakeSignalSourceHit = buildBulkBody({
- doc,
- ruleParams: sampleParams,
- id: sampleRuleGuid,
- name: 'rule-name',
- createdBy: 'elastic',
- updatedBy: 'elastic',
- interval: '5m',
- enabled: true,
- tags: ['some fake tag 1', 'some fake tag 2'],
- });
- // Timestamp will potentially always be different so remove it for the test
- delete fakeSignalSourceHit['@timestamp'];
- expect(fakeSignalSourceHit).toEqual({
- someKey: 'someValue',
- event: {
- action: 'socket_opened',
- dataset: 'socket',
- kind: 'signal',
- module: 'system',
- },
- signal: {
- original_event: {
- action: 'socket_opened',
- dataset: 'socket',
- module: 'system',
- },
- parent: {
- id: sampleIdGuid,
- type: 'event',
- index: 'myFakeSignalIndex',
- depth: 1,
- },
- original_time: 'someTimeStamp',
- status: 'open',
- rule: {
- id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
- rule_id: 'rule-1',
- false_positives: [],
- max_signals: 10000,
- risk_score: 50,
- output_index: '.siem-signals',
- description: 'Detecting root and admin users',
- from: 'now-6m',
- immutable: false,
- index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
- interval: '5m',
- language: 'kuery',
- name: 'rule-name',
- query: 'user.name: root or user.name: admin',
- references: ['http://google.com'],
- severity: 'high',
- tags: ['some fake tag 1', 'some fake tag 2'],
- type: 'query',
- to: 'now',
- enabled: true,
- created_by: 'elastic',
- updated_by: 'elastic',
- },
- },
- });
- });
-
- test('if bulk body builds original_event if it exists on the event to begin with with only kind information', () => {
- const sampleParams = sampleRuleAlertParams();
- const doc = sampleDocNoSortId();
- doc._source.event = {
- kind: 'event',
- };
- const fakeSignalSourceHit = buildBulkBody({
- doc,
- ruleParams: sampleParams,
- id: sampleRuleGuid,
- name: 'rule-name',
- createdBy: 'elastic',
- updatedBy: 'elastic',
- interval: '5m',
- enabled: true,
- tags: ['some fake tag 1', 'some fake tag 2'],
- });
- // Timestamp will potentially always be different so remove it for the test
- delete fakeSignalSourceHit['@timestamp'];
- expect(fakeSignalSourceHit).toEqual({
- someKey: 'someValue',
- event: {
- kind: 'signal',
- },
- signal: {
- original_event: {
- kind: 'event',
- },
- parent: {
- id: sampleIdGuid,
- type: 'event',
- index: 'myFakeSignalIndex',
- depth: 1,
- },
- original_time: 'someTimeStamp',
- status: 'open',
- rule: {
- id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
- rule_id: 'rule-1',
- false_positives: [],
- max_signals: 10000,
- risk_score: 50,
- output_index: '.siem-signals',
- description: 'Detecting root and admin users',
- from: 'now-6m',
- immutable: false,
- index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
- interval: '5m',
- language: 'kuery',
- name: 'rule-name',
- query: 'user.name: root or user.name: admin',
- references: ['http://google.com'],
- severity: 'high',
- tags: ['some fake tag 1', 'some fake tag 2'],
- type: 'query',
- to: 'now',
- enabled: true,
- created_by: 'elastic',
- updated_by: 'elastic',
- },
- },
- });
- });
- });
- describe('singleBulkCreate', () => {
- describe('create signal id gereateId', () => {
- test('two docs with same index, id, and version should have same id', () => {
- const findex = 'myfakeindex';
- const fid = 'somefakeid';
- const version = '1';
- const ruleId = 'rule-1';
- // 'myfakeindexsomefakeid1rule-1'
- const generatedHash = '342404d620be4344d6d90dd0461d1d1848aec457944d5c5f40cc0cbfedb36679';
- const firstHash = generateId(findex, fid, version, ruleId);
- const secondHash = generateId(findex, fid, version, ruleId);
- expect(firstHash).toEqual(generatedHash);
- expect(secondHash).toEqual(generatedHash);
- expect(Buffer.byteLength(firstHash, 'utf8')).toBeLessThan(512); // 512 bytes is maximum size of _id field
- expect(Buffer.byteLength(secondHash, 'utf8')).toBeLessThan(512);
- });
- test('two docs with different index, id, and version should have different id', () => {
- const findex = 'myfakeindex';
- const findex2 = 'mysecondfakeindex';
- const fid = 'somefakeid';
- const version = '1';
- const ruleId = 'rule-1';
- // 'myfakeindexsomefakeid1rule-1'
- const firstGeneratedHash =
- '342404d620be4344d6d90dd0461d1d1848aec457944d5c5f40cc0cbfedb36679';
- // 'mysecondfakeindexsomefakeid1rule-1'
- const secondGeneratedHash =
- 'a852941273f805ffe9006e574601acc8ae1148d6c0b3f7f8c4785cba8f6b768a';
- const firstHash = generateId(findex, fid, version, ruleId);
- const secondHash = generateId(findex2, fid, version, ruleId);
- expect(firstHash).toEqual(firstGeneratedHash);
- expect(secondHash).toEqual(secondGeneratedHash);
- expect(Buffer.byteLength(firstHash, 'utf8')).toBeLessThan(512); // 512 bytes is maximum size of _id field
- expect(Buffer.byteLength(secondHash, 'utf8')).toBeLessThan(512);
- expect(firstHash).not.toEqual(secondHash);
- });
- test('two docs with same index, different id, and same version should have different id', () => {
- const findex = 'myfakeindex';
- const fid = 'somefakeid';
- const fid2 = 'somefakeid2';
- const version = '1';
- const ruleId = 'rule-1';
- // 'myfakeindexsomefakeid1rule-1'
- const firstGeneratedHash =
- '342404d620be4344d6d90dd0461d1d1848aec457944d5c5f40cc0cbfedb36679';
- // 'myfakeindexsomefakeid21rule-1'
- const secondGeneratedHash =
- '7d33faea18159fd010c4b79890620e8b12cdc88ec1d370149d0e5552ce860255';
- const firstHash = generateId(findex, fid, version, ruleId);
- const secondHash = generateId(findex, fid2, version, ruleId);
- expect(firstHash).toEqual(firstGeneratedHash);
- expect(secondHash).toEqual(secondGeneratedHash);
- expect(Buffer.byteLength(firstHash, 'utf8')).toBeLessThan(512); // 512 bytes is maximum size of _id field
- expect(Buffer.byteLength(secondHash, 'utf8')).toBeLessThan(512);
- expect(firstHash).not.toEqual(secondHash);
- });
- test('two docs with same index, same id, and different version should have different id', () => {
- const findex = 'myfakeindex';
- const fid = 'somefakeid';
- const version = '1';
- const version2 = '2';
- const ruleId = 'rule-1';
- // 'myfakeindexsomefakeid1rule-1'
- const firstGeneratedHash =
- '342404d620be4344d6d90dd0461d1d1848aec457944d5c5f40cc0cbfedb36679';
- // myfakeindexsomefakeid2rule-1'
- const secondGeneratedHash =
- 'f016f3071fa9df9221d2fb2ba92389d4d388a4347c6ec7a4012c01cb1c640a40';
- const firstHash = generateId(findex, fid, version, ruleId);
- const secondHash = generateId(findex, fid, version2, ruleId);
- expect(firstHash).toEqual(firstGeneratedHash);
- expect(secondHash).toEqual(secondGeneratedHash);
- expect(Buffer.byteLength(firstHash, 'utf8')).toBeLessThan(512); // 512 bytes is maximum size of _id field
- expect(Buffer.byteLength(secondHash, 'utf8')).toBeLessThan(512);
- expect(firstHash).not.toEqual(secondHash);
- });
- test('Ensure generated id is less than 512 bytes, even for really really long strings', () => {
- const longIndexName =
- 'myfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindexmyfakeindex';
- const fid = 'somefakeid';
- const version = '1';
- const ruleId = 'rule-1';
- const firstHash = generateId(longIndexName, fid, version, ruleId);
- expect(Buffer.byteLength(firstHash, 'utf8')).toBeLessThan(512); // 512 bytes is maximum size of _id field
- });
- test('two docs with same index, same id, same version number, and different rule ids should have different id', () => {
- const findex = 'myfakeindex';
- const fid = 'somefakeid';
- const version = '1';
- const ruleId = 'rule-1';
- const ruleId2 = 'rule-2';
- // 'myfakeindexsomefakeid1rule-1'
- const firstGeneratedHash =
- '342404d620be4344d6d90dd0461d1d1848aec457944d5c5f40cc0cbfedb36679';
- // myfakeindexsomefakeid1rule-2'
- const secondGeneratedHash =
- '1eb04f997086f8b3b143d4d9b18ac178c4a7423f71a5dad9ba8b9e92603c6863';
- const firstHash = generateId(findex, fid, version, ruleId);
- const secondHash = generateId(findex, fid, version, ruleId2);
- expect(firstHash).toEqual(firstGeneratedHash);
- expect(secondHash).toEqual(secondGeneratedHash);
- expect(Buffer.byteLength(firstHash, 'utf8')).toBeLessThan(512); // 512 bytes is maximum size of _id field
- expect(Buffer.byteLength(secondHash, 'utf8')).toBeLessThan(512);
- expect(firstHash).not.toEqual(secondHash);
- });
- });
- test('create successful bulk create', async () => {
- const sampleParams = sampleRuleAlertParams();
- const sampleSearchResult = sampleDocSearchResultsNoSortId;
- mockService.callCluster.mockReturnValueOnce({
- took: 100,
- errors: false,
- items: [
- {
- fakeItemValue: 'fakeItemKey',
- },
- ],
- });
- const successfulsingleBulkCreate = await singleBulkCreate({
- someResult: sampleSearchResult(),
- ruleParams: sampleParams,
- services: mockService,
- logger: mockLogger,
- id: sampleRuleGuid,
- signalsIndex: DEFAULT_SIGNALS_INDEX,
- name: 'rule-name',
- createdBy: 'elastic',
- updatedBy: 'elastic',
- interval: '5m',
- enabled: true,
- tags: ['some fake tag 1', 'some fake tag 2'],
- });
- expect(successfulsingleBulkCreate).toEqual(true);
- });
- test('create successful bulk create with docs with no versioning', async () => {
- const sampleParams = sampleRuleAlertParams();
- const sampleSearchResult = sampleDocSearchResultsNoSortIdNoVersion;
- mockService.callCluster.mockReturnValueOnce({
- took: 100,
- errors: false,
- items: [
- {
- fakeItemValue: 'fakeItemKey',
- },
- ],
- });
- const successfulsingleBulkCreate = await singleBulkCreate({
- someResult: sampleSearchResult(),
- ruleParams: sampleParams,
- services: mockService,
- logger: mockLogger,
- id: sampleRuleGuid,
- signalsIndex: DEFAULT_SIGNALS_INDEX,
- name: 'rule-name',
- createdBy: 'elastic',
- updatedBy: 'elastic',
- interval: '5m',
- enabled: true,
- tags: ['some fake tag 1', 'some fake tag 2'],
- });
- expect(successfulsingleBulkCreate).toEqual(true);
- });
- test('create unsuccessful bulk create due to empty search results', async () => {
- const sampleParams = sampleRuleAlertParams();
- const sampleSearchResult = sampleEmptyDocSearchResults;
- mockService.callCluster.mockReturnValue(false);
- const successfulsingleBulkCreate = await singleBulkCreate({
- someResult: sampleSearchResult,
- ruleParams: sampleParams,
- services: mockService,
- logger: mockLogger,
- id: sampleRuleGuid,
- signalsIndex: DEFAULT_SIGNALS_INDEX,
- name: 'rule-name',
- createdBy: 'elastic',
- updatedBy: 'elastic',
- interval: '5m',
- enabled: true,
- tags: ['some fake tag 1', 'some fake tag 2'],
- });
- expect(successfulsingleBulkCreate).toEqual(true);
- });
- test('create successful bulk create when bulk create has errors', async () => {
- const sampleParams = sampleRuleAlertParams();
- const sampleSearchResult = sampleDocSearchResultsNoSortId;
- mockService.callCluster.mockReturnValue(sampleBulkCreateDuplicateResult);
- const successfulsingleBulkCreate = await singleBulkCreate({
- someResult: sampleSearchResult(),
- ruleParams: sampleParams,
- services: mockService,
- logger: mockLogger,
- id: sampleRuleGuid,
- signalsIndex: DEFAULT_SIGNALS_INDEX,
- name: 'rule-name',
- createdBy: 'elastic',
- updatedBy: 'elastic',
- interval: '5m',
- enabled: true,
- tags: ['some fake tag 1', 'some fake tag 2'],
- });
- expect(mockLogger.error).toHaveBeenCalled();
- expect(successfulsingleBulkCreate).toEqual(true);
- });
- });
- describe('singleSearchAfter', () => {
- test('if singleSearchAfter works without a given sort id', async () => {
- let searchAfterSortId;
- const sampleParams = sampleRuleAlertParams();
- mockService.callCluster.mockReturnValue(sampleDocSearchResultsNoSortId);
- await expect(
- singleSearchAfter({
- searchAfterSortId,
- ruleParams: sampleParams,
- services: mockService,
- logger: mockLogger,
- pageSize: 1,
- filter: undefined,
- })
- ).rejects.toThrow('Attempted to search after with empty sort id');
- });
- test('if singleSearchAfter works with a given sort id', async () => {
- const searchAfterSortId = '1234567891111';
- const sampleParams = sampleRuleAlertParams();
- mockService.callCluster.mockReturnValue(sampleDocSearchResultsWithSortId);
- const searchAfterResult = await singleSearchAfter({
- searchAfterSortId,
- ruleParams: sampleParams,
- services: mockService,
- logger: mockLogger,
- pageSize: 1,
- filter: undefined,
- });
- expect(searchAfterResult).toEqual(sampleDocSearchResultsWithSortId);
- });
- test('if singleSearchAfter throws error', async () => {
- const searchAfterSortId = '1234567891111';
- const sampleParams = sampleRuleAlertParams();
- mockService.callCluster.mockImplementation(async () => {
- throw Error('Fake Error');
- });
- await expect(
- singleSearchAfter({
- searchAfterSortId,
- ruleParams: sampleParams,
- services: mockService,
- logger: mockLogger,
- pageSize: 1,
- filter: undefined,
- })
- ).rejects.toThrow('Fake Error');
- });
- });
- describe('searchAfterAndBulkCreate', () => {
- test('if successful with empty search results', async () => {
- const sampleParams = sampleRuleAlertParams();
- const result = await searchAfterAndBulkCreate({
- someResult: sampleEmptyDocSearchResults,
- ruleParams: sampleParams,
- services: mockService,
- logger: mockLogger,
- id: sampleRuleGuid,
- signalsIndex: DEFAULT_SIGNALS_INDEX,
- name: 'rule-name',
- createdBy: 'elastic',
- updatedBy: 'elastic',
- interval: '5m',
- enabled: true,
- pageSize: 1,
- filter: undefined,
- tags: ['some fake tag 1', 'some fake tag 2'],
- });
- expect(mockService.callCluster).toHaveBeenCalledTimes(0);
- expect(result).toEqual(true);
- });
- test('if successful iteration of while loop with maxDocs', async () => {
- const sampleParams = sampleRuleAlertParams(30);
- const someGuids = Array.from({ length: 13 }).map(x => uuid.v4());
- mockService.callCluster
- .mockReturnValueOnce({
- took: 100,
- errors: false,
- items: [
- {
- fakeItemValue: 'fakeItemKey',
- },
- ],
- })
- .mockReturnValueOnce(repeatedSearchResultsWithSortId(3, 1, someGuids.slice(0, 3)))
- .mockReturnValueOnce({
- took: 100,
- errors: false,
- items: [
- {
- fakeItemValue: 'fakeItemKey',
- },
- ],
- })
- .mockReturnValueOnce(repeatedSearchResultsWithSortId(3, 1, someGuids.slice(3, 6)))
- .mockReturnValueOnce({
- took: 100,
- errors: false,
- items: [
- {
- fakeItemValue: 'fakeItemKey',
- },
- ],
- });
- const result = await searchAfterAndBulkCreate({
- someResult: repeatedSearchResultsWithSortId(3, 1, someGuids.slice(6, 9)),
- ruleParams: sampleParams,
- services: mockService,
- logger: mockLogger,
- id: sampleRuleGuid,
- signalsIndex: DEFAULT_SIGNALS_INDEX,
- name: 'rule-name',
- createdBy: 'elastic',
- updatedBy: 'elastic',
- interval: '5m',
- enabled: true,
- pageSize: 1,
- filter: undefined,
- tags: ['some fake tag 1', 'some fake tag 2'],
- });
- expect(mockService.callCluster).toHaveBeenCalledTimes(5);
- expect(result).toEqual(true);
- });
- test('if unsuccessful first bulk create', async () => {
- const someGuids = Array.from({ length: 4 }).map(x => uuid.v4());
- const sampleParams = sampleRuleAlertParams(10);
- mockService.callCluster.mockReturnValue(sampleBulkCreateDuplicateResult);
- const result = await searchAfterAndBulkCreate({
- someResult: repeatedSearchResultsWithSortId(4, 1, someGuids),
- ruleParams: sampleParams,
- services: mockService,
- logger: mockLogger,
- id: sampleRuleGuid,
- signalsIndex: DEFAULT_SIGNALS_INDEX,
- name: 'rule-name',
- createdBy: 'elastic',
- updatedBy: 'elastic',
- interval: '5m',
- enabled: true,
- pageSize: 1,
- filter: undefined,
- tags: ['some fake tag 1', 'some fake tag 2'],
- });
- expect(mockLogger.error).toHaveBeenCalled();
- expect(result).toEqual(false);
- });
- test('if unsuccessful iteration of searchAfterAndBulkCreate due to empty sort ids', async () => {
- const sampleParams = sampleRuleAlertParams();
- mockService.callCluster.mockReturnValueOnce({
- took: 100,
- errors: false,
- items: [
- {
- fakeItemValue: 'fakeItemKey',
- },
- ],
- });
- const result = await searchAfterAndBulkCreate({
- someResult: sampleDocSearchResultsNoSortId(),
- ruleParams: sampleParams,
- services: mockService,
- logger: mockLogger,
- id: sampleRuleGuid,
- signalsIndex: DEFAULT_SIGNALS_INDEX,
- name: 'rule-name',
- createdBy: 'elastic',
- updatedBy: 'elastic',
- interval: '5m',
- enabled: true,
- pageSize: 1,
- filter: undefined,
- tags: ['some fake tag 1', 'some fake tag 2'],
- });
- expect(mockLogger.error).toHaveBeenCalled();
- expect(result).toEqual(false);
- });
- test('if unsuccessful iteration of searchAfterAndBulkCreate due to empty sort ids and 0 total hits', async () => {
- const sampleParams = sampleRuleAlertParams();
- mockService.callCluster.mockReturnValueOnce({
- took: 100,
- errors: false,
- items: [
- {
- fakeItemValue: 'fakeItemKey',
- },
- ],
- });
- const result = await searchAfterAndBulkCreate({
- someResult: sampleDocSearchResultsNoSortIdNoHits(),
- ruleParams: sampleParams,
- services: mockService,
- logger: mockLogger,
- id: sampleRuleGuid,
- signalsIndex: DEFAULT_SIGNALS_INDEX,
- name: 'rule-name',
- createdBy: 'elastic',
- updatedBy: 'elastic',
- interval: '5m',
- enabled: true,
- pageSize: 1,
- filter: undefined,
- tags: ['some fake tag 1', 'some fake tag 2'],
- });
- expect(result).toEqual(true);
- });
- test('if successful iteration of while loop with maxDocs and search after returns results with no sort ids', async () => {
- const sampleParams = sampleRuleAlertParams(10);
- const someGuids = Array.from({ length: 4 }).map(x => uuid.v4());
- mockService.callCluster
- .mockReturnValueOnce({
- took: 100,
- errors: false,
- items: [
- {
- fakeItemValue: 'fakeItemKey',
- },
- ],
- })
- .mockReturnValueOnce(sampleDocSearchResultsNoSortId());
- const result = await searchAfterAndBulkCreate({
- someResult: repeatedSearchResultsWithSortId(4, 1, someGuids),
- ruleParams: sampleParams,
- services: mockService,
- logger: mockLogger,
- id: sampleRuleGuid,
- signalsIndex: DEFAULT_SIGNALS_INDEX,
- name: 'rule-name',
- createdBy: 'elastic',
- updatedBy: 'elastic',
- interval: '5m',
- enabled: true,
- pageSize: 1,
- filter: undefined,
- tags: ['some fake tag 1', 'some fake tag 2'],
- });
- expect(result).toEqual(true);
- });
- test('if successful iteration of while loop with maxDocs and search after returns empty results with no sort ids', async () => {
- const sampleParams = sampleRuleAlertParams(10);
- const someGuids = Array.from({ length: 4 }).map(x => uuid.v4());
- mockService.callCluster
- .mockReturnValueOnce({
- took: 100,
- errors: false,
- items: [
- {
- fakeItemValue: 'fakeItemKey',
- },
- ],
- })
- .mockReturnValueOnce(sampleEmptyDocSearchResults);
- const result = await searchAfterAndBulkCreate({
- someResult: repeatedSearchResultsWithSortId(4, 1, someGuids),
- ruleParams: sampleParams,
- services: mockService,
- logger: mockLogger,
- id: sampleRuleGuid,
- signalsIndex: DEFAULT_SIGNALS_INDEX,
- name: 'rule-name',
- createdBy: 'elastic',
- updatedBy: 'elastic',
- interval: '5m',
- enabled: true,
- pageSize: 1,
- filter: undefined,
- tags: ['some fake tag 1', 'some fake tag 2'],
- });
- expect(result).toEqual(true);
- });
- test('if returns false when singleSearchAfter throws an exception', async () => {
- const sampleParams = sampleRuleAlertParams(10);
- const someGuids = Array.from({ length: 4 }).map(x => uuid.v4());
- mockService.callCluster
- .mockReturnValueOnce({
- took: 100,
- errors: false,
- items: [
- {
- fakeItemValue: 'fakeItemKey',
- },
- ],
- })
- .mockImplementation(() => {
- throw Error('Fake Error');
- });
- const result = await searchAfterAndBulkCreate({
- someResult: repeatedSearchResultsWithSortId(4, 1, someGuids),
- ruleParams: sampleParams,
- services: mockService,
- logger: mockLogger,
- id: sampleRuleGuid,
- signalsIndex: DEFAULT_SIGNALS_INDEX,
- name: 'rule-name',
- createdBy: 'elastic',
- updatedBy: 'elastic',
- interval: '5m',
- enabled: true,
- pageSize: 1,
- filter: undefined,
- tags: ['some fake tag 1', 'some fake tag 2'],
- });
- expect(result).toEqual(false);
- });
- });
-
- describe('buildEventTypeSignal', () => {
- test('it returns the event appended of kind signal if it does not exist', () => {
- const doc = sampleDocNoSortId();
- delete doc._source.event;
- const eventType = buildEventTypeSignal(doc);
- const expected: object = { kind: 'signal' };
- expect(eventType).toEqual(expected);
- });
-
- test('it returns the event appended of kind signal if it is an empty object', () => {
- const doc = sampleDocNoSortId();
- doc._source.event = {};
- const eventType = buildEventTypeSignal(doc);
- const expected: object = { kind: 'signal' };
- expect(eventType).toEqual(expected);
- });
-
- test('it returns the event with kind signal and other properties if they exist', () => {
- const doc = sampleDocNoSortId();
- doc._source.event = {
- action: 'socket_opened',
- module: 'system',
- dataset: 'socket',
- };
- const eventType = buildEventTypeSignal(doc);
- const expected: object = {
- action: 'socket_opened',
- module: 'system',
- dataset: 'socket',
- kind: 'signal',
- };
- expect(eventType).toEqual(expected);
- });
- });
-
- describe('buildSignal', () => {
- test('it builds a signal as expected without original_event if event does not exist', () => {
- const doc = sampleDocNoSortId('d5e8eb51-a6a0-456d-8a15-4b79bfec3d71');
- delete doc._source.event;
- const rule: Partial = sampleRule();
- const signal = buildSignal(doc, rule);
- const expected: Signal = {
- parent: {
- id: 'd5e8eb51-a6a0-456d-8a15-4b79bfec3d71',
- type: 'event',
- index: 'myFakeSignalIndex',
- depth: 1,
- },
- original_time: 'someTimeStamp',
- status: 'open',
- rule: {
- created_by: 'elastic',
- description: 'Detecting root and admin users',
- enabled: true,
- false_positives: [],
- from: 'now-6m',
- id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
- immutable: false,
- index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
- interval: '5m',
- risk_score: 50,
- rule_id: 'rule-1',
- language: 'kuery',
- max_signals: 100,
- name: 'Detect Root/Admin Users',
- output_index: '.siem-signals',
- query: 'user.name: root or user.name: admin',
- references: ['http://www.example.com', 'https://ww.example.com'],
- severity: 'high',
- updated_by: 'elastic',
- tags: ['some fake tag 1', 'some fake tag 2'],
- to: 'now',
- type: 'query',
- },
- };
- expect(signal).toEqual(expected);
- });
-
- test('it builds a signal as expected with original_event if is present', () => {
- const doc = sampleDocNoSortId('d5e8eb51-a6a0-456d-8a15-4b79bfec3d71');
- doc._source.event = {
- action: 'socket_opened',
- dataset: 'socket',
- kind: 'event',
- module: 'system',
- };
- const rule: Partial = sampleRule();
- const signal = buildSignal(doc, rule);
- const expected: Signal = {
- parent: {
- id: 'd5e8eb51-a6a0-456d-8a15-4b79bfec3d71',
- type: 'event',
- index: 'myFakeSignalIndex',
- depth: 1,
- },
- original_time: 'someTimeStamp',
- original_event: {
- action: 'socket_opened',
- dataset: 'socket',
- kind: 'event',
- module: 'system',
- },
- status: 'open',
- rule: {
- created_by: 'elastic',
- description: 'Detecting root and admin users',
- enabled: true,
- false_positives: [],
- from: 'now-6m',
- id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
- immutable: false,
- index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
- interval: '5m',
- risk_score: 50,
- rule_id: 'rule-1',
- language: 'kuery',
- max_signals: 100,
- name: 'Detect Root/Admin Users',
- output_index: '.siem-signals',
- query: 'user.name: root or user.name: admin',
- references: ['http://www.example.com', 'https://ww.example.com'],
- severity: 'high',
- updated_by: 'elastic',
- tags: ['some fake tag 1', 'some fake tag 2'],
- to: 'now',
- type: 'query',
- },
- };
- expect(signal).toEqual(expected);
- });
- });
-
- describe('buildRule', () => {
- test('it builds a rule as expected with filters present', () => {
- const ruleParams = sampleRuleAlertParams();
- ruleParams.filters = [
- {
- query: 'host.name: Rebecca',
- },
- {
- query: 'host.name: Evan',
- },
- {
- query: 'host.name: Braden',
- },
- ];
- const rule = buildRule({
- ruleParams,
- name: 'some-name',
- id: sampleRuleGuid,
- enabled: false,
- createdBy: 'elastic',
- updatedBy: 'elastic',
- interval: 'some interval',
- tags: ['some fake tag 1', 'some fake tag 2'],
- });
- const expected: Partial = {
- created_by: 'elastic',
- description: 'Detecting root and admin users',
- enabled: false,
- false_positives: [],
- from: 'now-6m',
- id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
- immutable: false,
- index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
- interval: 'some interval',
- language: 'kuery',
- max_signals: 10000,
- name: 'some-name',
- output_index: '.siem-signals',
- query: 'user.name: root or user.name: admin',
- references: ['http://google.com'],
- risk_score: 50,
- rule_id: 'rule-1',
- severity: 'high',
- tags: ['some fake tag 1', 'some fake tag 2'],
- to: 'now',
- type: 'query',
- updated_by: 'elastic',
- filters: [
- {
- query: 'host.name: Rebecca',
- },
- {
- query: 'host.name: Evan',
- },
- {
- query: 'host.name: Braden',
- },
- ],
- };
- expect(rule).toEqual(expected);
- });
-
- test('it omits a null value such as if enabled is null if is present', () => {
- const ruleParams = sampleRuleAlertParams();
- ruleParams.filters = undefined;
- const rule = buildRule({
- ruleParams,
- name: 'some-name',
- id: sampleRuleGuid,
- enabled: true,
- createdBy: 'elastic',
- updatedBy: 'elastic',
- interval: 'some interval',
- tags: ['some fake tag 1', 'some fake tag 2'],
- });
- const expected: Partial = {
- created_by: 'elastic',
- description: 'Detecting root and admin users',
- enabled: true,
- false_positives: [],
- from: 'now-6m',
- id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
- immutable: false,
- index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
- interval: 'some interval',
- language: 'kuery',
- max_signals: 10000,
- name: 'some-name',
- output_index: '.siem-signals',
- query: 'user.name: root or user.name: admin',
- references: ['http://google.com'],
- risk_score: 50,
- rule_id: 'rule-1',
- severity: 'high',
- tags: ['some fake tag 1', 'some fake tag 2'],
- to: 'now',
- type: 'query',
- updated_by: 'elastic',
- };
- expect(rule).toEqual(expected);
- });
-
- test('it omits a null value such as if filters is undefined if is present', () => {
- const ruleParams = sampleRuleAlertParams();
- ruleParams.filters = undefined;
- const rule = buildRule({
- ruleParams,
- name: 'some-name',
- id: sampleRuleGuid,
- enabled: true,
- createdBy: 'elastic',
- updatedBy: 'elastic',
- interval: 'some interval',
- tags: ['some fake tag 1', 'some fake tag 2'],
- });
- const expected: Partial = {
- created_by: 'elastic',
- description: 'Detecting root and admin users',
- enabled: true,
- false_positives: [],
- from: 'now-6m',
- id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
- immutable: false,
- index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
- interval: 'some interval',
- language: 'kuery',
- max_signals: 10000,
- name: 'some-name',
- output_index: '.siem-signals',
- query: 'user.name: root or user.name: admin',
- references: ['http://google.com'],
- risk_score: 50,
- rule_id: 'rule-1',
- severity: 'high',
- tags: ['some fake tag 1', 'some fake tag 2'],
- to: 'now',
- type: 'query',
- updated_by: 'elastic',
- };
- expect(rule).toEqual(expected);
- });
- });
-});
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/alerts/utils.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/alerts/utils.ts
deleted file mode 100644
index 1787aa3a3081..000000000000
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/alerts/utils.ts
+++ /dev/null
@@ -1,408 +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 { createHash } from 'crypto';
-import { performance } from 'perf_hooks';
-import { pickBy } from 'lodash/fp';
-import { SignalHit, Signal } from '../../types';
-import { Logger } from '../../../../../../../../src/core/server';
-import { AlertServices } from '../../../../../alerting/server/types';
-import {
- SignalSourceHit,
- SignalSearchResponse,
- BulkResponse,
- RuleTypeParams,
- OutputRuleAlertRest,
-} from './types';
-import { buildEventsSearchQuery } from './build_events_query';
-
-interface BuildRuleParams {
- ruleParams: RuleTypeParams;
- name: string;
- id: string;
- enabled: boolean;
- createdBy: string;
- updatedBy: string;
- interval: string;
- tags: string[];
-}
-
-export const buildRule = ({
- ruleParams,
- name,
- id,
- enabled,
- createdBy,
- updatedBy,
- interval,
- tags,
-}: BuildRuleParams): Partial => {
- return pickBy((value: unknown) => value != null, {
- id,
- rule_id: ruleParams.ruleId,
- false_positives: ruleParams.falsePositives,
- saved_id: ruleParams.savedId,
- meta: ruleParams.meta,
- max_signals: ruleParams.maxSignals,
- risk_score: ruleParams.riskScore,
- output_index: ruleParams.outputIndex,
- description: ruleParams.description,
- from: ruleParams.from,
- immutable: ruleParams.immutable,
- index: ruleParams.index,
- interval,
- language: ruleParams.language,
- name,
- query: ruleParams.query,
- references: ruleParams.references,
- severity: ruleParams.severity,
- tags,
- type: ruleParams.type,
- to: ruleParams.to,
- enabled,
- filters: ruleParams.filters,
- created_by: createdBy,
- updated_by: updatedBy,
- threats: ruleParams.threats,
- });
-};
-
-export const buildSignal = (doc: SignalSourceHit, rule: Partial): Signal => {
- const signal: Signal = {
- parent: {
- id: doc._id,
- type: 'event',
- index: doc._index,
- depth: 1,
- },
- original_time: doc._source['@timestamp'],
- status: 'open',
- rule,
- };
- if (doc._source.event != null) {
- return { ...signal, original_event: doc._source.event };
- }
- return signal;
-};
-
-interface BuildBulkBodyParams {
- doc: SignalSourceHit;
- ruleParams: RuleTypeParams;
- id: string;
- name: string;
- createdBy: string;
- updatedBy: string;
- interval: string;
- enabled: boolean;
- tags: string[];
-}
-
-export const buildEventTypeSignal = (doc: SignalSourceHit): object => {
- if (doc._source.event != null && doc._source.event instanceof Object) {
- return { ...doc._source.event, kind: 'signal' };
- } else {
- return { kind: 'signal' };
- }
-};
-
-// format search_after result for signals index.
-export const buildBulkBody = ({
- doc,
- ruleParams,
- id,
- name,
- createdBy,
- updatedBy,
- interval,
- enabled,
- tags,
-}: BuildBulkBodyParams): SignalHit => {
- const rule = buildRule({
- ruleParams,
- id,
- name,
- enabled,
- createdBy,
- updatedBy,
- interval,
- tags,
- });
- const signal = buildSignal(doc, rule);
- const event = buildEventTypeSignal(doc);
- const signalHit: SignalHit = {
- ...doc._source,
- '@timestamp': new Date().toISOString(),
- event,
- signal,
- };
- return signalHit;
-};
-
-interface SingleBulkCreateParams {
- someResult: SignalSearchResponse;
- ruleParams: RuleTypeParams;
- services: AlertServices;
- logger: Logger;
- id: string;
- signalsIndex: string;
- name: string;
- createdBy: string;
- updatedBy: string;
- interval: string;
- enabled: boolean;
- tags: string[];
-}
-
-export const generateId = (
- docIndex: string,
- docId: string,
- version: string,
- ruleId: string
-): string =>
- createHash('sha256')
- .update(docIndex.concat(docId, version, ruleId))
- .digest('hex');
-
-// Bulk Index documents.
-export const singleBulkCreate = async ({
- someResult,
- ruleParams,
- services,
- logger,
- id,
- signalsIndex,
- name,
- createdBy,
- updatedBy,
- interval,
- enabled,
- tags,
-}: SingleBulkCreateParams): Promise => {
- if (someResult.hits.hits.length === 0) {
- return true;
- }
- // index documents after creating an ID based on the
- // source documents' originating index, and the original
- // document _id. This will allow two documents from two
- // different indexes with the same ID to be
- // indexed, and prevents us from creating any updates
- // to the documents once inserted into the signals index,
- // while preventing duplicates from being added to the
- // signals index if rules are re-run over the same time
- // span. Also allow for versioning.
- const bulkBody = someResult.hits.hits.flatMap(doc => [
- {
- create: {
- _index: signalsIndex,
- _id: generateId(
- doc._index,
- doc._id,
- doc._version ? doc._version.toString() : '',
- ruleParams.ruleId ?? ''
- ),
- },
- },
- buildBulkBody({ doc, ruleParams, id, name, createdBy, updatedBy, interval, enabled, tags }),
- ]);
- const time1 = performance.now();
- const firstResult: BulkResponse = await services.callCluster('bulk', {
- index: signalsIndex,
- refresh: false,
- body: bulkBody,
- });
- const time2 = performance.now();
- logger.debug(
- `individual bulk process time took: ${Number(time2 - time1).toFixed(2)} milliseconds`
- );
- logger.debug(`took property says bulk took: ${firstResult.took} milliseconds`);
- if (firstResult.errors) {
- // go through the response status errors and see what
- // types of errors they are, count them up, and log them.
- const errorCountMap = firstResult.items.reduce((acc: { [key: string]: number }, item) => {
- if (item.create.error) {
- const responseStatusKey = item.create.status.toString();
- acc[responseStatusKey] = acc[responseStatusKey] ? acc[responseStatusKey] + 1 : 1;
- }
- return acc;
- }, {});
- /*
- the logging output below should look like
- {'409': 55}
- which is read as "there were 55 counts of 409 errors returned from bulk create"
- */
- logger.error(
- `[-] bulkResponse had errors with response statuses:counts of...\n${JSON.stringify(
- errorCountMap,
- null,
- 2
- )}`
- );
- }
- return true;
-};
-
-interface SingleSearchAfterParams {
- searchAfterSortId: string | undefined;
- ruleParams: RuleTypeParams;
- services: AlertServices;
- logger: Logger;
- pageSize: number;
- filter: unknown;
-}
-
-// utilize search_after for paging results into bulk.
-export const singleSearchAfter = async ({
- searchAfterSortId,
- ruleParams,
- services,
- filter,
- logger,
- pageSize,
-}: SingleSearchAfterParams): Promise => {
- if (searchAfterSortId == null) {
- throw Error('Attempted to search after with empty sort id');
- }
- try {
- const searchAfterQuery = buildEventsSearchQuery({
- index: ruleParams.index,
- from: ruleParams.from,
- to: ruleParams.to,
- filter,
- size: pageSize,
- searchAfterSortId,
- });
- const nextSearchAfterResult: SignalSearchResponse = await services.callCluster(
- 'search',
- searchAfterQuery
- );
- return nextSearchAfterResult;
- } catch (exc) {
- logger.error(`[-] nextSearchAfter threw an error ${exc}`);
- throw exc;
- }
-};
-
-interface SearchAfterAndBulkCreateParams {
- someResult: SignalSearchResponse;
- ruleParams: RuleTypeParams;
- services: AlertServices;
- logger: Logger;
- id: string;
- signalsIndex: string;
- name: string;
- createdBy: string;
- updatedBy: string;
- interval: string;
- enabled: boolean;
- pageSize: number;
- filter: unknown;
- tags: string[];
-}
-
-// search_after through documents and re-index using bulk endpoint.
-export const searchAfterAndBulkCreate = async ({
- someResult,
- ruleParams,
- services,
- logger,
- id,
- signalsIndex,
- filter,
- name,
- createdBy,
- updatedBy,
- interval,
- enabled,
- pageSize,
- tags,
-}: SearchAfterAndBulkCreateParams): Promise => {
- if (someResult.hits.hits.length === 0) {
- return true;
- }
-
- logger.debug('[+] starting bulk insertion');
- await singleBulkCreate({
- someResult,
- ruleParams,
- services,
- logger,
- id,
- signalsIndex,
- name,
- createdBy,
- updatedBy,
- interval,
- enabled,
- tags,
- });
- const totalHits =
- typeof someResult.hits.total === 'number' ? someResult.hits.total : someResult.hits.total.value;
- // maxTotalHitsSize represents the total number of docs to
- // query for, no matter the size of each individual page of search results.
- // If the total number of hits for the overall search result is greater than
- // maxSignals, default to requesting a total of maxSignals, otherwise use the
- // totalHits in the response from the searchAfter query.
- const maxTotalHitsSize = totalHits >= ruleParams.maxSignals ? ruleParams.maxSignals : totalHits;
-
- // number of docs in the current search result
- let hitsSize = someResult.hits.hits.length;
- logger.debug(`first size: ${hitsSize}`);
- let sortIds = someResult.hits.hits[0].sort;
- if (sortIds == null && totalHits > 0) {
- logger.error('sortIds was empty on first search but expected more');
- return false;
- } else if (sortIds == null && totalHits === 0) {
- return true;
- }
- let sortId;
- if (sortIds != null) {
- sortId = sortIds[0];
- }
- while (hitsSize < maxTotalHitsSize && hitsSize !== 0) {
- try {
- logger.debug(`sortIds: ${sortIds}`);
- const searchAfterResult: SignalSearchResponse = await singleSearchAfter({
- searchAfterSortId: sortId,
- ruleParams,
- services,
- logger,
- filter,
- pageSize, // maximum number of docs to receive per search result.
- });
- if (searchAfterResult.hits.hits.length === 0) {
- return true;
- }
- hitsSize += searchAfterResult.hits.hits.length;
- logger.debug(`size adjusted: ${hitsSize}`);
- sortIds = searchAfterResult.hits.hits[0].sort;
- if (sortIds == null) {
- logger.debug('sortIds was empty on search');
- return true; // no more search results
- }
- sortId = sortIds[0];
- logger.debug('next bulk index');
- await singleBulkCreate({
- someResult: searchAfterResult,
- ruleParams,
- services,
- logger,
- id,
- signalsIndex,
- name,
- createdBy,
- updatedBy,
- interval,
- enabled,
- tags,
- });
- logger.debug('finished next bulk index');
- } catch (exc) {
- logger.error(`[-] search_after and bulk threw an error ${exc}`);
- return false;
- }
- }
- logger.debug(`[+] completed bulk index of ${maxTotalHitsSize}`);
- return true;
-};
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts
index cd8b716221b9..978434859ef9 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts
@@ -6,11 +6,13 @@
import { ServerInjectOptions } from 'hapi';
import { ActionResult } from '../../../../../../actions/server/types';
-import { RuleAlertParamsRest, RuleAlertType, SignalsRestParams } from '../../alerts/types';
+import { SignalsRestParams } from '../../signals/types';
import {
DETECTION_ENGINE_RULES_URL,
DETECTION_ENGINE_SIGNALS_STATUS_URL,
} from '../../../../../common/constants';
+import { RuleAlertType } from '../../rules/types';
+import { RuleAlertParamsRest } from '../../types';
// The Omit of filter is because of a Hapi Server Typing issue that I am unclear
// where it comes from. I would hope to remove the "filter" as an omit at some point
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/create_rules_route.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.test.ts
similarity index 96%
rename from x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/create_rules_route.test.ts
rename to x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.test.ts
index b271af2db1e7..094449a5f61a 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/create_rules_route.test.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.test.ts
@@ -9,7 +9,7 @@ import {
createMockServerWithoutActionClientDecoration,
createMockServerWithoutAlertClientDecoration,
createMockServerWithoutActionOrAlertClientDecoration,
-} from './__mocks__/_mock_server';
+} from '../__mocks__/_mock_server';
import { createRulesRoute } from './create_rules_route';
import { ServerInjectOptions } from 'hapi';
import {
@@ -18,8 +18,8 @@ import {
createActionResult,
getCreateRequest,
typicalPayload,
-} from './__mocks__/request_responses';
-import { DETECTION_ENGINE_RULES_URL } from '../../../../common/constants';
+} from '../__mocks__/request_responses';
+import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants';
describe('create_rules', () => {
let { server, alertsClient, actionsClient, elasticsearch } = createMockServer();
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/create_rules_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts
similarity index 85%
rename from x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/create_rules_route.ts
rename to x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts
index a137d5425018..0dc213e9e217 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/create_rules_route.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts
@@ -8,14 +8,15 @@ import Hapi from 'hapi';
import { isFunction } from 'lodash/fp';
import Boom from 'boom';
import uuid from 'uuid';
-import { DETECTION_ENGINE_RULES_URL } from '../../../../common/constants';
-import { createRules } from '../alerts/create_rules';
-import { RulesRequest } from '../alerts/types';
-import { createRulesSchema } from './schemas';
-import { ServerFacade } from '../../../types';
-import { readRules } from '../alerts/read_rules';
-import { transformOrError, transformError, getIndex, callWithRequestFactory } from './utils';
-import { getIndexExists } from '../index/get_index_exists';
+import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants';
+import { createRules } from '../../rules/create_rules';
+import { RulesRequest } from '../../rules/types';
+import { createRulesSchema } from '../schemas/create_rules_schema';
+import { ServerFacade } from '../../../../types';
+import { readRules } from '../../rules/read_rules';
+import { transformOrError } from './utils';
+import { getIndexExists } from '../../index/get_index_exists';
+import { callWithRequestFactory, getIndex, transformError } from '../utils';
export const createCreateRulesRoute = (server: ServerFacade): Hapi.ServerRoute => {
return {
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/delete_rules_route.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/delete_rules_route.test.ts
similarity index 96%
rename from x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/delete_rules_route.test.ts
rename to x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/delete_rules_route.test.ts
index 0808051964dc..cacafcf741e6 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/delete_rules_route.test.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/delete_rules_route.test.ts
@@ -9,7 +9,7 @@ import {
createMockServerWithoutActionClientDecoration,
createMockServerWithoutAlertClientDecoration,
createMockServerWithoutActionOrAlertClientDecoration,
-} from './__mocks__/_mock_server';
+} from '../__mocks__/_mock_server';
import { deleteRulesRoute } from './delete_rules_route';
import { ServerInjectOptions } from 'hapi';
@@ -19,8 +19,8 @@ import {
getDeleteRequest,
getFindResultWithSingleHit,
getDeleteRequestById,
-} from './__mocks__/request_responses';
-import { DETECTION_ENGINE_RULES_URL } from '../../../../common/constants';
+} from '../__mocks__/request_responses';
+import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants';
describe('delete_rules', () => {
let { server, alertsClient } = createMockServer();
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/delete_rules_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/delete_rules_route.ts
similarity index 78%
rename from x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/delete_rules_route.ts
rename to x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/delete_rules_route.ts
index fe8b139f11c0..c2b2e2fdbbae 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/delete_rules_route.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/delete_rules_route.ts
@@ -7,12 +7,13 @@
import Hapi from 'hapi';
import { isFunction } from 'lodash/fp';
-import { DETECTION_ENGINE_RULES_URL } from '../../../../common/constants';
-import { deleteRules } from '../alerts/delete_rules';
-import { ServerFacade } from '../../../types';
-import { queryRulesSchema } from './schemas';
-import { QueryRequest } from '../alerts/types';
-import { getIdError, transformOrError, transformError } from './utils';
+import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants';
+import { deleteRules } from '../../rules/delete_rules';
+import { ServerFacade } from '../../../../types';
+import { queryRulesSchema } from '../schemas/query_rules_schema';
+import { getIdError, transformOrError } from './utils';
+import { transformError } from '../utils';
+import { QueryRequest } from './types';
export const createDeleteRulesRoute: Hapi.ServerRoute = {
method: 'DELETE',
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/find_rules_route.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_route.test.ts
similarity index 94%
rename from x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/find_rules_route.test.ts
rename to x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_route.test.ts
index dae40f05155d..38937c13d302 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/find_rules_route.test.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_route.test.ts
@@ -9,12 +9,12 @@ import {
createMockServerWithoutActionClientDecoration,
createMockServerWithoutAlertClientDecoration,
createMockServerWithoutActionOrAlertClientDecoration,
-} from './__mocks__/_mock_server';
+} from '../__mocks__/_mock_server';
import { findRulesRoute } from './find_rules_route';
import { ServerInjectOptions } from 'hapi';
-import { getFindResult, getResult, getFindRequest } from './__mocks__/request_responses';
-import { DETECTION_ENGINE_RULES_URL } from '../../../../common/constants';
+import { getFindResult, getResult, getFindRequest } from '../__mocks__/request_responses';
+import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants';
describe('find_rules', () => {
let { server, alertsClient, actionsClient } = createMockServer();
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/find_rules_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_route.ts
similarity index 78%
rename from x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/find_rules_route.ts
rename to x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_route.ts
index 137dd9352699..6e89ddb19017 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/find_rules_route.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_route.ts
@@ -6,12 +6,13 @@
import Hapi from 'hapi';
import { isFunction } from 'lodash/fp';
-import { DETECTION_ENGINE_RULES_URL } from '../../../../common/constants';
-import { findRules } from '../alerts/find_rules';
-import { FindRulesRequest } from '../alerts/types';
-import { findRulesSchema } from './schemas';
-import { ServerFacade } from '../../../types';
-import { transformFindAlertsOrError, transformError } from './utils';
+import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants';
+import { findRules } from '../../rules/find_rules';
+import { FindRulesRequest } from '../../rules/types';
+import { findRulesSchema } from '../schemas/find_rules_schema';
+import { ServerFacade } from '../../../../types';
+import { transformFindAlertsOrError } from './utils';
+import { transformError } from '../utils';
export const createFindRulesRoute: Hapi.ServerRoute = {
method: 'GET',
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/read_rules_route.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/read_rules_route.test.ts
similarity index 94%
rename from x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/read_rules_route.test.ts
rename to x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/read_rules_route.test.ts
index 47ecf62f41be..0d77583573c1 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/read_rules_route.test.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/read_rules_route.test.ts
@@ -9,7 +9,7 @@ import {
createMockServerWithoutActionClientDecoration,
createMockServerWithoutAlertClientDecoration,
createMockServerWithoutActionOrAlertClientDecoration,
-} from './__mocks__/_mock_server';
+} from '../__mocks__/_mock_server';
import { readRulesRoute } from './read_rules_route';
import { ServerInjectOptions } from 'hapi';
@@ -18,8 +18,8 @@ import {
getResult,
getReadRequest,
getFindResultWithSingleHit,
-} from './__mocks__/request_responses';
-import { DETECTION_ENGINE_RULES_URL } from '../../../../common/constants';
+} from '../__mocks__/request_responses';
+import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants';
describe('read_signals', () => {
let { server, alertsClient } = createMockServer();
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/read_rules_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/read_rules_route.ts
similarity index 78%
rename from x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/read_rules_route.ts
rename to x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/read_rules_route.ts
index a7bda40fdc52..a842e68b6b7f 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/read_rules_route.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/read_rules_route.ts
@@ -6,13 +6,14 @@
import Hapi from 'hapi';
import { isFunction } from 'lodash/fp';
-import { DETECTION_ENGINE_RULES_URL } from '../../../../common/constants';
-import { getIdError, transformOrError, transformError } from './utils';
+import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants';
+import { getIdError, transformOrError } from './utils';
+import { transformError } from '../utils';
-import { readRules } from '../alerts/read_rules';
-import { ServerFacade } from '../../../types';
-import { queryRulesSchema } from './schemas';
-import { QueryRequest } from '../alerts/types';
+import { readRules } from '../../rules/read_rules';
+import { ServerFacade } from '../../../../types';
+import { queryRulesSchema } from '../schemas/query_rules_schema';
+import { QueryRequest } from './types';
export const createReadRulesRoute: Hapi.ServerRoute = {
method: 'GET',
diff --git a/x-pack/legacy/plugins/watcher/server/routes/api/fields/index.js b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/types.ts
similarity index 57%
rename from x-pack/legacy/plugins/watcher/server/routes/api/fields/index.js
rename to x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/types.ts
index 8474f8a614bf..f6878c9edc9b 100644
--- a/x-pack/legacy/plugins/watcher/server/routes/api/fields/index.js
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/types.ts
@@ -4,4 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export { registerFieldsRoutes } from './register_fields_routes';
+import { RequestFacade } from '../../../../types';
+
+export type QueryRequest = Omit & {
+ query: { id: string | undefined; rule_id: string | undefined };
+};
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/update_rules_route.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.test.ts
similarity index 97%
rename from x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/update_rules_route.test.ts
rename to x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.test.ts
index dfa1275a6b26..3cf5c07655d9 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/update_rules_route.test.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.test.ts
@@ -9,7 +9,7 @@ import {
createMockServerWithoutActionClientDecoration,
createMockServerWithoutAlertClientDecoration,
createMockServerWithoutActionOrAlertClientDecoration,
-} from './__mocks__/_mock_server';
+} from '../__mocks__/_mock_server';
import { updateRulesRoute } from './update_rules_route';
import { ServerInjectOptions } from 'hapi';
@@ -20,8 +20,8 @@ import {
getUpdateRequest,
typicalPayload,
getFindResultWithSingleHit,
-} from './__mocks__/request_responses';
-import { DETECTION_ENGINE_RULES_URL } from '../../../../common/constants';
+} from '../__mocks__/request_responses';
+import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants';
describe('update_rules', () => {
let { server, alertsClient, actionsClient } = createMockServer();
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/update_rules_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.ts
similarity index 84%
rename from x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/update_rules_route.ts
rename to x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.ts
index 943c41fd6dea..2e7b48afbb5d 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/update_rules_route.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.ts
@@ -6,12 +6,13 @@
import Hapi from 'hapi';
import { isFunction } from 'lodash/fp';
-import { DETECTION_ENGINE_RULES_URL } from '../../../../common/constants';
-import { updateRules } from '../alerts/update_rules';
-import { UpdateRulesRequest } from '../alerts/types';
-import { updateRulesSchema } from './schemas';
-import { ServerFacade } from '../../../types';
-import { getIdError, transformOrError, transformError } from './utils';
+import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants';
+import { updateRules } from '../../rules/update_rules';
+import { UpdateRulesRequest } from '../../rules/types';
+import { updateRulesSchema } from '../schemas/update_rules_schema';
+import { ServerFacade } from '../../../../types';
+import { getIdError, transformOrError } from './utils';
+import { transformError } from '../utils';
export const createUpdateRulesRoute: Hapi.ServerRoute = {
method: 'PUT',
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts
new file mode 100644
index 000000000000..d4e129f543cc
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts
@@ -0,0 +1,496 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import Boom from 'boom';
+
+import {
+ transformAlertToRule,
+ getIdError,
+ transformFindAlertsOrError,
+ transformOrError,
+} from './utils';
+import { getResult } from '../__mocks__/request_responses';
+
+describe('utils', () => {
+ describe('transformAlertToRule', () => {
+ test('should work with a full data set', () => {
+ const fullRule = getResult();
+ const rule = transformAlertToRule(fullRule);
+ expect(rule).toEqual({
+ created_by: 'elastic',
+ description: 'Detecting root and admin users',
+ enabled: true,
+ false_positives: [],
+ from: 'now-6m',
+ id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
+ immutable: false,
+ index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
+ interval: '5m',
+ risk_score: 50,
+ rule_id: 'rule-1',
+ language: 'kuery',
+ max_signals: 100,
+ name: 'Detect Root/Admin Users',
+ output_index: '.siem-signals',
+ query: 'user.name: root or user.name: admin',
+ references: ['http://www.example.com', 'https://ww.example.com'],
+ severity: 'high',
+ updated_by: 'elastic',
+ tags: [],
+ threats: [
+ {
+ framework: 'MITRE ATT&CK',
+ tactic: {
+ id: 'TA0040',
+ name: 'impact',
+ reference: 'https://attack.mitre.org/tactics/TA0040/',
+ },
+ techniques: [
+ {
+ id: 'T1499',
+ name: 'endpoint denial of service',
+ reference: 'https://attack.mitre.org/techniques/T1499/',
+ },
+ ],
+ },
+ ],
+ to: 'now',
+ type: 'query',
+ });
+ });
+
+ test('should work with a partial data set missing data', () => {
+ const fullRule = getResult();
+ const { from, language, ...omitData } = transformAlertToRule(fullRule);
+ expect(omitData).toEqual({
+ created_by: 'elastic',
+ description: 'Detecting root and admin users',
+ enabled: true,
+ false_positives: [],
+ id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
+ immutable: false,
+ index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
+ output_index: '.siem-signals',
+ interval: '5m',
+ risk_score: 50,
+ rule_id: 'rule-1',
+ max_signals: 100,
+ name: 'Detect Root/Admin Users',
+ query: 'user.name: root or user.name: admin',
+ references: ['http://www.example.com', 'https://ww.example.com'],
+ severity: 'high',
+ updated_by: 'elastic',
+ tags: [],
+ threats: [
+ {
+ framework: 'MITRE ATT&CK',
+ tactic: {
+ id: 'TA0040',
+ name: 'impact',
+ reference: 'https://attack.mitre.org/tactics/TA0040/',
+ },
+ techniques: [
+ {
+ id: 'T1499',
+ name: 'endpoint denial of service',
+ reference: 'https://attack.mitre.org/techniques/T1499/',
+ },
+ ],
+ },
+ ],
+ to: 'now',
+ type: 'query',
+ });
+ });
+
+ test('should omit query if query is null', () => {
+ const fullRule = getResult();
+ fullRule.params.query = null;
+ const rule = transformAlertToRule(fullRule);
+ expect(rule).toEqual({
+ created_by: 'elastic',
+ description: 'Detecting root and admin users',
+ enabled: true,
+ false_positives: [],
+ from: 'now-6m',
+ id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
+ immutable: false,
+ index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
+ output_index: '.siem-signals',
+ interval: '5m',
+ risk_score: 50,
+ rule_id: 'rule-1',
+ language: 'kuery',
+ max_signals: 100,
+ name: 'Detect Root/Admin Users',
+ references: ['http://www.example.com', 'https://ww.example.com'],
+ severity: 'high',
+ updated_by: 'elastic',
+ tags: [],
+ threats: [
+ {
+ framework: 'MITRE ATT&CK',
+ tactic: {
+ id: 'TA0040',
+ name: 'impact',
+ reference: 'https://attack.mitre.org/tactics/TA0040/',
+ },
+ techniques: [
+ {
+ id: 'T1499',
+ name: 'endpoint denial of service',
+ reference: 'https://attack.mitre.org/techniques/T1499/',
+ },
+ ],
+ },
+ ],
+ to: 'now',
+ type: 'query',
+ });
+ });
+
+ test('should omit query if query is undefined', () => {
+ const fullRule = getResult();
+ fullRule.params.query = undefined;
+ const rule = transformAlertToRule(fullRule);
+ expect(rule).toEqual({
+ created_by: 'elastic',
+ description: 'Detecting root and admin users',
+ enabled: true,
+ false_positives: [],
+ from: 'now-6m',
+ id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
+ immutable: false,
+ index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
+ output_index: '.siem-signals',
+ interval: '5m',
+ rule_id: 'rule-1',
+ risk_score: 50,
+ language: 'kuery',
+ max_signals: 100,
+ name: 'Detect Root/Admin Users',
+ references: ['http://www.example.com', 'https://ww.example.com'],
+ severity: 'high',
+ updated_by: 'elastic',
+ tags: [],
+ threats: [
+ {
+ framework: 'MITRE ATT&CK',
+ tactic: {
+ id: 'TA0040',
+ name: 'impact',
+ reference: 'https://attack.mitre.org/tactics/TA0040/',
+ },
+ techniques: [
+ {
+ id: 'T1499',
+ name: 'endpoint denial of service',
+ reference: 'https://attack.mitre.org/techniques/T1499/',
+ },
+ ],
+ },
+ ],
+ to: 'now',
+ type: 'query',
+ });
+ });
+
+ test('should omit a mix of undefined, null, and missing fields', () => {
+ const fullRule = getResult();
+ fullRule.params.query = undefined;
+ fullRule.params.language = null;
+ const { from, enabled, ...omitData } = transformAlertToRule(fullRule);
+ expect(omitData).toEqual({
+ created_by: 'elastic',
+ description: 'Detecting root and admin users',
+ false_positives: [],
+ id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
+ immutable: false,
+ output_index: '.siem-signals',
+ index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
+ interval: '5m',
+ rule_id: 'rule-1',
+ risk_score: 50,
+ max_signals: 100,
+ name: 'Detect Root/Admin Users',
+ references: ['http://www.example.com', 'https://ww.example.com'],
+ severity: 'high',
+ updated_by: 'elastic',
+ tags: [],
+ threats: [
+ {
+ framework: 'MITRE ATT&CK',
+ tactic: {
+ id: 'TA0040',
+ name: 'impact',
+ reference: 'https://attack.mitre.org/tactics/TA0040/',
+ },
+ techniques: [
+ {
+ id: 'T1499',
+ name: 'endpoint denial of service',
+ reference: 'https://attack.mitre.org/techniques/T1499/',
+ },
+ ],
+ },
+ ],
+ to: 'now',
+ type: 'query',
+ });
+ });
+
+ test('should return enabled is equal to false', () => {
+ const fullRule = getResult();
+ fullRule.enabled = false;
+ const ruleWithEnabledFalse = transformAlertToRule(fullRule);
+ expect(ruleWithEnabledFalse).toEqual({
+ created_by: 'elastic',
+ description: 'Detecting root and admin users',
+ enabled: false,
+ from: 'now-6m',
+ false_positives: [],
+ id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
+ immutable: false,
+ output_index: '.siem-signals',
+ index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
+ interval: '5m',
+ language: 'kuery',
+ risk_score: 50,
+ rule_id: 'rule-1',
+ max_signals: 100,
+ name: 'Detect Root/Admin Users',
+ query: 'user.name: root or user.name: admin',
+ references: ['http://www.example.com', 'https://ww.example.com'],
+ severity: 'high',
+ updated_by: 'elastic',
+ tags: [],
+ threats: [
+ {
+ framework: 'MITRE ATT&CK',
+ tactic: {
+ id: 'TA0040',
+ name: 'impact',
+ reference: 'https://attack.mitre.org/tactics/TA0040/',
+ },
+ techniques: [
+ {
+ id: 'T1499',
+ name: 'endpoint denial of service',
+ reference: 'https://attack.mitre.org/techniques/T1499/',
+ },
+ ],
+ },
+ ],
+ to: 'now',
+ type: 'query',
+ });
+ });
+
+ test('should return immutable is equal to false', () => {
+ const fullRule = getResult();
+ fullRule.params.immutable = false;
+ const ruleWithEnabledFalse = transformAlertToRule(fullRule);
+ expect(ruleWithEnabledFalse).toEqual({
+ created_by: 'elastic',
+ description: 'Detecting root and admin users',
+ enabled: true,
+ from: 'now-6m',
+ false_positives: [],
+ id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
+ immutable: false,
+ output_index: '.siem-signals',
+ index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
+ interval: '5m',
+ language: 'kuery',
+ risk_score: 50,
+ rule_id: 'rule-1',
+ max_signals: 100,
+ name: 'Detect Root/Admin Users',
+ query: 'user.name: root or user.name: admin',
+ references: ['http://www.example.com', 'https://ww.example.com'],
+ severity: 'high',
+ updated_by: 'elastic',
+ tags: [],
+ threats: [
+ {
+ framework: 'MITRE ATT&CK',
+ tactic: {
+ id: 'TA0040',
+ name: 'impact',
+ reference: 'https://attack.mitre.org/tactics/TA0040/',
+ },
+ techniques: [
+ {
+ id: 'T1499',
+ name: 'endpoint denial of service',
+ reference: 'https://attack.mitre.org/techniques/T1499/',
+ },
+ ],
+ },
+ ],
+ to: 'now',
+ type: 'query',
+ });
+ });
+ });
+
+ describe('getIdError', () => {
+ test('outputs message about id not being found if only id is defined and ruleId is undefined', () => {
+ const boom = getIdError({ id: '123', ruleId: undefined });
+ expect(boom.message).toEqual('id: "123" not found');
+ });
+
+ test('outputs message about id not being found if only id is defined and ruleId is null', () => {
+ const boom = getIdError({ id: '123', ruleId: null });
+ expect(boom.message).toEqual('id: "123" not found');
+ });
+
+ test('outputs message about ruleId not being found if only ruleId is defined and id is undefined', () => {
+ const boom = getIdError({ id: undefined, ruleId: 'rule-id-123' });
+ expect(boom.message).toEqual('rule_id: "rule-id-123" not found');
+ });
+
+ test('outputs message about ruleId not being found if only ruleId is defined and id is null', () => {
+ const boom = getIdError({ id: null, ruleId: 'rule-id-123' });
+ expect(boom.message).toEqual('rule_id: "rule-id-123" not found');
+ });
+
+ test('outputs message about both being not defined when both are undefined', () => {
+ const boom = getIdError({ id: undefined, ruleId: undefined });
+ expect(boom.message).toEqual('id or rule_id should have been defined');
+ });
+
+ test('outputs message about both being not defined when both are null', () => {
+ const boom = getIdError({ id: null, ruleId: null });
+ expect(boom.message).toEqual('id or rule_id should have been defined');
+ });
+
+ test('outputs message about both being not defined when id is null and ruleId is undefined', () => {
+ const boom = getIdError({ id: null, ruleId: undefined });
+ expect(boom.message).toEqual('id or rule_id should have been defined');
+ });
+
+ test('outputs message about both being not defined when id is undefined and ruleId is null', () => {
+ const boom = getIdError({ id: undefined, ruleId: null });
+ expect(boom.message).toEqual('id or rule_id should have been defined');
+ });
+ });
+
+ describe('transformFindAlertsOrError', () => {
+ test('outputs empty data set when data set is empty correct', () => {
+ const output = transformFindAlertsOrError({ data: [] });
+ expect(output).toEqual({ data: [] });
+ });
+
+ test('outputs 200 if the data is of type siem alert', () => {
+ const output = transformFindAlertsOrError({
+ data: [getResult()],
+ });
+ expect(output).toEqual({
+ data: [
+ {
+ created_by: 'elastic',
+ description: 'Detecting root and admin users',
+ enabled: true,
+ false_positives: [],
+ from: 'now-6m',
+ id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
+ immutable: false,
+ output_index: '.siem-signals',
+ index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
+ interval: '5m',
+ risk_score: 50,
+ rule_id: 'rule-1',
+ language: 'kuery',
+ max_signals: 100,
+ name: 'Detect Root/Admin Users',
+ query: 'user.name: root or user.name: admin',
+ references: ['http://www.example.com', 'https://ww.example.com'],
+ severity: 'high',
+ updated_by: 'elastic',
+ tags: [],
+ to: 'now',
+ type: 'query',
+ threats: [
+ {
+ framework: 'MITRE ATT&CK',
+ tactic: {
+ id: 'TA0040',
+ name: 'impact',
+ reference: 'https://attack.mitre.org/tactics/TA0040/',
+ },
+ techniques: [
+ {
+ id: 'T1499',
+ name: 'endpoint denial of service',
+ reference: 'https://attack.mitre.org/techniques/T1499/',
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ });
+ });
+
+ test('returns 500 if the data is not of type siem alert', () => {
+ const output = transformFindAlertsOrError({ data: [{ random: 1 }] });
+ expect((output as Boom).message).toEqual('Internal error transforming');
+ });
+ });
+
+ describe('transformOrError', () => {
+ test('outputs 200 if the data is of type siem alert', () => {
+ const output = transformOrError(getResult());
+ expect(output).toEqual({
+ created_by: 'elastic',
+ description: 'Detecting root and admin users',
+ enabled: true,
+ false_positives: [],
+ from: 'now-6m',
+ id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
+ immutable: false,
+ output_index: '.siem-signals',
+ index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
+ interval: '5m',
+ rule_id: 'rule-1',
+ risk_score: 50,
+ language: 'kuery',
+ max_signals: 100,
+ name: 'Detect Root/Admin Users',
+ query: 'user.name: root or user.name: admin',
+ references: ['http://www.example.com', 'https://ww.example.com'],
+ severity: 'high',
+ updated_by: 'elastic',
+ tags: [],
+ to: 'now',
+ type: 'query',
+ threats: [
+ {
+ framework: 'MITRE ATT&CK',
+ tactic: {
+ id: 'TA0040',
+ name: 'impact',
+ reference: 'https://attack.mitre.org/tactics/TA0040/',
+ },
+ techniques: [
+ {
+ id: 'T1499',
+ name: 'endpoint denial of service',
+ reference: 'https://attack.mitre.org/techniques/T1499/',
+ },
+ ],
+ },
+ ],
+ });
+ });
+
+ test('returns 500 if the data is not of type siem alert', () => {
+ const output = transformOrError({ data: [{ random: 1 }] });
+ expect((output as Boom).message).toEqual('Internal error transforming');
+ });
+ });
+});
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts
new file mode 100644
index 000000000000..c9ae3abdfdc6
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts
@@ -0,0 +1,76 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import Boom from 'boom';
+import { pickBy } from 'lodash/fp';
+import { RuleAlertType, isAlertType, isAlertTypes } from '../../rules/types';
+import { OutputRuleAlertRest } from '../../types';
+
+export const getIdError = ({
+ id,
+ ruleId,
+}: {
+ id: string | undefined | null;
+ ruleId: string | undefined | null;
+}) => {
+ if (id != null) {
+ return new Boom(`id: "${id}" not found`, { statusCode: 404 });
+ } else if (ruleId != null) {
+ return new Boom(`rule_id: "${ruleId}" not found`, { statusCode: 404 });
+ } else {
+ return new Boom(`id or rule_id should have been defined`, { statusCode: 404 });
+ }
+};
+
+// Transforms the data but will remove any null or undefined it encounters and not include
+// those on the export
+export const transformAlertToRule = (alert: RuleAlertType): Partial => {
+ return pickBy((value: unknown) => value != null, {
+ created_by: alert.createdBy,
+ description: alert.params.description,
+ enabled: alert.enabled,
+ false_positives: alert.params.falsePositives,
+ filters: alert.params.filters,
+ from: alert.params.from,
+ id: alert.id,
+ immutable: alert.params.immutable,
+ index: alert.params.index,
+ interval: alert.interval,
+ rule_id: alert.params.ruleId,
+ language: alert.params.language,
+ output_index: alert.params.outputIndex,
+ max_signals: alert.params.maxSignals,
+ risk_score: alert.params.riskScore,
+ name: alert.name,
+ query: alert.params.query,
+ references: alert.params.references,
+ saved_id: alert.params.savedId,
+ meta: alert.params.meta,
+ severity: alert.params.severity,
+ updated_by: alert.updatedBy,
+ tags: alert.tags,
+ to: alert.params.to,
+ type: alert.params.type,
+ threats: alert.params.threats,
+ });
+};
+
+export const transformFindAlertsOrError = (findResults: { data: unknown[] }): unknown | Boom => {
+ if (isAlertTypes(findResults.data)) {
+ findResults.data = findResults.data.map(alert => transformAlertToRule(alert));
+ return findResults;
+ } else {
+ return new Boom('Internal error transforming', { statusCode: 500 });
+ }
+};
+
+export const transformOrError = (alert: unknown): Partial | Boom => {
+ if (isAlertType(alert)) {
+ return transformAlertToRule(alert);
+ } else {
+ return new Boom('Internal error transforming', { statusCode: 500 });
+ }
+};
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas.test.ts
deleted file mode 100644
index f5147bc5a8f8..000000000000
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas.test.ts
+++ /dev/null
@@ -1,2133 +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 {
- createRulesSchema,
- updateRulesSchema,
- findRulesSchema,
- queryRulesSchema,
- setSignalsStatusSchema,
-} from './schemas';
-import {
- RuleAlertParamsRest,
- FindParamsRest,
- UpdateRuleAlertParamsRest,
- ThreatParams,
- SignalsRestParams,
-} from '../alerts/types';
-
-describe('schemas', () => {
- describe('create rules schema', () => {
- test('empty objects do not validate', () => {
- expect(createRulesSchema.validate>({}).error).toBeTruthy();
- });
-
- test('made up values do not validate', () => {
- expect(
- createRulesSchema.validate>({
- madeUp: 'hi',
- }).error
- ).toBeTruthy();
- });
-
- test('[rule_id] does not validate', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- }).error
- ).toBeTruthy();
- });
-
- test('[rule_id, description] does not validate', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- description: 'some description',
- }).error
- ).toBeTruthy();
- });
-
- test('[rule_id, description, from] does not validate', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- description: 'some description',
- from: 'now-5m',
- }).error
- ).toBeTruthy();
- });
-
- test('[rule_id, description, from, to] does not validate', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- }).error
- ).toBeTruthy();
- });
-
- test('[rule_id, description, from, to, name] does not validate', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- name: 'some-name',
- }).error
- ).toBeTruthy();
- });
-
- test('[rule_id, description, from, to, name, severity] does not validate', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- name: 'some-name',
- severity: 'severity',
- }).error
- ).toBeTruthy();
- });
-
- test('[rule_id, description, from, to, name, severity, type] does not validate', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- name: 'some-name',
- severity: 'severity',
- type: 'query',
- }).error
- ).toBeTruthy();
- });
-
- test('[rule_id, description, from, to, name, severity, type, interval] does not validate', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- name: 'some-name',
- severity: 'severity',
- interval: '5m',
- type: 'query',
- }).error
- ).toBeTruthy();
- });
-
- test('[rule_id, description, from, to, name, severity, type, interval, index] does not validate', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- name: 'some-name',
- severity: 'severity',
- type: 'query',
- interval: '5m',
- index: ['index-1'],
- }).error
- ).toBeTruthy();
- });
-
- test('[rule_id, description, from, to, name, severity, type, query, index, interval] does validate', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- risk_score: 50,
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- name: 'some-name',
- severity: 'severity',
- type: 'query',
- query: 'some query',
- index: ['index-1'],
- interval: '5m',
- }).error
- ).toBeFalsy();
- });
-
- test('[rule_id, description, from, to, index, name, severity, interval, type, query, language] does not validate', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- index: ['index-1'],
- name: 'some-name',
- severity: 'severity',
- interval: '5m',
- type: 'query',
- query: 'some query',
- language: 'kuery',
- }).error
- ).toBeTruthy();
- });
-
- test('[rule_id, description, from, to, index, name, severity, interval, type, query, language, risk_score] does validate', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- risk_score: 50,
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- index: ['index-1'],
- name: 'some-name',
- severity: 'severity',
- interval: '5m',
- type: 'query',
- query: 'some query',
- language: 'kuery',
- }).error
- ).toBeFalsy();
- });
-
- test('[rule_id, description, from, to, index, name, severity, interval, type, query, language, risk_score, output_index] does validate', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- output_index: '.siem-signals',
- risk_score: 50,
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- index: ['index-1'],
- name: 'some-name',
- severity: 'severity',
- interval: '5m',
- type: 'query',
- query: 'some query',
- language: 'kuery',
- }).error
- ).toBeFalsy();
- });
-
- test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score] does validate', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- index: ['index-1'],
- name: 'some-name',
- severity: 'severity',
- interval: '5m',
- type: 'query',
- risk_score: 50,
- }).error
- ).toBeFalsy();
- });
-
- test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, output_index] does validate', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- output_index: '.siem-signals',
- risk_score: 50,
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- index: ['index-1'],
- name: 'some-name',
- severity: 'severity',
- interval: '5m',
- type: 'query',
- }).error
- ).toBeFalsy();
- });
- test('You can send in an empty array to threats', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- output_index: '.siem-signals',
- risk_score: 50,
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- index: ['index-1'],
- name: 'some-name',
- severity: 'severity',
- interval: '5m',
- type: 'query',
- references: ['index-1'],
- query: 'some query',
- language: 'kuery',
- max_signals: 1,
- threats: [],
- }).error
- ).toBeFalsy();
- });
- test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, output_index, threats] does validate', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- output_index: '.siem-signals',
- risk_score: 50,
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- index: ['index-1'],
- name: 'some-name',
- severity: 'severity',
- interval: '5m',
- type: 'query',
- threats: [
- {
- framework: 'someFramework',
- tactic: {
- id: 'fakeId',
- name: 'fakeName',
- reference: 'fakeRef',
- },
- techniques: [
- {
- id: 'techniqueId',
- name: 'techniqueName',
- reference: 'techniqueRef',
- },
- ],
- },
- ],
- }).error
- ).toBeFalsy();
- });
-
- test('allows references to be sent as valid', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- output_index: '.siem-signals',
- risk_score: 50,
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- index: ['index-1'],
- name: 'some-name',
- severity: 'severity',
- interval: '5m',
- type: 'query',
- references: ['index-1'],
- query: 'some query',
- language: 'kuery',
- }).error
- ).toBeFalsy();
- });
-
- test('defaults references to an array', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- output_index: '.siem-signals',
- risk_score: 50,
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- index: ['index-1'],
- name: 'some-name',
- severity: 'severity',
- interval: '5m',
- type: 'query',
- query: 'some-query',
- language: 'kuery',
- }).value.references
- ).toEqual([]);
- });
-
- test('references cannot be numbers', () => {
- expect(
- createRulesSchema.validate<
- Partial> & { references: number[] }
- >({
- rule_id: 'rule-1',
- output_index: '.siem-signals',
- risk_score: 50,
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- index: ['index-1'],
- name: 'some-name',
- severity: 'severity',
- interval: '5m',
- type: 'query',
- query: 'some-query',
- language: 'kuery',
- references: [5],
- }).error
- ).toBeTruthy();
- });
-
- test('indexes cannot be numbers', () => {
- expect(
- createRulesSchema.validate<
- Partial> & { index: number[] }
- >({
- rule_id: 'rule-1',
- output_index: '.siem-signals',
- risk_score: 50,
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- index: [5],
- name: 'some-name',
- severity: 'severity',
- interval: '5m',
- type: 'query',
- query: 'some-query',
- language: 'kuery',
- }).error
- ).toBeTruthy();
- });
-
- test('defaults interval to 5 min', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- output_index: '.siem-signals',
- risk_score: 50,
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- index: ['index-1'],
- name: 'some-name',
- severity: 'severity',
- type: 'query',
- }).value.interval
- ).toEqual('5m');
- });
-
- test('defaults max signals to 100', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- output_index: '.siem-signals',
- risk_score: 50,
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- index: ['index-1'],
- name: 'some-name',
- severity: 'severity',
- interval: '5m',
- type: 'query',
- }).value.max_signals
- ).toEqual(100);
- });
-
- test('saved_id is required when type is saved_query and will not validate without out', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- output_index: '.siem-signals',
- risk_score: 50,
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- index: ['index-1'],
- name: 'some-name',
- severity: 'severity',
- interval: '5m',
- type: 'saved_query',
- }).error
- ).toBeTruthy();
- });
-
- test('saved_id is required when type is saved_query and validates with it', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- risk_score: 50,
- output_index: '.siem-signals',
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- index: ['index-1'],
- name: 'some-name',
- severity: 'severity',
- interval: '5m',
- type: 'saved_query',
- saved_id: 'some id',
- }).error
- ).toBeFalsy();
- });
-
- test('saved_query type can have filters with it', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- output_index: '.siem-signals',
- risk_score: 50,
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- index: ['index-1'],
- name: 'some-name',
- severity: 'severity',
- interval: '5m',
- type: 'saved_query',
- saved_id: 'some id',
- filters: [],
- }).error
- ).toBeFalsy();
- });
-
- test('filters cannot be a string', () => {
- expect(
- createRulesSchema.validate<
- Partial & { filters: string }>
- >({
- rule_id: 'rule-1',
- output_index: '.siem-signals',
- risk_score: 50,
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- index: ['index-1'],
- name: 'some-name',
- severity: 'severity',
- interval: '5m',
- type: 'saved_query',
- saved_id: 'some id',
- filters: 'some string',
- }).error
- ).toBeTruthy();
- });
-
- test('language validates with kuery', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- output_index: '.siem-signals',
- risk_score: 50,
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- index: ['index-1'],
- name: 'some-name',
- severity: 'severity',
- interval: '5m',
- type: 'query',
- references: ['index-1'],
- query: 'some query',
- language: 'kuery',
- }).error
- ).toBeFalsy();
- });
-
- test('language validates with lucene', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- risk_score: 50,
- output_index: '.siem-signals',
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- index: ['index-1'],
- name: 'some-name',
- severity: 'severity',
- interval: '5m',
- type: 'query',
- references: ['index-1'],
- query: 'some query',
- language: 'lucene',
- }).error
- ).toBeFalsy();
- });
-
- test('language does not validate with something made up', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- output_index: '.siem-signals',
- risk_score: 50,
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- index: ['index-1'],
- name: 'some-name',
- severity: 'severity',
- interval: '5m',
- type: 'query',
- references: ['index-1'],
- query: 'some query',
- language: 'something-made-up',
- }).error
- ).toBeTruthy();
- });
-
- test('max_signals cannot be negative', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- output_index: '.siem-signals',
- risk_score: 50,
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- index: ['index-1'],
- name: 'some-name',
- severity: 'severity',
- interval: '5m',
- type: 'query',
- references: ['index-1'],
- query: 'some query',
- language: 'kuery',
- max_signals: -1,
- }).error
- ).toBeTruthy();
- });
-
- test('max_signals cannot be zero', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- output_index: '.siem-signals',
- risk_score: 50,
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- index: ['index-1'],
- name: 'some-name',
- severity: 'severity',
- interval: '5m',
- type: 'query',
- references: ['index-1'],
- query: 'some query',
- language: 'kuery',
- max_signals: 0,
- }).error
- ).toBeTruthy();
- });
-
- test('max_signals can be 1', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- output_index: '.siem-signals',
- risk_score: 50,
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- index: ['index-1'],
- name: 'some-name',
- severity: 'severity',
- interval: '5m',
- type: 'query',
- references: ['index-1'],
- query: 'some query',
- language: 'kuery',
- max_signals: 1,
- }).error
- ).toBeFalsy();
- });
-
- test('You can optionally send in an array of tags', () => {
- expect(
- createRulesSchema.validate>({
- rule_id: 'rule-1',
- output_index: '.siem-signals',
- risk_score: 50,
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- index: ['index-1'],
- name: 'some-name',
- severity: 'severity',
- interval: '5m',
- type: 'query',
- references: ['index-1'],
- query: 'some query',
- language: 'kuery',
- max_signals: 1,
- tags: ['tag_1', 'tag_2'],
- }).error
- ).toBeFalsy();
- });
-
- test('You cannot send in an array of tags that are numbers', () => {
- expect(
- createRulesSchema.validate> & { tags: number[] }>(
- {
- rule_id: 'rule-1',
- output_index: '.siem-signals',
- risk_score: 50,
- description: 'some description',
- from: 'now-5m',
- to: 'now',
- index: ['index-1'],
- name: 'some-name',
- severity: 'severity',
- interval: '5m',
- type: 'query',
- references: ['index-1'],
- query: 'some query',
- language: 'kuery',
- max_signals: 1,
- tags: [0, 1, 2],
- }
- ).error
- ).toBeTruthy();
- });
-
- test('You cannot send in an array of threats that are missing "framework"', () => {
- expect(
- createRulesSchema.validate<
- Partial> & {
- threats: Array