mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Security Solutions] Removes POC transforms (#129673)
## Summary Removes the `metrics_entities` plugin and POC. As a different direction will be taken and people can look back at the git history for it as they see fit if they need to refer to it. Once it's re-added it it will be through an RFC process and re-discussed. Earlier PR's which added the POC: https://github.com/elastic/kibana/pull/96446 https://github.com/elastic/kibana/pull/104559 ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios
This commit is contained in:
parent
268470a440
commit
ce2f6171c1
189 changed files with 117 additions and 7545 deletions
126
.eslintrc.js
126
.eslintrc.js
|
@ -1242,132 +1242,6 @@ module.exports = {
|
|||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Metrics entities overrides. These rules below are maintained and owned by
|
||||
* the people within the security-solution-platform team. Please see ping them
|
||||
* or check with them if you are encountering issues, have suggestions, or would
|
||||
* like to add, change, or remove any particular rule. Linters, Typescript, and rules
|
||||
* evolve and change over time just like coding styles, so please do not hesitate to
|
||||
* reach out.
|
||||
*/
|
||||
{
|
||||
// front end and common typescript and javascript files only
|
||||
files: [
|
||||
'x-pack/plugins/metrics_entities/public/**/*.{js,mjs,ts,tsx}',
|
||||
'x-pack/plugins/metrics_entities/common/**/*.{js,mjs,ts,tsx}',
|
||||
],
|
||||
rules: {
|
||||
'import/no-nodejs-modules': 'error',
|
||||
'no-restricted-imports': [
|
||||
'error',
|
||||
{
|
||||
// prevents UI code from importing server side code and then webpack including it when doing builds
|
||||
patterns: ['**/server/*'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
// typescript and javascript for front and back end
|
||||
files: ['x-pack/plugins/metrics_entities/**/*.{js,mjs,ts,tsx}'],
|
||||
plugins: ['eslint-plugin-node'],
|
||||
env: {
|
||||
jest: true,
|
||||
},
|
||||
rules: {
|
||||
'accessor-pairs': 'error',
|
||||
'array-callback-return': 'error',
|
||||
'no-array-constructor': 'error',
|
||||
complexity: 'error',
|
||||
'consistent-return': 'error',
|
||||
'func-style': ['error', 'expression'],
|
||||
'import/order': [
|
||||
'error',
|
||||
{
|
||||
groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'],
|
||||
'newlines-between': 'always',
|
||||
},
|
||||
],
|
||||
'sort-imports': [
|
||||
'error',
|
||||
{
|
||||
ignoreDeclarationSort: true,
|
||||
},
|
||||
],
|
||||
'node/no-deprecated-api': 'error',
|
||||
'no-bitwise': 'error',
|
||||
'no-continue': 'error',
|
||||
'no-dupe-keys': 'error',
|
||||
'no-duplicate-case': 'error',
|
||||
'no-duplicate-imports': 'error',
|
||||
'no-empty-character-class': 'error',
|
||||
'no-empty-pattern': 'error',
|
||||
'no-ex-assign': 'error',
|
||||
'no-extend-native': 'error',
|
||||
'no-extra-bind': 'error',
|
||||
'no-extra-boolean-cast': 'error',
|
||||
'no-extra-label': 'error',
|
||||
'no-func-assign': 'error',
|
||||
'no-implicit-globals': 'error',
|
||||
'no-implied-eval': 'error',
|
||||
'no-invalid-regexp': 'error',
|
||||
'no-inner-declarations': 'error',
|
||||
'no-lone-blocks': 'error',
|
||||
'no-multi-assign': 'error',
|
||||
'no-misleading-character-class': 'error',
|
||||
'no-new-symbol': 'error',
|
||||
'no-obj-calls': 'error',
|
||||
'no-param-reassign': ['error', { props: true }],
|
||||
'no-process-exit': 'error',
|
||||
'no-prototype-builtins': 'error',
|
||||
'no-return-await': 'error',
|
||||
'no-self-compare': 'error',
|
||||
'no-shadow-restricted-names': 'error',
|
||||
'no-sparse-arrays': 'error',
|
||||
'no-this-before-super': 'error',
|
||||
// rely on typescript
|
||||
'no-undef': 'off',
|
||||
'no-unreachable': 'error',
|
||||
'no-unsafe-finally': 'error',
|
||||
'no-useless-call': 'error',
|
||||
'no-useless-catch': 'error',
|
||||
'no-useless-concat': 'error',
|
||||
'no-useless-computed-key': 'error',
|
||||
'no-useless-escape': 'error',
|
||||
'no-useless-rename': 'error',
|
||||
'no-useless-return': 'error',
|
||||
'no-void': 'error',
|
||||
'one-var-declaration-per-line': 'error',
|
||||
'prefer-object-spread': 'error',
|
||||
'prefer-promise-reject-errors': 'error',
|
||||
'prefer-rest-params': 'error',
|
||||
'prefer-spread': 'error',
|
||||
'prefer-template': 'error',
|
||||
'require-atomic-updates': 'error',
|
||||
'symbol-description': 'error',
|
||||
'vars-on-top': 'error',
|
||||
'@typescript-eslint/explicit-member-accessibility': 'error',
|
||||
'@typescript-eslint/no-this-alias': 'error',
|
||||
'@typescript-eslint/no-explicit-any': 'error',
|
||||
'@typescript-eslint/no-useless-constructor': 'error',
|
||||
'@typescript-eslint/unified-signatures': 'error',
|
||||
'@typescript-eslint/explicit-function-return-type': 'error',
|
||||
'@typescript-eslint/no-non-null-assertion': 'error',
|
||||
'@typescript-eslint/no-unused-vars': 'error',
|
||||
'no-template-curly-in-string': 'error',
|
||||
'sort-keys': 'error',
|
||||
'prefer-destructuring': 'error',
|
||||
'no-restricted-imports': [
|
||||
'error',
|
||||
{
|
||||
// prevents code from importing files that contain the name "legacy" within their name. This is a mechanism
|
||||
// to help deprecation and prevent accidental re-use/continued use of code we plan on removing. If you are
|
||||
// finding yourself turning this off a lot for "new code" consider renaming the file and functions if it has valid uses.
|
||||
patterns: ['*legacy*'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
/**
|
||||
* Alerting Services overrides
|
||||
*/
|
||||
|
|
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
|
@ -394,7 +394,6 @@
|
|||
/x-pack/test/plugin_functional/plugins/resolver_test/ @elastic/security-solution
|
||||
/x-pack/test/plugin_functional/test_suites/resolver/ @elastic/security-solution
|
||||
/x-pack/plugins/security_solution/ @elastic/security-solution
|
||||
/x-pack/plugins/metrics_entities/ @elastic/security-solution
|
||||
/x-pack/test/detection_engine_api_integration @elastic/security-solution
|
||||
/x-pack/test/lists_api_integration @elastic/security-solution
|
||||
/x-pack/test/api_integration/apis/security_solution @elastic/security-solution
|
||||
|
|
|
@ -524,12 +524,6 @@ using the CURL scripts in the scripts folder.
|
|||
|Visualize geo data from Elasticsearch or 3rd party geo-services.
|
||||
|
||||
|
||||
|{kib-repo}blob/{branch}/x-pack/plugins/metrics_entities/README.md[metricsEntities]
|
||||
|This is the metrics and entities plugin where you add can add transforms for your project
|
||||
and group those transforms into modules. You can also re-use existing transforms in your
|
||||
newly created modules as well.
|
||||
|
||||
|
||||
|{kib-repo}blob/{branch}/x-pack/plugins/ml/readme.md[ml]
|
||||
|This plugin provides access to the machine learning features provided by
|
||||
Elastic.
|
||||
|
|
|
@ -76,7 +76,6 @@ it('produces the right watch and ignore list', () => {
|
|||
<absolute path>/x-pack/plugins/lists/server/scripts,
|
||||
<absolute path>/x-pack/plugins/security_solution/scripts,
|
||||
<absolute path>/x-pack/plugins/security_solution/server/lib/detection_engine/scripts,
|
||||
<absolute path>/x-pack/plugins/metrics_entities/server/scripts,
|
||||
<absolute path>/x-pack/plugins/uptime/e2e,
|
||||
]
|
||||
`);
|
||||
|
|
|
@ -66,7 +66,6 @@ export function getServerWatchPaths({ pluginPaths, pluginScanDirs }: Options) {
|
|||
fromRoot('x-pack/plugins/lists/server/scripts'),
|
||||
fromRoot('x-pack/plugins/security_solution/scripts'),
|
||||
fromRoot('x-pack/plugins/security_solution/server/lib/detection_engine/scripts'),
|
||||
fromRoot('x-pack/plugins/metrics_entities/server/scripts'),
|
||||
fromRoot('x-pack/plugins/uptime/e2e'),
|
||||
];
|
||||
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
"xpack.logstash": ["plugins/logstash"],
|
||||
"xpack.main": "legacy/plugins/xpack_main",
|
||||
"xpack.maps": ["plugins/maps"],
|
||||
"xpack.metricsEntities": "plugins/metrics_entities",
|
||||
"xpack.ml": ["plugins/ml"],
|
||||
"xpack.monitoring": ["plugins/monitoring"],
|
||||
"xpack.osquery": ["plugins/osquery"],
|
||||
|
|
|
@ -1,322 +0,0 @@
|
|||
# metrics_entities
|
||||
|
||||
This is the metrics and entities plugin where you add can add transforms for your project
|
||||
and group those transforms into modules. You can also re-use existing transforms in your
|
||||
newly created modules as well.
|
||||
|
||||
## Turn on experimental flags
|
||||
During at least phase 1 of this development, please add these to your `kibana.dev.yml` file to turn on the feature:
|
||||
|
||||
```ts
|
||||
xpack.metricsEntities.enabled: true
|
||||
xpack.securitySolution.enableExperimental: ['metricsEntitiesEnabled']
|
||||
```
|
||||
|
||||
## Quick start on using scripts to call the API
|
||||
|
||||
The scripts rely on CURL and jq:
|
||||
|
||||
- [CURL](https://curl.haxx.se)
|
||||
- [jq](https://stedolan.github.io/jq/)
|
||||
|
||||
Install curl and jq
|
||||
|
||||
```sh
|
||||
brew update
|
||||
brew install curl
|
||||
brew install jq
|
||||
```
|
||||
|
||||
Open `$HOME/.zshrc` or `${HOME}.bashrc` depending on your SHELL output from `echo $SHELL`
|
||||
and add these environment variables:
|
||||
|
||||
```sh
|
||||
export ELASTICSEARCH_USERNAME=${user}
|
||||
export ELASTICSEARCH_PASSWORD=${password}
|
||||
export ELASTICSEARCH_URL=https://${ip}:9200
|
||||
export KIBANA_URL=http://localhost:5601
|
||||
```
|
||||
|
||||
source `$HOME/.zshrc` or `${HOME}.bashrc` to ensure variables are set:
|
||||
|
||||
```sh
|
||||
source ~/.zshrc
|
||||
```
|
||||
|
||||
Restart Kibana and ensure that you are using `--no-base-path` as changing the base path is a feature but will
|
||||
get in the way of the CURL scripts written as is.
|
||||
|
||||
Go to the scripts folder `cd kibana/x-pack/plugins/metrics_entities/server/scripts` and can run some of the scripts
|
||||
such as:
|
||||
|
||||
```sh
|
||||
./post_transforms.sh ./post_examples/all.json
|
||||
```
|
||||
|
||||
which will post transforms from the `all.json`
|
||||
|
||||
You can also delete them by running:
|
||||
|
||||
```sh
|
||||
./delete_transforms.sh ./delete_examples/all.json
|
||||
```
|
||||
|
||||
See the folder for other curl scripts that exercise parts of the REST API and feel free to add your own examples
|
||||
in the folder as well.
|
||||
|
||||
## Quick start on how to add a transform
|
||||
|
||||
You will want to figure out how you want your transform from within Kibana roughly using
|
||||
the UI and then copy the JSON. The JSON you will want to change and paste within a folder
|
||||
which represents a module.
|
||||
|
||||
For example, for the `host_entities` and a `host_entities_mapping` we created a folder called host_entities
|
||||
here:
|
||||
|
||||
```sh
|
||||
sever/modules/host_entities
|
||||
```
|
||||
|
||||
Then we add two files, a subset of the transform JSON and a mapping like so:
|
||||
|
||||
```sh
|
||||
server/modules/host_entities/host_entities_mapping.json <--- this is the mappings
|
||||
server/modules/host_entities/host_entities.json <--- This is a subset of the transform JSON
|
||||
index.ts <--- Import/export your json here
|
||||
```
|
||||
|
||||
The mappings can be normal mapping like so with `host_entities_mapping.json`:
|
||||
```json
|
||||
{
|
||||
"mappings": {
|
||||
"_meta": {
|
||||
"index": "host_ent"
|
||||
},
|
||||
"dynamic": "strict",
|
||||
"properties": {
|
||||
"@timestamp": {
|
||||
"type": "date"
|
||||
},
|
||||
"metrics": {
|
||||
"properties": {
|
||||
"host": {
|
||||
"properties": {
|
||||
"name": {
|
||||
"properties": {
|
||||
"value_count": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"host": {
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"os": {
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"version": {
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
One caveat is that you need to add this to the meta section to tell it what the name will be:
|
||||
```json
|
||||
"_meta": {
|
||||
"index": "host_ent"
|
||||
},
|
||||
```
|
||||
|
||||
Keep the name short as there is only 65 characters for a transform job and we prepend extra information to the mapping such as:
|
||||
* prefix
|
||||
* name of estc
|
||||
|
||||
Although not required, a `"dynamic": "strict"` is strongly encouraged to prevent mapping guesses from elastic and it will be better for us
|
||||
to spot errors quicker in the mappings such as type-o's if this is set to strict.
|
||||
|
||||
Next, for the transform, you should add a subset that doesn't have any additional settings or meta associated like so for `host_entities.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "host_ent",
|
||||
"description": "[host.name entities] grouped by @timestamp, host.name, os.name, and os.version, and aggregated on host.name",
|
||||
"pivot": {
|
||||
"group_by": {
|
||||
"@timestamp": {
|
||||
"date_histogram": {
|
||||
"field": "@timestamp",
|
||||
"calendar_interval": "1h"
|
||||
}
|
||||
},
|
||||
"host.name": {
|
||||
"terms": {
|
||||
"field": "host.name"
|
||||
}
|
||||
},
|
||||
"host.os.name": {
|
||||
"terms": {
|
||||
"field": "host.os.name",
|
||||
"missing_bucket": true
|
||||
}
|
||||
},
|
||||
"host.os.version": {
|
||||
"terms": {
|
||||
"field": "host.os.version",
|
||||
"missing_bucket": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"aggregations": {
|
||||
"metrics.host.name.value_count": {
|
||||
"value_count": {
|
||||
"field": "host.name"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Look in the `server/modules` for other examples, but it should be that clear cut. The final part is to wire everything up in the code by touching a few files
|
||||
to either add this to an existing module or create your own module. In `server/module/host_entities` we add an `index.ts` like so that does an import/export
|
||||
of the JSON:
|
||||
|
||||
```sh
|
||||
import hostEntities from './host_entities.json';
|
||||
import hostEntitiesMapping from './host_entities_mapping.json';
|
||||
export { hostEntities, hostEntitiesMapping };
|
||||
```
|
||||
|
||||
Then in `modules/index.ts` we add a new module name if we are creating a new module to the `export enum ModuleNames {` like so:
|
||||
|
||||
```ts
|
||||
// Import your host entities you just made
|
||||
import { hostEntities, hostEntitiesMapping } from './host_entities';
|
||||
|
||||
/**
|
||||
* These module names will map 1 to 1 to the REST interface.
|
||||
*/
|
||||
export enum ModuleNames {
|
||||
hostSummaryMetrics = 'host_metrics',
|
||||
hostSummaryEntities = 'host_entities', // <-- Add the entities/transform and give it a enum name and a module name
|
||||
networkSummaryEntities = 'network_entities',
|
||||
networkSummaryMetrics = 'network_metrics',
|
||||
userSummaryEntities = 'user_entities',
|
||||
userSummaryMetrics = 'user_metrics',
|
||||
}
|
||||
```
|
||||
|
||||
If you're not creating a new module but rather you are adding to an existing module, you can skip the above step. Next, you
|
||||
just need to add your installable transform and installable mapping to the two data structures of `installableTransforms` and
|
||||
`installableMappings` like so:
|
||||
|
||||
```ts
|
||||
/**
|
||||
* Add any new folders as modules with their names below and grouped with
|
||||
* key values.
|
||||
*/
|
||||
export const installableTransforms: Record<ModuleNames, Transforms[]> = {
|
||||
[ModuleNames.hostSummaryMetrics]: [hostMetrics],
|
||||
[ModuleNames.hostSummaryEntities]: [hostEntities], // <-- Adds my new module name and transform to a new array.
|
||||
[ModuleNames.networkSummaryEntities]: [
|
||||
destinationIpEntities, // <-- If instead I am adding to an existing module, I just add it to the array like these show
|
||||
sourceIpEntities,
|
||||
destinationCountryIsoCodeEntities,
|
||||
sourceCountryIsoCodeEntities,
|
||||
],
|
||||
[ModuleNames.networkSummaryMetrics]: [ipMetrics],
|
||||
[ModuleNames.userSummaryEntities]: [userEntities],
|
||||
[ModuleNames.userSummaryMetrics]: [userMetrics],
|
||||
};
|
||||
|
||||
/**
|
||||
* For all the mapping types, add each with their names below and grouped with
|
||||
* key values.
|
||||
*/
|
||||
export const installableMappings: Record<ModuleNames, Mappings[]> = {
|
||||
[ModuleNames.hostSummaryMetrics]: [hostMetricsMapping],
|
||||
[ModuleNames.hostSummaryEntities]: [hostEntitiesMapping], // <-- Adds my new module name and mapping to a new array.
|
||||
[ModuleNames.networkSummaryEntities]: [ // <-- If instead I am adding to an existing module, I just add it to the array like these show
|
||||
sourceIpEntitiesMapping,
|
||||
destinationIpEntitiesMapping,
|
||||
destinationCountryIsoCodeEntitiesMapping,
|
||||
sourceCountryIsoCodeEntitiesMapping,
|
||||
],
|
||||
[ModuleNames.networkSummaryMetrics]: [ipMetricsMapping],
|
||||
[ModuleNames.userSummaryEntities]: [userEntitiesMapping],
|
||||
[ModuleNames.userSummaryMetrics]: [userMetricsMapping],
|
||||
};
|
||||
```
|
||||
|
||||
And after that, you should check out if there are any existing e2e tests or unit tests to update here to ensure that your mapping and transform will
|
||||
pass ci. Create a pull request and your mapping and transform are completed.
|
||||
|
||||
To call into the code to activate your module and create your transforms and mappings would be the following where you substitute your
|
||||
${KIBANA_URL} with your kibana URL and the ${SPACE_URL} with any space id you have. If you're using the default space then you would use
|
||||
an empty string:
|
||||
```json
|
||||
POST ${KIBANA_URL}${SPACE_URL}/api/metrics_entities/transforms
|
||||
{
|
||||
"prefix": "all",
|
||||
"modules": [
|
||||
"host_entities",
|
||||
],
|
||||
"indices": [
|
||||
"auditbeat-*",
|
||||
"endgame-*",
|
||||
"filebeat-*",
|
||||
"logs-*",
|
||||
"packetbeat-*",
|
||||
"winlogbeat-*",
|
||||
"-*elastic-cloud-logs-*"
|
||||
],
|
||||
"auto_start": true,
|
||||
"settings": {
|
||||
"max_page_search_size": 5000
|
||||
},
|
||||
"query": {
|
||||
"range": {
|
||||
"@timestamp": {
|
||||
"gte": "now-1d/d",
|
||||
"format": "strict_date_optional_time"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Very similar to the regular transform REST API, with the caveats that you define which modules you want to install, the prefix name you want to use, and
|
||||
if you want to `auto_start` it or not. The rest such as `settings`, `query` will be the same as the transforms API. They will also push those same setting into
|
||||
each of your transforms within your module(s) as the same setting for each individual ones.
|
||||
|
||||
## TODO List
|
||||
During the phase 1, phase 2, phase N, this TODO will exist as a reminder and notes for what still needs to be developed. These are not in a priority order, but
|
||||
are notes during the phased approach. As we approach production and the feature flags are removed these TODO's should be removed in favor of Kibana issues or regular
|
||||
left over TODO's in the code base.
|
||||
|
||||
- Add these properties to the route which are:
|
||||
- disable_transforms/exclude flag to exclude 1 or more transforms within a module
|
||||
- pipeline flag
|
||||
- Change the REST routes on post to change the indexes for whichever indexes you want
|
||||
- Unit tests to ensure the data of the mapping.json includes the correct fields such as _meta, at least one alias, a mapping section, etc...
|
||||
- Add text/keyword and other things to the mappings (not just keyword maybe?) ... At least review the mappings one more time
|
||||
- Add a sort of @timestamp to the output destination indexes?
|
||||
- Add the REST Kibana security based tags if needed and push those to any plugins using this plugin. Something like: tags: ['access:metricsEntities-read'] and ['access:metricsEntities-all'],
|
||||
- Add schema validation choosing some schema library (io-ts or Kibana Schema or ... )
|
||||
- Add unit tests
|
||||
- Add e2e tests
|
||||
- Any UI code should not end up here. There is none right now, but all UI code should be within a kbn package or security_solutions
|
|
@ -1,21 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base route
|
||||
*/
|
||||
export const METRICS_ENTITIES_URL = '/api/metrics_entities';
|
||||
|
||||
/**
|
||||
* Transforms route
|
||||
*/
|
||||
export const METRICS_ENTITIES_TRANSFORMS = `${METRICS_ENTITIES_URL}/transforms`;
|
||||
|
||||
/**
|
||||
* Global prefix for all the transform jobs
|
||||
*/
|
||||
export const ELASTIC_NAME = 'estc';
|
|
@ -1,13 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
// Careful of exporting anything from this file as any file(s) you export here will cause your functions to be exposed as public.
|
||||
// If you're using functions/types/etc... internally or within integration tests it's best to import directly from their paths
|
||||
// than expose the functions/types/etc... here. You should _only_ expose functions/types/etc... that need to be shared with other plugins here.
|
||||
// When you do have to add things here you might want to consider creating a package such to share with other plugins instead as packages
|
||||
// are easier to break down.
|
||||
// See: https://docs.elastic.dev/kibana-dev-docs/key-concepts/platform-intro#public-plugin-api
|
|
@ -1,14 +0,0 @@
|
|||
{
|
||||
"id": "metricsEntities",
|
||||
"owner": {
|
||||
"name": "Security solution",
|
||||
"githubTeam": "security-solution"
|
||||
},
|
||||
"version": "8.0.0",
|
||||
"kibanaVersion": "kibana",
|
||||
"configPath": ["xpack", "metricsEntities"],
|
||||
"server": true,
|
||||
"ui": false,
|
||||
"requiredPlugins": ["data", "dataEnhanced"],
|
||||
"optionalPlugins": []
|
||||
}
|
|
@ -1,17 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
export class ErrorWithStatusCode extends Error {
|
||||
private readonly statusCode: number;
|
||||
|
||||
constructor(message: string, statusCode: number) {
|
||||
super(message);
|
||||
this.statusCode = statusCode;
|
||||
}
|
||||
|
||||
public getStatusCode = (): number => this.statusCode;
|
||||
}
|
|
@ -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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
|
||||
import { PluginInitializerContext } from '../../../../src/core/server';
|
||||
|
||||
import { MetricsEntitiesPlugin } from './plugin';
|
||||
|
||||
// This exports static code and TypeScript types,
|
||||
// as well as, Kibana Platform `plugin()` initializer.
|
||||
|
||||
export const plugin = (initializerContext: PluginInitializerContext): MetricsEntitiesPlugin => {
|
||||
return new MetricsEntitiesPlugin(initializerContext);
|
||||
};
|
||||
|
||||
export type { MetricsEntitiesPluginSetup, MetricsEntitiesPluginStart } from './types';
|
||||
|
||||
export const config = {
|
||||
schema: schema.object({
|
||||
// This plugin is experimental and should be disabled by default.
|
||||
enabled: schema.boolean({ defaultValue: false }),
|
||||
}),
|
||||
};
|
|
@ -1,4 +0,0 @@
|
|||
# Modules
|
||||
|
||||
This is where all the module types exist so you can load different bundled modules
|
||||
with a REST endpoint.
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"id": "host_ent",
|
||||
"description": "[host.name entities] grouped by @timestamp, host.name, os.name, and os.version, and aggregated on host.name",
|
||||
"pivot": {
|
||||
"group_by": {
|
||||
"@timestamp": {
|
||||
"date_histogram": {
|
||||
"field": "@timestamp",
|
||||
"calendar_interval": "1h"
|
||||
}
|
||||
},
|
||||
"host.name": {
|
||||
"terms": {
|
||||
"field": "host.name"
|
||||
}
|
||||
},
|
||||
"host.os.name": {
|
||||
"terms": {
|
||||
"field": "host.os.name",
|
||||
"missing_bucket": true
|
||||
}
|
||||
},
|
||||
"host.os.version": {
|
||||
"terms": {
|
||||
"field": "host.os.version",
|
||||
"missing_bucket": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"aggregations": {
|
||||
"metrics.host.name.value_count": {
|
||||
"value_count": {
|
||||
"field": "host.name"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
{
|
||||
"mappings": {
|
||||
"_meta": {
|
||||
"index": "host_ent"
|
||||
},
|
||||
"dynamic": "strict",
|
||||
"properties": {
|
||||
"@timestamp": {
|
||||
"type": "date"
|
||||
},
|
||||
"metrics": {
|
||||
"properties": {
|
||||
"host": {
|
||||
"properties": {
|
||||
"name": {
|
||||
"properties": {
|
||||
"value_count": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"host": {
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"os": {
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"version": {
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import hostEntities from './host_entities.json';
|
||||
import hostEntitiesMapping from './host_entities_mapping.json';
|
||||
export { hostEntities, hostEntitiesMapping };
|
|
@ -1,21 +0,0 @@
|
|||
{
|
||||
"id": "host_met",
|
||||
"description": "[host.name metrics] grouped by @timestamp and aggregated on host.name",
|
||||
"pivot": {
|
||||
"group_by": {
|
||||
"@timestamp": {
|
||||
"date_histogram": {
|
||||
"field": "@timestamp",
|
||||
"calendar_interval": "1h"
|
||||
}
|
||||
}
|
||||
},
|
||||
"aggregations": {
|
||||
"metrics.host.name.cardinality": {
|
||||
"cardinality": {
|
||||
"field": "host.name"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
{
|
||||
"mappings": {
|
||||
"_meta": {
|
||||
"index": "host_met"
|
||||
},
|
||||
"properties": {
|
||||
"metrics": {
|
||||
"properties": {
|
||||
"source": {
|
||||
"properties": {
|
||||
"ip": {
|
||||
"properties": {
|
||||
"value_count": {
|
||||
"type": "long"
|
||||
},
|
||||
"cardinality": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"bytes": {
|
||||
"properties": {
|
||||
"sum": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"destination": {
|
||||
"properties": {
|
||||
"ip": {
|
||||
"properties": {
|
||||
"value_count": {
|
||||
"type": "long"
|
||||
},
|
||||
"cardinality": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"bytes": {
|
||||
"properties": {
|
||||
"sum": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"network": {
|
||||
"properties": {
|
||||
"community_id": {
|
||||
"properties": {
|
||||
"cardinality": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"host": {
|
||||
"properties": {
|
||||
"name": {
|
||||
"properties": {
|
||||
"value_count": {
|
||||
"type": "long"
|
||||
},
|
||||
"cardinality": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@timestamp": {
|
||||
"type": "date"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import hostMetrics from './host_metrics.json';
|
||||
import hostMetricsMapping from './host_metrics_mapping.json';
|
||||
|
||||
export { hostMetrics, hostMetricsMapping };
|
|
@ -1,71 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { hostMetrics, hostMetricsMapping } from './host_metrics';
|
||||
import { userMetrics, userMetricsMapping } from './user_metrics';
|
||||
import { ipMetrics, ipMetricsMapping } from './network_metrics';
|
||||
import { hostEntities, hostEntitiesMapping } from './host_entities';
|
||||
import {
|
||||
destinationCountryIsoCodeEntities,
|
||||
destinationCountryIsoCodeEntitiesMapping,
|
||||
destinationIpEntities,
|
||||
destinationIpEntitiesMapping,
|
||||
sourceCountryIsoCodeEntities,
|
||||
sourceCountryIsoCodeEntitiesMapping,
|
||||
sourceIpEntities,
|
||||
sourceIpEntitiesMapping,
|
||||
} from './network_entities';
|
||||
import { Mappings, Transforms } from './types';
|
||||
import { userEntities, userEntitiesMapping } from './user_entities';
|
||||
|
||||
/**
|
||||
* These module names will map 1 to 1 to the REST interface.
|
||||
*/
|
||||
export enum ModuleNames {
|
||||
hostSummaryMetrics = 'host_metrics',
|
||||
hostSummaryEntities = 'host_entities',
|
||||
networkSummaryEntities = 'network_entities',
|
||||
networkSummaryMetrics = 'network_metrics',
|
||||
userSummaryEntities = 'user_entities',
|
||||
userSummaryMetrics = 'user_metrics',
|
||||
}
|
||||
|
||||
/**
|
||||
* Add any new folders as modules with their names below and grouped with
|
||||
* key values.
|
||||
*/
|
||||
export const installableTransforms: Record<ModuleNames, Transforms[]> = {
|
||||
[ModuleNames.hostSummaryMetrics]: [hostMetrics],
|
||||
[ModuleNames.hostSummaryEntities]: [hostEntities],
|
||||
[ModuleNames.networkSummaryEntities]: [
|
||||
destinationIpEntities,
|
||||
sourceIpEntities,
|
||||
destinationCountryIsoCodeEntities,
|
||||
sourceCountryIsoCodeEntities,
|
||||
],
|
||||
[ModuleNames.networkSummaryMetrics]: [ipMetrics],
|
||||
[ModuleNames.userSummaryEntities]: [userEntities],
|
||||
[ModuleNames.userSummaryMetrics]: [userMetrics],
|
||||
};
|
||||
|
||||
/**
|
||||
* For all the mapping types, add each with their names below and grouped with
|
||||
* key values.
|
||||
*/
|
||||
export const installableMappings: Record<ModuleNames, Mappings[]> = {
|
||||
[ModuleNames.hostSummaryMetrics]: [hostMetricsMapping],
|
||||
[ModuleNames.hostSummaryEntities]: [hostEntitiesMapping],
|
||||
[ModuleNames.networkSummaryEntities]: [
|
||||
sourceIpEntitiesMapping,
|
||||
destinationIpEntitiesMapping,
|
||||
destinationCountryIsoCodeEntitiesMapping,
|
||||
sourceCountryIsoCodeEntitiesMapping,
|
||||
],
|
||||
[ModuleNames.networkSummaryMetrics]: [ipMetricsMapping],
|
||||
[ModuleNames.userSummaryEntities]: [userEntitiesMapping],
|
||||
[ModuleNames.userSummaryMetrics]: [userMetricsMapping],
|
||||
};
|
|
@ -1,51 +0,0 @@
|
|||
{
|
||||
"id": "dest_iso_ent",
|
||||
"description": "[destination.geo.country_iso_code entities] grouped by @timestamp and aggregated on source.bytes, destination.bytes, network.community_id, destination.ip, and source.ip",
|
||||
"pivot": {
|
||||
"group_by": {
|
||||
"@timestamp": {
|
||||
"date_histogram": {
|
||||
"field": "@timestamp",
|
||||
"calendar_interval": "1h"
|
||||
}
|
||||
},
|
||||
"destination.geo.country_iso_code": {
|
||||
"terms": {
|
||||
"field": "destination.geo.country_iso_code"
|
||||
}
|
||||
}
|
||||
},
|
||||
"aggregations": {
|
||||
"metrics.destination.geo.country_iso_code.value_count": {
|
||||
"value_count": {
|
||||
"field": "destination.geo.country_iso_code"
|
||||
}
|
||||
},
|
||||
"metrics.source.bytes.sum": {
|
||||
"sum": {
|
||||
"field": "source.bytes"
|
||||
}
|
||||
},
|
||||
"metrics.destination.bytes.sum": {
|
||||
"sum": {
|
||||
"field": "destination.bytes"
|
||||
}
|
||||
},
|
||||
"metrics.network.community_id.cardinality": {
|
||||
"cardinality": {
|
||||
"field": "network.community_id"
|
||||
}
|
||||
},
|
||||
"metrics.source.ip.cardinality": {
|
||||
"cardinality": {
|
||||
"field": "source.ip"
|
||||
}
|
||||
},
|
||||
"metrics.destination.ip.cardinality": {
|
||||
"cardinality": {
|
||||
"field": "destination.ip"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
{
|
||||
"mappings": {
|
||||
"_meta": {
|
||||
"index": "dest_iso_ent"
|
||||
},
|
||||
"dynamic": "strict",
|
||||
"properties": {
|
||||
"@timestamp": {
|
||||
"type": "date"
|
||||
},
|
||||
"metrics": {
|
||||
"properties": {
|
||||
"source": {
|
||||
"properties": {
|
||||
"ip": {
|
||||
"properties": {
|
||||
"value_count": {
|
||||
"type": "long"
|
||||
},
|
||||
"cardinality": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"bytes": {
|
||||
"properties": {
|
||||
"sum": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"geo": {
|
||||
"properties": {
|
||||
"country_iso_code": {
|
||||
"properties": {
|
||||
"value_count": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"destination": {
|
||||
"properties": {
|
||||
"ip": {
|
||||
"properties": {
|
||||
"value_count": {
|
||||
"type": "long"
|
||||
},
|
||||
"cardinality": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"bytes": {
|
||||
"properties": {
|
||||
"sum": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"geo": {
|
||||
"properties": {
|
||||
"country_iso_code": {
|
||||
"properties": {
|
||||
"value_count": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"network": {
|
||||
"properties": {
|
||||
"community_id": {
|
||||
"properties": {
|
||||
"cardinality": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"source": {
|
||||
"properties": {
|
||||
"ip": {
|
||||
"type": "ip"
|
||||
},
|
||||
"geo": {
|
||||
"properties": {
|
||||
"country_iso_code": {
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"destination": {
|
||||
"properties": {
|
||||
"ip": {
|
||||
"type": "ip"
|
||||
},
|
||||
"geo": {
|
||||
"properties": {
|
||||
"country_iso_code": {
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
{
|
||||
"id": "dest_ip_ent",
|
||||
"description": "[destination.ip entities] grouped by @timestamp and aggregated on destination.ip, source.bytes, destination.bytes, network.community_id, and source.ip",
|
||||
"pivot": {
|
||||
"group_by": {
|
||||
"@timestamp": {
|
||||
"date_histogram": {
|
||||
"field": "@timestamp",
|
||||
"calendar_interval": "1h"
|
||||
}
|
||||
},
|
||||
"destination.ip": {
|
||||
"terms": {
|
||||
"field": "destination.ip"
|
||||
}
|
||||
}
|
||||
},
|
||||
"aggregations": {
|
||||
"metrics.destination.ip.value_count": {
|
||||
"value_count": {
|
||||
"field": "destination.ip"
|
||||
}
|
||||
},
|
||||
"metrics.source.bytes.sum": {
|
||||
"sum": {
|
||||
"field": "source.bytes"
|
||||
}
|
||||
},
|
||||
"metrics.destination.bytes.sum": {
|
||||
"sum": {
|
||||
"field": "destination.bytes"
|
||||
}
|
||||
},
|
||||
"metrics.network.community_id.cardinality": {
|
||||
"cardinality": {
|
||||
"field": "network.community_id"
|
||||
}
|
||||
},
|
||||
"metrics.source.ip.cardinality": {
|
||||
"cardinality": {
|
||||
"field": "source.ip"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
{
|
||||
"mappings": {
|
||||
"_meta": {
|
||||
"index": "dest_ip_ent"
|
||||
},
|
||||
"dynamic": "strict",
|
||||
"properties": {
|
||||
"@timestamp": {
|
||||
"type": "date"
|
||||
},
|
||||
"metrics": {
|
||||
"properties": {
|
||||
"source": {
|
||||
"properties": {
|
||||
"ip": {
|
||||
"properties": {
|
||||
"value_count": {
|
||||
"type": "long"
|
||||
},
|
||||
"cardinality": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"bytes": {
|
||||
"properties": {
|
||||
"sum": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"destination": {
|
||||
"properties": {
|
||||
"ip": {
|
||||
"properties": {
|
||||
"value_count": {
|
||||
"type": "long"
|
||||
},
|
||||
"cardinality": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"bytes": {
|
||||
"properties": {
|
||||
"sum": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"network": {
|
||||
"properties": {
|
||||
"community_id": {
|
||||
"properties": {
|
||||
"cardinality": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"source": {
|
||||
"properties": {
|
||||
"ip": {
|
||||
"type": "ip"
|
||||
}
|
||||
}
|
||||
},
|
||||
"destination": {
|
||||
"properties": {
|
||||
"ip": {
|
||||
"type": "ip"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,26 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import sourceIpEntities from './source_ip_entities.json';
|
||||
import destinationIpEntities from './destination_ip_entities.json';
|
||||
import sourceIpEntitiesMapping from './source_ip_entities_mapping.json';
|
||||
import destinationIpEntitiesMapping from './destination_ip_entities_mapping.json';
|
||||
import destinationCountryIsoCodeEntities from './destination_country_iso_code_entities.json';
|
||||
import destinationCountryIsoCodeEntitiesMapping from './destination_country_iso_code_entities_mapping.json';
|
||||
import sourceCountryIsoCodeEntities from './source_country_iso_code_entities.json';
|
||||
import sourceCountryIsoCodeEntitiesMapping from './source_country_iso_code_entities_mapping.json';
|
||||
|
||||
export {
|
||||
sourceIpEntities,
|
||||
destinationIpEntities,
|
||||
sourceCountryIsoCodeEntities,
|
||||
sourceCountryIsoCodeEntitiesMapping,
|
||||
destinationCountryIsoCodeEntities,
|
||||
destinationCountryIsoCodeEntitiesMapping,
|
||||
sourceIpEntitiesMapping,
|
||||
destinationIpEntitiesMapping,
|
||||
};
|
|
@ -1,51 +0,0 @@
|
|||
{
|
||||
"id": "src_iso_ent",
|
||||
"description": "[source.geo.country_iso_code entities] grouped by @timestamp and aggregated on source.geo.country_iso_code, source.bytes, destination.bytes, network.community_id, source.ip, and destination.ip",
|
||||
"pivot": {
|
||||
"group_by": {
|
||||
"@timestamp": {
|
||||
"date_histogram": {
|
||||
"field": "@timestamp",
|
||||
"calendar_interval": "1h"
|
||||
}
|
||||
},
|
||||
"source.geo.country_iso_code": {
|
||||
"terms": {
|
||||
"field": "source.geo.country_iso_code"
|
||||
}
|
||||
}
|
||||
},
|
||||
"aggregations": {
|
||||
"metrics.source.geo.country_iso_code.value_count": {
|
||||
"value_count": {
|
||||
"field": "source.geo.country_iso_code"
|
||||
}
|
||||
},
|
||||
"metrics.source.bytes.sum": {
|
||||
"sum": {
|
||||
"field": "source.bytes"
|
||||
}
|
||||
},
|
||||
"metrics.destination.bytes.sum": {
|
||||
"sum": {
|
||||
"field": "destination.bytes"
|
||||
}
|
||||
},
|
||||
"metrics.network.community_id.cardinality": {
|
||||
"cardinality": {
|
||||
"field": "network.community_id"
|
||||
}
|
||||
},
|
||||
"metrics.source.ip.cardinality": {
|
||||
"cardinality": {
|
||||
"field": "source.ip"
|
||||
}
|
||||
},
|
||||
"metrics.destination.ip.cardinality": {
|
||||
"cardinality": {
|
||||
"field": "destination.ip"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
{
|
||||
"mappings": {
|
||||
"_meta": {
|
||||
"index": "src_iso_ent"
|
||||
},
|
||||
"dynamic": "strict",
|
||||
"properties": {
|
||||
"@timestamp": {
|
||||
"type": "date"
|
||||
},
|
||||
"metrics": {
|
||||
"properties": {
|
||||
"source": {
|
||||
"properties": {
|
||||
"ip": {
|
||||
"properties": {
|
||||
"value_count": {
|
||||
"type": "long"
|
||||
},
|
||||
"cardinality": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"bytes": {
|
||||
"properties": {
|
||||
"sum": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"geo": {
|
||||
"properties": {
|
||||
"country_iso_code": {
|
||||
"properties": {
|
||||
"value_count": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"destination": {
|
||||
"properties": {
|
||||
"ip": {
|
||||
"properties": {
|
||||
"value_count": {
|
||||
"type": "long"
|
||||
},
|
||||
"cardinality": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"bytes": {
|
||||
"properties": {
|
||||
"sum": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"geo": {
|
||||
"properties": {
|
||||
"country_iso_code": {
|
||||
"properties": {
|
||||
"value_count": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"network": {
|
||||
"properties": {
|
||||
"community_id": {
|
||||
"properties": {
|
||||
"cardinality": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"source": {
|
||||
"properties": {
|
||||
"ip": {
|
||||
"type": "ip"
|
||||
},
|
||||
"geo": {
|
||||
"properties": {
|
||||
"country_iso_code": {
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"destination": {
|
||||
"properties": {
|
||||
"ip": {
|
||||
"type": "ip"
|
||||
},
|
||||
"geo": {
|
||||
"properties": {
|
||||
"country_iso_code": {
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
{
|
||||
"id": "src_ip_ent",
|
||||
"description": "[source.ip entities] grouped by @timestamp and aggregated on destination.ip, source.bytes, destination.bytes, network.community_id, and destination.ip",
|
||||
"pivot": {
|
||||
"group_by": {
|
||||
"@timestamp": {
|
||||
"date_histogram": {
|
||||
"field": "@timestamp",
|
||||
"calendar_interval": "1h"
|
||||
}
|
||||
},
|
||||
"source.ip": {
|
||||
"terms": {
|
||||
"field": "source.ip"
|
||||
}
|
||||
}
|
||||
},
|
||||
"aggregations": {
|
||||
"metrics.source.ip.value_count": {
|
||||
"value_count": {
|
||||
"field": "source.ip"
|
||||
}
|
||||
},
|
||||
"metrics.source.bytes.sum": {
|
||||
"sum": {
|
||||
"field": "source.bytes"
|
||||
}
|
||||
},
|
||||
"metrics.destination.bytes.sum": {
|
||||
"sum": {
|
||||
"field": "destination.bytes"
|
||||
}
|
||||
},
|
||||
"metrics.network.community_id.cardinality": {
|
||||
"cardinality": {
|
||||
"field": "network.community_id"
|
||||
}
|
||||
},
|
||||
"metrics.destination.ip.cardinality": {
|
||||
"cardinality": {
|
||||
"field": "destination.ip"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
{
|
||||
"mappings": {
|
||||
"_meta": {
|
||||
"index": "src_ip_ent"
|
||||
},
|
||||
"dynamic": "strict",
|
||||
"properties": {
|
||||
"@timestamp": {
|
||||
"type": "date"
|
||||
},
|
||||
"metrics": {
|
||||
"properties": {
|
||||
"source": {
|
||||
"properties": {
|
||||
"ip": {
|
||||
"properties": {
|
||||
"value_count": {
|
||||
"type": "long"
|
||||
},
|
||||
"cardinality": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"bytes": {
|
||||
"properties": {
|
||||
"sum": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"destination": {
|
||||
"properties": {
|
||||
"ip": {
|
||||
"properties": {
|
||||
"value_count": {
|
||||
"type": "long"
|
||||
},
|
||||
"cardinality": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"bytes": {
|
||||
"properties": {
|
||||
"sum": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"network": {
|
||||
"properties": {
|
||||
"community_id": {
|
||||
"properties": {
|
||||
"cardinality": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"source": {
|
||||
"properties": {
|
||||
"ip": {
|
||||
"type": "ip"
|
||||
}
|
||||
}
|
||||
},
|
||||
"destination": {
|
||||
"properties": {
|
||||
"ip": {
|
||||
"type": "ip"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import ipMetrics from './ip_metrics.json';
|
||||
import ipMetricsMapping from './ip_metrics_mapping.json';
|
||||
|
||||
export { ipMetrics, ipMetricsMapping };
|
|
@ -1,116 +0,0 @@
|
|||
{
|
||||
"id": "ip_met",
|
||||
"description": "[source.ip metrics] grouped by @timestamp, source.ip, destination.ip and aggregated on tls.version, suricata.eve.tls.version, zeek.ssl.version, dns.question.name, and zeek.dns.query",
|
||||
"pivot": {
|
||||
"group_by": {
|
||||
"@timestamp": {
|
||||
"date_histogram": {
|
||||
"field": "@timestamp",
|
||||
"calendar_interval": "1h"
|
||||
}
|
||||
}
|
||||
},
|
||||
"aggregations": {
|
||||
"metrics.source.ip.cardinality": {
|
||||
"cardinality": {
|
||||
"field": "source.ip"
|
||||
}
|
||||
},
|
||||
"metrics.destination.ip.cardinality": {
|
||||
"cardinality": {
|
||||
"field": "destination.ip"
|
||||
}
|
||||
},
|
||||
"metrics.network": {
|
||||
"filter": {
|
||||
"bool": {
|
||||
"should": [
|
||||
{
|
||||
"exists": {
|
||||
"field": "source.ip"
|
||||
}
|
||||
},
|
||||
{
|
||||
"exists": {
|
||||
"field": "destination.ip"
|
||||
}
|
||||
}
|
||||
],
|
||||
"minimum_should_match": 1
|
||||
}
|
||||
},
|
||||
"aggs": {
|
||||
"events.value_count": {
|
||||
"value_count": {
|
||||
"field": "@timestamp"
|
||||
}
|
||||
},
|
||||
"tls": {
|
||||
"filter": {
|
||||
"bool": {
|
||||
"should": [
|
||||
{
|
||||
"exists": {
|
||||
"field": "tls.version"
|
||||
}
|
||||
},
|
||||
{
|
||||
"exists": {
|
||||
"field": "suricata.eve.tls.version"
|
||||
}
|
||||
},
|
||||
{
|
||||
"exists": {
|
||||
"field": "zeek.ssl.version"
|
||||
}
|
||||
}
|
||||
],
|
||||
"minimum_should_match": 1
|
||||
}
|
||||
},
|
||||
"aggs": {
|
||||
"version.value_count": {
|
||||
"value_count": {
|
||||
"field": "@timestamp"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"metrics.dns": {
|
||||
"filter": {
|
||||
"bool": {
|
||||
"should": [
|
||||
{
|
||||
"exists": {
|
||||
"field": "dns.question.name"
|
||||
}
|
||||
},
|
||||
{
|
||||
"term": {
|
||||
"suricata.eve.dns.type": {
|
||||
"value": "query"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"exists": {
|
||||
"field": "zeek.dns.query"
|
||||
}
|
||||
}
|
||||
],
|
||||
"minimum_should_match": 1
|
||||
}
|
||||
},
|
||||
"aggs": {
|
||||
"queries.value_count": {
|
||||
"value_count": {
|
||||
"field": "@timestamp"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
{
|
||||
"mappings": {
|
||||
"_meta": {
|
||||
"index": "ip_met"
|
||||
},
|
||||
"dynamic": "strict",
|
||||
"properties": {
|
||||
"@timestamp": {
|
||||
"type": "date"
|
||||
},
|
||||
"metrics": {
|
||||
"properties": {
|
||||
"source": {
|
||||
"properties": {
|
||||
"ip": {
|
||||
"properties": {
|
||||
"value_count": {
|
||||
"type": "long"
|
||||
},
|
||||
"cardinality": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"bytes": {
|
||||
"properties": {
|
||||
"sum": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"destination": {
|
||||
"properties": {
|
||||
"ip": {
|
||||
"properties": {
|
||||
"value_count": {
|
||||
"type": "long"
|
||||
},
|
||||
"cardinality": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"bytes": {
|
||||
"properties": {
|
||||
"sum": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"network": {
|
||||
"properties": {
|
||||
"events": {
|
||||
"properties": {
|
||||
"value_count": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tls": {
|
||||
"properties": {
|
||||
"version": {
|
||||
"properties": {
|
||||
"value_count": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"dns": {
|
||||
"properties": {
|
||||
"queries": {
|
||||
"properties": {
|
||||
"value_count": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Loose type for the mappings
|
||||
*/
|
||||
export interface Mappings {
|
||||
[key: string]: unknown;
|
||||
mappings: {
|
||||
[key: string]: unknown;
|
||||
_meta: {
|
||||
index: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Loose type for the transforms. id is marked optional so we can delete it before
|
||||
* pushing it through elastic client.
|
||||
* TODO: Can we use stricter pre-defined typings for the transforms here or is this ours because we define it slightly different?
|
||||
*/
|
||||
export interface Transforms {
|
||||
[key: string]: unknown;
|
||||
id: string;
|
||||
dest?: Partial<{
|
||||
index: string;
|
||||
pipeline: string;
|
||||
}>;
|
||||
source?: Partial<{}>;
|
||||
settings?: Partial<{
|
||||
max_page_search_size: number;
|
||||
docs_per_second: number | null;
|
||||
}>;
|
||||
}
|
|
@ -1,10 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import userEntities from './user_entities.json';
|
||||
import userEntitiesMapping from './user_entities_mapping.json';
|
||||
export { userEntities, userEntitiesMapping };
|
|
@ -1,51 +0,0 @@
|
|||
{
|
||||
"id": "user_ent",
|
||||
"description": "[user.name entities] grouped by @timestamp and aggregated on user.name, and event.categories of success, failure, and unknown",
|
||||
"pivot": {
|
||||
"group_by": {
|
||||
"@timestamp": {
|
||||
"date_histogram": {
|
||||
"field": "@timestamp",
|
||||
"calendar_interval": "1h"
|
||||
}
|
||||
},
|
||||
"user.name": {
|
||||
"terms": {
|
||||
"field": "user.name"
|
||||
}
|
||||
}
|
||||
},
|
||||
"aggregations": {
|
||||
"metrics.event.authentication": {
|
||||
"filter": {
|
||||
"term": {
|
||||
"event.category": "authentication"
|
||||
}
|
||||
},
|
||||
"aggs": {
|
||||
"success.value_count": {
|
||||
"filter": {
|
||||
"term": {
|
||||
"event.outcome": "success"
|
||||
}
|
||||
}
|
||||
},
|
||||
"failure.value_count": {
|
||||
"filter": {
|
||||
"term": {
|
||||
"event.outcome": "failure"
|
||||
}
|
||||
}
|
||||
},
|
||||
"unknown.value_count": {
|
||||
"filter": {
|
||||
"term": {
|
||||
"event.outcome": "unknown"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
{
|
||||
"mappings": {
|
||||
"_meta": {
|
||||
"index": "user_ent"
|
||||
},
|
||||
"dynamic": "strict",
|
||||
"properties": {
|
||||
"@timestamp": {
|
||||
"type": "date"
|
||||
},
|
||||
"metrics": {
|
||||
"properties": {
|
||||
"event": {
|
||||
"properties": {
|
||||
"authentication": {
|
||||
"properties": {
|
||||
"failure": {
|
||||
"properties": {
|
||||
"value_count": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"success": {
|
||||
"properties": {
|
||||
"value_count": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"unknown": {
|
||||
"properties": {
|
||||
"value_count": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import userMetrics from './user_metrics.json';
|
||||
import userMetricsMapping from './user_metrics_mapping.json';
|
||||
|
||||
export { userMetrics, userMetricsMapping };
|
|
@ -1,56 +0,0 @@
|
|||
{
|
||||
"id": "user_met",
|
||||
"description": "[event.category authentication metrics] grouped by @timestamp and aggregated on success, failure, and unknown",
|
||||
"source": {
|
||||
"query": {
|
||||
"bool": {
|
||||
"filter": [
|
||||
{
|
||||
"bool": {
|
||||
"filter": [
|
||||
{
|
||||
"term": {
|
||||
"event.category": "authentication"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"pivot": {
|
||||
"group_by": {
|
||||
"@timestamp": {
|
||||
"date_histogram": {
|
||||
"field": "@timestamp",
|
||||
"calendar_interval": "1h"
|
||||
}
|
||||
}
|
||||
},
|
||||
"aggregations": {
|
||||
"metrics.event.authentication.success.value_count": {
|
||||
"filter": {
|
||||
"term": {
|
||||
"event.outcome": "success"
|
||||
}
|
||||
}
|
||||
},
|
||||
"metrics.event.authentication.failure.value_count": {
|
||||
"filter": {
|
||||
"term": {
|
||||
"event.outcome": "failure"
|
||||
}
|
||||
}
|
||||
},
|
||||
"metrics.event.authentication.unknown.value_count": {
|
||||
"filter": {
|
||||
"term": {
|
||||
"event.outcome": "unknown"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
{
|
||||
"mappings": {
|
||||
"_meta": {
|
||||
"index": "user_met"
|
||||
},
|
||||
"dynamic": "strict",
|
||||
"properties": {
|
||||
"metrics": {
|
||||
"properties": {
|
||||
"event": {
|
||||
"properties": {
|
||||
"authentication": {
|
||||
"properties": {
|
||||
"failure": {
|
||||
"properties": {
|
||||
"value_count": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"success": {
|
||||
"properties": {
|
||||
"value_count": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"unknown": {
|
||||
"properties": {
|
||||
"value_count": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@timestamp": {
|
||||
"type": "date"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,90 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
CoreSetup,
|
||||
CoreStart,
|
||||
Logger,
|
||||
Plugin,
|
||||
PluginInitializerContext,
|
||||
} from '../../../../src/core/server';
|
||||
|
||||
import {
|
||||
ContextProvider,
|
||||
ContextProviderReturn,
|
||||
MetricsEntitiesPluginSetup,
|
||||
MetricsEntitiesPluginStart,
|
||||
MetricsEntitiesRequestHandlerContext,
|
||||
} from './types';
|
||||
import { getTransforms, postTransforms } from './routes';
|
||||
import { MetricsEntitiesClient } from './services/metrics_entities_client';
|
||||
import { deleteTransforms } from './routes/delete_transforms';
|
||||
|
||||
export class MetricsEntitiesPlugin
|
||||
implements Plugin<MetricsEntitiesPluginSetup, MetricsEntitiesPluginStart>
|
||||
{
|
||||
private readonly logger: Logger;
|
||||
private kibanaVersion: string;
|
||||
|
||||
constructor(initializerContext: PluginInitializerContext) {
|
||||
this.logger = initializerContext.logger.get();
|
||||
this.kibanaVersion = initializerContext.env.packageInfo.version;
|
||||
}
|
||||
|
||||
public setup(core: CoreSetup): MetricsEntitiesPluginSetup {
|
||||
const router = core.http.createRouter();
|
||||
|
||||
core.http.registerRouteHandlerContext<MetricsEntitiesRequestHandlerContext, 'metricsEntities'>(
|
||||
'metricsEntities',
|
||||
this.createRouteHandlerContext()
|
||||
);
|
||||
|
||||
// Register server side APIs
|
||||
// TODO: Add all of these into a separate file and call that file called init_routes.ts
|
||||
getTransforms(router);
|
||||
postTransforms(router);
|
||||
deleteTransforms(router);
|
||||
|
||||
return {
|
||||
getMetricsEntitiesClient: (esClient): MetricsEntitiesClient =>
|
||||
new MetricsEntitiesClient({
|
||||
esClient,
|
||||
kibanaVersion: this.kibanaVersion,
|
||||
logger: this.logger,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
public start(core: CoreStart): void {
|
||||
this.logger.debug('Starting plugin');
|
||||
}
|
||||
|
||||
public stop(): void {
|
||||
this.logger.debug('Stopping plugin');
|
||||
}
|
||||
|
||||
private createRouteHandlerContext = (): ContextProvider => {
|
||||
return async (context): ContextProviderReturn => {
|
||||
const {
|
||||
core: {
|
||||
elasticsearch: {
|
||||
client: { asCurrentUser: esClient },
|
||||
},
|
||||
},
|
||||
} = context;
|
||||
return {
|
||||
getMetricsEntitiesClient: (): MetricsEntitiesClient =>
|
||||
new MetricsEntitiesClient({
|
||||
esClient,
|
||||
kibanaVersion: this.kibanaVersion,
|
||||
logger: this.logger,
|
||||
}),
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,54 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
|
||||
import { IRouter } from '../../../../../src/core/server';
|
||||
import { METRICS_ENTITIES_TRANSFORMS } from '../../common/constants';
|
||||
import { ModuleNames } from '../modules';
|
||||
|
||||
import { getMetricsEntitiesClient } from './utils/get_metrics_entities_client';
|
||||
|
||||
/**
|
||||
* Deletes transforms.
|
||||
* NOTE: We use a POST rather than a DELETE on purpose here to ensure that there
|
||||
* are not problems with the body being sent.
|
||||
* @param router The router to delete the collection of transforms
|
||||
*/
|
||||
export const deleteTransforms = (router: IRouter): void => {
|
||||
router.post(
|
||||
{
|
||||
path: `${METRICS_ENTITIES_TRANSFORMS}/_delete`,
|
||||
validate: {
|
||||
// TODO: Add the validation instead of allowing handler to have access to raw non-validated in runtime
|
||||
body: schema.object({}, { unknowns: 'allow' }),
|
||||
query: schema.object({}, { unknowns: 'allow' }),
|
||||
},
|
||||
},
|
||||
async (context, request, response) => {
|
||||
// TODO: Type this through validation above and remove the weird casting of: "as { modules: ModuleNames };"
|
||||
// TODO: Validate for runtime that the module exists or not and throw before pushing the module name lower
|
||||
// TODO: Change modules to be part of the body and become an array of values
|
||||
// TODO: Wrap this in a try catch block and report errors
|
||||
const {
|
||||
modules,
|
||||
prefix = '',
|
||||
suffix = '',
|
||||
} = request.body as {
|
||||
modules: ModuleNames[];
|
||||
prefix: string;
|
||||
suffix: string;
|
||||
};
|
||||
const metrics = getMetricsEntitiesClient(context);
|
||||
await metrics.deleteTransforms({ modules, prefix, suffix });
|
||||
|
||||
return response.custom({
|
||||
statusCode: 204,
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
|
@ -1,36 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { IRouter } from '../../../../../src/core/server';
|
||||
import { METRICS_ENTITIES_TRANSFORMS } from '../../common/constants';
|
||||
|
||||
import { getMetricsEntitiesClient } from './utils/get_metrics_entities_client';
|
||||
|
||||
/**
|
||||
* Returns all transforms from all modules
|
||||
* TODO: Add support for specific modules and prefix
|
||||
* @param router The router to get the collection of transforms
|
||||
*/
|
||||
export const getTransforms = (router: IRouter): void => {
|
||||
router.get(
|
||||
{
|
||||
path: METRICS_ENTITIES_TRANSFORMS,
|
||||
// TODO: Add the validation instead of false
|
||||
// TODO: Add the prefix and module support
|
||||
validate: false,
|
||||
},
|
||||
async (context, _, response) => {
|
||||
const metrics = getMetricsEntitiesClient(context);
|
||||
const summaries = await metrics.getTransforms();
|
||||
return response.ok({
|
||||
body: {
|
||||
summaries,
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
|
@ -1,10 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
export * from './delete_transforms';
|
||||
export * from './get_transforms';
|
||||
export * from './post_transforms';
|
|
@ -1,96 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
|
||||
import { IRouter } from '../../../../../src/core/server';
|
||||
import { METRICS_ENTITIES_TRANSFORMS } from '../../common/constants';
|
||||
import { ModuleNames } from '../modules';
|
||||
|
||||
import { getMetricsEntitiesClient } from './utils/get_metrics_entities_client';
|
||||
|
||||
/**
|
||||
* Creates transforms.
|
||||
* @param router The router to get the collection of transforms
|
||||
*/
|
||||
export const postTransforms = (router: IRouter): void => {
|
||||
router.post(
|
||||
{
|
||||
path: METRICS_ENTITIES_TRANSFORMS,
|
||||
validate: {
|
||||
// TODO: Add the validation instead of allowing handler to have access to raw non-validated in runtime
|
||||
body: schema.object({}, { unknowns: 'allow' }),
|
||||
query: schema.object({}, { unknowns: 'allow' }),
|
||||
},
|
||||
},
|
||||
async (context, request, response) => {
|
||||
// TODO: Type this through validation above and remove the weird casting of: "as { modules: ModuleNames };"
|
||||
// TODO: Validate for runtime that the module exists or not and throw before pushing the module name lower
|
||||
// TODO: Change modules to be part of the body and become an array of values
|
||||
// TODO: Wrap this in a try catch block and report errors
|
||||
const {
|
||||
modules,
|
||||
auto_start: autoStart = false,
|
||||
settings: {
|
||||
max_page_search_size: maxPageSearchSize = 500,
|
||||
docs_per_second: docsPerSecond = undefined,
|
||||
} = {
|
||||
docsPerSecond: undefined,
|
||||
maxPageSearchSize: 500,
|
||||
},
|
||||
frequency = '1m',
|
||||
indices,
|
||||
query = { match_all: {} },
|
||||
prefix = '',
|
||||
suffix = '',
|
||||
sync = {
|
||||
time: {
|
||||
delay: '60s',
|
||||
field: '@timestamp',
|
||||
},
|
||||
},
|
||||
} = request.body as {
|
||||
modules: ModuleNames[];
|
||||
auto_start: boolean;
|
||||
indices: string[];
|
||||
// We can blow up at 65 character+ for transform id. We need to validate the prefix + transform jobs and return an error
|
||||
prefix: string;
|
||||
query: object;
|
||||
suffix: string;
|
||||
frequency: string;
|
||||
settings: {
|
||||
max_page_search_size: number;
|
||||
docs_per_second: number;
|
||||
};
|
||||
sync: {
|
||||
time: {
|
||||
delay: string;
|
||||
field: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
const metrics = getMetricsEntitiesClient(context);
|
||||
await metrics.postTransforms({
|
||||
autoStart,
|
||||
docsPerSecond,
|
||||
frequency,
|
||||
indices,
|
||||
maxPageSearchSize,
|
||||
modules,
|
||||
prefix,
|
||||
query,
|
||||
suffix,
|
||||
sync,
|
||||
});
|
||||
|
||||
return response.custom({
|
||||
body: { acknowledged: true },
|
||||
statusCode: 201,
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
|
@ -1,21 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ErrorWithStatusCode } from '../../error_with_status_code';
|
||||
import { MetricsEntitiesClient } from '../../services/metrics_entities_client';
|
||||
import type { MetricsEntitiesRequestHandlerContext } from '../../types';
|
||||
|
||||
export const getMetricsEntitiesClient = (
|
||||
context: MetricsEntitiesRequestHandlerContext
|
||||
): MetricsEntitiesClient => {
|
||||
const metricsEntities = context.metricsEntities?.getMetricsEntitiesClient();
|
||||
if (metricsEntities == null) {
|
||||
throw new ErrorWithStatusCode('Metrics Entities is not found as a plugin', 404);
|
||||
} else {
|
||||
return metricsEntities;
|
||||
}
|
||||
};
|
|
@ -1,8 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
export * from './get_metrics_entities_client';
|
|
@ -1,32 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
# or more contributor license agreements. Licensed under the Elastic License
|
||||
# 2.0; you may not use this file except in compliance with the Elastic License
|
||||
# 2.0.
|
||||
#
|
||||
|
||||
# Add this to the start of any scripts to detect if env variables are set
|
||||
|
||||
set -e
|
||||
|
||||
if [ -z "${ELASTICSEARCH_USERNAME}" ]; then
|
||||
echo "Set ELASTICSEARCH_USERNAME in your environment"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "${ELASTICSEARCH_PASSWORD}" ]; then
|
||||
echo "Set ELASTICSEARCH_PASSWORD in your environment"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "${ELASTICSEARCH_URL}" ]; then
|
||||
echo "Set ELASTICSEARCH_URL in your environment"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "${KIBANA_URL}" ]; then
|
||||
echo "Set KIBANA_URL in your environment"
|
||||
exit 1
|
||||
fi
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"prefix": "all",
|
||||
"modules": [
|
||||
"host_metrics",
|
||||
"host_entities",
|
||||
"network_metrics",
|
||||
"network_entities",
|
||||
"user_entities",
|
||||
"user_metrics"
|
||||
]
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"prefix": "auditbeat",
|
||||
"modules": [
|
||||
"host_metrics",
|
||||
"host_entities",
|
||||
"network_metrics",
|
||||
"network_entities",
|
||||
"user_entities",
|
||||
"user_metrics"
|
||||
]
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"modules": ["network_entities"]
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"modules": ["user_entities"]
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"modules": ["host_metrics", "host_entities"]
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
# or more contributor license agreements. Licensed under the Elastic License
|
||||
# 2.0; you may not use this file except in compliance with the Elastic License
|
||||
# 2.0.
|
||||
#
|
||||
|
||||
set -e
|
||||
./check_env_variables.sh
|
||||
|
||||
# Uses a default if no argument is specified
|
||||
FILE=${1:-./post_examples/one_module.json}
|
||||
|
||||
# Example: ./delete_transforms.sh ./delete_examples/one_module.json
|
||||
curl -s -k \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'kbn-xsrf: 123' \
|
||||
-u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \
|
||||
-X POST ${KIBANA_URL}${SPACE_URL}/api/metrics_entities/transforms/_delete \
|
||||
-d @${FILE} \
|
||||
| jq .
|
|
@ -1,16 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
# or more contributor license agreements. Licensed under the Elastic License
|
||||
# 2.0; you may not use this file except in compliance with the Elastic License
|
||||
# 2.0.
|
||||
#
|
||||
|
||||
set -e
|
||||
./check_env_variables.sh
|
||||
|
||||
# Example: ./get_transforms.sh
|
||||
curl -s -k \
|
||||
-u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \
|
||||
-X GET ${KIBANA_URL}${SPACE_URL}/api/metrics_entities/transforms | jq .
|
|
@ -1,17 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
# or more contributor license agreements. Licensed under the Elastic License
|
||||
# 2.0; you may not use this file except in compliance with the Elastic License
|
||||
# 2.0.
|
||||
#
|
||||
|
||||
# TODO Make this work
|
||||
|
||||
set -e
|
||||
./check_env_variables.sh
|
||||
|
||||
# remove all templates
|
||||
# add all templates again and start them
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
{
|
||||
"prefix": "all",
|
||||
"modules": [
|
||||
"host_metrics",
|
||||
"host_entities",
|
||||
"network_metrics",
|
||||
"network_entities",
|
||||
"user_entities",
|
||||
"user_metrics"
|
||||
],
|
||||
"indices": [
|
||||
"auditbeat-*",
|
||||
"endgame-*",
|
||||
"filebeat-*",
|
||||
"logs-*",
|
||||
"packetbeat-*",
|
||||
"winlogbeat-*",
|
||||
"-*elastic-cloud-logs-*"
|
||||
],
|
||||
"auto_start": true,
|
||||
"settings": {
|
||||
"max_page_search_size": 5000
|
||||
},
|
||||
"query": {
|
||||
"range": {
|
||||
"@timestamp": {
|
||||
"gte": "now-1d/d",
|
||||
"format": "strict_date_optional_time"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
{
|
||||
"modules": [
|
||||
"host_metrics",
|
||||
"host_entities",
|
||||
"network_metrics",
|
||||
"network_entities",
|
||||
"user_entities",
|
||||
"user_metrics"
|
||||
],
|
||||
"indices": ["auditbeat-*"],
|
||||
"auto_start": true,
|
||||
"settings": {
|
||||
"max_page_search_size": 5000
|
||||
},
|
||||
"query": {
|
||||
"range": {
|
||||
"@timestamp": {
|
||||
"gte": "now-1d/d",
|
||||
"format": "strict_date_optional_time"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"modules": ["network_entities"],
|
||||
"indices": ["auditbeat-*"]
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
{
|
||||
"modules": ["network_metrics"],
|
||||
"indices": [
|
||||
"auditbeat-*",
|
||||
"endgame-*",
|
||||
"filebeat-*",
|
||||
"logs-*",
|
||||
"packetbeat-*",
|
||||
"winlogbeat-*",
|
||||
"-*elastic-cloud-logs-*"
|
||||
],
|
||||
"auto_start": true,
|
||||
"query": {
|
||||
"range": {
|
||||
"@timestamp": {
|
||||
"gte": "now-1d/d",
|
||||
"format": "strict_date_optional_time"
|
||||
}
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"max_page_search_size": 5000
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
{
|
||||
"modules": ["network_metrics"],
|
||||
"indices": ["auditbeat-*"],
|
||||
"auto_start": true,
|
||||
"query": {
|
||||
"range": {
|
||||
"@timestamp": {
|
||||
"gte": "now-1d/d",
|
||||
"format": "strict_date_optional_time"
|
||||
}
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"max_page_search_size": 5000
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
"modules": ["host_metrics"],
|
||||
"indices": ["auditbeat-*"],
|
||||
"auto_start": true,
|
||||
"settings": {
|
||||
"max_page_search_size": 5000
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"modules": ["host_metrics"],
|
||||
"indices": ["auditbeat-*"],
|
||||
"prefix": ["default_"]
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
{
|
||||
"modules": ["network_metrics", "network_entities"],
|
||||
"indices": [
|
||||
"auditbeat-*",
|
||||
"endgame-*",
|
||||
"filebeat-*",
|
||||
"logs-*",
|
||||
"packetbeat-*",
|
||||
"winlogbeat-*",
|
||||
"-*elastic-cloud-logs-*"
|
||||
],
|
||||
"auto_start": true,
|
||||
"query": {
|
||||
"range": {
|
||||
"@timestamp": {
|
||||
"gte": "now-1d/d",
|
||||
"format": "strict_date_optional_time"
|
||||
}
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"max_page_search_size": 5000
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"modules": ["host_metrics", "host_entities"],
|
||||
"indices": ["auditbeat-*"]
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
# or more contributor license agreements. Licensed under the Elastic License
|
||||
# 2.0; you may not use this file except in compliance with the Elastic License
|
||||
# 2.0.
|
||||
#
|
||||
|
||||
set -e
|
||||
./check_env_variables.sh
|
||||
|
||||
# Uses a default if no argument is specified
|
||||
FILE=${1:-./post_examples/one_module_auditbeat.json}
|
||||
|
||||
# Example: ./post_transforms.sh ./post_examples/one_module_auditbeat.json
|
||||
# Example: ./post_transforms.sh ./post_examples/one_module_namespace_auditbeat.json
|
||||
curl -s -k \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'kbn-xsrf: 123' \
|
||||
-u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \
|
||||
-X POST ${KIBANA_URL}${SPACE_URL}/api/metrics_entities/transforms \
|
||||
-d @${FILE} \
|
||||
| jq .
|
|
@ -1,13 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
# or more contributor license agreements. Licensed under the Elastic License
|
||||
# 2.0; you may not use this file except in compliance with the Elastic License
|
||||
# 2.0.
|
||||
#
|
||||
|
||||
set -e
|
||||
./check_env_variables.sh
|
||||
|
||||
# TODO Make this work
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ElasticsearchClient } from 'kibana/server';
|
||||
|
||||
import { ModuleNames, installableMappings, installableTransforms } from '../modules';
|
||||
import type { Logger } from '../../../../../src/core/server';
|
||||
|
||||
import { uninstallMappings } from './uninstall_mappings';
|
||||
import { uninstallTransforms } from './uninstall_transforms';
|
||||
|
||||
interface DeleteTransformsOptions {
|
||||
esClient: ElasticsearchClient;
|
||||
logger: Logger;
|
||||
modules: ModuleNames[];
|
||||
prefix: string;
|
||||
suffix: string;
|
||||
}
|
||||
|
||||
export const deleteTransforms = async ({
|
||||
esClient,
|
||||
logger,
|
||||
modules,
|
||||
prefix,
|
||||
suffix,
|
||||
}: DeleteTransformsOptions): Promise<void> => {
|
||||
for (const moduleName of modules) {
|
||||
const mappings = installableMappings[moduleName];
|
||||
const transforms = installableTransforms[moduleName];
|
||||
|
||||
await uninstallTransforms({ esClient, logger, prefix, suffix, transforms });
|
||||
await uninstallMappings({ esClient, logger, mappings, prefix, suffix });
|
||||
}
|
||||
};
|
|
@ -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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ElasticsearchClient } from 'kibana/server';
|
||||
|
||||
import type { Logger } from '../../../../../src/core/server';
|
||||
|
||||
interface GetTransformsOptions {
|
||||
esClient: ElasticsearchClient;
|
||||
logger: Logger;
|
||||
}
|
||||
|
||||
// TODO: Type the Promise<unknown> to a stronger type
|
||||
export const getTransforms = async ({ esClient }: GetTransformsOptions): Promise<unknown> => {
|
||||
const body = await esClient.transform.getTransform({
|
||||
size: 1000,
|
||||
transform_id: '*',
|
||||
});
|
||||
return body;
|
||||
};
|
|
@ -1,15 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
export * from './delete_transforms';
|
||||
export * from './get_transforms';
|
||||
export * from './install_mappings';
|
||||
export * from './install_transforms';
|
||||
export * from './metrics_entities_client';
|
||||
export * from './post_transforms';
|
||||
export * from './uninstall_mappings';
|
||||
export * from './uninstall_transforms';
|
|
@ -1,82 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ElasticsearchClient } from 'kibana/server';
|
||||
|
||||
import { Mappings } from '../modules/types';
|
||||
import type { Logger } from '../../../../../src/core/server';
|
||||
|
||||
import {
|
||||
computeMappingId,
|
||||
getIndexExists,
|
||||
logMappingDebug,
|
||||
logMappingError,
|
||||
logMappingInfo,
|
||||
} from './utils';
|
||||
|
||||
interface CreateMappingOptions {
|
||||
esClient: ElasticsearchClient;
|
||||
mappings: Mappings[];
|
||||
prefix: string;
|
||||
suffix: string;
|
||||
logger: Logger;
|
||||
kibanaVersion: string;
|
||||
}
|
||||
|
||||
export const installMappings = async ({
|
||||
esClient,
|
||||
kibanaVersion,
|
||||
mappings,
|
||||
prefix,
|
||||
suffix,
|
||||
logger,
|
||||
}: CreateMappingOptions): Promise<void> => {
|
||||
for (const mapping of mappings) {
|
||||
const { index } = mapping.mappings._meta;
|
||||
const mappingId = computeMappingId({ id: index, prefix, suffix });
|
||||
const exists = await getIndexExists(esClient, mappingId);
|
||||
const computedBody = {
|
||||
...mapping,
|
||||
...{
|
||||
mappings: {
|
||||
...mapping.mappings,
|
||||
_meta: {
|
||||
...mapping.mappings._meta,
|
||||
...{
|
||||
created_by: 'metrics_entities',
|
||||
index: mappingId,
|
||||
version: kibanaVersion,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
if (!exists) {
|
||||
try {
|
||||
logMappingInfo({ id: mappingId, logger, message: 'does not exist, creating the mapping' });
|
||||
await esClient.indices.create({
|
||||
body: computedBody,
|
||||
index: mappingId,
|
||||
});
|
||||
} catch (error) {
|
||||
logMappingError({
|
||||
error,
|
||||
id: mappingId,
|
||||
logger,
|
||||
message: 'cannot install mapping',
|
||||
postBody: computedBody,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
logMappingDebug({
|
||||
id: mappingId,
|
||||
logger,
|
||||
message: 'mapping already exists. It will not be recreated',
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
|
@ -1,122 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ElasticsearchClient } from 'kibana/server';
|
||||
|
||||
import { Transforms } from '../modules/types';
|
||||
import type { Logger } from '../../../../../src/core/server';
|
||||
|
||||
import {
|
||||
computeMappingId,
|
||||
computeTransformId,
|
||||
getTransformExists,
|
||||
logTransformDebug,
|
||||
logTransformError,
|
||||
logTransformInfo,
|
||||
} from './utils';
|
||||
|
||||
interface CreateTransformOptions {
|
||||
esClient: ElasticsearchClient;
|
||||
transforms: Transforms[];
|
||||
autoStart: boolean;
|
||||
indices: string[];
|
||||
frequency: string;
|
||||
logger: Logger;
|
||||
query: object;
|
||||
docsPerSecond: number | undefined;
|
||||
maxPageSearchSize: number;
|
||||
sync: {
|
||||
time: {
|
||||
delay: string;
|
||||
field: string;
|
||||
};
|
||||
};
|
||||
prefix: string;
|
||||
suffix: string;
|
||||
}
|
||||
|
||||
export const installTransforms = async ({
|
||||
autoStart,
|
||||
esClient,
|
||||
frequency,
|
||||
indices,
|
||||
docsPerSecond,
|
||||
logger,
|
||||
maxPageSearchSize,
|
||||
prefix,
|
||||
suffix,
|
||||
transforms,
|
||||
query,
|
||||
sync,
|
||||
}: CreateTransformOptions): Promise<void> => {
|
||||
for (const transform of transforms) {
|
||||
const destIndex = transform?.dest?.index ?? transform.id;
|
||||
const computedMappingIndex = computeMappingId({ id: destIndex, prefix, suffix });
|
||||
const { id, ...transformNoId } = {
|
||||
...transform,
|
||||
...{ source: { ...transform.source, index: indices, query } },
|
||||
...{ dest: { ...transform.dest, index: computedMappingIndex } },
|
||||
...{
|
||||
settings: {
|
||||
...transform.settings,
|
||||
docs_per_second: docsPerSecond,
|
||||
max_page_search_size: maxPageSearchSize,
|
||||
},
|
||||
},
|
||||
frequency,
|
||||
sync,
|
||||
};
|
||||
|
||||
const computedName = computeTransformId({ id, prefix, suffix });
|
||||
const exists = await getTransformExists(esClient, computedName);
|
||||
if (!exists) {
|
||||
try {
|
||||
logTransformInfo({
|
||||
id: computedName,
|
||||
logger,
|
||||
message: 'does not exist, creating the transform',
|
||||
});
|
||||
await esClient.transform.putTransform({
|
||||
body: transformNoId,
|
||||
defer_validation: true,
|
||||
transform_id: computedName,
|
||||
});
|
||||
|
||||
if (autoStart) {
|
||||
logTransformInfo({
|
||||
id: computedName,
|
||||
logger,
|
||||
message: 'is being auto started',
|
||||
});
|
||||
await esClient.transform.startTransform({
|
||||
transform_id: computedName,
|
||||
});
|
||||
} else {
|
||||
logTransformInfo({
|
||||
id: computedName,
|
||||
logger,
|
||||
message: 'is not being auto started',
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
logTransformError({
|
||||
error,
|
||||
id: computedName,
|
||||
logger,
|
||||
message: 'Could not create and/or start',
|
||||
postBody: transformNoId,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
logTransformDebug({
|
||||
id: computedName,
|
||||
logger,
|
||||
message: 'already exists. It will not be recreated',
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
|
@ -1,76 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ElasticsearchClient } from 'kibana/server';
|
||||
|
||||
import type { Logger } from '../../../../../src/core/server';
|
||||
|
||||
import { getTransforms } from './get_transforms';
|
||||
import {
|
||||
ConstructorOptions,
|
||||
DeleteTransformsOptions,
|
||||
PostTransformsOptions,
|
||||
} from './metrics_entities_client_types';
|
||||
import { postTransforms } from './post_transforms';
|
||||
import { deleteTransforms } from './delete_transforms';
|
||||
|
||||
export class MetricsEntitiesClient {
|
||||
private readonly esClient: ElasticsearchClient;
|
||||
private readonly logger: Logger;
|
||||
private readonly kibanaVersion: string;
|
||||
|
||||
constructor({ esClient, logger, kibanaVersion }: ConstructorOptions) {
|
||||
this.esClient = esClient;
|
||||
this.logger = logger;
|
||||
this.kibanaVersion = kibanaVersion;
|
||||
}
|
||||
|
||||
// TODO: Type the unknown to be stronger
|
||||
public getTransforms = async (): Promise<unknown> => {
|
||||
const { esClient, logger } = this;
|
||||
return getTransforms({ esClient, logger });
|
||||
};
|
||||
|
||||
public postTransforms = async ({
|
||||
autoStart,
|
||||
frequency,
|
||||
docsPerSecond,
|
||||
maxPageSearchSize,
|
||||
modules,
|
||||
indices,
|
||||
prefix,
|
||||
suffix,
|
||||
query,
|
||||
sync,
|
||||
}: PostTransformsOptions): Promise<void> => {
|
||||
const { esClient, logger, kibanaVersion } = this;
|
||||
return postTransforms({
|
||||
autoStart,
|
||||
docsPerSecond,
|
||||
esClient,
|
||||
frequency,
|
||||
indices,
|
||||
kibanaVersion,
|
||||
logger,
|
||||
maxPageSearchSize,
|
||||
modules,
|
||||
prefix,
|
||||
query,
|
||||
suffix,
|
||||
sync,
|
||||
});
|
||||
};
|
||||
|
||||
public deleteTransforms = async ({
|
||||
modules,
|
||||
prefix,
|
||||
suffix,
|
||||
}: DeleteTransformsOptions): Promise<void> => {
|
||||
const { esClient, logger } = this;
|
||||
return deleteTransforms({ esClient, logger, modules, prefix, suffix });
|
||||
};
|
||||
}
|
|
@ -1,41 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ElasticsearchClient } from 'kibana/server';
|
||||
|
||||
import type { Logger } from '../../../../../src/core/server';
|
||||
import { ModuleNames } from '../modules';
|
||||
|
||||
export interface ConstructorOptions {
|
||||
esClient: ElasticsearchClient;
|
||||
logger: Logger;
|
||||
kibanaVersion: string;
|
||||
}
|
||||
|
||||
export interface PostTransformsOptions {
|
||||
modules: ModuleNames[];
|
||||
autoStart: boolean;
|
||||
frequency: string;
|
||||
indices: string[];
|
||||
docsPerSecond: number | undefined;
|
||||
maxPageSearchSize: number;
|
||||
prefix: string;
|
||||
query: object;
|
||||
suffix: string;
|
||||
sync: {
|
||||
time: {
|
||||
delay: string;
|
||||
field: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export interface DeleteTransformsOptions {
|
||||
modules: ModuleNames[];
|
||||
prefix: string;
|
||||
suffix: string;
|
||||
}
|
|
@ -1,72 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ElasticsearchClient } from 'kibana/server';
|
||||
|
||||
import { ModuleNames, installableMappings, installableTransforms } from '../modules';
|
||||
import type { Logger } from '../../../../../src/core/server';
|
||||
|
||||
import { installMappings } from './install_mappings';
|
||||
import { installTransforms } from './install_transforms';
|
||||
|
||||
interface PostTransformsOptions {
|
||||
logger: Logger;
|
||||
esClient: ElasticsearchClient;
|
||||
modules: ModuleNames[];
|
||||
autoStart: boolean;
|
||||
frequency: string;
|
||||
indices: string[];
|
||||
docsPerSecond: number | undefined;
|
||||
kibanaVersion: string;
|
||||
maxPageSearchSize: number;
|
||||
query: object;
|
||||
prefix: string;
|
||||
suffix: string;
|
||||
sync: {
|
||||
time: {
|
||||
delay: string;
|
||||
field: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export const postTransforms = async ({
|
||||
autoStart,
|
||||
logger,
|
||||
esClient,
|
||||
frequency,
|
||||
indices,
|
||||
docsPerSecond,
|
||||
kibanaVersion,
|
||||
maxPageSearchSize,
|
||||
modules,
|
||||
prefix,
|
||||
suffix,
|
||||
query,
|
||||
sync,
|
||||
}: PostTransformsOptions): Promise<void> => {
|
||||
for (const moduleName of modules) {
|
||||
const mappings = installableMappings[moduleName];
|
||||
const transforms = installableTransforms[moduleName];
|
||||
|
||||
await installMappings({ esClient, kibanaVersion, logger, mappings, prefix, suffix });
|
||||
await installTransforms({
|
||||
autoStart,
|
||||
docsPerSecond,
|
||||
esClient,
|
||||
frequency,
|
||||
indices,
|
||||
logger,
|
||||
maxPageSearchSize,
|
||||
prefix,
|
||||
query,
|
||||
suffix,
|
||||
sync,
|
||||
transforms,
|
||||
});
|
||||
}
|
||||
};
|
|
@ -1,8 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
// TODO: Write this
|
|
@ -1,55 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ElasticsearchClient } from 'kibana/server';
|
||||
|
||||
import { Mappings } from '../modules/types';
|
||||
import type { Logger } from '../../../../../src/core/server';
|
||||
|
||||
import { computeMappingId, logMappingInfo } from './utils';
|
||||
import { logMappingError } from './utils/log_mapping_error';
|
||||
|
||||
interface UninstallMappingOptions {
|
||||
esClient: ElasticsearchClient;
|
||||
mappings: Mappings[];
|
||||
prefix: string;
|
||||
suffix: string;
|
||||
logger: Logger;
|
||||
}
|
||||
|
||||
export const uninstallMappings = async ({
|
||||
esClient,
|
||||
logger,
|
||||
mappings,
|
||||
prefix,
|
||||
suffix,
|
||||
}: UninstallMappingOptions): Promise<void> => {
|
||||
const indices = mappings.map((mapping) => {
|
||||
const { index } = mapping.mappings._meta;
|
||||
return computeMappingId({ id: index, prefix, suffix });
|
||||
});
|
||||
logMappingInfo({
|
||||
id: indices.join(),
|
||||
logger,
|
||||
message: 'deleting indices',
|
||||
});
|
||||
try {
|
||||
await esClient.indices.delete({
|
||||
allow_no_indices: true,
|
||||
ignore_unavailable: true,
|
||||
index: indices,
|
||||
});
|
||||
} catch (error) {
|
||||
logMappingError({
|
||||
error,
|
||||
id: indices.join(),
|
||||
logger,
|
||||
message: 'could not delete index',
|
||||
postBody: undefined,
|
||||
});
|
||||
}
|
||||
};
|
|
@ -1,93 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ElasticsearchClient } from 'kibana/server';
|
||||
import { asyncForEach } from '@kbn/std';
|
||||
|
||||
import { Transforms } from '../modules/types';
|
||||
import type { Logger } from '../../../../../src/core/server';
|
||||
|
||||
import {
|
||||
computeTransformId,
|
||||
getTransformExists,
|
||||
logTransformError,
|
||||
logTransformInfo,
|
||||
} from './utils';
|
||||
|
||||
interface UninstallTransformsOptions {
|
||||
esClient: ElasticsearchClient;
|
||||
transforms: Transforms[];
|
||||
prefix: string;
|
||||
suffix: string;
|
||||
logger: Logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstalls all the transforms underneath a given module
|
||||
*/
|
||||
export const uninstallTransforms = async ({
|
||||
esClient,
|
||||
logger,
|
||||
prefix,
|
||||
suffix,
|
||||
transforms,
|
||||
}: UninstallTransformsOptions): Promise<void> => {
|
||||
await asyncForEach(transforms, async (transform) => {
|
||||
const { id } = transform;
|
||||
const computedId = computeTransformId({ id, prefix, suffix });
|
||||
const exists = await getTransformExists(esClient, computedId);
|
||||
if (exists) {
|
||||
logTransformInfo({
|
||||
id: computedId,
|
||||
logger,
|
||||
message: 'stopping transform',
|
||||
});
|
||||
try {
|
||||
await esClient.transform.stopTransform({
|
||||
allow_no_match: true,
|
||||
force: true,
|
||||
timeout: '5s',
|
||||
transform_id: computedId,
|
||||
wait_for_completion: true,
|
||||
});
|
||||
} catch (error) {
|
||||
logTransformError({
|
||||
error,
|
||||
id: computedId,
|
||||
logger,
|
||||
message: 'Could not stop transform, still attempting to delete it',
|
||||
postBody: undefined,
|
||||
});
|
||||
}
|
||||
logTransformInfo({
|
||||
id: computedId,
|
||||
logger,
|
||||
message: 'deleting transform',
|
||||
});
|
||||
try {
|
||||
await esClient.transform.deleteTransform({
|
||||
force: true,
|
||||
transform_id: computedId,
|
||||
});
|
||||
} catch (error) {
|
||||
logTransformError({
|
||||
error,
|
||||
id: computedId,
|
||||
logger,
|
||||
message: 'Could not create and/or start',
|
||||
postBody: undefined,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
logTransformInfo({
|
||||
id: computedId,
|
||||
logger,
|
||||
message: 'transform does not exist to delete',
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
|
@ -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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { computeTransformId } from './compute_transform_id';
|
||||
|
||||
export const computeMappingId = ({
|
||||
prefix,
|
||||
id,
|
||||
suffix,
|
||||
}: {
|
||||
prefix: string;
|
||||
id: string;
|
||||
suffix: string;
|
||||
}): string => {
|
||||
// TODO: This causes issues if above 65 character limit. We should limit the prefix
|
||||
// and anything else on the incoming routes to avoid this causing an issue. We should still
|
||||
// throw here in case I change the prefix or other names and cause issues.
|
||||
const computedId = computeTransformId({ id, prefix, suffix });
|
||||
return `.${computedId}`;
|
||||
};
|
|
@ -1,33 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ELASTIC_NAME } from '../../../common/constants';
|
||||
|
||||
export const computeTransformId = ({
|
||||
prefix,
|
||||
id,
|
||||
suffix,
|
||||
}: {
|
||||
prefix: string;
|
||||
id: string;
|
||||
suffix: string;
|
||||
}): string => {
|
||||
const prefixExists = prefix.trim() !== '';
|
||||
const suffixExists = suffix.trim() !== '';
|
||||
|
||||
// TODO: Check for invalid characters on the main route for prefixExists and suffixExists and do an invalidation
|
||||
// if either have invalid characters for a job name. Might want to add that same check within the API too at a top level?
|
||||
if (prefixExists && suffixExists) {
|
||||
return `${ELASTIC_NAME}_${prefix}_${id}_${suffix}`;
|
||||
} else if (prefixExists) {
|
||||
return `${ELASTIC_NAME}_${prefix}_${id}`;
|
||||
} else if (suffixExists) {
|
||||
return `${ELASTIC_NAME}_${id}_${suffix}`;
|
||||
} else {
|
||||
return `${ELASTIC_NAME}_${id}`;
|
||||
}
|
||||
};
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ElasticsearchClient } from 'kibana/server';
|
||||
|
||||
/**
|
||||
* Tried and true, copied forever again and again, the way we check if an index exists
|
||||
* with the least amount of privileges.
|
||||
* @param esClient The client to check if the index already exists
|
||||
* @param index The index to check for
|
||||
* @returns true if it exists, otherwise false
|
||||
*/
|
||||
export const getIndexExists = async (
|
||||
esClient: ElasticsearchClient,
|
||||
index: string
|
||||
): Promise<boolean> => {
|
||||
try {
|
||||
const response = await esClient.search({
|
||||
allow_no_indices: true,
|
||||
body: {
|
||||
terminate_after: 1,
|
||||
},
|
||||
index,
|
||||
size: 0,
|
||||
});
|
||||
return response._shards.total > 0;
|
||||
} catch (err) {
|
||||
if (err.body?.status === 404) {
|
||||
return false;
|
||||
} else {
|
||||
throw err.body ? err.body : err;
|
||||
}
|
||||
}
|
||||
};
|
|
@ -1,10 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
// TODO: Move indent to configuration part or flip to default false
|
||||
export const getJSON = (body: unknown, indent: boolean = true): string =>
|
||||
indent ? JSON.stringify(body, null, 2) : JSON.stringify(body);
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ElasticsearchClient } from 'kibana/server';
|
||||
|
||||
export const getTransformExists = async (
|
||||
esClient: ElasticsearchClient,
|
||||
id: string
|
||||
): Promise<boolean> => {
|
||||
try {
|
||||
const { count } = await esClient.transform.getTransform({
|
||||
size: 1000,
|
||||
transform_id: id,
|
||||
});
|
||||
return count > 0;
|
||||
} catch (err) {
|
||||
if (err.body?.status === 404) {
|
||||
return false;
|
||||
} else {
|
||||
throw err.body ? err.body : err;
|
||||
}
|
||||
}
|
||||
};
|
|
@ -1,17 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
export * from './compute_mapping_index';
|
||||
export * from './compute_transform_id';
|
||||
export * from './get_index_exists';
|
||||
export * from './get_transform_exists';
|
||||
export * from './log_mapping_debug';
|
||||
export * from './log_mapping_error';
|
||||
export * from './log_mapping_info';
|
||||
export * from './log_transform_debug';
|
||||
export * from './log_transform_error';
|
||||
export * from './log_transform_info';
|
|
@ -1,20 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { Logger } from '../../../../../../src/core/server';
|
||||
|
||||
export const logMappingDebug = ({
|
||||
logger,
|
||||
id,
|
||||
message,
|
||||
}: {
|
||||
logger: Logger;
|
||||
id: string;
|
||||
message: string;
|
||||
}): void => {
|
||||
logger.debug(`mapping id: "${id}", ${message}`);
|
||||
};
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { Logger } from '../../../../../../src/core/server';
|
||||
|
||||
import { getJSON } from './get_json';
|
||||
|
||||
export const logMappingError = ({
|
||||
logger,
|
||||
id,
|
||||
message,
|
||||
error,
|
||||
postBody,
|
||||
}: {
|
||||
logger: Logger;
|
||||
id: string;
|
||||
error: unknown;
|
||||
message: string;
|
||||
postBody: {} | undefined;
|
||||
}): void => {
|
||||
const postString = postBody != null ? `, post body: "${getJSON(postBody)}"` : '';
|
||||
logger.error(`${message}, mapping id: "${id}"${postString}, error: ${getJSON(error)}`);
|
||||
};
|
|
@ -1,20 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { Logger } from '../../../../../../src/core/server';
|
||||
|
||||
export const logMappingInfo = ({
|
||||
logger,
|
||||
id,
|
||||
message,
|
||||
}: {
|
||||
logger: Logger;
|
||||
id: string;
|
||||
message: string;
|
||||
}): void => {
|
||||
logger.info(`mapping id: "${id}", ${message}`);
|
||||
};
|
|
@ -1,20 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { Logger } from '../../../../../../src/core/server';
|
||||
|
||||
export const logTransformDebug = ({
|
||||
logger,
|
||||
id,
|
||||
message,
|
||||
}: {
|
||||
logger: Logger;
|
||||
id: string;
|
||||
message: string;
|
||||
}): void => {
|
||||
logger.debug(`transform id: "${id}", ${message}`);
|
||||
};
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { Logger } from '../../../../../../src/core/server';
|
||||
|
||||
import { getJSON } from './get_json';
|
||||
|
||||
export const logTransformError = ({
|
||||
id,
|
||||
logger,
|
||||
error,
|
||||
postBody,
|
||||
message,
|
||||
}: {
|
||||
logger: Logger;
|
||||
id: string;
|
||||
error: unknown;
|
||||
message: string;
|
||||
postBody: {} | undefined;
|
||||
}): void => {
|
||||
const postString = postBody != null ? `, post body: "${getJSON(postBody)}"` : '';
|
||||
logger.error(`${message}, transform id: ${id}${postString}, response error: ${getJSON(error)}`);
|
||||
};
|
|
@ -1,20 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { Logger } from '../../../../../../src/core/server';
|
||||
|
||||
export const logTransformInfo = ({
|
||||
logger,
|
||||
id,
|
||||
message,
|
||||
}: {
|
||||
logger: Logger;
|
||||
id: string;
|
||||
message: string;
|
||||
}): void => {
|
||||
logger.info(`transform id: "${id}", ${message}`);
|
||||
};
|
|
@ -1,36 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ElasticsearchClient, IContextProvider, RequestHandlerContext } from 'kibana/server';
|
||||
|
||||
import { MetricsEntitiesClient } from './services/metrics_entities_client';
|
||||
|
||||
export type GetMetricsEntitiesClientType = (esClient: ElasticsearchClient) => MetricsEntitiesClient;
|
||||
|
||||
export interface MetricsEntitiesPluginSetup {
|
||||
getMetricsEntitiesClient: GetMetricsEntitiesClientType;
|
||||
}
|
||||
|
||||
export type MetricsEntitiesPluginStart = void;
|
||||
|
||||
export type ContextProvider = IContextProvider<
|
||||
MetricsEntitiesRequestHandlerContext,
|
||||
'metricsEntities'
|
||||
>;
|
||||
|
||||
export interface MetricsEntitiesApiRequestHandlerContext {
|
||||
getMetricsEntitiesClient: () => MetricsEntitiesClient;
|
||||
}
|
||||
|
||||
export interface MetricsEntitiesRequestHandlerContext extends RequestHandlerContext {
|
||||
metricsEntities?: MetricsEntitiesApiRequestHandlerContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export type ContextProviderReturn = Promise<MetricsEntitiesApiRequestHandlerContext>;
|
|
@ -1,26 +0,0 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./target/types",
|
||||
"emitDeclarationOnly": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true
|
||||
},
|
||||
"include": [
|
||||
"common/**/*",
|
||||
"public/**/*",
|
||||
"server/**/*",
|
||||
// have to declare *.json explicitly due to https://github.com/microsoft/TypeScript/issues/25636
|
||||
"server/**/*.json",
|
||||
"../../../typings/**/*"
|
||||
],
|
||||
"references": [
|
||||
{ "path": "../../../src/core/tsconfig.json" },
|
||||
{ "path": "../spaces/tsconfig.json" },
|
||||
{ "path": "../security/tsconfig.json" },
|
||||
{ "path": "../licensing/tsconfig.json" },
|
||||
{ "path": "../features/tsconfig.json" },
|
||||
{ "path": "../../../src/plugins/usage_collection/tsconfig.json" },
|
||||
{ "path": "../../../src/plugins/kibana_utils/tsconfig.json" }
|
||||
]
|
||||
}
|
|
@ -5,8 +5,6 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { TransformConfigSchema } from './transforms/types';
|
||||
|
||||
/**
|
||||
* as const
|
||||
*
|
||||
|
@ -54,7 +52,6 @@ export const DEFAULT_INTERVAL_PAUSE = true as const;
|
|||
export const DEFAULT_INTERVAL_TYPE = 'manual' as const;
|
||||
export const DEFAULT_INTERVAL_VALUE = 300000 as const; // ms
|
||||
export const DEFAULT_TIMEPICKER_QUICK_RANGES = 'timepicker:quickRanges' as const;
|
||||
export const DEFAULT_TRANSFORMS = 'securitySolution:transforms' as const;
|
||||
export const SCROLLING_DISABLED_CLASS_NAME = 'scrolling-disabled' as const;
|
||||
export const GLOBAL_HEADER_HEIGHT = 96 as const; // px
|
||||
export const FILTERS_GLOBAL_HEIGHT = 109 as const; // px
|
||||
|
@ -203,38 +200,6 @@ export const IP_REPUTATION_LINKS_SETTING_DEFAULT = `[
|
|||
{ "name": "talosIntelligence.com", "url_template": "https://talosintelligence.com/reputation_center/lookup?search={{ip}}" }
|
||||
]`;
|
||||
|
||||
/** The default settings for the transforms */
|
||||
export const defaultTransformsSetting: TransformConfigSchema = {
|
||||
enabled: false,
|
||||
auto_start: true,
|
||||
auto_create: true,
|
||||
query: {
|
||||
range: {
|
||||
'@timestamp': {
|
||||
gte: 'now-1d/d',
|
||||
format: 'strict_date_optional_time',
|
||||
},
|
||||
},
|
||||
},
|
||||
retention_policy: {
|
||||
time: {
|
||||
field: '@timestamp',
|
||||
max_age: '1w',
|
||||
},
|
||||
},
|
||||
max_page_search_size: 5000,
|
||||
settings: [
|
||||
{
|
||||
prefix: 'all',
|
||||
indices: ['auditbeat-*', 'endgame-*', 'filebeat-*', 'logs-*', 'packetbeat-*', 'winlogbeat-*'],
|
||||
data_sources: [
|
||||
['auditbeat-*', 'endgame-*', 'filebeat-*', 'logs-*', 'packetbeat-*', 'winlogbeat-*'],
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
export const DEFAULT_TRANSFORMS_SETTING = JSON.stringify(defaultTransformsSetting, null, 2);
|
||||
|
||||
/**
|
||||
* Id for the notifications alerting type
|
||||
* @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function
|
||||
|
@ -371,13 +336,6 @@ export const showAllOthersBucket: string[] = [
|
|||
'user.name',
|
||||
];
|
||||
|
||||
/**
|
||||
* Used for transforms for metrics_entities. If the security_solutions pulls in
|
||||
* the metrics_entities plugin, then it should pull this constant from there rather
|
||||
* than use it from here.
|
||||
*/
|
||||
export const ELASTIC_NAME = 'estc' as const;
|
||||
|
||||
export const RISKY_HOSTS_INDEX_PREFIX = 'ml_host_risk_score_' as const;
|
||||
|
||||
export const RISKY_USERS_INDEX_PREFIX = 'ml_user_risk_score_' as const;
|
||||
|
|
|
@ -12,7 +12,6 @@ export type ExperimentalFeatures = typeof allowedExperimentalValues;
|
|||
* This object is then used to validate and parse the value entered.
|
||||
*/
|
||||
export const allowedExperimentalValues = Object.freeze({
|
||||
metricsEntitiesEnabled: false,
|
||||
ruleRegistryEnabled: true,
|
||||
tGridEnabled: true,
|
||||
tGridEventRenderedViewEnabled: true,
|
||||
|
|
|
@ -17,7 +17,6 @@ export enum HostsQueries {
|
|||
details = 'hostDetails',
|
||||
firstOrLastSeen = 'firstOrLastSeen',
|
||||
hosts = 'hosts',
|
||||
hostsEntities = 'hostsEntities',
|
||||
overview = 'overviewHost',
|
||||
uncommonProcesses = 'uncommonProcesses',
|
||||
}
|
||||
|
|
|
@ -12,8 +12,6 @@ import { HostsKpiHistogramData } from '../common';
|
|||
|
||||
export interface HostsKpiAuthenticationsHistogramCount {
|
||||
doc_count: number;
|
||||
// TODO: Should I keep this or split this interface into two for entities and non-entities?
|
||||
value?: number;
|
||||
}
|
||||
|
||||
export type HostsKpiAuthenticationsRequestOptions = RequestBasicOptions;
|
||||
|
|
|
@ -16,11 +16,8 @@ import { HostsKpiUniqueIpsStrategyResponse } from './unique_ips';
|
|||
|
||||
export enum HostsKpiQueries {
|
||||
kpiAuthentications = 'hostsKpiAuthentications',
|
||||
kpiAuthenticationsEntities = 'hostsKpiAuthenticationsEntities',
|
||||
kpiHosts = 'hostsKpiHosts',
|
||||
kpiHostsEntities = 'hostsKpiHostsEntities',
|
||||
kpiUniqueIps = 'hostsKpiUniqueIps',
|
||||
kpiUniqueIpsEntities = 'hostsKpiUniqueIpsEntities',
|
||||
}
|
||||
|
||||
export type HostsKpiStrategyResponse =
|
||||
|
|
|
@ -59,7 +59,6 @@ import {
|
|||
} from './network';
|
||||
import {
|
||||
MatrixHistogramQuery,
|
||||
MatrixHistogramQueryEntities,
|
||||
MatrixHistogramRequestOptions,
|
||||
MatrixHistogramStrategyResponse,
|
||||
} from './matrix_histogram';
|
||||
|
@ -106,8 +105,7 @@ export type FactoryQueryTypes =
|
|||
| NetworkKpiQueries
|
||||
| RiskQueries
|
||||
| CtiQueries
|
||||
| typeof MatrixHistogramQuery
|
||||
| typeof MatrixHistogramQueryEntities;
|
||||
| typeof MatrixHistogramQuery;
|
||||
|
||||
export interface RequestBasicOptions extends IEsSearchRequest {
|
||||
timerange: TimerangeInput;
|
||||
|
|
|
@ -25,11 +25,9 @@ export * from './events';
|
|||
export * from './preview';
|
||||
|
||||
export const MatrixHistogramQuery = 'matrixHistogram';
|
||||
export const MatrixHistogramQueryEntities = 'matrixHistogramEntities';
|
||||
|
||||
export enum MatrixHistogramType {
|
||||
authentications = 'authentications',
|
||||
authenticationsEntities = 'authenticationsEntities',
|
||||
anomalies = 'anomalies',
|
||||
events = 'events',
|
||||
alerts = 'alerts',
|
||||
|
@ -41,7 +39,6 @@ export const MatrixHistogramTypeToAggName = {
|
|||
[MatrixHistogramType.alerts]: 'aggregations.alertsGroup.buckets',
|
||||
[MatrixHistogramType.anomalies]: 'aggregations.anomalyActionGroup.buckets',
|
||||
[MatrixHistogramType.authentications]: 'aggregations.eventActionGroup.buckets',
|
||||
[MatrixHistogramType.authenticationsEntities]: 'aggregations.events.buckets',
|
||||
[MatrixHistogramType.dns]: 'aggregations.dns_name_query_count.buckets',
|
||||
[MatrixHistogramType.events]: 'aggregations.eventActionGroup.buckets',
|
||||
[MatrixHistogramType.preview]: 'aggregations.preview.buckets',
|
||||
|
|
|
@ -23,8 +23,6 @@ export enum NetworkQueries {
|
|||
overview = 'overviewNetwork',
|
||||
tls = 'tls',
|
||||
topCountries = 'topCountries',
|
||||
topCountriesEntities = 'topCountriesEntities',
|
||||
topNFlow = 'topNFlow',
|
||||
topNFlowEntities = 'topNFlowEntities',
|
||||
users = 'users',
|
||||
}
|
||||
|
|
|
@ -19,14 +19,10 @@ import { NetworkKpiUniquePrivateIpsStrategyResponse } from './unique_private_ips
|
|||
|
||||
export enum NetworkKpiQueries {
|
||||
dns = 'networkKpiDns',
|
||||
dnsEntities = 'networkKpiDnsEntities',
|
||||
networkEvents = 'networkKpiNetworkEvents',
|
||||
networkEventsEntities = 'networkKpiNetworkEventsEntities',
|
||||
tlsHandshakes = 'networkKpiTlsHandshakes',
|
||||
tlsHandshakesEntities = 'networkKpiTlsHandshakesEntities',
|
||||
uniqueFlows = 'networkKpiUniqueFlows',
|
||||
uniquePrivateIps = 'networkKpiUniquePrivateIps',
|
||||
uniquePrivateIpsEntities = 'networkKpiUniquePrivateIpsEntities',
|
||||
}
|
||||
|
||||
export type NetworkKpiStrategyResponse =
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue